tvg_format: force to check for compatibility by version comparision.
authorHermet Park <hermetpark@gmail.com>
Wed, 4 Aug 2021 06:31:06 +0000 (15:31 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Fri, 6 Aug 2021 01:04:06 +0000 (10:04 +0900)
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
src/lib/tvgCommon.h
src/lib/tvgInitializer.cpp
src/loaders/tvg/tvgTvgLoadParser.cpp
src/loaders/tvg/tvgTvgLoadParser.h
src/loaders/tvg/tvgTvgLoader.cpp
src/loaders/tvg/tvgTvgLoader.h
src/savers/tvg/tvgTvgSaver.cpp

index 239ce51..9658bc3 100644 (file)
@@ -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
index 95a1071..596746d 100644 (file)
@@ -62,4 +62,6 @@ enum class FileType { Tvg = 0, Svg, Raw, Png, Jpg, Unknown };
     #define TVGLOG(...)
 #endif
 
+uint16_t THORVG_VERSION_NUMBER();
+
 #endif //_TVG_COMMON_H_
index e5d7750..0b63cf3 100644 (file)
 /************************************************************************/
 
 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;
+}
index 7979fb2..62250b5 100644 (file)
 /* 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)
-{
-    auto end = ptr + size;
-    if (!_readTvgHeader(&ptr, w, h) || ptr >= end) return false;
-    return true;
-}
-
-unique_ptr<Scene> tvgLoadData(const char *ptr, uint32_t size)
+unique_ptr<Scene> tvgLoadData(const char *ptr, const char* end)
 {
-    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<Scene> tvgLoadData(const char *ptr, uint32_t size)
     }
 
     return move(scene);
-}
+}
\ No newline at end of file
index 437670e..3e2daf7 100644 (file)
 #include "tvgCommon.h"
 #include "tvgBinaryDesc.h"
 
-bool tvgValidateData(const char *ptr, uint32_t size, float* w, float* h);
-unique_ptr<Scene> 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<Scene> tvgLoadData(const char* ptr, const char* end);
 
 #endif //_TVG_TVG_LOAD_PARSER_H_
index 593187e..00c31a8 100644 (file)
 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<Paint> TvgLoader::paint()
     this->done();
     if (root) return move(root);
     return nullptr;
-}
\ No newline at end of file
+}
index c138ced..d48e13b 100644 (file)
@@ -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<Scene> root = nullptr;
     bool copy = false;
 
@@ -45,6 +46,7 @@ public:
     unique_ptr<Paint> paint() override;
 
 private:
+    bool readHeader();
     void run(unsigned tid) override;
     void clear();
 };
index e8e1a24..52de8d9 100644 (file)
@@ -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;
 }