• 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 
16 #ifndef _SERIALIZER_BASE_H
17 #define _SERIALIZER_BASE_H
18 
19 #include <cstdint>
20 #include <cstdio>
21 #include <cstring>
22 #include <string>
23 #include <memory>
24 #include <cstddef>
25 #include <vector>
26 
27 #include "callback-resource.h"
28 #include "interop-types.h"
29 #include "koala-types.h"
30 #include "interop-logging.h"
31 
32 #ifdef __arm__
33 #define KOALA_NO_UNALIGNED_ACCESS 1
34 #endif
35 
36 constexpr int BUFFER_MAX_LEN = 64;
37 
38 template <typename T>
39 inline InteropRuntimeType runtimeType(const T& value) = delete;
40 
41 template <>
runtimeType(const InteropCustomObject & value)42 inline InteropRuntimeType runtimeType(const InteropCustomObject& value) {
43   return INTEROP_RUNTIME_OBJECT;
44 }
45 
46 template <>
runtimeType(const InteropMaterialized & value)47 inline InteropRuntimeType runtimeType(const InteropMaterialized& value) {
48   return INTEROP_RUNTIME_OBJECT;
49 }
50 
51 static const std::size_t buffer_size = 1024 * 1024; // 1 MB
52 static std::size_t offset = 0;
53 alignas(std::max_align_t) static char buffer[buffer_size];
54 
55 template <typename T, std::size_t size>
allocArray(const std::array<T,size> & ref)56 T* allocArray(const std::array<T, size>& ref) {
57   std::size_t space = sizeof(buffer) - offset;
58   void* ptr = buffer + offset;
59   void* aligned_ptr = std::align(alignof(T), sizeof(T) * size, ptr, space);
60   ASSERT(aligned_ptr != nullptr); // "Insufficient space or alignment failed!"
61   offset = (char*)aligned_ptr + sizeof(T) * size - buffer;
62   T* array = reinterpret_cast<T*>(aligned_ptr);
63   for (size_t i = 0; i < size; ++i) {
64     new (&array[i]) T(ref[i]);
65   }
66   return array;
67 }
68 
69 class SerializerBase {
70 private:
71     uint8_t* data;
72     uint32_t dataLength;
73     uint32_t position;
74     bool ownData;
75     CallbackResourceHolder* resourceHolder;
resize(uint32_t newLength)76     void resize(uint32_t newLength) {
77         ASSERT(ownData);
78         ASSERT(newLength > dataLength);
79         auto* newData = reinterpret_cast<uint8_t*>(malloc(newLength));
80 #ifdef __STDC_LIB_EXT1__
81         errno_t res = memcpy_s(newData, newLength, data, position);
82         if (res != EOK) {
83             return;
84         }
85 #else
86         memcpy(newData, data, position);
87 #endif
88         free(data);
89         data = newData;
90     }
91 public:
92     SerializerBase(CallbackResourceHolder* resourceHolder = nullptr):
93         position(0), ownData(true), resourceHolder(resourceHolder) {
94         this->dataLength = 256;
95         this->data = reinterpret_cast<uint8_t*>(malloc(this->dataLength));
96     }
97 
98     SerializerBase(uint8_t* data, uint32_t dataLength, CallbackResourceHolder* resourceHolder = nullptr):
data(data)99         data(data), dataLength(dataLength), position(0), ownData(false), resourceHolder(resourceHolder) {
100     }
101 
~SerializerBase()102     virtual ~SerializerBase() {
103         if (ownData) {
104             free(data);
105         }
106     }
107 
108     SerializerBase(const SerializerBase&) = delete;
109     SerializerBase& operator=(const SerializerBase&) = delete;
110 
release()111     void* release() {
112         ownData = false;
113         return data;
114     }
length()115     int length() {
116         return position;
117     }
118 
check(int more)119     inline void check(int more) {
120         if (position + more > dataLength) {
121             if (ownData) {
122                 resize(dataLength * 3 / 2 + 2);
123             } else {
124                 INTEROP_FATAL("Buffer overrun: %d > %d\n", position + more, dataLength);
125             }
126         }
127     }
128 
writeInt8(InteropInt8 value)129     void writeInt8(InteropInt8 value) {
130         check(1);
131         *((InteropInt8*)(data + position)) = value;
132         position += 1;
133     }
134 
writeInt32(InteropInt32 value)135     void writeInt32(InteropInt32 value) {
136         check(4);
137 #ifdef KOALA_NO_UNALIGNED_ACCESS
138 #ifdef __STDC_LIB_EXT1__
139         errno_t res = memcpy_s(data + position, dataLength, &value, 4);
140         if (res != EOK) {
141             return;
142         }
143 #else
144         memcpy(data + position, &value, 4);
145 #endif
146 #else
147         *((InteropInt32*)(data + position)) = value;
148 #endif
149         position += 4;
150     }
151 
writeInt64(InteropInt64 value)152     void writeInt64(InteropInt64 value) {
153         check(8);
154 #ifdef KOALA_NO_UNALIGNED_ACCESS
155 #ifdef __STDC_LIB_EXT1__
156         errno_t res = memcpy_s(data + position, dataLength, &value, 8);
157         if (res != EOK) {
158             return;
159         }
160 #else
161         memcpy(data + position, &value, 8);
162 #endif
163 #else
164         *((InteropInt64*)(data + position)) = value;
165 #endif
166         position += 8;
167     }
168 
writeUInt64(InteropUInt64 value)169     void writeUInt64(InteropUInt64 value) {
170         check(8);
171 #ifdef KOALA_NO_UNALIGNED_ACCESS
172 #ifdef __STDC_LIB_EXT1__
173         errno_t res = memcpy_s(data + position, dataLength, &value, 8);
174         if (res != EOK) {
175             return;
176         }
177 #else
178         memcpy(data + position, &value, 8);
179 #endif
180 #else
181         *((InteropUInt64*)(data + position)) = value;
182 #endif
183         position += 8;
184     }
185 
writeFloat32(InteropFloat32 value)186     void writeFloat32(InteropFloat32 value) {
187         check(8);
188 #ifdef KOALA_NO_UNALIGNED_ACCESS
189 #ifdef __STDC_LIB_EXT1__
190         errno_t res = memcpy_s(data + position, dataLength, &value, 4);
191         if (res != EOK) {
192             return;
193         }
194 #else
195         memcpy(data + position, &value, 4);
196 #endif
197 #else
198         *((InteropFloat32*)(data + position)) = value;
199 #endif
200         position += 4;
201     }
202 
writePointer(InteropNativePointer value)203     void writePointer(InteropNativePointer value) {
204         check(8);
205 #ifdef KOALA_NO_UNALIGNED_ACCESS
206 #ifdef __STDC_LIB_EXT1__
207         errno_t res = memcpy_s(data + position, dataLength, &value64, 8);
208         if (res != EOK) {
209             return;
210         }
211 #else
212         memcpy(data + position, &value, 8);
213 #endif
214 #else
215         *((int64_t*)(data + position)) = reinterpret_cast<int64_t>(value);
216 #endif
217         position += 8;
218     }
219 
writeFunction(InteropFunction value)220     void writeFunction(InteropFunction value) {
221         // TODO: ignored, remove!
222         writeInt32(0x666);
223     }
224 
writeNumber(InteropNumber value)225     void writeNumber(InteropNumber value) {
226         writeInt8(value.tag);
227         if (value.tag == InteropTag::INTEROP_TAG_INT32) {
228             writeInt32(value.i32);
229         } else if (value.tag == InteropTag::INTEROP_TAG_FLOAT32) {
230             writeFloat32(value.f32);
231         } else {
232             INTEROP_FATAL("Unknown tag number");
233         }
234     }
235 
writeString(InteropString value)236     void writeString(InteropString value) {
237         writeInt32(value.length + 1);
238         check(value.length + 1);
239         strcpy((char*)(data + position), value.chars);
240         position += value.length + 1;
241     }
242 
writeBoolean(InteropBoolean value)243     void writeBoolean(InteropBoolean value) {
244         writeInt8(value);
245     }
246 
writeLength(InteropLength value)247     void writeLength(InteropLength value) {
248         InteropRuntimeType tag = (InteropRuntimeType) value.type;
249         writeInt8(tag);
250         switch (tag) {
251             case INTEROP_RUNTIME_NUMBER:
252                 writeFloat32(value.value);
253                 break;
254             case INTEROP_RUNTIME_OBJECT:
255                 writeInt32(value.resource);
256                 break;
257             case INTEROP_RUNTIME_STRING: {
258                 char buf[BUFFER_MAX_LEN];
259                 std::string suffix;
260                 switch (value.unit) {
261                     case 0: suffix = "px"; break;
262                     case 1: suffix = "vp"; break;
263                     case 2: suffix = "fp"; break;
264                     case 3: suffix = "%"; break;
265                     case 4: suffix = "lpx"; break;
266                 }
267 #ifdef __STDC_LIB_EXT1__
268                 errno_t res = snprintf_s(buf, BUFFER_MAX_LEN, "%.8f%s", value.value, suffix.c_str());
269                 if (res != EOK) {
270                     return;
271                 }
272 #else
273                 snprintf(buf, BUFFER_MAX_LEN, "%.8f%s", value.value, suffix.c_str());
274 #endif
275                 InteropString str =  { buf, (InteropInt32) strlen(buf) };
276                 writeString(str);
277                 break;
278             }
279             default:
280                 break;
281         }
282     }
283 
writeCallbackResource(const InteropCallbackResource resource)284     void writeCallbackResource(const InteropCallbackResource resource) {
285         writeInt32(resource.resourceId);
286         writePointer(reinterpret_cast<void*>(resource.hold));
287         writePointer(reinterpret_cast<void*>(resource.release));
288         if (this->resourceHolder != nullptr) {
289             this->resourceHolder->holdCallbackResource(&resource);
290         }
291     }
292 
writeCustomObject(std::string type,InteropCustomObject value)293     void writeCustomObject(std::string type, InteropCustomObject value) {
294         // TODO implement
295     }
296 
writeBuffer(InteropBuffer buffer)297     void writeBuffer(InteropBuffer buffer) {
298         writeCallbackResource(buffer.resource);
299         writePointer((void*)buffer.data);
300         writeInt64(buffer.length);
301     }
302 
toReturnBuffer()303     KInteropReturnBuffer toReturnBuffer() {
304         if (this->ownData) {
305             KInteropReturnBuffer buffer {this->length(), this->release(), [](KNativePointer data, KInt length) { free(data); }};
306             // TODO fix memory issues
307             return buffer;
308         } else {
309             return {this->length(), this->data, nullptr};
310         }
311     }
312 };
313 
314 #endif // _SERIALIZER_BASE_H