From 927fd537e5c20255e195acea32564315eadc3366 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 7 Feb 2025 12:53:01 +0100 Subject: [PATCH] lottie: fix & enhance parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The object type key does not need to be provided first. Previously, content was skipped until the "ty" type key was found. If the key was placed at the end, the entire object was ignored. Now, before parsing subsequent elements, finding the "ty" key is enforced. Since in-situ parsing does not support backtracking, the key is searched with an internal function. Introducing support for the "ty" key placed anywhere highlighted the use of redundant logic for parsing the list of shapes — this duplicate logic has been removed. --- src/loaders/lottie/tvgLottieParser.cpp | 41 +++++++++++-------- src/loaders/lottie/tvgLottieParser.h | 2 +- src/loaders/lottie/tvgLottieParserHandler.cpp | 36 +++++++++++++++- src/loaders/lottie/tvgLottieParserHandler.h | 2 + 4 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index 4c6af859..d385718c 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -849,10 +849,12 @@ LottieOffsetPath* LottieParser::parseOffsetPath() } -LottieObject* LottieParser::parseObject() +LottieObject* LottieParser::parseObject(const char* type) { - auto type = getString(); - if (!type) return nullptr; + if (!type) { + type = getString(); + if (!type) return nullptr; + } if (!strcmp(type, "gr")) return parseGroup(); else if (!strcmp(type, "rc")) return parseRect(); @@ -879,6 +881,24 @@ LottieObject* LottieParser::parseObject() void LottieParser::parseObject(Array& parent) { enterObject(); + + + //object type key is not listed as the first one + auto value = peekValue(); + if (value && strcmp(value->GetString(), "ty")) { + if (auto type = findObjectType()) { + if (auto child = parseObject(type)) { + if (child->hidden) delete (child); + else parent.push(child); + } else { + //skip unsupported type + while (nextObjectKey()) skip(); + } + free(type); + return; + } + } + //object type key either listed as the first one or never - skip the entire object while (auto key = nextObjectKey()) { if (KEY_AS("ty")) { if (auto child = parseObject()) { @@ -1081,20 +1101,7 @@ void LottieParser::parseTimeRemap(LottieLayer* layer) void LottieParser::parseShapes(Array& parent) { enterArray(); - while (nextArrayValue()) { - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("it")) { - enterArray(); - while (nextArrayValue()) parseObject(parent); - } else if (KEY_AS("ty")) { - if (auto child = parseObject()) { - if (child->hidden) delete(child); - else parent.push(child); - } - } else skip(); - } - } + while (nextArrayValue()) parseObject(parent); } diff --git a/src/loaders/lottie/tvgLottieParser.h b/src/loaders/lottie/tvgLottieParser.h index aa1e85d5..9666fd2d 100644 --- a/src/loaders/lottie/tvgLottieParser.h +++ b/src/loaders/lottie/tvgLottieParser.h @@ -75,7 +75,7 @@ private: template void parseProperty(T& prop, LottieObject* obj = nullptr); template void parseSlotProperty(T& prop); - LottieObject* parseObject(); + LottieObject* parseObject(const char* type = nullptr); LottieObject* parseAsset(); void parseImage(LottieImage* image, const char* data, const char* subPath, bool embedded, float width, float height); LottieLayer* parseLayer(LottieLayer* precomp); diff --git a/src/loaders/lottie/tvgLottieParserHandler.cpp b/src/loaders/lottie/tvgLottieParserHandler.cpp index e5506f99..de454cf7 100644 --- a/src/loaders/lottie/tvgLottieParserHandler.cpp +++ b/src/loaders/lottie/tvgLottieParserHandler.cpp @@ -1,4 +1,4 @@ -/* + /* * Copyright (c) 2023 - 2025 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -43,6 +43,7 @@ */ #include "tvgLottieParserHandler.h" +#include "tvgStr.h" /************************************************************************/ @@ -184,6 +185,14 @@ int LookaheadParserHandler::peekType() } +Value* LookaheadParserHandler::peekValue() { + if (state >= kHasNull && state <= kHasKey) { + return &val; + } + return nullptr; +} + + void LookaheadParserHandler::skipOut(int depth) { do { @@ -233,6 +242,31 @@ void LookaheadParserHandler::skip() } +char* LookaheadParserHandler::findObjectType() +{ + auto level = 0; + for (auto p = iss.src_; *p != '\0'; ++p) { + if (*p == '{') level++; + else if (*p == '}') { + if (--level < 0) break; + } else if (level == 0) { + if (!strncmp(p, "\"ty\"", 4)) { + p += 4; + while (*p != '\0' && (isspace(*p) || *p == '\n')) ++p; + if (*p++ != ':') return nullptr; + while (*p != '\0' && (isspace(*p) || *p == '\n')) ++p; + if (*p++ != '\"') return nullptr; + const char* start = p; + while (*p != '\0' && *p != '\"') ++p; + if (*p == '\"') return strDuplicate(start, p - start); + return nullptr; + } + } + } + return nullptr; +} + + char* LookaheadParserHandler::getPos() { return iss.src_; diff --git a/src/loaders/lottie/tvgLottieParserHandler.h b/src/loaders/lottie/tvgLottieParserHandler.h index 6c595022..7e18d493 100644 --- a/src/loaders/lottie/tvgLottieParserHandler.h +++ b/src/loaders/lottie/tvgLottieParserHandler.h @@ -195,6 +195,8 @@ struct LookaheadParserHandler void skip(); void skipOut(int depth); int peekType(); + Value* peekValue(); + char* findObjectType(); char* getPos(); };