From a51dd094212564faf151d31f95217430cb6b53dc Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sun, 19 Apr 2020 23:04:07 -0700 Subject: [PATCH] jpegdec: cleanup results to use atmosphere style --- .../impl/ams_system_thread_definitions.hpp | 1 + .../vapours/results/capsrv_results.hpp | 103 +++++++++--------- stratosphere/jpegdec/jpegdec.json | 3 + .../jpegdec/source/impl/jpegdec_turbo.cpp | 64 ++++++----- .../jpegdec/source/jpegdec_decode_service.cpp | 26 +++-- stratosphere/jpegdec/source/jpegdec_main.cpp | 7 +- 6 files changed, 114 insertions(+), 90 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp b/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp index 029df0fbe..82da25ee9 100644 --- a/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp +++ b/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp @@ -102,6 +102,7 @@ namespace ams::impl { AMS_DEFINE_SYSTEM_THREAD(21, erpt, Main); AMS_DEFINE_SYSTEM_THREAD(21, erpt, IpcServer); + /* jpegdec. */ AMS_DEFINE_SYSTEM_THREAD(21, jpegdec, Main); /* pgl. */ diff --git a/libraries/libvapours/include/vapours/results/capsrv_results.hpp b/libraries/libvapours/include/vapours/results/capsrv_results.hpp index 4b5e20af7..809b18215 100644 --- a/libraries/libvapours/include/vapours/results/capsrv_results.hpp +++ b/libraries/libvapours/include/vapours/results/capsrv_results.hpp @@ -20,67 +20,72 @@ namespace ams::capsrv { R_DEFINE_NAMESPACE_RESULT_MODULE(206); - R_DEFINE_ERROR_RESULT(InvalidArgument, 2); - R_DEFINE_ERROR_RESULT(OutOfMemory, 3); + R_DEFINE_ERROR_RANGE(AlbumError, 2, 99); + R_DEFINE_ERROR_RESULT(AlbumWorkMemoryError, 3); - R_DEFINE_ERROR_RESULT(InvalidState, 7); - R_DEFINE_ERROR_RESULT(OutOfRange, 8); + R_DEFINE_ERROR_RESULT(AlbumAlreadyOpened, 7); + R_DEFINE_ERROR_RESULT(AlbumOutOfRange, 8); - R_DEFINE_ERROR_RESULT(InvalidApplicationId, 10); - R_DEFINE_ERROR_RESULT(InvalidUnknown, 11); - R_DEFINE_ERROR_RESULT(InvalidFileId, 12); - R_DEFINE_ERROR_RESULT(InvalidStorageId, 13); - R_DEFINE_ERROR_RESULT(InvalidContentType, 14); + R_DEFINE_ERROR_RANGE(AlbumInvalidFileId, 10, 19); + R_DEFINE_ERROR_RESULT(AlbumInvalidApplicationId, 11); + R_DEFINE_ERROR_RESULT(AlbumInvalidTimestamp, 12); + R_DEFINE_ERROR_RESULT(AlbumInvalidStorage, 13); + R_DEFINE_ERROR_RESULT(AlbumInvalidFileContents, 14); - R_DEFINE_ERROR_RESULT(FailedToMountImageDirectory, 21); - R_DEFINE_ERROR_RESULT(ReachedSizeLimit, 22); - R_DEFINE_ERROR_RESULT(FileInaccessible, 23); - R_DEFINE_ERROR_RESULT(InvalidFileData, 24); - R_DEFINE_ERROR_RESULT(ReachedCountLimit, 25); - R_DEFINE_ERROR_RESULT(InvalidThumbnail, 26); + R_DEFINE_ERROR_RESULT(AlbumIsNotMounted, 21); + R_DEFINE_ERROR_RESULT(AlbumIsFull, 22); + R_DEFINE_ERROR_RESULT(AlbumFileNotFound, 23); + R_DEFINE_ERROR_RESULT(AlbumInvalidFileData, 24); + R_DEFINE_ERROR_RESULT(AlbumFileCountLimit, 25); + R_DEFINE_ERROR_RESULT(AlbumFileNoThumbnail, 26); - R_DEFINE_ERROR_RESULT(BufferInsufficient, 30); + R_DEFINE_ERROR_RESULT(AlbumReadBufferShortage, 30); - R_DEFINE_ERROR_RESULT(FileReserved, 94); - R_DEFINE_ERROR_RESULT(FileReservedRead, 96); + R_DEFINE_ERROR_RANGE(AlbumFileSystemError, 90, 99); + R_DEFINE_ERROR_RANGE(AlbumAccessCorrupted, 94, 96); + R_DEFINE_ERROR_RESULT(AlbumDestinationAccessCorrupted, 96); - R_DEFINE_ERROR_RESULT(TooManyApplicationsRegistered, 820); - R_DEFINE_ERROR_RESULT(ApplicationNotRegistered, 822); + R_DEFINE_ERROR_RANGE(ControlError, 800, 899); + R_DEFINE_ERROR_RESULT(ControlResourceLimit, 820); + R_DEFINE_ERROR_RESULT(ControlNotOpened, 822); - R_DEFINE_ERROR_RESULT(DebugModeDisabled, 1023); - R_DEFINE_ERROR_RESULT(InvalidMakerNote, 1024); + R_DEFINE_ERROR_RESULT(NotSupported, 1023); - R_DEFINE_ERROR_RESULT(OutOfWorkMemory, 1212); + R_DEFINE_ERROR_RANGE(InternalError, 1024, 2047); + R_DEFINE_ERROR_RESULT(InternalJpegWorkMemoryShortage, 1212); - R_DEFINE_ERROR_RANGE(JpegMeta, 1300, 1399); - R_DEFINE_ERROR_RESULT(ContentTypeMissmatch, 1300); - R_DEFINE_ERROR_RESULT(InvalidJPEG, 1301); - R_DEFINE_ERROR_RESULT(InvalidJFIF, 1302); - R_DEFINE_ERROR_RESULT(InvalidEXIF, 1303); - R_DEFINE_ERROR_RESULT(MissingDateTime, 1304); - R_DEFINE_ERROR_RESULT(InvalidDateTimeLength, 1305); - R_DEFINE_ERROR_RESULT(DateTimeMissmatch, 1306); - R_DEFINE_ERROR_RESULT(MissingMakerNote, 1307); - R_DEFINE_ERROR_RESULT(ApplicationIdMissmatch, 1308); - R_DEFINE_ERROR_RESULT(InvalidMacHash, 1309); - R_DEFINE_ERROR_RESULT(InvalidOrientation, 1310); - R_DEFINE_ERROR_RESULT(InvalidDimension, 1311); - R_DEFINE_ERROR_RESULT(MakerNoteUnk, 1312); + R_DEFINE_ERROR_RANGE(InternalFileDataVerificationError, 1300, 1399); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationEmptyFileData, 1301); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationExifExtractionFailed, 1302); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationExifAnalyzationFailed, 1303); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationDateTimeExtractionFailed, 1304); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationInvalidDateTimeLength, 1305); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationInconsistentDateTime, 1306); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationMakerNoteExtractionFailed, 1307); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationInconsistentApplicationId, 1308); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationInconsistentSignature, 1309); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationUnsupportedOrientation, 1310); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationInvalidDataDimension, 1311); + R_DEFINE_ERROR_RESULT(InternalFileDataVerificationInconsistentOrientation, 1312); - R_DEFINE_ERROR_RESULT(TooManyFiles, 1401); + R_DEFINE_ERROR_RANGE(InternalAlbumLimitationError, 1400, 1499); + R_DEFINE_ERROR_RESULT(InternalAlbumLimitationFileCountLimit, 1401); - R_DEFINE_ERROR_RESULT(InvalidJpegHeader, 1501); - R_DEFINE_ERROR_RESULT(InvalidJpegSize, 1502); + R_DEFINE_ERROR_RANGE(InternalSignatureError, 1500, 1599); + R_DEFINE_ERROR_RESULT(InternalSignatureExifExtractionFailed, 1501); + R_DEFINE_ERROR_RESULT(InternalSignatureMakerNoteExtractionFailed, 1502); - R_DEFINE_ERROR_RESULT(SessionAllocationFailure, 1701); + R_DEFINE_ERROR_RANGE(InternalAlbumSessionError, 1700, 1799); + R_DEFINE_ERROR_RESULT(InternalAlbumLimitationSessionCountLimit, 1701); - R_DEFINE_ERROR_RANGE(TemporaryFile, 1900, 1999); - R_DEFINE_ERROR_RESULT(TemporaryFileMaxCountReached, 1901); - R_DEFINE_ERROR_RESULT(TemporaryFileOpenFailed, 1902); - R_DEFINE_ERROR_RESULT(TemporaryFileAccessFailed, 1903); - R_DEFINE_ERROR_RESULT(TemporaryFileGetCountFailed, 1904); - R_DEFINE_ERROR_RESULT(TemporaryFileSetSizeFailed, 1906); - R_DEFINE_ERROR_RESULT(TemporaryFileReadFailed, 1907); - R_DEFINE_ERROR_RESULT(TemporaryFileWriteFailed, 1908); + R_DEFINE_ERROR_RANGE(InternalAlbumTemporaryFileError, 1900, 1999); + R_DEFINE_ERROR_RESULT(InternalAlbumTemporaryFileCountLimit, 1901); + R_DEFINE_ERROR_RESULT(InternalAlbumTemporaryFileCreateError, 1902); + R_DEFINE_ERROR_RESULT(InternalAlbumTemporaryFileCreateRetryCountLimit, 1903); + R_DEFINE_ERROR_RESULT(InternalAlbumTemporaryFileOpenError, 1904); + R_DEFINE_ERROR_RESULT(InternalAlbumTemporaryFileGetFileSizeError, 1905); + R_DEFINE_ERROR_RESULT(InternalAlbumTemporaryFileSetFileSizeError, 1906); + R_DEFINE_ERROR_RESULT(InternalAlbumTemporaryFileReadFileError, 1907); + R_DEFINE_ERROR_RESULT(InternalAlbumTemporaryFileWriteFileError, 1908); } diff --git a/stratosphere/jpegdec/jpegdec.json b/stratosphere/jpegdec/jpegdec.json index 6c69a8350..43b4fdc07 100644 --- a/stratosphere/jpegdec/jpegdec.json +++ b/stratosphere/jpegdec/jpegdec.json @@ -90,5 +90,8 @@ }, { "type": "min_kernel_version", "value": "0x0030" + }, { + "type": "handle_table_size", + "value": 16 }] } \ No newline at end of file diff --git a/stratosphere/jpegdec/source/impl/jpegdec_turbo.cpp b/stratosphere/jpegdec/source/impl/jpegdec_turbo.cpp index 220a7c357..e1cc657c1 100644 --- a/stratosphere/jpegdec/source/impl/jpegdec_turbo.cpp +++ b/stratosphere/jpegdec/source/impl/jpegdec_turbo.cpp @@ -19,10 +19,25 @@ namespace ams::jpegdec::impl { + #define CAPSRV_ABORT_UNLESS(expr) { \ + const bool __capsrv_assert_res = (expr); \ + AMS_ASSERT(__capsrv_assert_res); \ + AMS_ABORT_UNLESS(__capsrv_assert_res); \ + } while (0) + + #define CAPSRV_ASSERT(expr) do { \ + const bool __capsrv_assert_res = (expr); \ + AMS_ASSERT(__capsrv_assert_res); \ + R_UNLESS(__capsrv_assert_res, capsrv::ResultAlbumError()); \ + } while (0) + namespace { - constexpr const size_t LinebufferCount = 4; - constexpr const size_t ColorComponents = 3; + constexpr size_t LinebufferCount = 4; + constexpr size_t ColorComponents = 3; + + constexpr int ImageSizeHorizonalUnit = 0x10; + constexpr int ImageSizeVerticalUnit = 0x4; struct RGB { u8 r, g, b; @@ -38,18 +53,18 @@ namespace ams::jpegdec::impl { } Result DecodeJpeg(DecodeOutput &out, const DecodeInput &in, u8 *work, size_t work_size) { - AMS_ASSERT(util::IsAligned(in.width, 0x10)); - AMS_ASSERT(util::IsAligned(in.height, 0x4)); + CAPSRV_ABORT_UNLESS(util::IsAligned(in.width, ImageSizeHorizonalUnit)); + CAPSRV_ABORT_UNLESS(util::IsAligned(in.height, ImageSizeVerticalUnit)); - AMS_ASSERT(out.bmp != nullptr); - AMS_ASSERT(out.bmp_size >= 4 * in.width * in.height); + CAPSRV_ABORT_UNLESS(out.bmp != nullptr); + CAPSRV_ABORT_UNLESS(out.bmp_size >= 4 * in.width * in.height); - AMS_ASSERT(out.width != nullptr); - AMS_ASSERT(out.height != nullptr); + CAPSRV_ABORT_UNLESS(out.width != nullptr); + CAPSRV_ABORT_UNLESS(out.height != nullptr); const size_t linebuffer_size = ColorComponents * in.width; const size_t total_linebuffer_size = LinebufferCount * linebuffer_size; - R_UNLESS(work_size >= total_linebuffer_size, capsrv::ResultOutOfWorkMemory()); + R_UNLESS(work_size >= total_linebuffer_size, capsrv::ResultInternalJpegWorkMemoryShortage()); jpeg_decompress_struct cinfo; std::memset(&cinfo, 0, sizeof(cinfo)); @@ -60,7 +75,7 @@ namespace ams::jpegdec::impl { cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = JpegErrorExit; - /* ? */ + /* TODO: Here Nintendo uses setjmp, on longjmp to error ResultAlbumInvalidFileData is returned. */ jpeg_create_decompress(&cinfo); @@ -70,27 +85,22 @@ namespace ams::jpegdec::impl { jpeg_mem_src(&cinfo, in.jpeg, in.jpeg_size); - int res = jpeg_read_header(&cinfo, true); + R_UNLESS(jpeg_read_header(&cinfo, true) == JPEG_HEADER_OK, capsrv::ResultAlbumInvalidFileData()); - R_UNLESS(res == JPEG_HEADER_OK, capsrv::ResultInvalidFileData()); - - R_UNLESS(cinfo.image_width == in.width, capsrv::ResultInvalidFileData()); - R_UNLESS(cinfo.image_height == in.height, capsrv::ResultInvalidFileData()); + R_UNLESS(cinfo.image_width == in.width, capsrv::ResultAlbumInvalidFileData()); + R_UNLESS(cinfo.image_height == in.height, capsrv::ResultAlbumInvalidFileData()); cinfo.out_color_space = JCS_RGB; cinfo.dct_method = JDCT_ISLOW; cinfo.do_fancy_upsampling = in.fancy_upsampling; cinfo.do_block_smoothing = in.block_smoothing; - res = jpeg_start_decompress(&cinfo); + R_UNLESS(jpeg_start_decompress(&cinfo) == TRUE, capsrv::ResultAlbumInvalidFileData()); - R_UNLESS(res == TRUE, capsrv::ResultInvalidFileData()); - - R_UNLESS(cinfo.output_width == in.width, capsrv::ResultInvalidArgument()); - R_UNLESS(cinfo.output_height == in.height, capsrv::ResultInvalidArgument()); - - R_UNLESS(cinfo.out_color_components == ColorComponents, capsrv::ResultInvalidArgument()); - R_UNLESS(cinfo.output_components == ColorComponents, capsrv::ResultInvalidArgument()); + CAPSRV_ASSERT(cinfo.output_width == in.width); + CAPSRV_ASSERT(cinfo.output_height == in.height); + CAPSRV_ASSERT(cinfo.out_color_components == ColorComponents); + CAPSRV_ASSERT(cinfo.output_components == ColorComponents); /* Pointer to output. */ RGBX *bmp = reinterpret_cast(out.bmp); @@ -107,11 +117,8 @@ namespace ams::jpegdec::impl { while (cinfo.output_scanline < cinfo.output_height) { /* Decode scanlines. */ int parsed = jpeg_read_scanlines(&cinfo, linebuffer, 4); + CAPSRV_ASSERT(parsed <= ImageSizeVerticalUnit); - /* Done! */ - if (parsed == 0) - break; - /* Line by line */ for (int index = 0; index < parsed; index++) { u8 *buffer = linebuffer[index]; @@ -130,8 +137,7 @@ namespace ams::jpegdec::impl { } } - res = jpeg_finish_decompress(&cinfo); - R_UNLESS(res == TRUE, capsrv::ResultInvalidFileData()); + R_UNLESS(jpeg_finish_decompress(&cinfo) == TRUE, capsrv::ResultAlbumInvalidFileData()); *out.width = cinfo.output_width; *out.height = cinfo.output_height; diff --git a/stratosphere/jpegdec/source/jpegdec_decode_service.cpp b/stratosphere/jpegdec/source/jpegdec_decode_service.cpp index c93a7b1b1..8146346ea 100644 --- a/stratosphere/jpegdec/source/jpegdec_decode_service.cpp +++ b/stratosphere/jpegdec/source/jpegdec_decode_service.cpp @@ -34,14 +34,14 @@ namespace ams::jpegdec { memset(g_workmem, 0, sizeof(g_workmem)); memset(bmp, 0, bmp_size); - R_UNLESS(util::IsAligned(width, 0x10), capsrv::ResultOutOfRange()); - R_UNLESS(util::IsAligned(height, 0x4), capsrv::ResultOutOfRange()); + R_UNLESS(util::IsAligned(width, 0x10), capsrv::ResultAlbumOutOfRange()); + R_UNLESS(util::IsAligned(height, 0x4), capsrv::ResultAlbumOutOfRange()); - R_UNLESS(bmp != nullptr, capsrv::ResultBufferInsufficient()); - R_UNLESS(bmp_size >= 4 * width * height, capsrv::ResultBufferInsufficient()); + R_UNLESS(bmp != nullptr, capsrv::ResultAlbumReadBufferShortage()); + R_UNLESS(bmp_size >= 4 * width * height, capsrv::ResultAlbumReadBufferShortage()); - R_UNLESS(jpeg != nullptr, capsrv::ResultInvalidFileData()); - R_UNLESS(jpeg_size != 0, capsrv::ResultInvalidFileData()); + R_UNLESS(jpeg != nullptr, capsrv::ResultAlbumInvalidFileData()); + R_UNLESS(jpeg_size != 0, capsrv::ResultAlbumInvalidFileData()); impl::DecodeInput decode_input = { .jpeg = jpeg, @@ -62,14 +62,18 @@ namespace ams::jpegdec { .bmp_size = bmp_size, }; - Result rc = impl::DecodeJpeg(decode_output, decode_input, g_workmem, sizeof(g_workmem)); + /* Clear output memory on decode failure. */ + /* NOTE: Nintendo does not do this. */ + auto clear_guard = SCOPE_GUARD { std::memset(bmp, 0, bmp_size); }; - /* Null output on failure */ - if (rc.IsFailure()) - memset(bmp, 0, bmp_size); + /* Decode the jpeg. */ + R_TRY(impl::DecodeJpeg(decode_output, decode_input, g_workmem, sizeof(g_workmem))); + clear_guard.Cancel(); + /* Clear the work memory. */ + /* NOTE: Nintendo does not do this. */ std::memset(g_workmem, 0, sizeof(g_workmem)); - return rc; + return ResultSuccess(); } } \ No newline at end of file diff --git a/stratosphere/jpegdec/source/jpegdec_main.cpp b/stratosphere/jpegdec/source/jpegdec_main.cpp index 9e3eaf81d..ef649e85c 100644 --- a/stratosphere/jpegdec/source/jpegdec_main.cpp +++ b/stratosphere/jpegdec/source/jpegdec_main.cpp @@ -23,7 +23,7 @@ extern "C" { #define INNER_HEAP_SIZE 0x18000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; - + void __libnx_initheap(void); void __appInit(void); void __appExit(void); @@ -69,6 +69,7 @@ void __appInit(void) { } void __appExit(void) { + /* ... */ } namespace { @@ -85,7 +86,11 @@ int main(int argc, char **argv) { /* Set thread name. */ os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(jpegdec, Main)); + + /* Official jpegdec changes its thread priority to 21 in main. */ + /* This is because older versions of the sysmodule had priority 20 in npdm. */ os::ChangeThreadPriority(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_PRIORITY(jpegdec, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(jpegdec, Main)); /* Create service. */ R_ASSERT(g_server_manager.RegisterServer(DecodeServiceName, DecodeMaxSessions));