From e7d29e166b2e5a59c7e65a75beed4476d9612915 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 17 Aug 2023 16:37:46 +0900 Subject: [PATCH] loaders: unify duplicated b64 decoders. - move the svg/lottie b64 decoders to tvgLzw. - renames tvgLzw -> tvgCompressor --- src/loaders/lottie/tvgLottieParser.cpp | 43 +----------- src/loaders/svg/tvgSvgSceneBuilder.cpp | 12 +++- src/loaders/svg/tvgSvgUtil.cpp | 42 ------------ src/loaders/svg/tvgSvgUtil.h | 1 - src/loaders/tvg/tvgTvgLoader.cpp | 2 +- src/savers/tvg/tvgTvgSaver.cpp | 2 +- src/utils/meson.build | 4 +- src/utils/{tvgLzw.cpp => tvgCompressor.cpp} | 73 +++++++++++++++++---- src/utils/{tvgLzw.h => tvgCompressor.h} | 7 +- 9 files changed, 81 insertions(+), 105 deletions(-) rename src/utils/{tvgLzw.cpp => tvgCompressor.cpp} (88%) rename src/utils/{tvgLzw.h => tvgCompressor.h} (90%) diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index 80dcdab0..d277d60f 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -21,6 +21,7 @@ */ #include "tvgStr.h" +#include "tvgCompressor.h" #include "tvgLottieModel.h" #include "tvgLottieParser.h" @@ -29,16 +30,6 @@ /* Internal Class Implementation */ /************************************************************************/ -static constexpr const char B64_INDEX[256] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 -}; static char* _int2str(int num) @@ -49,31 +40,6 @@ static char* _int2str(int num) } -static void _decodeB64(const uint8_t* input, const size_t len, Array& output) -{ - int pad = len > 0 && (len % 4 || input[len - 1] == '='); - const size_t L = ((len + 3) / 4 - pad) * 4; - output.reserve(L / 4 * 3 + pad + 1); - output.data[output.reserved - 1] = '\0'; - - for (size_t i = 0; i < L; i += 4) { - int n = B64_INDEX[input[i]] << 18 | B64_INDEX[input[i + 1]] << 12 | B64_INDEX[input[i + 2]] << 6 | B64_INDEX[input[i + 3]]; - output.push(n >> 16); - output.push(n >> 8 & 0xFF); - output.push(n & 0xFF); - } - if (pad) { - int n = B64_INDEX[input[L]] << 18 | B64_INDEX[input[L + 1]] << 12; - output.last() = n >> 16; - if (len > L + 2 && input[L + 2] != '=') { - n |= B64_INDEX[input[L + 2]] << 6; - output.push(n >> 8 & 0xFF); - } - } - output.count = output.reserved; -} - - static void _updateRoundedCorner(LottieGroup* parent, LottieRoundedCorner* roundedCorner) { for (auto child = parent->children.data; child < parent->children.end(); ++child) { @@ -860,12 +826,7 @@ LottieImage* LottieParser::parseImage(const char* key) //b64 data auto b64Data = strstr(data, ",") + 1; size_t length = strlen(data) - (b64Data - data); - - Array decoded; - _decodeB64(reinterpret_cast(b64Data), length, decoded); - image->b64Data = decoded.data; - image->size = decoded.count; - decoded.data = nullptr; + image->size = b64Decode(b64Data, length, &image->b64Data); //external image resource } else { auto len = strlen(dirName) + strlen(subPath) + strlen(data) + 1; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index f3d3079e..8f3ee506 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -23,6 +23,7 @@ #include "tvgMath.h" /* to include math.h before cstring */ #include #include +#include "tvgCompressor.h" #include "tvgSvgLoaderCommon.h" #include "tvgSvgSceneBuilder.h" #include "tvgSvgPath.h" @@ -543,10 +544,17 @@ static unique_ptr _imageBuildHelper(SvgNode* node, const Box& vBox, con imageMimeTypeEncoding encoding; if (!_isValidImageMimeTypeAndEncoding(&href, &mimetype, &encoding)) return nullptr; //not allowed mime type or encoding if (encoding == imageMimeTypeEncoding::base64) { - string decoded = svgUtilBase64Decode(href); - if (picture->load(decoded.c_str(), decoded.size(), mimetype, true) != Result::Success) return nullptr; + char* decoded = nullptr; + auto size = b64Decode(href, strlen(href), &decoded); + //OPTIMIZE: Skip data copy. + if (picture->load(decoded, size, mimetype, true) != Result::Success) { + free(decoded); + return nullptr; + } + free(decoded); } else { string decoded = svgUtilURLDecode(href); + //OPTIMIZE: Skip data copy. if (picture->load(decoded.c_str(), decoded.size(), mimetype, true) != Result::Success) return nullptr; } } else { diff --git a/src/loaders/svg/tvgSvgUtil.cpp b/src/loaders/svg/tvgSvgUtil.cpp index b5a96191..065f12a3 100644 --- a/src/loaders/svg/tvgSvgUtil.cpp +++ b/src/loaders/svg/tvgSvgUtil.cpp @@ -34,15 +34,6 @@ static uint8_t _hexCharToDec(const char c) else return c - '0'; } -static uint8_t _base64Value(const char chr) -{ - if (chr >= 'A' && chr <= 'Z') return chr - 'A'; - else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1; - else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2; - else if (chr == '+' || chr == '-') return 62; - else return 63; -} - /************************************************************************/ /* External Class Implementation */ @@ -73,37 +64,4 @@ string svgUtilURLDecode(const char *src) } } return decoded; -} - - -string svgUtilBase64Decode(const char *src) -{ - if (!src) return nullptr; - - auto length = strlen(src); - if (length == 0) return nullptr; - - string decoded; - decoded.reserve(3*(1+(length >> 2))); - - while (*src && *(src+1)) { - if (*src <= 0x20) { - ++src; - continue; - } - - auto value1 = _base64Value(src[0]); - auto value2 = _base64Value(src[1]); - decoded += (value1 << 2) + ((value2 & 0x30) >> 4); - - if (!src[2] || src[2] == '=' || src[2] == '.') break; - auto value3 = _base64Value(src[2]); - decoded += ((value2 & 0x0f) << 4) + ((value3 & 0x3c) >> 2); - - if (!src[3] || src[3] == '=' || src[3] == '.') break; - auto value4 = _base64Value(src[3]); - decoded += ((value3 & 0x03) << 6) + value4; - src += 4; - } - return decoded; } \ No newline at end of file diff --git a/src/loaders/svg/tvgSvgUtil.h b/src/loaders/svg/tvgSvgUtil.h index 3a7a161c..e914eadc 100644 --- a/src/loaders/svg/tvgSvgUtil.h +++ b/src/loaders/svg/tvgSvgUtil.h @@ -26,6 +26,5 @@ #include "tvgCommon.h" string svgUtilURLDecode(const char *src); -string svgUtilBase64Decode(const char *src); #endif //_TVG_SVG_UTIL_H_ diff --git a/src/loaders/tvg/tvgTvgLoader.cpp b/src/loaders/tvg/tvgTvgLoader.cpp index 8db452d5..ab8aaa3d 100644 --- a/src/loaders/tvg/tvgTvgLoader.cpp +++ b/src/loaders/tvg/tvgTvgLoader.cpp @@ -24,7 +24,7 @@ #include #include "tvgLoader.h" #include "tvgTvgLoader.h" -#include "tvgLzw.h" +#include "tvgCompressor.h" /************************************************************************/ diff --git a/src/savers/tvg/tvgTvgSaver.cpp b/src/savers/tvg/tvgTvgSaver.cpp index c8b6bf5e..29edea4a 100644 --- a/src/savers/tvg/tvgTvgSaver.cpp +++ b/src/savers/tvg/tvgTvgSaver.cpp @@ -24,7 +24,7 @@ #include "tvgSaveModule.h" #include "tvgTvgSaver.h" -#include "tvgLzw.h" +#include "tvgCompressor.h" #include "tvgShapeImpl.h" #include "tvgPictureImpl.h" diff --git a/src/utils/meson.build b/src/utils/meson.build index 7211ca1c..5ad2ff70 100644 --- a/src/utils/meson.build +++ b/src/utils/meson.build @@ -1,11 +1,11 @@ source_file = [ 'tvgArray.h', 'tvgBezier.h', - 'tvgLzw.h', + 'tvgCompressor.h', 'tvgMath.h', 'tvgStr.h', 'tvgBezier.cpp', - 'tvgLzw.cpp', + 'tvgCompressor.cpp', 'tvgMath.cpp', 'tvgStr.cpp' ] diff --git a/src/utils/tvgLzw.cpp b/src/utils/tvgCompressor.cpp similarity index 88% rename from src/utils/tvgLzw.cpp rename to src/utils/tvgCompressor.cpp index 90b7dc29..7fa6bf6d 100644 --- a/src/utils/tvgLzw.cpp +++ b/src/utils/tvgCompressor.cpp @@ -56,15 +56,18 @@ #include "config.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ #include #include -#include "tvgLzw.h" +#include "tvgCompressor.h" + +namespace tvg { + + +/************************************************************************/ +/* LZW Implementation */ +/************************************************************************/ -namespace { //LZW Dictionary helper: constexpr int Nil = -1; @@ -334,15 +337,8 @@ static bool outputSequence(const Dictionary& dict, int code, uint8_t*& output, i } return true; } -} -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -namespace tvg { - uint8_t* lzwDecode(const uint8_t* compressed, uint32_t compressedSizeBytes, uint32_t compressedSizeBits, uint32_t uncompressedSizeBytes) { int code = Nil; @@ -423,4 +419,57 @@ uint8_t* lzwEncode(const uint8_t* uncompressed, uint32_t uncompressedSizeBytes, return bitStream.release(); } + +/************************************************************************/ +/* B64 Implementation */ +/************************************************************************/ + + +size_t b64Decode(const char* encoded, const size_t len, char** decoded) +{ + static constexpr const char B64_INDEX[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 + }; + + + if (!decoded || !encoded || len == 0) return 0; + + auto reserved = 3 * (1 + (len >> 2)) + 1; + auto output = static_cast(malloc(reserved * sizeof(char))); + if (!output) return 0; + output[reserved - 1] = '\0'; + + size_t idx = 0; + + while (*encoded && *(encoded + 1)) { + if (*encoded <= 0x20) { + ++encoded; + continue; + } + + auto value1 = B64_INDEX[(size_t)encoded[0]]; + auto value2 = B64_INDEX[(size_t)encoded[1]]; + output[idx++] = (value1 << 2) + ((value2 & 0x30) >> 4); + + if (!encoded[2] || encoded[2] == '=' || encoded[2] == '.') break; + auto value3 = B64_INDEX[(size_t)encoded[2]]; + output[idx++] = ((value2 & 0x0f) << 4) + ((value3 & 0x3c) >> 2); + + if (!encoded[3] || encoded[3] == '=' || encoded[3] == '.') break; + auto value4 = B64_INDEX[(size_t)encoded[3]]; + output[idx++] = ((value3 & 0x03) << 6) + value4; + encoded += 4; + } + *decoded = output; + return reserved; +} + + } \ No newline at end of file diff --git a/src/utils/tvgLzw.h b/src/utils/tvgCompressor.h similarity index 90% rename from src/utils/tvgLzw.h rename to src/utils/tvgCompressor.h index bd4e783f..05d23f42 100644 --- a/src/utils/tvgLzw.h +++ b/src/utils/tvgCompressor.h @@ -20,8 +20,8 @@ * SOFTWARE. */ -#ifndef _TVG_LZW_H_ -#define _TVG_LZW_H_ +#ifndef _TVG_COMPRESSOR_H_ +#define _TVG_COMPRESSOR_H_ #include @@ -29,6 +29,7 @@ namespace tvg { uint8_t* lzwEncode(const uint8_t* uncompressed, uint32_t uncompressedSizeBytes, uint32_t* compressedSizeBytes, uint32_t* compressedSizeBits); uint8_t* lzwDecode(const uint8_t* compressed, uint32_t compressedSizeBytes, uint32_t compressedSizeBits, uint32_t uncompressedSizeBytes); + size_t b64Decode(const char* encoded, const size_t len, char** decoded); } -#endif //_TVG_LZW_H +#endif //_TVG_COMPRESSOR_H_