• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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