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 #ifndef _DESERIALIZER_BASE_H_
16 #define _DESERIALIZER_BASE_H_
17
18 #include <stdint.h>
19 #include <cstring>
20 #include <string>
21 #include <vector>
22 #include <charconv>
23
24 #include "interop-types.h"
25 #include "interop-logging.h"
26 #include "koala-types.h"
27
28 void holdManagedCallbackResource(InteropInt32);
29 void releaseManagedCallbackResource(InteropInt32);
30
31 #ifdef __arm__
32 #define KOALA_NO_UNALIGNED_ACCESS 1
33 #endif
34
tagName(InteropTag tag)35 inline const char *tagName(InteropTag tag)
36 {
37 switch (tag)
38 {
39 case InteropTag::INTEROP_TAG_UNDEFINED:
40 return "UNDEFINED";
41 case InteropTag::INTEROP_TAG_INT32:
42 return "INT32";
43 case InteropTag::INTEROP_TAG_FLOAT32:
44 return "FLOAT32";
45 case InteropTag::INTEROP_TAG_LENGTH:
46 return "LENGTH";
47 case InteropTag::INTEROP_TAG_RESOURCE:
48 return "RESOURCE";
49 case InteropTag::INTEROP_TAG_STRING:
50 return "STRING";
51 case InteropTag::INTEROP_TAG_OBJECT:
52 return "OBJECT";
53 }
54 INTEROP_FATAL("Fatal error");
55 }
56
tagNameExact(InteropTag tag)57 inline const char *tagNameExact(InteropTag tag)
58 {
59 switch (tag)
60 {
61 case InteropTag::INTEROP_TAG_UNDEFINED:
62 return "INTEROP_TAG_UNDEFINED";
63 case InteropTag::INTEROP_TAG_INT32:
64 return "INTEROP_TAG_INT32";
65 case InteropTag::INTEROP_TAG_FLOAT32:
66 return "INTEROP_TAG_FLOAT32";
67 case InteropTag::INTEROP_TAG_LENGTH:
68 return "INTEROP_TAG_LENGTH";
69 case InteropTag::INTEROP_TAG_RESOURCE:
70 return "INTEROP_TAG_RESOURCE";
71 case InteropTag::INTEROP_TAG_STRING:
72 return "INTEROP_TAG_STRING";
73 case InteropTag::INTEROP_TAG_OBJECT:
74 return "INTEROP_TAG_OBJECT";
75 }
76 INTEROP_FATAL("Fatal error");
77 }
78
makeArkFunctionFromId(InteropInt32 id)79 inline InteropFunction makeArkFunctionFromId(InteropInt32 id) {
80 InteropFunction result;
81 result.id = id;
82 return result;
83 }
84
getUnitName(int value)85 inline const char *getUnitName(int value)
86 {
87 switch (value)
88 {
89 case 0:
90 return "px";
91 case 1:
92 return "vp";
93 case 2:
94 return "fp";
95 case 3:
96 return "%";
97 case 4:
98 return "lpx";
99 default:
100 return "<unknown>";
101 }
102 }
103
parseDimension(const InteropString & string,InteropLength * result)104 inline void parseDimension(const InteropString &string, InteropLength *result)
105 {
106 char *suffixPtr = nullptr;
107 float value = std::strtof(string.chars, &suffixPtr);
108
109 if (!suffixPtr || suffixPtr == string.chars)
110 {
111 // not a numeric value
112 result->unit = -1;
113 return;
114 }
115 result->value = value;
116 if (suffixPtr[0] == '\0' || (suffixPtr[0] == 'v' && suffixPtr[1] == 'p'))
117 {
118 result->unit = 1;
119 }
120 else if (suffixPtr[0] == '%')
121 {
122 result->unit = 3;
123 }
124 else if (suffixPtr[0] == 'p' && suffixPtr[1] == 'x')
125 {
126 result->unit = 0;
127 }
128 else if (suffixPtr[0] == 'l' && suffixPtr[1] == 'p' && suffixPtr[2] == 'x')
129 {
130 result->unit = 4;
131 }
132 else if (suffixPtr[0] == 'f' && suffixPtr[1] == 'p')
133 {
134 result->unit = 2;
135 }
136 else
137 {
138 result->unit = -1;
139 }
140 }
141
142 template <typename T>
143 inline void convertor(T value) = delete;
144
145 // TODO: restore full printing!
146 template <typename T>
147 inline void WriteToString(std::string *result, T value) = delete;
148
149 template <>
WriteToString(std::string * result,const InteropEmpty & value)150 inline void WriteToString(std::string *result, const InteropEmpty &value)
151 {
152 result->append("{");
153 result->append(".dummy=" + std::to_string(value.dummy));
154 result->append("}");
155 }
156
157 struct Error
158 {
159 std::string message;
ErrorError160 Error(const std::string &message) : message(message) {}
161 };
162
163 template <>
WriteToString(std::string * result,InteropTag value)164 inline void WriteToString(std::string *result, InteropTag value)
165 {
166 result->append(".tag=");
167 result->append(tagName(value));
168 }
169
170 template <>
WriteToString(std::string * result,InteropNativePointer value)171 inline void WriteToString(std::string *result, InteropNativePointer value)
172 {
173 result->append("0x" + std::to_string((uint64_t)value));
174 }
175
176 template <>
WriteToString(std::string * result,InteropNodeHandle value)177 inline void WriteToString(std::string *result, InteropNodeHandle value)
178 {
179 result->append("0x" + std::to_string((uint64_t)value));
180 }
181
182 template <>
WriteToString(std::string * result,InteropFunction value)183 inline void WriteToString(std::string *result, InteropFunction value)
184 {
185 result->append("{");
186 result->append(".id=" + std::to_string(value.id));
187 result->append("}");
188 }
189
190 template <>
WriteToString(std::string * result,const InteropFunction * value)191 inline void WriteToString(std::string *result, const InteropFunction* value)
192 {
193 result->append("{");
194 result->append(".id=" + std::to_string(value->id));
195 result->append("}");
196 }
197
198 template <>
WriteToString(std::string * result,const InteropMaterialized * value)199 inline void WriteToString(std::string *result, const InteropMaterialized *value)
200 {
201 char hex[20];
202 #ifdef __STDC_LIB_EXT1__
203 errno_t res = std::snprintf_s(hex, sizeof(hex), "0x%llx", (long long)value->ptr);
204 if (res != EOK) {
205 return;
206 }
207 #else
208 std::snprintf(hex, sizeof(hex), "0x%llx", (long long)value->ptr);
209 #endif
210 result->append("\"");
211 result->append("Materialized ");
212 result->append(hex);
213 result->append("\"");
214 }
215
216 // TODO: generate!
217 template<>
WriteToString(std::string * result,const InteropCallbackResource * value)218 inline void WriteToString(std::string *result, const InteropCallbackResource *value)
219 {
220 result->append("{");
221 result->append(".resourceId=" + std::to_string(value->resourceId));
222 result->append(", .hold=0");
223 result->append(", .release=0");
224 result->append("}");
225 }
226
227 class DeserializerBase;
228
229 template <>
WriteToString(std::string * result,InteropUndefined value)230 inline void WriteToString(std::string *result, InteropUndefined value)
231 {
232 result->append("{}");
233 }
234 template <>
WriteToString(std::string * result,const InteropUndefined * value)235 inline void WriteToString(std::string *result, const InteropUndefined *value)
236 {
237 result->append("{}");
238 }
239 template <>
WriteToString(std::string * result,InteropVoid value)240 inline void WriteToString(std::string *result, InteropVoid value)
241 {
242 result->append("{}");
243 }
244 template <>
WriteToString(std::string * result,const InteropVoid * value)245 inline void WriteToString(std::string *result, const InteropVoid *value)
246 {
247 result->append("{}");
248 }
249 template <>
WriteToString(std::string * result,const InteropCustomObject * value)250 inline void WriteToString(std::string *result, const InteropCustomObject *value)
251 {
252 if (strcmp(value->kind, "NativeErrorFunction") == 0)
253 {
254 result->append("() => {} /* TBD: Function*/");
255 return;
256 }
257 result->append("{");
258 result->append(".kind=\"");
259 result->append(value->kind);
260 result->append("\"}");
261 }
262
263 struct CustomDeserializer
264 {
~CustomDeserializerCustomDeserializer265 virtual ~CustomDeserializer() {}
supportsCustomDeserializer266 virtual bool supports(const std::string &kind) { return false; }
deserializeCustomDeserializer267 virtual InteropCustomObject deserialize(DeserializerBase *deserializer, const std::string &kind)
268 {
269 InteropCustomObject result;
270 strcpy(result.kind, "error");
271 return result;
272 }
273 CustomDeserializer *next = nullptr;
274 };
275
276 class DeserializerBase
277 {
278 protected:
279 uint8_t *data;
280 int32_t length;
281 int32_t position;
282 std::vector<void *> toClean;
283
284 static CustomDeserializer *customDeserializers;
285
286 public:
DeserializerBase(uint8_t * data,int32_t length)287 DeserializerBase(uint8_t *data, int32_t length)
288 : data(data), length(length), position(0) {}
289
~DeserializerBase()290 ~DeserializerBase()
291 {
292 for (auto data : toClean)
293 {
294 free(data);
295 }
296 }
297
registerCustomDeserializer(CustomDeserializer * deserializer)298 static void registerCustomDeserializer(CustomDeserializer *deserializer)
299 {
300 if (DeserializerBase::customDeserializers == nullptr)
301 {
302 DeserializerBase::customDeserializers = deserializer;
303 }
304 else
305 {
306 auto *current = DeserializerBase::customDeserializers;
307 while (current->next != nullptr)
308 current = current->next;
309 current->next = deserializer;
310 }
311 }
312
313 template <typename T, typename E>
resizeArray(T * array,int32_t length)314 void resizeArray(T *array, int32_t length)
315 {
316 void *value = nullptr;
317 if (length > 0)
318 {
319 value = malloc(length * sizeof(E));
320 #ifdef __STDC_LIB_EXT1__
321 errno_t res = memset_s(value, length * sizeof(E), 0, length * sizeof(E));
322 if (res != EOK) {
323 return;
324 }
325 #else
326 memset(value, 0, length * sizeof(E));
327 #endif
328 toClean.push_back(value);
329 }
330 array->length = length;
331 array->array = reinterpret_cast<E *>(value);
332 }
333
334 template <typename T, typename K, typename V>
resizeMap(T * map,int32_t length)335 void resizeMap(T *map, int32_t length)
336 {
337 void *keys = nullptr;
338 void *values = nullptr;
339 if (length > 0) {
340 keys = malloc(length * sizeof(K));
341 #ifdef __STDC_LIB_EXT1__
342 errno_t res = memset_s(keys, length * sizeof(K), 0, length * sizeof(K));
343 if (res != EOK) {
344 return;
345 }
346 #else
347 memset(keys, 0, length * sizeof(K));
348 #endif
349 toClean.push_back(keys);
350
351 values = malloc(length * sizeof(V));
352 #ifdef __STDC_LIB_EXT1__
353 errno_t res = memset_s(values, length * sizeof(V), 0, length * sizeof(V));
354 if (res != EOK) {
355 return;
356 }
357 #else
358 memset(values, 0, length * sizeof(V));
359 #endif
360 toClean.push_back(values);
361 }
362 map->size = length;
363 map->keys = reinterpret_cast<K *>(keys);
364 map->values = reinterpret_cast<V *>(values);
365 }
366
currentPosition()367 int32_t currentPosition() const { return this->position; }
368
check(int32_t count)369 void check(int32_t count)
370 {
371 if (position + count > length) {
372 fprintf(stderr, "Incorrect serialized data, check for %d, buffer %d position %d\n", count, length, position);
373 ASSERT(false);
374 abort();
375 }
376 }
377
readCustomObject(std::string kind)378 InteropCustomObject readCustomObject(std::string kind)
379 {
380 auto *current = DeserializerBase::customDeserializers;
381 while (current)
382 {
383 if (current->supports(kind))
384 return current->deserialize(this, kind);
385 current = current->next;
386 }
387 LOGE("Unsupported custom deserialization for %s\n", kind.c_str());
388 auto tag = readTag();
389 if (tag == INTEROP_TAG_UNDEFINED) LOGE("Undefined interop tag");
390 // Skip undefined tag!.
391 InteropCustomObject result;
392 strcpy(result.kind, "Error");
393 strcat(result.kind, kind.c_str());
394 return result;
395 }
396
readCallbackResource()397 InteropCallbackResource readCallbackResource() {
398 InteropCallbackResource result = {};
399 result.resourceId = readInt32();
400 result.hold = reinterpret_cast<void(*)(InteropInt32)>(readPointerOrDefault(reinterpret_cast<void*>(holdManagedCallbackResource)));
401 result.release = reinterpret_cast<void(*)(InteropInt32)>(readPointerOrDefault(reinterpret_cast<void*>(releaseManagedCallbackResource)));
402 return result;
403 }
404
readInt8()405 int8_t readInt8()
406 {
407 check(1);
408 int8_t value = *(data + position);
409 position += 1;
410 return value;
411 }
readTag()412 InteropTag readTag()
413 {
414 return (InteropTag)readInt8();
415 }
readBoolean()416 InteropBoolean readBoolean()
417 {
418 check(1);
419 int8_t value = *(data + position);
420 position += 1;
421 return value;
422 }
readInt32()423 InteropInt32 readInt32()
424 {
425 check(4);
426 #ifdef KOALA_NO_UNALIGNED_ACCESS
427 InteropInt32 value;
428 #ifdef __STDC_LIB_EXT1__
429 errno_t res = memcpy_s(&value, 4, data + position, 4);
430 if (res != EOK) {
431 return value;
432 }
433 #else
434 memcpy(&value, data + position, 4);
435 #endif
436 #else
437 auto value = *(InteropInt32 *)(data + position);
438 #endif
439 position += 4;
440 return value;
441 }
readInt64()442 InteropInt64 readInt64()
443 {
444 check(8);
445 #ifdef KOALA_NO_UNALIGNED_ACCESS
446 InteropInt64 value;
447 #ifdef __STDC_LIB_EXT1__
448 errno_t res = memcpy_s(&value, 4, data + position, 4);
449 if (res != EOK) {
450 return value;
451 }
452 #else
453 memcpy(&value, data + position, 4);
454 #endif
455 #else
456 auto value = *(InteropInt64 *)(data + position);
457 #endif
458 position += 8;
459 return value;
460 }
readUInt64()461 InteropUInt64 readUInt64()
462 {
463 check(8);
464 #ifdef KOALA_NO_UNALIGNED_ACCESS
465 InteropInt64 value;
466 #ifdef __STDC_LIB_EXT1__
467 errno_t res = memcpy_s(&value, 4, data + position, 4);
468 if (res != EOK) {
469 return value;
470 }
471 #else
472 memcpy(&value, data + position, 4);
473 #endif
474 #else
475 auto value = *(InteropUInt64 *)(data + position);
476 #endif
477 position += 8;
478 return value;
479 }
readFloat32()480 InteropFloat32 readFloat32()
481 {
482 check(4);
483 #ifdef KOALA_NO_UNALIGNED_ACCESS
484 InteropFloat32 value;
485 #ifdef __STDC_LIB_EXT1__
486 errno_t res = memcpy_s(&value, 4, data + position, 4);
487 if (res != EOK) {
488 return value;
489 }
490 #else
491 memcpy(&value, data + position, 4);
492 #endif
493 #else
494 auto value = *(InteropFloat32 *)(data + position);
495 #endif
496 position += 4;
497 return value;
498 }
readPointer()499 InteropNativePointer readPointer()
500 {
501 check(8);
502 #ifdef KOALA_NO_UNALIGNED_ACCESS
503 int64_t value = 0;
504 #ifdef __STDC_LIB_EXT1__
505 errno_t res = memcpy_s(&value, 8, data + position, 8);
506 if (res != EOK) {
507 return value;
508 }
509 #else
510 memcpy(&value, data + position, 8);
511 #endif
512 #else
513 int64_t value = *(int64_t *)(data + position);
514 #endif
515 position += 8;
516 return reinterpret_cast<InteropNativePointer>(static_cast<uintptr_t>(value));
517 }
readPointerOrDefault(InteropNativePointer defaultValue)518 InteropNativePointer readPointerOrDefault(InteropNativePointer defaultValue)
519 {
520 const InteropNativePointer value = this->readPointer();
521 return value ? value : defaultValue;
522 }
readNumber()523 InteropNumber readNumber()
524 {
525 check(5);
526 InteropNumber result;
527 result.tag = readTag();
528 if (result.tag == InteropTag::INTEROP_TAG_INT32)
529 {
530 result.i32 = readInt32();
531 }
532 else if (result.tag == InteropTag::INTEROP_TAG_FLOAT32)
533 {
534 result.f32 = readFloat32();
535 }
536 else
537 {
538 INTEROP_FATAL("Fatal error");
539 }
540 return result;
541 }
readBuffer()542 InteropBuffer readBuffer()
543 {
544 InteropCallbackResource resource = readCallbackResource();
545 InteropNativePointer data = readPointer();
546 InteropInt64 length = readInt64();
547 return InteropBuffer { resource, (void*)data, length };
548 }
549
550 // TODO: produce them with prefix in generator.
readLength()551 InteropLength readLength()
552 {
553 InteropLength result = {};
554 result.unit = 1;
555 result.type = readInt8();
556 switch (result.type)
557 {
558 case INTEROP_RUNTIME_OBJECT:
559 {
560 result.resource = readInt32();
561 break;
562 }
563 case INTEROP_RUNTIME_STRING:
564 {
565 InteropString string = readString();
566 parseDimension(string, &result);
567 break;
568 }
569 case INTEROP_RUNTIME_NUMBER:
570 {
571 result.value = readFloat32();
572 break;
573 }
574 default:
575 {
576 INTEROP_FATAL("Fatal error");
577 }
578 }
579 return result;
580 }
581
readString()582 InteropString readString()
583 {
584 InteropString result;
585 InteropInt32 length = readInt32();
586 check(length);
587 // We refer to string data in-place.
588 result.chars = (const char *)(data + position);
589 result.length = length - 1;
590 this->position += length;
591 return result;
592 }
593
readFunction()594 InteropFunction readFunction()
595 {
596 InteropFunction result;
597 result.id = readInt32();
598 return result;
599 }
600
readMaterialized()601 InteropMaterialized readMaterialized()
602 {
603 InteropMaterialized result;
604 result.ptr = readPointer();
605 return result;
606 }
607
readUndefined()608 InteropUndefined readUndefined()
609 {
610 return InteropUndefined();
611 }
612 };
613 template <>
WriteToString(std::string * result,InteropBoolean value)614 inline void WriteToString(std::string *result, InteropBoolean value)
615 {
616 result->append(value ? "true" : "false");
617 }
618 template <>
WriteToString(std::string * result,InteropInt32 value)619 inline void WriteToString(std::string *result, InteropInt32 value)
620 {
621 result->append(std::to_string(value));
622 }
623 template <>
WriteToString(std::string * result,const InteropInt32 * value)624 inline void WriteToString(std::string *result, const InteropInt32* value)
625 {
626 result->append(std::to_string(*value));
627 }
628 template <>
WriteToString(std::string * result,InteropInt64 value)629 inline void WriteToString(std::string *result, InteropInt64 value)
630 {
631 result->append(std::to_string(value));
632 }
633 template <>
WriteToString(std::string * result,InteropUInt32 value)634 inline void WriteToString(std::string *result, InteropUInt32 value)
635 {
636 result->append(std::to_string(value));
637 }
638 template <>
WriteToString(std::string * result,InteropFloat32 value)639 inline void WriteToString(std::string *result, InteropFloat32 value)
640 {
641 #if (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED < 130300L))
642 // to_chars() is not available on older macOS.
643 char buf[20];
644 #ifdef __STDC_LIB_EXT1__
645 errno_t res = snprintf_s(buf, sizeof buf, "%f", value);
646 if (res != EOK) {
647 return;
648 }
649 #else
650 snprintf(buf, sizeof buf, "%f", value);
651 #endif
652 result->append(buf);
653 #else
654 std::string storage;
655 storage.resize(20);
656 // We use to_chars() to avoid locale issues.
657 auto rc = std::to_chars(storage.data(), storage.data() + storage.size(), value);
658 storage.resize(rc.ptr - storage.data());
659 result->append(storage);
660 #endif
661 }
662 template <>
WriteToString(std::string * result,const InteropBuffer * value)663 inline void WriteToString(std::string* result, const InteropBuffer* value) {
664 result->append("{.data=nullptr, .length=");
665 result->append(std::to_string(value->length));
666 result->append("}");
667 }
668 template <>
WriteToString(std::string * result,InteropBuffer value)669 inline void WriteToString(std::string* result, InteropBuffer value) {
670 result->append("{.data=nullptr, .length=");
671 result->append(std::to_string(value.length));
672 result->append("}");
673 }
674 template <>
WriteToString(std::string * result,const InteropString * value)675 inline void WriteToString(std::string *result, const InteropString *value)
676 {
677 result->append("{");
678 if (value->chars) {
679 result->append(".chars=\"");
680 result->append(value->chars);
681 result->append("\"");
682 } else {
683 result->append(".chars=\"\"");
684 }
685 result->append(", .length=");
686 WriteToString(result, value->length);
687 result->append("}");
688 }
689
690 template <>
WriteToString(std::string * result,const InteropNumber * value)691 inline void WriteToString(std::string *result, const InteropNumber *value)
692 {
693 result->append("{.tag=" + std::to_string(value->tag) + ", ");
694
695 if (value->tag == INTEROP_TAG_FLOAT32)
696 {
697 std::string valueString;
698 result->append(".f32=");
699 WriteToString(result, value->f32);
700 } else {
701 result->append(".i32=" + std::to_string(value->i32));
702 }
703
704 result->append("}");
705 }
706
707 template <>
WriteToString(std::string * result,const InteropLength * value)708 inline void WriteToString(std::string *result, const InteropLength *value)
709 {
710 result->append("{");
711 result->append(".type=" + std::to_string(value->type));
712 result->append(", .value=");
713 WriteToString(result, value->value);
714 result->append(", .unit=" + std::to_string(value->unit));
715 result->append(", .resource=" + std::to_string(value->resource));
716 result->append("}");
717 }
718
719 #endif // _DESERIALIZER_BASE_H_
720