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.
This commit is contained in:
Hermet Park 2021-08-04 15:31:06 +09:00 committed by GitHub
parent 19b11277a0
commit a042e771e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 97 additions and 65 deletions

View 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

View file

@ -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_

View file

@ -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;
}

View file

@ -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<Scene> tvgLoadData(const char *ptr, const char* end)
{
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)
{
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);
}
}

View file

@ -26,7 +26,10 @@
#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_

View file

@ -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<Paint> TvgLoader::paint()
this->done();
if (root) return move(root);
return nullptr;
}
}

View 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();
};

View 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;
}