diff --git a/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp b/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp index 4df193b536..f6b6e5db98 100644 --- a/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp @@ -727,7 +727,7 @@ error_code cellHttpUtilFormUrlDecode(vm::ptr out, u32 size, vm::cptr i return CELL_HTTP_UTIL_ERROR_INVALID_URI; } - const auto FUN_00036710 = [](b8 c) + const auto check_char = [](b8 c) { u32 utmp = static_cast(c); s32 stmp = utmp - 48; @@ -746,8 +746,8 @@ error_code cellHttpUtilFormUrlDecode(vm::ptr out, u32 size, vm::cptr i return stmp; }; - const s32 tmp1 = FUN_00036710(c2); - const s32 tmp2 = FUN_00036710(c3); + const s32 tmp1 = check_char(c2); + const s32 tmp2 = check_char(c3); if (tmp1 < 0 || tmp2 < 0) { diff --git a/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp b/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp index 40628668d1..dc8336f66d 100644 --- a/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/IdManager.h" #include "cellPngEnc.h" +#include "png.h" LOG_CHANNEL(cellPngEnc); @@ -27,57 +29,199 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +struct png_encoder +{ + shared_mutex mutex; + CellPngEncConfig config{}; + CellPngEncResource resource{}; + CellPngEncResourceEx resourceEx{}; +}; + +bool check_config(vm::cptr config) +{ + if (!config || + config->maxWidth == 0 || config->maxWidth > 1000000 || + config->maxHeight == 0 || config->maxHeight > 1000000 || + config->maxBitDepth != 8 && config->maxBitDepth != 16 || + static_cast(config->addMemSize) < 0 || + config->exParamNum != 0) + { + return false; + } + + return true; +} + +u32 get_mem_size(vm::cptr config) +{ + return config->addMemSize + + (config->enableSpu ? 0x78200 : 0x47a00) + + (config->maxBitDepth >> 1) * config->maxWidth * 7; +} + + error_code cellPngEncQueryAttr(vm::cptr config, vm::ptr attr) { cellPngEnc.todo("cellPngEncQueryAttr(config=*0x%x, attr=*0x%x)", config, attr); + + if (!attr || !check_config(config)) + { + return CELL_PNGENC_ERROR_ARG; + } + + const u32 memsize = get_mem_size(config); + attr->memSize = memsize + 0x1780; + attr->cmdQueueDepth = 4; + attr->versionLower = 0; + attr->versionUpper = 0x270000; + return CELL_OK; } -error_code cellPngEncOpen(vm::cptr config, vm::cptr resource, vm::pptr handle) +error_code cellPngEncOpen(vm::cptr config, vm::cptr resource, vm::ptr handle) { - cellPngEnc.todo("cellPngEncOpen(config=*0x%x, resource=*0x%x, handle=*0x%x)", config, resource, handle); + cellPngEnc.todo("cellPngEncOpen(config=*0x%x, resource=*0x%x, handle=0x%x)", config, resource, handle); + + if (!handle || !check_config(config) || + !resource || !resource->memAddr || !resource->memSize || + resource->ppuThreadPriority < 0 || resource->ppuThreadPriority > 0xbff || + resource->spuThreadPriority < 0 || resource->ppuThreadPriority > 0xff) + { + return CELL_PNGENC_ERROR_ARG; + } + + const u32 required_memsize = get_mem_size(config); + + if (resource->memSize < required_memsize + 0x1780U) + { + return CELL_PNGENC_ERROR_ARG; + } + + auto& encoder = g_fxo->get(); + { + std::lock_guard lock(encoder.mutex); + encoder.config = *config; + encoder.resource = *resource; + } + return CELL_OK; } -error_code cellPngEncOpenEx(vm::cptr config, vm::cptr resourceEx, vm::pptr handle) +error_code cellPngEncOpenEx(vm::cptr config, vm::cptr resource, vm::ptr handle) { - cellPngEnc.todo("cellPngEncOpenEx(config=*0x%x, resourceEx=*0x%x, handle=*0x%x)", config, resourceEx, handle); + cellPngEnc.todo("cellPngEncOpenEx(config=*0x%x, resourceEx=*0x%x, handle=0x%x)", config, resource, handle); + + if (!handle || !check_config(config) || + !resource || !resource->memAddr || !resource->memSize || + resource->ppuThreadPriority < 0 || resource->ppuThreadPriority > 0xbff || + resource->priority[0] > 15 || resource->priority[1] > 15 || + resource->priority[2] > 15 || resource->priority[3] > 15 || + resource->priority[4] > 15 || resource->priority[5] > 15 || + resource->priority[6] > 15 || resource->priority[7] > 15) + { + return CELL_PNGENC_ERROR_ARG; + } + + const u32 required_memsize = get_mem_size(config); + + if (resource->memSize < required_memsize + 0x1780U) + { + return CELL_PNGENC_ERROR_ARG; + } + + auto& encoder = g_fxo->get(); + { + std::lock_guard lock(encoder.mutex); + encoder.config = *config; + encoder.resourceEx = *resource; + } + return CELL_OK; } -error_code cellPngEncClose(vm::ptr handle) +error_code cellPngEncClose(u32 handle) { - cellPngEnc.todo("cellPngEncClose(handle=*0x%x)", handle); + cellPngEnc.todo("cellPngEncClose(handle=0x%x)", handle); + + if (!handle) + { + return CELL_PNGENC_ERROR_ARG; + } + return CELL_OK; } -error_code cellPngEncWaitForInput(vm::ptr handle, b8 block) +error_code cellPngEncWaitForInput(u32 handle, b8 block) { - cellPngEnc.todo("cellPngEncWaitForInput(handle=*0x%x, block=%d)", handle, block); + cellPngEnc.todo("cellPngEncWaitForInput(handle=0x%x, block=%d)", handle, block); + + if (!handle) + { + return CELL_PNGENC_ERROR_ARG; + } + return CELL_OK; } -error_code cellPngEncEncodePicture(vm::ptr handle, vm::cptr picture, vm::cptr encodeParam, vm::cptr outputParam) +error_code cellPngEncEncodePicture(u32 handle, vm::cptr picture, vm::cptr encodeParam, vm::cptr outputParam) { - cellPngEnc.todo("cellPngEncEncodePicture(handle=*0x%x, picture=*0x%x, encodeParam=*0x%x, outputParam=*0x%x)", handle, picture, encodeParam, outputParam); + cellPngEnc.todo("cellPngEncEncodePicture(handle=0x%x, picture=*0x%x, encodeParam=*0x%x, outputParam=*0x%x)", handle, picture, encodeParam, outputParam); + + if (!handle || !picture || !picture->width || !picture->height || + (picture->packedPixel && picture->bitDepth >= 8) || + !picture->pictureAddr || picture->colorSpace > CELL_PNGENC_COLOR_SPACE_ARGB) + { + return CELL_PNGENC_ERROR_ARG; + } + + auto& encoder = g_fxo->get(); + { + std::lock_guard lock(encoder.mutex); + + if (picture->width > encoder.config.maxWidth || + picture->height > encoder.config.maxHeight || + picture->bitDepth > encoder.config.maxBitDepth) + { + return CELL_PNGENC_ERROR_ARG; + } + } + return CELL_OK; } -error_code cellPngEncWaitForOutput(vm::ptr handle, vm::ptr streamInfoNum, b8 block) +error_code cellPngEncWaitForOutput(u32 handle, vm::ptr streamInfoNum, b8 block) { - cellPngEnc.todo("cellPngEncWaitForOutput(handle=*0x%x, streamInfoNum=*0x%x, block=%d)", handle, streamInfoNum, block); + cellPngEnc.todo("cellPngEncWaitForOutput(handle=0x%x, streamInfoNum=*0x%x, block=%d)", handle, streamInfoNum, block); + + if (!handle || !streamInfoNum) + { + return CELL_PNGENC_ERROR_ARG; + } + return CELL_OK; } -error_code cellPngEncGetStreamInfo(vm::ptr handle, vm::ptr streamInfo) +error_code cellPngEncGetStreamInfo(u32 handle, vm::ptr streamInfo) { - cellPngEnc.todo("cellPngEncGetStreamInfo(handle=*0x%x, streamInfo=*0x%x)", handle, streamInfo); + cellPngEnc.todo("cellPngEncGetStreamInfo(handle=0x%x, streamInfo=*0x%x)", handle, streamInfo); + + if (!handle || !streamInfo) + { + return CELL_PNGENC_ERROR_ARG; + } + return CELL_OK; } -error_code cellPngEncReset(vm::ptr handle) +error_code cellPngEncReset(u32 handle) { - cellPngEnc.todo("cellPngEncReset(handle=*0x%x)", handle); + cellPngEnc.todo("cellPngEncReset(handle=0x%x)", handle); + + if (!handle) + { + return CELL_PNGENC_ERROR_ARG; + } + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellPngEnc.h b/rpcs3/Emu/Cell/Modules/cellPngEnc.h index 81ab2885fe..1ab0e87c86 100644 --- a/rpcs3/Emu/Cell/Modules/cellPngEnc.h +++ b/rpcs3/Emu/Cell/Modules/cellPngEnc.h @@ -78,32 +78,34 @@ enum CellPngEncLocation //typedef void *CellPngEncHandle; -struct CellPngEncExParam +struct CellPngEncExParam // Size 8 { be_t index; vm::bptr value; }; -struct CellPngEncConfig +struct CellPngEncConfig // Size 28 { be_t maxWidth; be_t maxHeight; be_t maxBitDepth; b8 enableSpu; + u8 padding[3]; be_t addMemSize; vm::bptr exParamList; be_t exParamNum; }; -struct CellPngEncAttr +struct CellPngEncAttr // Size 16 { be_t memSize; // usz u8 cmdQueueDepth; + u8 padding[3]; be_t versionUpper; be_t versionLower; }; -struct CellPngEncResource +struct CellPngEncResource // Size 16 { vm::bptr memAddr; be_t memSize; // usz @@ -111,7 +113,7 @@ struct CellPngEncResource be_t spuThreadPriority; }; -struct CellPngEncResourceEx +struct CellPngEncResourceEx // Size 24 { vm::bptr memAddr; be_t memSize; // usz @@ -120,7 +122,7 @@ struct CellPngEncResourceEx u8 priority[8]; }; -struct CellPngEncPicture +struct CellPngEncPicture // Size 40 { be_t width; be_t height; @@ -128,19 +130,21 @@ struct CellPngEncPicture be_t colorSpace; // CellPngEncColorSpace be_t bitDepth; b8 packedPixel; + u8 padding[3]; // TODO: is this correct? vm::bptr pictureAddr; be_t userData; }; -struct CellPngEncAncillaryChunk +struct CellPngEncAncillaryChunk // Size 8 { be_t chunkType; // CellPngEncChunkType vm::bptr chunkData; }; -struct CellPngEncEncodeParam +struct CellPngEncEncodeParam // Size 24 { b8 enableSpu; + u8 padding[3]; be_t encodeColorSpace; // CellPngEncColorSpace be_t compressionLevel; // CellPngEncCompressionLevel be_t filterType; @@ -148,7 +152,7 @@ struct CellPngEncEncodeParam be_t ancillaryChunkNum; }; -struct CellPngEncOutputParam +struct CellPngEncOutputParam // Size 16 { be_t location; // CellPngEncLocation vm::bcptr streamFileName; @@ -156,7 +160,7 @@ struct CellPngEncOutputParam be_t limitSize; // usz }; -struct CellPngEncStreamInfo +struct CellPngEncStreamInfo // Size 40 { be_t state; be_t location; // CellPngEncLocation @@ -166,4 +170,5 @@ struct CellPngEncStreamInfo be_t streamSize; // usz be_t processedLine; be_t userData; + // TODO: where are the missing 4 bytes? };