Skip to content

Commit cfd9a8e

Browse files
committed
Improvements
1 parent 890e915 commit cfd9a8e

3 files changed

Lines changed: 38 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3131
- EffectModule - Refactor and stablising
3232
- EffectFileHandler: Refactor effect file management
3333
- EffectEngine: Added dedicated `hyperion.effect` debug logging category
34-
- Empty image consistency applied. An image sized 1x1 is not treated as an empty one any longer, only 0x0 is empty.
34+
- Empty image consistency applied. 0×0 is now the canonical empty image; 1×1 is no longer treated as empty
3535

3636
## [2.2.1](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.2.1) - 2026-04-06
3737

libsrc/effectengine/EffectFileHandler.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,18 @@ QString EffectFileHandler::saveEffectImage(const QJsonObject& message, const QJs
190190
return "";
191191

192192
QJsonObject args = message["args"].toObject();
193-
const QString effectsDirPath = effectArray[0].toString().replace("$ROOT", _rootPath);
194-
const QString effectsDirAbs = QFileInfo(effectsDirPath).absoluteFilePath();
195-
const QString imageFilePath = effectsDirPath + '/' + args.value("file").toString();
196-
const QFileInfo imageFileName(imageFilePath);
197-
if (!imageFileName.absoluteFilePath().startsWith(effectsDirAbs + '/'))
198-
return QString("Invalid image file path '%1'.").arg(args.value("file").toString());
199-
200-
if (!FileUtils::writeFile(imageFileName.absoluteFilePath(), QByteArray::fromBase64(message["imageData"].toString("").toUtf8()), _log))
201-
return QString("Error while saving image file '%1', please check the Hyperion Log").arg(message["args"].toObject().value("file").toString());
193+
const QString requestedFile = args.value("file").toString();
194+
if (requestedFile.contains('/') || requestedFile.contains('\\') || requestedFile.contains(".."))
195+
return QString("Invalid image file path '%1'.").arg(requestedFile);
196+
197+
const QDir effectsDir(effectArray[0].toString().replace("$ROOT", _rootPath));
198+
const QString effectsDirAbs = QDir::cleanPath(effectsDir.absolutePath());
199+
const QString imageFilePath = QDir::cleanPath(effectsDir.absoluteFilePath(requestedFile));
200+
if (!imageFilePath.startsWith(effectsDirAbs + QDir::separator()))
201+
return QString("Invalid image file path '%1'.").arg(requestedFile);
202+
203+
if (!FileUtils::writeFile(imageFilePath, QByteArray::fromBase64(message["imageData"].toString("").toUtf8()), _log))
204+
return QString("Error while saving image file '%1', please check the Hyperion Log").arg(requestedFile);
202205

203206
args["file"] = imageFilePath;
204207
effectJson["args"] = args;

libsrc/effectengine/EffectModule.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <cmath>
2+
#include <limits>
23

34
#include <effectengine/Effect.h>
45
#include <effectengine/EffectModule.h>
@@ -277,12 +278,26 @@ PyObject* EffectModule::wrapSetImage(PyObject* /*self*/, PyObject* args)
277278
{
278279
if (PyByteArray_Check(bytearray))
279280
{
281+
if (width <= 0 || height <= 0)
282+
{
283+
PyErr_SetString(PyExc_ValueError, "Image width and height must be positive");
284+
return nullptr;
285+
}
286+
280287
Py_ssize_t length = PyByteArray_Size(bytearray);
281-
if (length == 3 * width * height)
288+
const uint64_t pixelCount = static_cast<uint64_t>(width) * static_cast<uint64_t>(height);
289+
if (pixelCount > static_cast<uint64_t>(std::numeric_limits<Py_ssize_t>::max()) / 3U)
290+
{
291+
PyErr_SetString(PyExc_OverflowError, "Image dimensions are too large");
292+
return nullptr;
293+
}
294+
295+
const Py_ssize_t expectedLength = static_cast<Py_ssize_t>(pixelCount * 3U);
296+
if (length == expectedLength)
282297
{
283298
Image<ColorRgb> image(width, height);
284299
const char* data = PyByteArray_AS_STRING(bytearray);
285-
memcpy(image.memptr(), data, length);
300+
memcpy(image.memptr(), data, static_cast<size_t>(length));
286301
emit getEffect()->setInputImage(getEffect()->_priority, image, getEffect()->getRemaining(), false);
287302
Py_RETURN_NONE;
288303
}
@@ -906,7 +921,12 @@ PyObject* EffectModule::wrapImageDrawPie(PyObject* /*self*/, PyObject* args)
906921
(uint8_t)(data[idx + 4])
907922
));
908923
}
924+
909925
painter->setBrush(gradient);
926+
QPen oldPen = painter->pen();
927+
painter->setPen(Qt::NoPen);
928+
painter->drawPie(centerX - radius, centerY - radius, radius * 2, radius * 2, startAngle * 16, spanAngle * 16);
929+
painter->setPen(oldPen);
910930
Py_RETURN_NONE;
911931
}
912932

@@ -1185,11 +1205,10 @@ PyObject* EffectModule::wrapImageCOffset(PyObject* /*self*/, PyObject* args)
11851205
{
11861206
int offsetX = 0;
11871207
int offsetY = 0;
1188-
Py_ssize_t argCount = PyTuple_Size(args);
1189-
1190-
if (argCount == 2)
1208+
if (!PyArg_ParseTuple(args, "ii", &offsetX, &offsetY))
11911209
{
1192-
PyArg_ParseTuple(args, "ii", &offsetX, &offsetY);
1210+
if (!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "Invalid argument count or type."); }
1211+
return nullptr;
11931212
}
11941213

11951214
getEffect()->_painter->translate(QPoint(offsetX, offsetY));

0 commit comments

Comments
 (0)