1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "metav1_compat.h"
16
17#include <meta/ext/serialization/common_value_serializers.h>
18
19META_BEGIN_NAMESPACE()
20namespace Serialization {
21
22using BasicMetaTypes = TypeList<float, double, bool, uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t,
23    int64_t, BASE_NS::Uid, BASE_NS::string, BASE_NS::string_view, BASE_NS::Math::Vec2, BASE_NS::Math::UVec2,
24    BASE_NS::Math::IVec2, BASE_NS::Math::Vec3, BASE_NS::Math::UVec3, BASE_NS::Math::IVec3, BASE_NS::Math::Vec4,
25    BASE_NS::Math::UVec4, BASE_NS::Math::IVec4, BASE_NS::Math::Quat, BASE_NS::Math::Mat3X3, BASE_NS::Math::Mat4X4>;
26
27static bool IsV1Property(ObjectId oid)
28{
29    static const BASE_NS::Uid propertyUid("00000000-0000-0000-5072-6f7065727479");
30    return oid.ToUid().data[1] == propertyUid.data[1];
31}
32
33template<typename... Types>
34static bool CheckBasicMetaTypes(ObjectId oid, ObjectId& out, TypeList<Types...>)
35{
36    return (false || ... ||
37            (UidFromType<Types[]>().data[0] == oid.ToUid().data[0] ? (out = UidFromType<Types>(), true) : false));
38}
39
40static bool IsV1BasicArray(ObjectId oid, ObjectId& out)
41{
42    return CheckBasicMetaTypes(oid, out, BasicMetaTypes {});
43}
44
45static bool IsV1Any(ObjectId oid)
46{
47    static const BASE_NS::Uid anyUid("00000000-0000-0000-5479-706564416e79");
48    return oid.ToUid().data[1] == anyUid.data[1];
49}
50
51static ObjectId MakeAny(ObjectId oid)
52{
53    BASE_NS::Uid uid("00000000-0000-0000-4275-696c74416e79");
54    uid.data[0] = oid.ToUid().data[0];
55    return uid;
56}
57
58static ObjectId MakeArrayAny(ObjectId oid)
59{
60    BASE_NS::Uid uid("00000000-0000-0000-4172-726179416e79");
61    uid.data[0] = oid.ToUid().data[0];
62    return uid;
63}
64
65class NodeVisitor : public IntroduceInterfaces<ISerNodeVisitor> {
66public:
67    static ISerNode::Ptr VisitNode(ISerNode::Ptr node)
68    {
69        if (!node) {
70            return nullptr;
71        }
72        NodeVisitor v;
73        node->Apply(v);
74        return v.node;
75    }
76
77    void Visit(const IRootNode& n) override
78    {
79        node.reset(new RootNode(n.GetSerializerVersion(), VisitNode(n.GetObject())));
80    }
81    void Visit(const IObjectNode& n) override
82    {
83        node.reset(new ObjectNode(
84            n.GetObjectClassName(), n.GetObjectName(), n.GetObjectId(), n.GetInstanceId(), VisitNode(n.GetMembers())));
85    }
86    void Visit(const IArrayNode& n) override
87    {
88        BASE_NS::vector<ISerNode::Ptr> arr;
89        for (auto&& m : n.GetMembers()) {
90            if (auto n = VisitNode(m)) {
91                arr.push_back(n);
92            }
93        }
94        node.reset(new ArrayNode(BASE_NS::move(arr)));
95    }
96    ISerNode::Ptr RewriteValueToAny(ObjectId property, ISerNode::Ptr node)
97    {
98        if (auto n = interface_cast<IObjectNode>(node)) {
99            if (IsV1Any(n->GetObjectId())) {
100                return ISerNode::Ptr(new ObjectNode("Any", n->GetObjectName(), MakeAny(n->GetObjectId()),
101                    n->GetInstanceId(), VisitNode(n->GetMembers())));
102            }
103        }
104        BASE_NS::vector<NamedNode> m;
105        if (auto n = VisitNode(node)) {
106            m.push_back(NamedNode { "value", n });
107        }
108        ObjectId any = MakeAny(property);
109        ObjectId uid;
110        if (IsV1BasicArray(property, uid)) {
111            any = MakeArrayAny(uid);
112        }
113        return ISerNode::Ptr(new ObjectNode("Any", "", any, {}, CreateShared<MapNode>(m)));
114    }
115
116    ISerNode::Ptr RewritePropertyFlags(ISerNode::Ptr n)
117    {
118        uint64_t value {};
119        uint64_t converted { uint64_t(ObjectFlagBits::SERIALIZE) };
120        if (ExtractNumber(n, value)) {
121            if (value & 8) {
122                converted |= 8;
123            }
124            if (value & 128) {
125                converted |= 16;
126            }
127            if (converted != uint64_t(ObjectFlagBits::SERIALIZE)) {
128                return ISerNode::Ptr(new UIntNode(converted));
129            }
130        }
131        return nullptr;
132    }
133
134    ISerNode::Ptr RewriteProperty(BASE_NS::string name, const IObjectNode& n)
135    {
136        BASE_NS::vector<NamedNode> map;
137        ISerNode::Ptr value;
138        bool hasDefaultValue = false;
139        if (auto m = interface_cast<IMapNode>(n.GetMembers())) {
140            for (auto&& node : m->GetMembers()) {
141                auto nn = node.node;
142                if (node.name == "flags") {
143                    node.name = "__flags";
144                    nn = RewritePropertyFlags(nn);
145                } else if (node.name == "defaultValue") {
146                    hasDefaultValue = true;
147                    nn = RewriteValueToAny(n.GetObjectId(), nn);
148                } else if (node.name == "value" || node.name == "valueObject") {
149                    node.name = "values";
150                    value = RewriteValueToAny(n.GetObjectId(), nn);
151                    nn = ISerNode::Ptr(new ArrayNode({ value }));
152                } else {
153                    nn = VisitNode(nn);
154                }
155                if (nn) {
156                    map.push_back(NamedNode { node.name, nn });
157                }
158            }
159            if (!value) {
160                map.push_back(NamedNode { "values", ISerNode::Ptr(new ArrayNode(BASE_NS::vector<ISerNode::Ptr> {})) });
161                if (!hasDefaultValue) {
162                    CORE_LOG_E("Invalid json file, property doesn't have value or defaultValue");
163                }
164            } else if (!hasDefaultValue) {
165                map.push_back(NamedNode { "defaultValue", value });
166            }
167            map.push_back(NamedNode { "modifiers", ISerNode::Ptr(new ArrayNode(BASE_NS::vector<ISerNode::Ptr> {})) });
168        }
169        auto mapNode = CreateShared<MapNode>(BASE_NS::move(map));
170        return ISerNode::Ptr(new ObjectNode("Property", name, ClassId::StackProperty, n.GetInstanceId(), mapNode));
171    }
172    ISerNode::Ptr RewriteObject(BASE_NS::string name, IObjectNode& n)
173    {
174        if (IsV1Property(n.GetObjectId())) {
175            return RewriteProperty(name, n);
176        }
177        return ISerNode::Ptr(new ObjectNode(
178            n.GetObjectClassName(), n.GetObjectName(), n.GetObjectId(), n.GetInstanceId(), VisitNode(n.GetMembers())));
179    }
180    ISerNode::Ptr RewritePropertyMap(const NamedNode& node)
181    {
182        BASE_NS::vector<ISerNode::Ptr> arr;
183        auto n = VisitNode(node.node);
184        if (auto map = interface_cast<IMapNode>(n)) {
185            for (auto&& m : map->GetMembers()) {
186                // the rewrite was already done by the above VisitNode call
187                arr.push_back(m.node);
188            }
189        }
190        return ISerNode::Ptr(new ArrayNode(arr));
191    }
192    void AddProperties(BASE_NS::vector<ISerNode::Ptr> properties, IMapNode& map)
193    {
194        if (auto p = interface_cast<IArrayNode>(map.FindNode("__properties"))) {
195            for (auto&& n : properties) {
196                p->AddNode(n);
197            }
198        } else {
199            map.AddNode("__properties", IArrayNode::Ptr(new ArrayNode(properties)));
200        }
201    }
202    void Visit(const IMapNode& n) override
203    {
204        BASE_NS::vector<NamedNode> map;
205        BASE_NS::vector<ISerNode::Ptr> properties;
206        for (auto&& m : n.GetMembers()) {
207            ISerNode::Ptr p;
208            if (auto obj = interface_cast<IObjectNode>(m.node)) {
209                p = RewriteObject(m.name, *obj);
210                if (IsV1Property(obj->GetObjectId())) {
211                    properties.push_back(p);
212                    p = nullptr;
213                }
214            } else if (m.name == "__properties") {
215                p = RewritePropertyMap(m);
216            } else {
217                p = VisitNode(m.node);
218            }
219            if (p) {
220                map.push_back(NamedNode { m.name, p });
221            }
222        }
223        auto mapNode = IMapNode::Ptr(new MapNode(BASE_NS::move(map)));
224        if (!properties.empty()) {
225            AddProperties(properties, *mapNode);
226        }
227        node = mapNode;
228    }
229    void Visit(const INilNode& n) override
230    {
231        node.reset(new NilNode);
232    }
233    void Visit(const IBoolNode& n) override
234    {
235        node.reset(new BoolNode(n.GetValue()));
236    }
237    void Visit(const IDoubleNode& n) override
238    {
239        node.reset(new DoubleNode(n.GetValue()));
240    }
241    void Visit(const IIntNode& n) override
242    {
243        node.reset(new IntNode(n.GetValue()));
244    }
245    void Visit(const IUIntNode& n) override
246    {
247        node.reset(new UIntNode(n.GetValue()));
248    }
249    void Visit(const IStringNode& n) override
250    {
251        node.reset(new StringNode(n.GetValue()));
252    }
253    void Visit(const IRefUriNode& n) override
254    {
255        node.reset(new RefNode(n.GetValue()));
256    }
257    void Visit(const ISerNode&) override
258    {
259        CORE_LOG_E("Unknown node type");
260    }
261
262    ISerNode::Ptr node;
263};
264
265ISerNode::Ptr RewriteMetaV1NodeTree(ISerNode::Ptr tree)
266{
267    NodeVisitor v;
268    tree->Apply(v);
269    return v.node;
270}
271
272} // namespace Serialization
273META_END_NAMESPACE()
274