From a042e771e48e535ed0f2637ae2657a8772559d6a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 4 Aug 2021 15:31:06 +0900 Subject: [PATCH] tvg_format: force to check for compatibility by version comparision. tvg file stores the version info of thorvg when it's generated, in order to compare it with the runtime thorvg version when it's loaded. For this, thorvg builds up the current version of symbol on the initilaization step, that can be referred by the tvg loader. --- meson.build | 2 ++ src/lib/tvgCommon.h | 2 ++ src/lib/tvgInitializer.cpp | 41 +++++++++++++++++++++++++ src/loaders/tvg/tvgTvgLoadParser.cpp | 45 ++-------------------------- src/loaders/tvg/tvgTvgLoadParser.h | 7 +++-- src/loaders/tvg/tvgTvgLoader.cpp | 45 ++++++++++++++++++++++------ src/loaders/tvg/tvgTvgLoader.h | 4 ++- src/savers/tvg/tvgTvgSaver.cpp | 16 ++++------ 8 files changed, 97 insertions(+), 65 deletions(-) diff --git a/meson.build b/meson.build index 239ce518..9658bc3f 100644 --- a/meson.build +++ b/meson.build @@ -10,6 +10,8 @@ add_project_arguments('-DEXAMPLE_DIR="@0@/src/examples/images"'.format(meson.cur '-DTEST_DIR="@0@/test/images"'.format(meson.current_source_dir()), language : 'cpp') +config_h.set_quoted('THORVG_VERSION_STRING', meson.project_version()) + if get_option('engines').contains('sw') == true config_h.set10('THORVG_SW_RASTER_SUPPORT', true) endif diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index e8dd0b80..9389156a 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -56,4 +56,6 @@ enum class FileType { Tvg = 0, Svg, Raw, Png, Jpg, Unknown }; #define TVGLOG(...) #endif +uint16_t THORVG_VERSION_NUMBER(); + #endif //_TVG_COMMON_H_ \ No newline at end of file diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index e5d7750b..0b63cf3a 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -37,6 +37,39 @@ /************************************************************************/ static int _initCnt = 0; +static uint16_t _version = 0; + + +static bool _buildVersionInfo() +{ + auto SRC = THORVG_VERSION_STRING; //ex) 0.3.99 + auto p = SRC; + const char* x; + + char major[3]; + x = strchr(p, '.'); + if (!x) return false; + strncpy(major, p, x - p); + p = x + 1; + + char minor[3]; + x = strchr(p, '.'); + if (!x) return false; + strncpy(minor, p, x - p); + p = x + 1; + + char micro[3]; + x = SRC + strlen(THORVG_VERSION_STRING); + if (!x) return false; + strncpy(micro, p, x - p); + + char sum[7]; + snprintf(sum, sizeof(sum), "%s%s%s", major, minor, micro); + + _version = atoi(sum); + + return true; +} /************************************************************************/ @@ -65,6 +98,8 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept if (_initCnt++ > 0) return Result::Success; + if (!_buildVersionInfo()) return Result::Unknown; + if (!LoaderMgr::init()) return Result::Unknown; TaskScheduler::init(threads); @@ -103,3 +138,9 @@ Result Initializer::term(CanvasEngine engine) noexcept return Result::Success; } + + +uint16_t THORVG_VERSION_NUMBER() +{ + return _version; +} diff --git a/src/loaders/tvg/tvgTvgLoadParser.cpp b/src/loaders/tvg/tvgTvgLoadParser.cpp index 7979fb2f..62250b59 100644 --- a/src/loaders/tvg/tvgTvgLoadParser.cpp +++ b/src/loaders/tvg/tvgTvgLoadParser.cpp @@ -28,10 +28,6 @@ /* Internal Class Implementation */ /************************************************************************/ -#define SIZE(A) sizeof(A) -#define READ_UI32(dst, src) memcpy(dst, (src), sizeof(uint32_t)) -#define READ_FLOAT(dst, src) memcpy(dst, (src), sizeof(float)) - struct TvgBinBlock { TvgBinTag type; @@ -64,29 +60,6 @@ static TvgBinBlock _readBlock(const char *ptr) return block; } -static bool _readTvgHeader(const char **ptr, float* w, float* h) -{ - if (!*ptr) return false; - - //Sign phase, always TVG_HEADER_SIGNATURE is declared - if (memcmp(*ptr, TVG_HEADER_SIGNATURE, TVG_HEADER_SIGNATURE_LENGTH)) return false; - *ptr += TVG_HEADER_SIGNATURE_LENGTH; - - //Version number, declared in TVG_HEADER_VERSION - if (memcmp(*ptr, TVG_HEADER_VERSION, TVG_HEADER_VERSION_LENGTH)) return false; - *ptr += TVG_HEADER_VERSION_LENGTH; - - //View width - if (w) READ_FLOAT(w, *ptr); - *ptr += SIZE(float); - - //View height - if (h) READ_FLOAT(h, *ptr); - *ptr += SIZE(float); - - return true; -} - static bool _parseCmpTarget(const char *ptr, const char *end, Paint *paint) { @@ -492,22 +465,8 @@ static Paint* _parsePaint(TvgBinBlock baseBlock) /* External Class Implementation */ /************************************************************************/ -bool tvgValidateData(const char *ptr, uint32_t size, float* w, float* h) +unique_ptr tvgLoadData(const char *ptr, const char* end) { - auto end = ptr + size; - if (!_readTvgHeader(&ptr, w, h) || ptr >= end) return false; - return true; -} - -unique_ptr tvgLoadData(const char *ptr, uint32_t size) -{ - auto end = ptr + size; - - if (!_readTvgHeader(&ptr, nullptr, nullptr) || ptr >= end) { - TVGLOG("TVG", "Invalid TVG Data!"); - return nullptr; - } - auto scene = Scene::gen(); if (!scene) return nullptr; @@ -519,4 +478,4 @@ unique_ptr tvgLoadData(const char *ptr, uint32_t size) } return move(scene); -} +} \ No newline at end of file diff --git a/src/loaders/tvg/tvgTvgLoadParser.h b/src/loaders/tvg/tvgTvgLoadParser.h index 437670eb..3e2daf7c 100644 --- a/src/loaders/tvg/tvgTvgLoadParser.h +++ b/src/loaders/tvg/tvgTvgLoadParser.h @@ -26,7 +26,10 @@ #include "tvgCommon.h" #include "tvgBinaryDesc.h" -bool tvgValidateData(const char *ptr, uint32_t size, float* w, float* h); -unique_ptr tvgLoadData(const char *ptr, uint32_t size); +#define SIZE(A) sizeof(A) +#define READ_UI32(dst, src) memcpy(dst, (src), sizeof(uint32_t)) +#define READ_FLOAT(dst, src) memcpy(dst, (src), sizeof(float)) + +unique_ptr tvgLoadData(const char* ptr, const char* end); #endif //_TVG_TVG_LOAD_PARSER_H_ diff --git a/src/loaders/tvg/tvgTvgLoader.cpp b/src/loaders/tvg/tvgTvgLoader.cpp index 593187eb..00c31a81 100644 --- a/src/loaders/tvg/tvgTvgLoader.cpp +++ b/src/loaders/tvg/tvgTvgLoader.cpp @@ -34,13 +34,40 @@ void TvgLoader::clear() { if (copy) free((char*)data); - data = nullptr; - pointer = nullptr; + ptr = data = nullptr; size = 0; copy = false; } +/* WARNING: Header format shall not change! */ +bool TvgLoader::readHeader() +{ + if (!ptr) return false; + + //1. Signature + if (memcmp(ptr, TVG_HEADER_SIGNATURE, TVG_HEADER_SIGNATURE_LENGTH)) return false; + ptr += TVG_HEADER_SIGNATURE_LENGTH; + + //2. Version + char version[TVG_HEADER_VERSION_LENGTH]; + memcpy(version, ptr, TVG_HEADER_VERSION_LENGTH); + ptr += TVG_HEADER_VERSION_LENGTH; + this->version = atoi(version); + if (this->version > THORVG_VERSION_NUMBER()) { + TVGLOG("TVG", "This TVG file expects a higher version(%d) of ThorVG symbol!, Current ThorVG(%d)", this->version, THORVG_VERSION_NUMBER()); + } + + //3. View Size + READ_FLOAT(&w, ptr); + ptr += SIZE(float); + READ_FLOAT(&h, ptr); + ptr += SIZE(float); + + return true; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -80,9 +107,9 @@ bool TvgLoader::open(const string &path) f.close(); - pointer = data; + ptr = data; - return tvgValidateData(pointer, size, &w, &h); + return readHeader(); } @@ -96,11 +123,11 @@ bool TvgLoader::open(const char *data, uint32_t size, bool copy) memcpy((char*)this->data, data, size); } else this->data = data; - this->pointer = this->data; + this->ptr = this->data; this->size = size; this->copy = copy; - return tvgValidateData(pointer, size, &w, &h); + return readHeader(); } @@ -129,7 +156,7 @@ bool TvgLoader::resize(Paint* paint, float w, float h) bool TvgLoader::read() { - if (!pointer || size == 0) return false; + if (!ptr || size == 0) return false; TaskScheduler::request(this); @@ -148,7 +175,7 @@ bool TvgLoader::close() void TvgLoader::run(unsigned tid) { if (root) root.reset(); - root = tvgLoadData(pointer, size); + root = tvgLoadData(ptr, data + size); if (!root) clear(); } @@ -158,4 +185,4 @@ unique_ptr TvgLoader::paint() this->done(); if (root) return move(root); return nullptr; -} \ No newline at end of file +} diff --git a/src/loaders/tvg/tvgTvgLoader.h b/src/loaders/tvg/tvgTvgLoader.h index c138ced4..d48e13be 100644 --- a/src/loaders/tvg/tvgTvgLoader.h +++ b/src/loaders/tvg/tvgTvgLoader.h @@ -29,8 +29,9 @@ class TvgLoader : public LoadModule, public Task { public: const char* data = nullptr; - const char* pointer = nullptr; + const char* ptr = nullptr; uint32_t size = 0; + uint16_t version = 0; unique_ptr root = nullptr; bool copy = false; @@ -45,6 +46,7 @@ public: unique_ptr paint() override; private: + bool readHeader(); void run(unsigned tid) override; void clear(); }; diff --git a/src/savers/tvg/tvgTvgSaver.cpp b/src/savers/tvg/tvgTvgSaver.cpp index e8e1a241..52de8d92 100644 --- a/src/savers/tvg/tvgTvgSaver.cpp +++ b/src/savers/tvg/tvgTvgSaver.cpp @@ -52,29 +52,26 @@ bool TvgSaver::flushTo(const std::string& path) } +/* WARNING: Header format shall not changed! */ bool TvgSaver::writeHeader() { buffer.grow(TVG_HEADER_SIGNATURE_LENGTH + TVG_HEADER_VERSION_LENGTH); + //1. Signature auto ptr = buffer.ptr(); memcpy(ptr, TVG_HEADER_SIGNATURE, TVG_HEADER_SIGNATURE_LENGTH); ptr += TVG_HEADER_SIGNATURE_LENGTH; + + //2. Version memcpy(ptr, TVG_HEADER_VERSION, TVG_HEADER_VERSION_LENGTH); ptr += TVG_HEADER_VERSION_LENGTH; buffer.count += (TVG_HEADER_SIGNATURE_LENGTH + TVG_HEADER_VERSION_LENGTH); - return true; -} - - -bool TvgSaver::writeViewSize() -{ + //3. View Size float var[2]; paint->bounds(nullptr, nullptr, &var[0], &var[1]); - - if (var[0] <= 0.0f || var[1] <= 0.0f) return false; - + if (var[0] <= FLT_EPSILON || var[1] <= FLT_EPSILON) return false; writeData(var, SIZE(var)); return true; @@ -413,7 +410,6 @@ TvgBinCounter TvgSaver::serialize(const Paint* paint) void TvgSaver::run(unsigned tid) { if (!writeHeader()) return; - if (!writeViewSize()) return; if (serialize(paint) == 0) return; if (!flushTo(path)) return; }