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
16 #ifndef SCENE_PLUGIN_JSON_H
17 #define SCENE_PLUGIN_JSON_H
18
19 #include <core/json/json.h>
20
21 CORE_BEGIN_NAMESPACE()
22
23 constexpr int JSON_DEFAULT_INDENTATION = 2;
24
25 template<typename T>
26 BASE_NS::string to_formatted_string(const CORE_NS::json::value_t<T>& value,
27 const int indentation = JSON_DEFAULT_INDENTATION, const int currentIndentation = 0);
28
29 #ifdef JSON_IMPL
30 using namespace CORE_NS::json;
31
32 template<typename T>
append(BASE_NS::string & out,const typename value_t<T>::string & string)33 void append(BASE_NS::string& out, const typename value_t<T>::string& string)
34 {
35 out += '"';
36 out.append(escape(string));
37 out += '"';
38 }
39
40 template<typename T>
append(BASE_NS::string & out,const typename value_t<T>::object & object,const int indentation,int currentIndentation)41 void append(
42 BASE_NS::string& out, const typename value_t<T>::object& object, const int indentation, int currentIndentation)
43 {
44 if (object.empty()) {
45 // Keep empty objects on one row.
46 out.append("{}");
47 return;
48 }
49
50 out += "{\n";
51 currentIndentation += indentation;
52 out.append(currentIndentation, ' ');
53
54 int count = 0;
55 for (const auto& v : object) {
56 if (count++) {
57 out += ",\n";
58 out.append(currentIndentation, ' ');
59 }
60 CORE_NS::append<T>(out, v.key);
61 out += ": ";
62 out += to_formatted_string(v.value, indentation, currentIndentation);
63 }
64 currentIndentation -= indentation;
65 out += '\n';
66 out.append(currentIndentation, ' ');
67 out += '}';
68 }
69
70 template<typename T>
append(BASE_NS::string & out,const typename value_t<T>::array & array,const int indentation,int currentIndentation)71 void append(
72 BASE_NS::string& out, const typename value_t<T>::array& array, const int indentation, int currentIndentation)
73 {
74 if (array.empty()) {
75 // Keep empty arrays on one row.
76 out.append("[]");
77 return;
78 }
79
80 out += "[\n";
81 currentIndentation += indentation;
82 out.append(currentIndentation, ' ');
83 int count = 0;
84 for (const auto& v : array) {
85 if (count++) {
86 out += ",\n";
87 out.append(currentIndentation, ' ');
88 }
89 out += to_formatted_string(v, indentation, currentIndentation);
90 }
91 currentIndentation -= indentation;
92 out += '\n';
93 out.append(currentIndentation, ' ');
94 out += ']';
95 }
96
97 template<typename T>
append(BASE_NS::string & out,const double floatingPoint)98 void append(BASE_NS::string& out, const double floatingPoint)
99 {
100 const char* FLOATING_FORMAT_STR = "%.17g";
101 const int size = snprintf(nullptr, 0, FLOATING_FORMAT_STR, floatingPoint);
102 const size_t oldSize = out.size();
103 out.resize(oldSize + size);
104 const size_t newSize = out.size();
105 // "At most bufsz - 1 characters are written." string has size() characters + 1 for null so use size() +
106 // 1 as the total size. If resize() failed string size() hasn't changed, buffer will point to the null
107 // character and bufsz will be 1 i.e. only the null character will be written.
108 snprintf_s(out.data() + oldSize, newSize + 1 - oldSize, size, FLOATING_FORMAT_STR, floatingPoint);
109 }
110
111 template<typename T>
to_formatted_string(const value_t<T> & value,const int indentation,const int currentIndentation)112 BASE_NS::string to_formatted_string(const value_t<T>& value, const int indentation, const int currentIndentation)
113 {
114 BASE_NS::string out;
115 switch (value.type) {
116 case type::uninitialized:
117 out += "{}";
118 break;
119
120 case type::object:
121 append<T>(out, value.object_, indentation, currentIndentation);
122 break;
123
124 case type::array:
125 append<T>(out, value.array_, indentation, currentIndentation);
126 break;
127
128 case type::string:
129 CORE_NS::append<T>(out, value.string_);
130 break;
131
132 case type::floating_point:
133 CORE_NS::append<T>(out, value.float_);
134 break;
135
136 case type::signed_int:
137 out += BASE_NS::to_string(value.signed_);
138 break;
139
140 case type::unsigned_int:
141 out += BASE_NS::to_string(value.unsigned_);
142 break;
143
144 case type::boolean:
145 if (value.boolean_) {
146 out += "true";
147 } else {
148 out += "false";
149 }
150 break;
151
152 case type::null:
153 out += "null";
154 break;
155
156 default:
157 break;
158 }
159 return out;
160 }
161
162 // Explicit template instantiation for the needed types.
163 template BASE_NS::string to_formatted_string(const value& value, const int indentation, const int currentIndentation);
164 template BASE_NS::string to_formatted_string(
165 const standalone_value& value, const int indentation, const int currentIndentation);
166
167 #endif // JSON_IMPL
168
169 CORE_END_NAMESPACE()
170
171 #endif // SCENE_PLUGIN_JSON_H
172