1 /*
2 * Copyright (c) 2025 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 #include "ets_exceptions.h"
17 #include "ets_handle.h"
18 #include "include/thread_scopes.h"
19 #include "macros.h"
20 #include "types/ets_escompat_array.h"
21 #include "types/ets_object.h"
22 #include "json_helper.h"
23 #include "ets_to_string_cache.h"
24 namespace ark::ets::intrinsics::helpers {
25
26 static constexpr int RECORD_HEAD_ENTRY_INDEX = 3;
27 static constexpr int RECORD_NEXT_FIELD_INDEX = 1;
28 static constexpr int RECORD_KEY_FIELD_INDEX = 2;
29 static constexpr int RECORD_VAL_FIELD_INDEX = 3;
30
AppendJSONString(EtsHandle<EtsObject> & value,bool hasContent)31 bool JSONStringifier::AppendJSONString(EtsHandle<EtsObject> &value, bool hasContent)
32 {
33 if (hasContent) {
34 buffer_ += ",";
35 }
36 buffer_ += "\"";
37 buffer_ += key_;
38 buffer_ += "\":";
39 return SerializeObject(value);
40 }
41
AppendJSONPrimitive(const PandaString & value,bool hasContent)42 void JSONStringifier::AppendJSONPrimitive(const PandaString &value, bool hasContent)
43 {
44 if (hasContent) {
45 buffer_ += ",";
46 }
47
48 buffer_ += "\"";
49 buffer_ += key_;
50 buffer_ += "\":";
51
52 if ((value == "NaN") || (value == "Infinity") || (value == "-Infinity")) {
53 buffer_ += "null";
54 } else {
55 buffer_ += value;
56 }
57 }
58
AppendJSONPointPrimitive(const PandaString & value,bool hasContent)59 void JSONStringifier::AppendJSONPointPrimitive(const PandaString &value, bool hasContent)
60 {
61 if (hasContent) {
62 buffer_ += ",";
63 }
64
65 buffer_ += "\"";
66 buffer_ += key_;
67 buffer_ += "\":";
68
69 if ((value == "NaN") || (value == "Infinity") || (value == "-Infinity")) {
70 buffer_ += "null";
71 } else {
72 buffer_ += value;
73 }
74 }
75
SerializeFields(EtsHandle<EtsObject> & value)76 bool JSONStringifier::SerializeFields(EtsHandle<EtsObject> &value)
77 {
78 ASSERT(value.GetPtr() != nullptr);
79 bool hasContent = false;
80 auto keys = PandaUnorderedSet<PandaString>();
81 bool isSuccessful = false;
82
83 value->GetClass()->EnumerateBaseClasses([&](EtsClass *c) {
84 auto fields = c->GetRuntimeClass()->GetFields();
85 for (auto &field : fields) {
86 if (!HandleField(value, EtsField::FromRuntimeField(&field), hasContent, keys)) {
87 isSuccessful = false;
88 return true;
89 }
90 isSuccessful = true;
91 }
92 return false;
93 });
94 return isSuccessful;
95 }
96
SerializeJSONObject(EtsHandle<EtsObject> & value)97 bool JSONStringifier::SerializeJSONObject(EtsHandle<EtsObject> &value)
98 {
99 bool isContain = PushValue(value);
100 if (isContain) {
101 ThrowEtsException(EtsCoroutine::GetCurrent(), panda_file_items::class_descriptors::TYPE_ERROR,
102 "cyclic object value");
103 return false;
104 }
105 buffer_ += "{";
106 if (!SerializeFields(value)) {
107 return false;
108 };
109 buffer_ += "}";
110 return true;
111 }
112
SerializeJSONObjectArray(EtsHandle<EtsObject> & value)113 bool JSONStringifier::SerializeJSONObjectArray(EtsHandle<EtsObject> &value)
114 {
115 auto coro = EtsCoroutine::GetCurrent();
116 EtsHandleScope scope(coro);
117
118 bool isSuccessful = false;
119 buffer_ += "[";
120
121 auto array = EtsHandle<EtsArrayObject<EtsObject>>(coro, EtsArrayObject<EtsObject>::FromEtsObject(value.GetPtr()));
122 auto realArray = EtsHandle<EtsObjectArray>(coro, array->GetData());
123 ASSERT(realArray.GetPtr() != nullptr);
124 auto length = array->GetActualLength();
125
126 for (size_t i = 0; i < length; ++i) {
127 auto elem = EtsHandle<EtsObject>(coro, realArray->Get(i));
128 if (elem.GetPtr() == nullptr || elem->GetClass()->IsFunction()) {
129 buffer_ += "null";
130 isSuccessful = true;
131 } else {
132 isSuccessful = SerializeObject(elem);
133 }
134 if (!isSuccessful) {
135 return false;
136 }
137 if (i != length - 1) {
138 buffer_ += ",";
139 }
140 }
141
142 buffer_ += "]";
143 return isSuccessful;
144 }
145
DealSpecialCharacter(uint8_t ch)146 bool JSONStringifier::DealSpecialCharacter(uint8_t ch)
147 {
148 bool isSpecialCharacter = true;
149 switch (ch) {
150 case '\"':
151 buffer_ += "\\\"";
152 break;
153 case '\\':
154 buffer_ += "\\\\";
155 break;
156 case '\b':
157 buffer_ += "\\b";
158 break;
159 case '\f':
160 buffer_ += "\\f";
161 break;
162 case '\n':
163 buffer_ += "\\n";
164 break;
165 case '\r':
166 buffer_ += "\\r";
167 break;
168 case '\t':
169 buffer_ += "\\t";
170 break;
171 case '\0':
172 buffer_ += "\\u0000";
173 break;
174 default:
175 if (ch < CODE_SPACE) {
176 AppendUnicodeEscape(static_cast<uint32_t>(ch));
177 } else {
178 isSpecialCharacter = false;
179 }
180 }
181 return isSpecialCharacter;
182 }
183
DealUtf16Character(uint16_t ch0,uint16_t ch1)184 void JSONStringifier::DealUtf16Character(uint16_t ch0, uint16_t ch1)
185 {
186 if ((IsHighSurrogate(ch0) && !IsLowSurrogate(ch1)) || IsLowSurrogate(ch0)) {
187 AppendUnicodeEscape(static_cast<uint32_t>(ch0));
188 return;
189 }
190
191 utf::Utf8Char uc = utf::ConvertUtf16ToUtf8(ch0, ch1, modify_);
192 for (size_t j = 0; j < uc.n; ++j) {
193 if (uc.n == utf::UtfLength::ONE && DealSpecialCharacter(uc.ch[j])) {
194 break;
195 }
196 buffer_ += uc.ch[j];
197 }
198 }
199
AppendUtf16ToQuotedString(const Span<const uint16_t> & sp)200 void JSONStringifier::AppendUtf16ToQuotedString(const Span<const uint16_t> &sp)
201 {
202 buffer_ += "\"";
203 uint16_t next16Code = 0;
204 for (uint32_t i = 0; i < sp.size(); ++i) {
205 const auto ch = sp[i];
206 if (IsHighSurrogate(ch) && (i + 1 < sp.size()) && IsLowSurrogate(sp[i + 1])) {
207 next16Code = sp[i + 1];
208 i++;
209 } else {
210 next16Code = 0;
211 }
212 DealUtf16Character(ch, next16Code);
213 }
214 buffer_ += "\"";
215 }
216
AppendUtf8Character(const Span<const uint8_t> & sp,uint32_t index)217 uint32_t JSONStringifier::AppendUtf8Character(const Span<const uint8_t> &sp, uint32_t index)
218 {
219 uint8_t len {0};
220 const auto ch = sp[index];
221 if (ch < utf::BIT_MASK_1) {
222 len = utf::UtfLength::ONE;
223 } else if ((ch & utf::BIT_MASK_3) == utf::BIT_MASK_2) {
224 len = utf::UtfLength::TWO;
225 } else if ((ch & utf::BIT_MASK_4) == utf::BIT_MASK_3) {
226 len = utf::UtfLength::THREE;
227 } else if ((ch & utf::BIT_MASK_5) == utf::BIT_MASK_4) {
228 len = utf::UtfLength::FOUR;
229 } else {
230 UNREACHABLE();
231 }
232 ASSERT(index + len <= sp.size());
233 for (uint32_t i = 0; i < len; i++) {
234 buffer_ += sp[index + i];
235 }
236 return len;
237 }
238
AppendUtf8ToQuotedString(const Span<const uint8_t> & sp)239 void JSONStringifier::AppendUtf8ToQuotedString(const Span<const uint8_t> &sp)
240 {
241 buffer_ += "\"";
242 for (uint32_t i = 0; i < sp.size();) {
243 const auto ch = sp[i];
244 if (DealSpecialCharacter(ch)) {
245 i++;
246 continue;
247 }
248 i += AppendUtf8Character(sp, i);
249 }
250 buffer_ += "\"";
251 }
252
SerializeJSONString(EtsHandle<EtsObject> & value)253 bool JSONStringifier::SerializeJSONString(EtsHandle<EtsObject> &value)
254 {
255 EtsHandleScope scope(EtsCoroutine::GetCurrent());
256 auto stringHandle = EtsHandle<EtsString>(EtsCoroutine::GetCurrent(), EtsString::FromEtsObject(value.GetPtr()));
257 ASSERT(stringHandle.GetPtr() != nullptr);
258 if (stringHandle->IsEmpty()) {
259 buffer_ += "\"\"";
260 } else if (stringHandle->IsUtf16()) {
261 Span<const uint16_t> sp(stringHandle->GetDataUtf16(), stringHandle->GetLength());
262 AppendUtf16ToQuotedString(sp);
263 } else {
264 Span<const uint8_t> sp(stringHandle->GetDataMUtf8(), stringHandle->GetLength());
265 AppendUtf8ToQuotedString(sp);
266 }
267 return true;
268 }
269
SerializeJSONBoxedBoolean(EtsHandle<EtsObject> & value)270 bool JSONStringifier::SerializeJSONBoxedBoolean(EtsHandle<EtsObject> &value)
271 {
272 auto val = EtsBoxPrimitive<EtsBoolean>::Unbox(value.GetPtr());
273 if (val == 0) {
274 buffer_ += "false";
275 } else {
276 buffer_ += "true";
277 }
278 return true;
279 }
280
SerializeJSONBoxedDouble(EtsHandle<EtsObject> & value)281 bool JSONStringifier::SerializeJSONBoxedDouble(EtsHandle<EtsObject> &value)
282 {
283 auto val = EtsBoxPrimitive<EtsDouble>::Unbox(value.GetPtr());
284 auto cache = PandaEtsVM::GetCurrent()->GetDoubleToStringCache();
285 auto coro = EtsCoroutine::GetCurrent();
286 PandaString v = cache->GetOrCache(coro, val)->GetMutf8();
287 if ((v == "NaN") || (v == "Infinity") || (v == "-Infinity")) {
288 buffer_ += "null";
289 } else {
290 buffer_ += v;
291 }
292 return true;
293 }
294
SerializeJSONBoxedFloat(EtsHandle<EtsObject> & value)295 bool JSONStringifier::SerializeJSONBoxedFloat(EtsHandle<EtsObject> &value)
296 {
297 auto val = EtsBoxPrimitive<EtsFloat>::Unbox(value.GetPtr());
298 auto cache = PandaEtsVM::GetCurrent()->GetFloatToStringCache();
299 auto coro = EtsCoroutine::GetCurrent();
300 PandaString v = cache->GetOrCache(coro, val)->GetMutf8();
301 if ((v == "NaN") || (v == "Infinity") || (v == "-Infinity")) {
302 buffer_ += "null";
303 } else {
304 buffer_ += v;
305 }
306 return true;
307 }
308
SerializeJSONBoxedLong(EtsHandle<EtsObject> & value)309 bool JSONStringifier::SerializeJSONBoxedLong(EtsHandle<EtsObject> &value)
310 {
311 auto val = EtsBoxPrimitive<EtsLong>::Unbox(value.GetPtr());
312 auto cache = PandaEtsVM::GetCurrent()->GetLongToStringCache();
313 auto coro = EtsCoroutine::GetCurrent();
314 PandaString v = cache->GetOrCache(coro, val)->GetMutf8();
315 if ((v == "NaN") || (v == "Infinity") || (v == "-Infinity")) {
316 buffer_ += "null";
317 } else {
318 buffer_ += v;
319 }
320 return true;
321 }
322
323 template <typename T>
SerializeJSONBoxedPrimitiveNoCache(EtsHandle<EtsObject> & value)324 bool JSONStringifier::SerializeJSONBoxedPrimitiveNoCache(EtsHandle<EtsObject> &value)
325 {
326 T val = EtsBoxPrimitive<T>::Unbox(value.GetPtr());
327 if constexpr (std::is_same_v<T, EtsChar>) {
328 buffer_ += "\"";
329 buffer_ += static_cast<char>(val);
330 buffer_ += "\"";
331 } else {
332 buffer_ += std::to_string(val);
333 }
334 return true;
335 }
336
SerializeEmptyObject()337 bool JSONStringifier::SerializeEmptyObject()
338 {
339 buffer_ += "{}";
340 return true;
341 }
342
SerializeJSONNullValue()343 bool JSONStringifier::SerializeJSONNullValue()
344 {
345 buffer_ += "null";
346 return true;
347 }
348
349 template <typename T>
HandleNumeric(EtsHandle<EtsObject> & value)350 PandaString JSONStringifier::HandleNumeric(EtsHandle<EtsObject> &value)
351 {
352 PandaString result;
353 auto coro = EtsCoroutine::GetCurrent();
354 if constexpr (std::is_same_v<T, EtsDouble>) {
355 auto val = EtsBoxPrimitive<EtsDouble>::Unbox(value.GetPtr());
356 auto cache = PandaEtsVM::GetCurrent()->GetDoubleToStringCache();
357 auto v = cache->GetOrCache(coro, val)->GetMutf8();
358 if ((v == "NaN") || (v == "Infinity") || (v == "-Infinity")) {
359 result = "null";
360 } else {
361 result = v;
362 }
363 } else if constexpr (std::is_same_v<T, EtsFloat>) {
364 auto val = EtsBoxPrimitive<EtsFloat>::Unbox(value.GetPtr());
365 auto cache = PandaEtsVM::GetCurrent()->GetFloatToStringCache();
366 auto v = cache->GetOrCache(coro, val)->GetMutf8();
367 if ((v == "NaN") || (v == "Infinity") || (v == "-Infinity")) {
368 result = "null";
369 } else {
370 result = v;
371 }
372 } else if constexpr (std::is_same_v<T, EtsLong>) {
373 auto val = EtsBoxPrimitive<EtsLong>::Unbox(value.GetPtr());
374 auto cache = PandaEtsVM::GetCurrent()->GetLongToStringCache();
375 auto v = cache->GetOrCache(coro, val)->GetMutf8();
376 if ((v == "NaN") || (v == "Infinity") || (v == "-Infinity")) {
377 result = "null";
378 } else {
379 result = v;
380 }
381 } else if constexpr (std::is_same<T, EtsBoolean>()) {
382 auto val = EtsBoxPrimitive<EtsBoolean>::Unbox(value.GetPtr());
383 result = val == 0 ? "false" : "true";
384 } else if constexpr (std::is_same<T, EtsChar>()) {
385 auto val = EtsBoxPrimitive<EtsChar>::Unbox(value.GetPtr());
386 result = static_cast<char>(val);
387 } else {
388 T val = EtsBoxPrimitive<T>::Unbox(value.GetPtr());
389 result = std::to_string(val);
390 }
391 return result;
392 }
393
HandleRecordKey(EtsHandle<EtsObject> & key)394 bool JSONStringifier::HandleRecordKey(EtsHandle<EtsObject> &key)
395 {
396 ASSERT(key.GetPtr() != nullptr);
397 if (key->IsStringClass()) {
398 key_ = EtsString::FromEtsObject(key.GetPtr())->GetMutf8();
399 } else {
400 auto desc = key->GetClass()->GetDescriptor();
401 if (desc == panda_file_items::class_descriptors::BOX_BOOLEAN) {
402 key_ = HandleNumeric<EtsBoolean>(key);
403 } else if (desc == panda_file_items::class_descriptors::BOX_DOUBLE) {
404 key_ = HandleNumeric<EtsDouble>(key);
405 } else if (desc == panda_file_items::class_descriptors::BOX_FLOAT) {
406 key_ = HandleNumeric<EtsFloat>(key);
407 } else if (desc == panda_file_items::class_descriptors::BOX_LONG) {
408 key_ = HandleNumeric<EtsLong>(key);
409 } else if (desc == panda_file_items::class_descriptors::BOX_BYTE) {
410 key_ = HandleNumeric<EtsByte>(key);
411 } else if (desc == panda_file_items::class_descriptors::BOX_SHORT) {
412 key_ = HandleNumeric<EtsShort>(key);
413 } else if (desc == panda_file_items::class_descriptors::BOX_CHAR) {
414 key_ = HandleNumeric<EtsChar>(key);
415 } else if (desc == panda_file_items::class_descriptors::BOX_INT) {
416 key_ = HandleNumeric<EtsInt>(key);
417 }
418 }
419 return true;
420 }
421
SerializeJSONRecord(EtsHandle<EtsObject> & value)422 bool JSONStringifier::SerializeJSONRecord(EtsHandle<EtsObject> &value)
423 {
424 bool isContain = PushValue(value);
425 if (isContain) {
426 ThrowEtsException(EtsCoroutine::GetCurrent(), panda_file_items::class_descriptors::TYPE_ERROR,
427 "cyclic object value");
428 return false;
429 }
430 buffer_ += "{";
431 ASSERT(value.GetPtr() != nullptr);
432 auto cls = value->GetClass();
433 auto headEntry = cls->GetFieldByIndex(RECORD_HEAD_ENTRY_INDEX);
434 auto coro = EtsCoroutine::GetCurrent();
435
436 EtsHandleScope scope(coro);
437 EtsHandle<EtsObject> head(coro, value->GetFieldObject(headEntry));
438 if (head.GetPtr() == nullptr) {
439 buffer_ += "}";
440 return true;
441 }
442 auto hasContent = false;
443 EtsHandle<EtsObject> next(coro, head->GetFieldObject(head->GetClass()->GetFieldByIndex(RECORD_NEXT_FIELD_INDEX)));
444 if (next.GetPtr() == nullptr) {
445 buffer_ += "}";
446 return true;
447 }
448 do {
449 EtsHandle<EtsObject> key(coro, next->GetFieldObject(next->GetClass()->GetFieldByIndex(RECORD_KEY_FIELD_INDEX)));
450 EtsHandle<EtsObject> val(coro, next->GetFieldObject(next->GetClass()->GetFieldByIndex(RECORD_VAL_FIELD_INDEX)));
451 next = EtsHandle<EtsObject>(coro,
452 next->GetFieldObject(next->GetClass()->GetFieldByIndex(RECORD_NEXT_FIELD_INDEX)));
453 if (key.GetPtr() == nullptr || val.GetPtr() == nullptr) {
454 continue;
455 }
456 if (val->GetClass()->IsFunction()) {
457 continue;
458 }
459 HandleRecordKey(key);
460 AppendJSONString(val, hasContent);
461 hasContent = true;
462 } while (head.GetPtr() != next.GetPtr() && next.GetPtr() != nullptr);
463 buffer_ += "}";
464 return true;
465 }
466
PushValue(EtsHandle<EtsObject> & value)467 bool JSONStringifier::PushValue(EtsHandle<EtsObject> &value)
468 {
469 ASSERT(value.GetPtr() != nullptr);
470 if (path_.find(value->GetHashCode()) != path_.end()) {
471 return true;
472 }
473 path_.insert(value->GetHashCode());
474 return false;
475 }
476
ResolveDisplayName(const EtsField * field)477 PandaString JSONStringifier::ResolveDisplayName(const EtsField *field)
478 {
479 auto fieldNameData = field->GetCoreType()->GetName();
480 auto fieldNameLength = fieldNameData.utf16Length;
481 std::string_view fieldName(utf::Mutf8AsCString(fieldNameData.data), fieldNameLength);
482 if (fieldName.rfind(PROPERTY, 0) == 0) {
483 ASSERT(fieldNameLength > PROPERTY_PREFIX_LENGTH);
484 return PandaString(reinterpret_cast<const char *>(
485 fieldNameData.data + // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
486 PROPERTY_PREFIX_LENGTH),
487 fieldNameLength - PROPERTY_PREFIX_LENGTH);
488 }
489 return PandaString(reinterpret_cast<const char *>(fieldNameData.data), fieldNameLength);
490 }
491
CheckUnsupportedAnnotation(EtsField * field)492 bool JSONStringifier::CheckUnsupportedAnnotation(EtsField *field)
493 {
494 auto *runtimeClass = field->GetDeclaringClass()->GetRuntimeClass();
495 const panda_file::File &pf = *runtimeClass->GetPandaFile();
496 panda_file::FieldDataAccessor fda(pf, field->GetRuntimeField()->GetFileId());
497 bool hasAnnotation = false;
498 fda.EnumerateAnnotations([&hasAnnotation]([[maybe_unused]] panda_file::File::EntityId annId) {
499 hasAnnotation = true;
500 return;
501 });
502 return hasAnnotation;
503 }
504
505 // CC-OFFNXT(huge_method[C++], huge_cyclomatic_complexity[C++], G.FUN.01-CPP) solid logic
506 // CC-OFFNXT(huge_cca_cyclomatic_complexity[C++]) solid logic
SerializeObject(EtsHandle<EtsObject> & value)507 bool JSONStringifier::SerializeObject(EtsHandle<EtsObject> &value)
508 {
509 if (value.GetPtr() == nullptr) {
510 return true;
511 }
512
513 auto coro = EtsCoroutine::GetCurrent();
514 auto platformTypes = PlatformTypes(coro);
515 bool isSuccessful = false;
516
517 auto desc = value->GetClass()->GetDescriptor();
518 if (desc == panda_file_items::class_descriptors::BOX_BOOLEAN) {
519 buffer_ += HandleNumeric<EtsBoolean>(value);
520 isSuccessful = true;
521 } else if (desc == panda_file_items::class_descriptors::BOX_DOUBLE) {
522 buffer_ += HandleNumeric<EtsDouble>(value);
523 isSuccessful = true;
524 } else if (desc == panda_file_items::class_descriptors::BOX_FLOAT) {
525 buffer_ += HandleNumeric<EtsFloat>(value);
526 isSuccessful = true;
527 } else if (desc == panda_file_items::class_descriptors::BOX_LONG) {
528 buffer_ += HandleNumeric<EtsLong>(value);
529 isSuccessful = true;
530 } else if (desc == panda_file_items::class_descriptors::BOX_BYTE) {
531 buffer_ += HandleNumeric<EtsByte>(value);
532 isSuccessful = true;
533 } else if (desc == panda_file_items::class_descriptors::BOX_SHORT) {
534 buffer_ += HandleNumeric<EtsShort>(value);
535 isSuccessful = true;
536 } else if (desc == panda_file_items::class_descriptors::BOX_CHAR) {
537 buffer_ += "\"" + HandleNumeric<EtsChar>(value) + "\"";
538 isSuccessful = true;
539 } else if (desc == panda_file_items::class_descriptors::BOX_INT) {
540 buffer_ += HandleNumeric<EtsInt>(value);
541 isSuccessful = true;
542 } else if (desc == panda_file_items::class_descriptors::STRING) {
543 isSuccessful = SerializeJSONString(value);
544 } else if (desc == panda_file_items::class_descriptors::RECORD) {
545 coro->ManagedCodeEnd();
546 {
547 ScopedManagedCodeThread v(coro);
548 isSuccessful = SerializeJSONRecord(value);
549 }
550 coro->ManagedCodeBegin();
551 } else if (desc == panda_file_items::class_descriptors::DATE) {
552 isSuccessful = false;
553 } else if (desc == panda_file_items::class_descriptors::ARRAY) {
554 coro->ManagedCodeEnd();
555 {
556 ScopedManagedCodeThread v(coro);
557 isSuccessful = SerializeJSONObjectArray(value);
558 }
559 coro->ManagedCodeBegin();
560 } else if (desc == panda_file_items::class_descriptors::PROMISE ||
561 desc == panda_file_items::class_descriptors::SET || desc == panda_file_items::class_descriptors::MAP ||
562 desc == panda_file_items::class_descriptors::MAPENTRY) {
563 isSuccessful = SerializeEmptyObject();
564 } else if (desc == panda_file_items::class_descriptors::NULL_VALUE) {
565 isSuccessful = SerializeJSONNullValue();
566 } else if (desc == panda_file_items::class_descriptors::JS_VALUE) {
567 isSuccessful = false;
568 } else {
569 if (value->IsInstanceOf(platformTypes->escompatRegExpExecArray)) {
570 coro->ManagedCodeEnd();
571 {
572 ScopedManagedCodeThread v(coro);
573 auto result = EtsHandle<EtsObject>(coro, value->GetFieldObject(value->GetClass()->GetFieldByIndex(1)));
574 isSuccessful = SerializeJSONObjectArray(result);
575 }
576 coro->ManagedCodeBegin();
577 } else if (value->IsInstanceOf(platformTypes->escompatJsonReplacer)) {
578 PandaVector<Value> args {Value(value->GetCoreType())};
579 auto jsonReplacerMethod = value->GetClass()->GetInstanceMethod("jsonReplacer", nullptr)->GetPandaMethod();
580 auto ret = jsonReplacerMethod->Invoke(coro, args.data());
581 if (UNLIKELY(coro->HasPendingException())) {
582 return false;
583 }
584 auto retobj = EtsHandle<EtsObject>(coro, EtsObject::FromCoreType(ret.GetAs<ObjectHeader *>()));
585 coro->ManagedCodeEnd();
586 {
587 ScopedManagedCodeThread v(coro);
588 isSuccessful = SerializeJSONRecord(retobj);
589 }
590 coro->ManagedCodeBegin();
591 } else if (value->IsArrayClass()) {
592 coro->ManagedCodeEnd();
593 {
594 ScopedManagedCodeThread v(coro);
595 isSuccessful = SerializeJSONObjectArray(value);
596 }
597 coro->ManagedCodeBegin();
598 } else if (value->GetClass()->IsFunction()) {
599 buffer_ += "undefined";
600 } else if (value->IsInstanceOf(platformTypes->coreTuple)) {
601 isSuccessful = false;
602 } else if (value->GetClass()->IsClass()) {
603 coro->ManagedCodeEnd();
604 {
605 ScopedManagedCodeThread v(coro);
606 isSuccessful = SerializeJSONObject(value);
607 }
608 coro->ManagedCodeBegin();
609 } else {
610 LOG(ERROR, ETS) << "Unsupported type: " << value->GetClass()->GetDescriptor();
611 return false;
612 }
613 }
614 return isSuccessful;
615 }
616
617 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
HandleField(EtsHandle<EtsObject> & obj,EtsField * etsField,bool & hasContent,PandaUnorderedSet<PandaString> & keys)618 bool JSONStringifier::HandleField(EtsHandle<EtsObject> &obj, EtsField *etsField, bool &hasContent,
619 PandaUnorderedSet<PandaString> &keys)
620 {
621 if (etsField->IsStatic()) {
622 return true;
623 }
624
625 if (CheckUnsupportedAnnotation(etsField)) {
626 return false;
627 }
628 key_ = ResolveDisplayName(etsField);
629 if (keys.find(key_) != keys.end()) {
630 return false;
631 }
632 keys.insert(key_);
633 auto coro = EtsCoroutine::GetCurrent();
634 auto etsType = etsField->GetEtsType();
635
636 switch (etsType) {
637 case EtsType::BOOLEAN: {
638 auto val = obj->GetFieldPrimitive<EtsBoolean>(etsField);
639 PandaString value = val == 0 ? "false" : "true";
640 AppendJSONPrimitive(value, hasContent);
641 break;
642 }
643 case EtsType::BYTE: {
644 auto val = obj->GetFieldPrimitive<EtsByte>(etsField);
645 AppendJSONPrimitive(PandaString(std::to_string(val)), hasContent);
646 break;
647 }
648 case EtsType::CHAR: {
649 auto val = obj->GetFieldPrimitive<EtsChar>(etsField);
650 AppendJSONPrimitive(PandaString(std::to_string(val)), hasContent);
651 break;
652 }
653 case EtsType::SHORT: {
654 auto val = obj->GetFieldPrimitive<EtsShort>(etsField);
655 AppendJSONPrimitive(PandaString(std::to_string(val)), hasContent);
656 break;
657 }
658 case EtsType::INT: {
659 auto val = obj->GetFieldPrimitive<EtsInt>(etsField);
660 AppendJSONPrimitive(PandaString(std::to_string(val)), hasContent);
661 break;
662 }
663 case EtsType::LONG: {
664 ASSERT(obj.GetPtr() != nullptr);
665 auto val = obj->GetFieldPrimitive<EtsLong>(etsField);
666 auto cache = PandaEtsVM::GetCurrent()->GetLongToStringCache();
667 PandaString v = cache->GetOrCache(coro, val)->GetMutf8();
668 AppendJSONPrimitive(v, hasContent);
669 break;
670 }
671 case EtsType::FLOAT: {
672 auto val = obj->GetFieldPrimitive<EtsFloat>(etsField);
673 auto cache = PandaEtsVM::GetCurrent()->GetFloatToStringCache();
674 PandaString v = cache->GetOrCache(coro, val)->GetMutf8();
675 AppendJSONPrimitive(v, hasContent);
676 break;
677 }
678 case EtsType::DOUBLE: {
679 auto val = obj->GetFieldPrimitive<EtsDouble>(etsField);
680 auto cache = PandaEtsVM::GetCurrent()->GetDoubleToStringCache();
681 PandaString v = cache->GetOrCache(coro, val)->GetMutf8();
682 AppendJSONPrimitive(v, hasContent);
683 break;
684 }
685 default:
686 auto fieldObj = EtsHandle<EtsObject>(EtsCoroutine::GetCurrent(), obj->GetFieldObject(etsField));
687 if (fieldObj.GetPtr() == nullptr || fieldObj->GetClass()->IsFunction()) {
688 return true;
689 }
690 if (!AppendJSONString(fieldObj, hasContent)) {
691 return false;
692 }
693 break;
694 }
695 hasContent = true;
696 return true;
697 }
698
Stringify(EtsHandle<EtsObject> & value)699 EtsString *JSONStringifier::Stringify(EtsHandle<EtsObject> &value)
700 {
701 bool result = false;
702 auto coro = EtsCoroutine::GetCurrent();
703 ASSERT(coro != nullptr);
704 result = SerializeObject(value);
705 if (!result || coro->HasPendingException()) {
706 return nullptr;
707 }
708 return EtsString::CreateFromUtf8(buffer_.c_str(), buffer_.length());
709 }
710
711 } // namespace ark::ets::intrinsics::helpers
712