/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "metav1_compat.h"
#include
META_BEGIN_NAMESPACE()
namespace Serialization {
using BasicMetaTypes = TypeList;
static bool IsV1Property(ObjectId oid)
{
static const BASE_NS::Uid propertyUid("00000000-0000-0000-5072-6f7065727479");
return oid.ToUid().data[1] == propertyUid.data[1];
}
template
static bool CheckBasicMetaTypes(ObjectId oid, ObjectId& out, TypeList)
{
return (false || ... ||
(UidFromType().data[0] == oid.ToUid().data[0] ? (out = UidFromType(), true) : false));
}
static bool IsV1BasicArray(ObjectId oid, ObjectId& out)
{
return CheckBasicMetaTypes(oid, out, BasicMetaTypes {});
}
static bool IsV1Any(ObjectId oid)
{
static const BASE_NS::Uid anyUid("00000000-0000-0000-5479-706564416e79");
return oid.ToUid().data[1] == anyUid.data[1];
}
static ObjectId MakeAny(ObjectId oid)
{
BASE_NS::Uid uid("00000000-0000-0000-4275-696c74416e79");
uid.data[0] = oid.ToUid().data[0];
return uid;
}
static ObjectId MakeArrayAny(ObjectId oid)
{
BASE_NS::Uid uid("00000000-0000-0000-4172-726179416e79");
uid.data[0] = oid.ToUid().data[0];
return uid;
}
class NodeVisitor : public IntroduceInterfaces {
public:
static ISerNode::Ptr VisitNode(ISerNode::Ptr node)
{
if (!node) {
return nullptr;
}
NodeVisitor v;
node->Apply(v);
return v.node;
}
void Visit(const IRootNode& n) override
{
node.reset(new RootNode(n.GetSerializerVersion(), VisitNode(n.GetObject())));
}
void Visit(const IObjectNode& n) override
{
node.reset(new ObjectNode(
n.GetObjectClassName(), n.GetObjectName(), n.GetObjectId(), n.GetInstanceId(), VisitNode(n.GetMembers())));
}
void Visit(const IArrayNode& n) override
{
BASE_NS::vector arr;
for (auto&& m : n.GetMembers()) {
if (auto n = VisitNode(m)) {
arr.push_back(n);
}
}
node.reset(new ArrayNode(BASE_NS::move(arr)));
}
ISerNode::Ptr RewriteValueToAny(ObjectId property, ISerNode::Ptr node)
{
if (auto n = interface_cast(node)) {
if (IsV1Any(n->GetObjectId())) {
return ISerNode::Ptr(new ObjectNode("Any", n->GetObjectName(), MakeAny(n->GetObjectId()),
n->GetInstanceId(), VisitNode(n->GetMembers())));
}
}
BASE_NS::vector m;
if (auto n = VisitNode(node)) {
m.push_back(NamedNode { "value", n });
}
ObjectId any = MakeAny(property);
ObjectId uid;
if (IsV1BasicArray(property, uid)) {
any = MakeArrayAny(uid);
}
return ISerNode::Ptr(new ObjectNode("Any", "", any, {}, CreateShared(m)));
}
ISerNode::Ptr RewritePropertyFlags(ISerNode::Ptr n)
{
uint64_t value {};
uint64_t converted { uint64_t(ObjectFlagBits::SERIALIZE) };
if (ExtractNumber(n, value)) {
if (value & 8) {
converted |= 8;
}
if (value & 128) {
converted |= 16;
}
if (converted != uint64_t(ObjectFlagBits::SERIALIZE)) {
return ISerNode::Ptr(new UIntNode(converted));
}
}
return nullptr;
}
ISerNode::Ptr RewriteProperty(BASE_NS::string name, const IObjectNode& n)
{
BASE_NS::vector map;
ISerNode::Ptr value;
bool hasDefaultValue = false;
if (auto m = interface_cast(n.GetMembers())) {
for (auto&& node : m->GetMembers()) {
auto nn = node.node;
if (node.name == "flags") {
node.name = "__flags";
nn = RewritePropertyFlags(nn);
} else if (node.name == "defaultValue") {
hasDefaultValue = true;
nn = RewriteValueToAny(n.GetObjectId(), nn);
} else if (node.name == "value" || node.name == "valueObject") {
node.name = "values";
value = RewriteValueToAny(n.GetObjectId(), nn);
nn = ISerNode::Ptr(new ArrayNode({ value }));
} else {
nn = VisitNode(nn);
}
if (nn) {
map.push_back(NamedNode { node.name, nn });
}
}
if (!value) {
map.push_back(NamedNode { "values", ISerNode::Ptr(new ArrayNode(BASE_NS::vector {})) });
if (!hasDefaultValue) {
CORE_LOG_E("Invalid json file, property doesn't have value or defaultValue");
}
} else if (!hasDefaultValue) {
map.push_back(NamedNode { "defaultValue", value });
}
map.push_back(NamedNode { "modifiers", ISerNode::Ptr(new ArrayNode(BASE_NS::vector {})) });
}
auto mapNode = CreateShared(BASE_NS::move(map));
return ISerNode::Ptr(new ObjectNode("Property", name, ClassId::StackProperty, n.GetInstanceId(), mapNode));
}
ISerNode::Ptr RewriteObject(BASE_NS::string name, IObjectNode& n)
{
if (IsV1Property(n.GetObjectId())) {
return RewriteProperty(name, n);
}
return ISerNode::Ptr(new ObjectNode(
n.GetObjectClassName(), n.GetObjectName(), n.GetObjectId(), n.GetInstanceId(), VisitNode(n.GetMembers())));
}
ISerNode::Ptr RewritePropertyMap(const NamedNode& node)
{
BASE_NS::vector arr;
auto n = VisitNode(node.node);
if (auto map = interface_cast(n)) {
for (auto&& m : map->GetMembers()) {
// the rewrite was already done by the above VisitNode call
arr.push_back(m.node);
}
}
return ISerNode::Ptr(new ArrayNode(arr));
}
void AddProperties(BASE_NS::vector properties, IMapNode& map)
{
if (auto p = interface_cast(map.FindNode("__properties"))) {
for (auto&& n : properties) {
p->AddNode(n);
}
} else {
map.AddNode("__properties", IArrayNode::Ptr(new ArrayNode(properties)));
}
}
void Visit(const IMapNode& n) override
{
BASE_NS::vector map;
BASE_NS::vector properties;
for (auto&& m : n.GetMembers()) {
ISerNode::Ptr p;
if (auto obj = interface_cast(m.node)) {
p = RewriteObject(m.name, *obj);
if (IsV1Property(obj->GetObjectId())) {
properties.push_back(p);
p = nullptr;
}
} else if (m.name == "__properties") {
p = RewritePropertyMap(m);
} else {
p = VisitNode(m.node);
}
if (p) {
map.push_back(NamedNode { m.name, p });
}
}
auto mapNode = IMapNode::Ptr(new MapNode(BASE_NS::move(map)));
if (!properties.empty()) {
AddProperties(properties, *mapNode);
}
node = mapNode;
}
void Visit(const INilNode& n) override
{
node.reset(new NilNode);
}
void Visit(const IBoolNode& n) override
{
node.reset(new BoolNode(n.GetValue()));
}
void Visit(const IDoubleNode& n) override
{
node.reset(new DoubleNode(n.GetValue()));
}
void Visit(const IIntNode& n) override
{
node.reset(new IntNode(n.GetValue()));
}
void Visit(const IUIntNode& n) override
{
node.reset(new UIntNode(n.GetValue()));
}
void Visit(const IStringNode& n) override
{
node.reset(new StringNode(n.GetValue()));
}
void Visit(const IRefUriNode& n) override
{
node.reset(new RefNode(n.GetValue()));
}
void Visit(const ISerNode&) override
{
CORE_LOG_E("Unknown node type");
}
ISerNode::Ptr node;
};
ISerNode::Ptr RewriteMetaV1NodeTree(ISerNode::Ptr tree)
{
NodeVisitor v;
tree->Apply(v);
return v.node;
}
} // namespace Serialization
META_END_NAMESPACE()