File: No-cyclic-structures.patch

package info (click to toggle)
rlottie 0.1%2Bdfsg-4.3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,948 kB
  • sloc: cpp: 20,376; asm: 221; ansic: 194; makefile: 16
file content (97 lines) | stat: -rw-r--r-- 2,967 bytes parent folder | download | duplicates (3)
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
Description: Deal with cyclic structures, avoid stack overflow in Lottie model
Bug: https://github.com/Samsung/rlottie/issues/522
Author: Nicholas Guriev <guriev-ns@ya.ru>
Last-Update: Sat, 10 Sep 2022 18:26:32 +0300

--- a/src/lottie/lottiemodel.cpp
+++ b/src/lottie/lottiemodel.cpp
@@ -19,10 +19,26 @@
 #include "lottiemodel.h"
 #include <cassert>
 #include <iterator>
+#include <set>
 #include <stack>
 #include "vimageloader.h"
 #include "vline.h"
 
+bool LOTData::includes(const LOTData *pointer) const {
+    if (this == pointer) {
+        return true;
+    }
+    if (type() != Type::ShapeGroup && type() != Type::Layer) {
+        return false;
+    }
+    for (LOTData *child : static_cast<const LOTGroupData *>(this)->mChildren) {
+        if (child->includes(pointer)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 /*
  * We process the iterator objects in the children list
  * by iterating from back to front. when we find a repeater object
@@ -73,6 +89,8 @@ public:
 
     void visit(LOTData *obj)
     {
+        if (!mVisited.insert(obj).second) return;
+
         switch (obj->type()) {
         case LOTData::Type::ShapeGroup:
         case LOTData::Type::Layer: {
@@ -83,6 +101,9 @@ public:
             break;
         }
     }
+
+private:
+    std::set<LOTData*> mVisited;
 };
 
 class LottieUpdateStatVisitor {
@@ -120,6 +141,8 @@ public:
     }
     void visit(LOTData *obj)
     {
+        if (!mVisited.insert(obj).second) return;
+
         switch (obj->type()) {
         case LOTData::Type::Layer: {
             visitLayer(static_cast<LOTLayerData *>(obj));
@@ -138,6 +161,8 @@ public:
         }
     }
 
+private:
+    std::set<LOTData*> mVisited;
 };
 
 void LOTCompositionData::processRepeaterObjects()
--- a/src/lottie/lottiemodel.h
+++ b/src/lottie/lottiemodel.h
@@ -460,6 +460,7 @@ public:
         }
     }
     const char* name() const {return shortString() ? mData._buffer : mPtr;}
+    bool includes(const LOTData *) const;
 private:
     static constexpr unsigned char maxShortStringLength = 14;
     void setShortString(bool value) {mData._shortString = value;}
--- a/src/lottie/lottieparser.cpp
+++ b/src/lottie/lottieparser.cpp
@@ -608,7 +608,12 @@ void LottieParserImpl::resolveLayerRefs(
             if (layer->mLayerType == LayerType::Image) {
                 layer->extra()->mAsset = search->second;
             } else if (layer->mLayerType == LayerType::Precomp) {
-                layer->mChildren = search->second->mLayers;
+                layer->mChildren.clear();
+                layer->mChildren.reserve(search->second->mLayers.size());
+                for (LOTData *candidate : search->second->mLayers) {
+                    if (candidate->includes(layer)) continue;
+                    layer->mChildren.push_back(candidate);
+                }
                 layer->setStatic(layer->isStatic() &&
                                  search->second->isStatic());
             }