From 29115e711bf8e967c6428a3a06c3e494621d330c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 2 May 2021 23:18:13 -0700 Subject: [PATCH] Util: Improve speed of UPS patch loading --- CHANGES | 1 + src/util/patch-ups.c | 64 +++++++++++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/CHANGES b/CHANGES index b1dec75e7..af2f38fe1 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,7 @@ Other fixes: - Util: Fix loading UPS patches that affect the last byte of the file Misc: - Qt: Rearrange menus some + - Util: Improve speed of UPS patch loading 0.9.1: (2021-04-18) Emulation fixes: diff --git a/src/util/patch-ups.c b/src/util/patch-ups.c index 6c0334feb..bce88e74d 100644 --- a/src/util/patch-ups.c +++ b/src/util/patch-ups.c @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include #include #include #include @@ -13,6 +14,8 @@ enum { IN_CHECKSUM = -12, OUT_CHECKSUM = -8, PATCH_CHECKSUM = -4, + + BUFFER_SIZE = 128 }; static size_t _UPSOutputSize(struct Patch* patch, size_t inSize); @@ -20,7 +23,7 @@ static size_t _UPSOutputSize(struct Patch* patch, size_t inSize); static bool _UPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* out, size_t outSize); static bool _BPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* out, size_t outSize); -static size_t _decodeLength(struct VFile* vf); +static size_t _decodeLength(struct VFile* vf, struct CircleBuffer* buffer); bool loadPatchUPS(struct Patch* patch) { patch->vf->seek(patch->vf, 0, SEEK_SET); @@ -58,10 +61,10 @@ bool loadPatchUPS(struct Patch* patch) { size_t _UPSOutputSize(struct Patch* patch, size_t inSize) { UNUSED(inSize); patch->vf->seek(patch->vf, 4, SEEK_SET); - if (_decodeLength(patch->vf) != inSize) { + if (_decodeLength(patch->vf, NULL) != inSize) { return 0; } - return _decodeLength(patch->vf); + return _decodeLength(patch->vf, NULL); } bool _UPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* out, size_t outSize) { @@ -69,36 +72,47 @@ bool _UPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* ou size_t filesize = patch->vf->size(patch->vf); patch->vf->seek(patch->vf, 4, SEEK_SET); - _decodeLength(patch->vf); // Discard input size - if (_decodeLength(patch->vf) != outSize) { + _decodeLength(patch->vf, NULL); // Discard input size + if (_decodeLength(patch->vf, NULL) != outSize) { return false; } + struct CircleBuffer buffer; memcpy(out, in, inSize > outSize ? outSize : inSize); size_t offset = 0; size_t alreadyRead = 0; uint8_t* buf = out; + CircleBufferInit(&buffer, BUFFER_SIZE); while (alreadyRead < filesize + IN_CHECKSUM) { - offset += _decodeLength(patch->vf); - uint8_t byte; + offset += _decodeLength(patch->vf, &buffer); + int8_t byte; while (true) { - if (patch->vf->read(patch->vf, &byte, 1) != 1) { - return false; + if (!CircleBufferSize(&buffer)) { + uint8_t block[BUFFER_SIZE]; + ssize_t read = patch->vf->read(patch->vf, block, sizeof(block)); + if (read < 1) { + CircleBufferDeinit(&buffer); + return false; + } + CircleBufferWrite(&buffer, block, read); } + CircleBufferRead8(&buffer, &byte); if (!byte) { break; } if (offset >= outSize) { + CircleBufferDeinit(&buffer); return false; } buf[offset] ^= byte; ++offset; } ++offset; - alreadyRead = patch->vf->seek(patch->vf, 0, SEEK_CUR); + alreadyRead = patch->vf->seek(patch->vf, 0, SEEK_CUR) - CircleBufferSize(&buffer); } + CircleBufferDeinit(&buffer); uint32_t goodCrc32; patch->vf->seek(patch->vf, OUT_CHECKSUM, SEEK_END); @@ -129,14 +143,14 @@ bool _BPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* ou ssize_t filesize = patch->vf->size(patch->vf); patch->vf->seek(patch->vf, 4, SEEK_SET); - _decodeLength(patch->vf); // Discard input size - if (_decodeLength(patch->vf) != outSize) { + _decodeLength(patch->vf, NULL); // Discard input size + if (_decodeLength(patch->vf, NULL) != outSize) { return false; } if (inSize > SSIZE_MAX || outSize > SSIZE_MAX) { return false; } - size_t metadataLength = _decodeLength(patch->vf); + size_t metadataLength = _decodeLength(patch->vf, NULL); patch->vf->seek(patch->vf, metadataLength, SEEK_CUR); // Skip metadata size_t writeLocation = 0; ssize_t readSourceLocation = 0; @@ -145,7 +159,7 @@ bool _BPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* ou uint8_t* writeBuffer = out; const uint8_t* readBuffer = in; while (patch->vf->seek(patch->vf, 0, SEEK_CUR) < filesize + IN_CHECKSUM) { - size_t command = _decodeLength(patch->vf); + size_t command = _decodeLength(patch->vf, NULL); size_t length = (command >> 2) + 1; if (writeLocation + length > outSize) { return false; @@ -168,7 +182,7 @@ bool _BPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* ou break; case 0x2: // SourceCopy - readOffset = _decodeLength(patch->vf); + readOffset = _decodeLength(patch->vf, NULL); if (readOffset & 1) { readSourceLocation -= readOffset >> 1; } else { @@ -184,7 +198,7 @@ bool _BPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* ou break; case 0x3: // TargetCopy - readOffset = _decodeLength(patch->vf); + readOffset = _decodeLength(patch->vf, NULL); if (readOffset & 1) { readTargetLocation -= readOffset >> 1; } else { @@ -209,13 +223,25 @@ bool _BPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* ou return true; } -size_t _decodeLength(struct VFile* vf) { +size_t _decodeLength(struct VFile* vf, struct CircleBuffer* buffer) { size_t shift = 1; size_t value = 0; uint8_t byte; while (true) { - if (vf->read(vf, &byte, 1) != 1) { - break; + if (buffer) { + if (!CircleBufferSize(buffer)) { + uint8_t block[BUFFER_SIZE]; + ssize_t read = vf->read(vf, block, sizeof(block)); + if (read < 1) { + return false; + } + CircleBufferWrite(buffer, block, read); + } + CircleBufferRead8(buffer, (int8_t*) &byte); + } else { + if (vf->read(vf, &byte, 1) != 1) { + break; + } } value += (byte & 0x7f) * shift; if (byte & 0x80) {