1#include "Library/Yaml/ByamlIter.h"
2
3#include "Library/Yaml/ByamlContainerHeader.h"
4#include "Library/Yaml/ByamlData.h"
5#include "Library/Yaml/ByamlHeader.h"
6
7namespace al {
8ByamlIter::ByamlIter() : mData(nullptr), mRootNode(nullptr) {}
9
10ByamlIter::ByamlIter(const u8* data) : mData(data), mRootNode(nullptr) {
11 if (!data)
12 return;
13 if (!alByamlLocalUtil::verifiByaml(data)) {
14 mData = nullptr;
15 mRootNode = nullptr;
16 return;
17 }
18
19 const ByamlHeader* header = mHeader;
20 if (!header->getDataOffset())
21 return;
22
23 mRootNode = &mData[header->getDataOffset()];
24}
25
26ByamlIter::ByamlIter(const u8* data, const u8* root_node) : mData(data), mRootNode(root_node) {}
27
28bool ByamlIter::isValid() const {
29 return mData != nullptr;
30}
31
32bool ByamlIter::isTypeHash() const {
33 return mRootNode ? mRootNode[0] == ByamlDataType::TYPE_HASH : false;
34}
35
36bool ByamlIter::isTypeArray() const {
37 return mRootNode ? mRootNode[0] == ByamlDataType::TYPE_ARRAY : false;
38}
39
40bool ByamlIter::isTypeContainer() const {
41 return isTypeHash() || isTypeArray();
42}
43
44// NON_MATCHING: stack allocated differently
45bool ByamlIter::isExistKey(const char* key) const {
46 if (!mRootNode || *mRootNode != ByamlDataType::TYPE_HASH)
47 return false;
48
49 s32 index = getKeyIndex(key);
50 if (index < 0)
51 return false;
52
53 ByamlHashIter iter = {mRootNode, isInvertOrder()};
54 return iter.findPair(key: index);
55}
56
57s32 ByamlIter::getKeyIndex(const char* key) const {
58 ByamlStringTableIter hash = alByamlLocalUtil::getHashKeyTable(data: mData);
59 if (!hash.isValidate())
60 return -1;
61
62 return hash.findStringIndex(str: key);
63}
64
65bool ByamlIter::isInvertOrder() const {
66 return mHeader->isInvertOrder();
67}
68
69s32 ByamlIter::getSize() const {
70 if (!mRootNode)
71 return false;
72 ByamlContainerHeader* header = (ByamlContainerHeader*)mRootNode;
73 u32 type = *mRootNode;
74 if (type == ByamlDataType::TYPE_ARRAY || type == ByamlDataType::TYPE_HASH)
75 return header->getCount(isRev: isInvertOrder());
76 return 0;
77}
78
79ByamlIter ByamlIter::getIterByIndex(s32 index) const {
80 ByamlData data;
81 if (!getByamlDataByIndex(data: &data, index))
82 return nullptr;
83 if (data.getType() != ByamlDataType::TYPE_ARRAY && data.getType() != ByamlDataType::TYPE_HASH) {
84 if (data.getType() == ByamlDataType::TYPE_NULL)
85 return {mData, nullptr};
86 return {};
87 }
88 return {mData, &mData[data.getValue()]};
89}
90
91bool ByamlIter::getByamlDataByIndex(ByamlData* data, s32 index) const {
92 if (!mRootNode)
93 return false;
94 if (*mRootNode == ByamlDataType::TYPE_ARRAY) {
95 ByamlArrayIter iter = {mRootNode, isInvertOrder()};
96 return iter.getDataByIndex(data, index);
97 }
98 if (*mRootNode == ByamlDataType::TYPE_HASH) {
99 ByamlHashIter iter = {mRootNode, isInvertOrder()};
100 return iter.getDataByIndex(data, index);
101 }
102 return false;
103}
104
105ByamlIter ByamlIter::getIterByKey(const char* key) const {
106 ByamlData data;
107 if (!getByamlDataByKey(data: &data, key))
108 return nullptr;
109 if (data.getType() != ByamlDataType::TYPE_ARRAY && data.getType() != ByamlDataType::TYPE_HASH) {
110 if (data.getType() == ByamlDataType::TYPE_NULL)
111 return {mData, nullptr};
112 return {};
113 }
114 return {mData, &mData[data.getValue()]};
115}
116
117bool ByamlIter::getByamlDataByKey(ByamlData* data, const char* key) const {
118 if (!mRootNode || *mRootNode != ByamlDataType::TYPE_HASH)
119 return false;
120 ByamlStringTableIter hash_table = alByamlLocalUtil::getHashKeyTable(data: mData);
121 if (!hash_table.isValidate())
122 return false;
123
124 bool isRev = isInvertOrder();
125 ByamlHashIter iter = {mRootNode, isRev};
126 s32 lowerBound = 0;
127 s32 upperBound = iter.getSize();
128 while (lowerBound < upperBound) {
129 s32 avg = (lowerBound + upperBound) / 2;
130 const ByamlHashPair* pair = iter.getPairByIndex(index: avg);
131 s32 result = strcmp(key, hash_table.getString(index: pair->getKey(isRev)));
132 if (result == 0) {
133 data->set(hash_pair: pair, isRev);
134 return true;
135 }
136
137 if (result > 0)
138 lowerBound = avg + 1;
139 else
140 upperBound = avg;
141 }
142 return false;
143}
144
145bool ByamlIter::getByamlDataByKeyIndex(ByamlData* data, s32 index) const {
146 if (!mRootNode || *mRootNode != ByamlDataType::TYPE_HASH)
147 return false;
148
149 ByamlHashIter iter = {mRootNode, isInvertOrder()};
150 return iter.getDataByKey(data, key: index);
151}
152
153bool ByamlIter::getByamlDataAndKeyName(ByamlData* data, const char** key, s32 index) const {
154 if (!mRootNode || *mRootNode != ByamlDataType::TYPE_HASH)
155 return false;
156
157 ByamlHashIter iter = {mRootNode, isInvertOrder()};
158 const ByamlHashPair* pair = iter.getPairByIndex(index);
159 if (!pair)
160 return false;
161
162 if (data)
163 data->set(hash_pair: pair, isRev: isInvertOrder());
164 ByamlStringTableIter hash_table = alByamlLocalUtil::getHashKeyTable(data: mData);
165 if (!hash_table.isValidate())
166 return false;
167
168 *key = hash_table.getString(index: pair->getKey(isRev: isInvertOrder()));
169 return true;
170}
171
172bool ByamlIter::getKeyName(const char** key, s32 index) const {
173 return getByamlDataAndKeyName(data: nullptr, key, index);
174}
175
176bool ByamlIter::tryGetIterByIndex(ByamlIter* iter, s32 index) const {
177 *iter = getIterByIndex(index);
178 return iter->isValid();
179}
180
181bool ByamlIter::tryGetIterAndKeyNameByIndex(ByamlIter* iter, const char** key, s32 index) const {
182 ByamlData data;
183 if (!getByamlDataAndKeyName(data: &data, key, index)) {
184 *key = nullptr;
185 *iter = getIterByIndex(index);
186 return iter->isValid();
187 }
188
189 if (data.getType() == ByamlDataType::TYPE_ARRAY || data.getType() == ByamlDataType::TYPE_HASH)
190 *iter = {mData, &mData[data.getValue()]};
191 if (data.getType() == ByamlDataType::TYPE_NULL)
192 *iter = {mData, nullptr};
193 return true;
194}
195
196bool ByamlIter::tryGetIterByKey(ByamlIter* iter, const char* key) const {
197 *iter = getIterByKey(key);
198 return iter->isValid();
199}
200
201bool ByamlIter::tryConvertIter(ByamlIter* iter, const ByamlData* data) const {
202 if (data->getType() == ByamlDataType::TYPE_ARRAY ||
203 data->getType() == ByamlDataType::TYPE_HASH) {
204 *iter = {mData, &mData[data->getValue()]};
205 return true;
206 }
207 if (data->getType() == ByamlDataType::TYPE_NULL) {
208 *iter = {mData, nullptr};
209 return true;
210 }
211 return false;
212}
213
214bool ByamlIter::tryGetStringByIndex(const char** value, s32 index) const {
215 ByamlData data;
216 if (!getByamlDataByIndex(data: &data, index))
217 return false;
218
219 return tryConvertString(string: value, data: &data);
220}
221
222bool ByamlIter::tryGetStringByKey(const char** value, const char* key) const {
223 ByamlData data;
224 if (!getByamlDataByKey(data: &data, key))
225 return false;
226
227 if (data.getType() == ByamlDataType::TYPE_NULL)
228 return false;
229 return tryConvertString(string: value, data: &data);
230}
231
232bool ByamlIter::tryConvertString(const char** value, const ByamlData* data) const {
233 if (data->getType() != ByamlDataType::TYPE_STRING)
234 return false;
235
236 ByamlStringTableIter string_table = alByamlLocalUtil::getStringTable(data: mData);
237 if (!string_table.isValidate())
238 return false;
239 *value = string_table.getString(index: data->getValue());
240
241 return true;
242}
243
244bool ByamlIter::tryGetBinaryByIndex(const u8** value, s32* size, s32 index) const {
245 ByamlData data;
246 if (!getByamlDataByIndex(data: &data, index))
247 return false;
248
249 return tryConvertBinary(binary: value, size, data: &data);
250}
251
252bool ByamlIter::tryGetBinaryByKey(const u8** value, s32* size, const char* key) const {
253 ByamlData data;
254 if (!getByamlDataByKey(data: &data, key))
255 return false;
256
257 return tryConvertBinary(binary: value, size, data: &data);
258}
259
260bool ByamlIter::tryConvertBinary(const u8** value, s32* size, const ByamlData* data) const {
261 if (data->getType() != ByamlDataType::TYPE_STRING)
262 return false;
263
264 ByamlStringTableIter string_table = alByamlLocalUtil::getStringTable(data: mData);
265 if (!string_table.isValidate())
266 return false;
267 *value = (const u8*)string_table.getString(index: data->getValue());
268 *size = string_table.getStringSize(index: data->getValue());
269
270 return true;
271}
272
273bool ByamlIter::tryGetIntByIndex(s32* value, s32 index) const {
274 ByamlData data;
275 if (!getByamlDataByIndex(data: &data, index))
276 return false;
277
278 return tryConvertInt(val: value, data: &data);
279}
280
281bool ByamlIter::tryGetIntByKey(s32* value, const char* key) const {
282 ByamlData data;
283 if (!getByamlDataByKey(data: &data, key))
284 return false;
285
286 if (data.getType() == ByamlDataType::TYPE_NULL)
287 return false;
288 return tryConvertInt(val: value, data: &data);
289}
290
291bool ByamlIter::tryConvertInt(s32* value, const ByamlData* data) const {
292 if (data->getType() != ByamlDataType::TYPE_INT)
293 return false;
294
295 *value = data->getValue();
296 return true;
297}
298
299// NON_MATCHING: mismatch in inlined convert
300bool ByamlIter::tryGetUIntByIndex(u32* value, s32 index) const {
301 ByamlData data;
302 if (!getByamlDataByIndex(data: &data, index))
303 return false;
304
305 return tryConvertUInt(val: value, data: &data);
306}
307
308// NON_MATCHING: mismatch in inlined convert
309bool ByamlIter::tryGetUIntByKey(u32* value, const char* key) const {
310 ByamlData data;
311 if (!getByamlDataByKey(data: &data, key))
312 return false;
313
314 if (data.getType() == ByamlDataType::TYPE_NULL)
315 return false;
316 return tryConvertUInt(val: value, data: &data);
317}
318
319bool ByamlIter::tryConvertUInt(u32* value, const ByamlData* data) const {
320 s32 val = data->getValue<s32>();
321 if (data->getType() == ByamlDataType::TYPE_INT) {
322 bool result = val >= 0;
323 *value = val < 0 ? 0 : val;
324 return result;
325 }
326 if (data->getType() == ByamlDataType::TYPE_UINT) {
327 *value = val;
328 return true;
329 }
330
331 return false;
332}
333
334bool ByamlIter::tryGetFloatByIndex(f32* value, s32 index) const {
335 ByamlData data;
336 if (!getByamlDataByIndex(data: &data, index))
337 return false;
338
339 return tryConvertFloat(val: value, data: &data);
340}
341
342bool ByamlIter::tryGetFloatByKey(f32* value, const char* key) const {
343 ByamlData data;
344 if (!getByamlDataByKey(data: &data, key))
345 return false;
346
347 if (data.getType() == ByamlDataType::TYPE_NULL)
348 return false;
349 return tryConvertFloat(val: value, data: &data);
350}
351
352bool ByamlIter::tryConvertFloat(f32* value, const ByamlData* data) const {
353 if (data->getType() != ByamlDataType::TYPE_FLOAT)
354 return false;
355
356 *value = data->getValue<f32>();
357 return true;
358}
359
360bool ByamlIter::tryGetBoolByIndex(bool* value, s32 index) const {
361 ByamlData data;
362 if (!getByamlDataByIndex(data: &data, index))
363 return false;
364
365 return tryConvertBool(val: value, data: &data);
366}
367
368bool ByamlIter::tryGetBoolByKey(bool* value, const char* key) const {
369 ByamlData data;
370 if (!getByamlDataByKey(data: &data, key))
371 return false;
372
373 if (data.getType() == ByamlDataType::TYPE_NULL)
374 return false;
375 return tryConvertBool(val: value, data: &data);
376}
377
378bool ByamlIter::tryConvertBool(bool* value, const ByamlData* data) const {
379 if (data->getType() != ByamlDataType::TYPE_BOOL)
380 return false;
381
382 *value = data->getValue() != 0;
383 return true;
384}
385
386bool ByamlIter::tryGetInt64ByIndex(s64* value, s32 index) const {
387 ByamlData data;
388 if (!getByamlDataByIndex(data: &data, index))
389 return false;
390
391 if (data.getType() == ByamlDataType::TYPE_NULL)
392 return false;
393 return tryConvertInt64(val: value, data: &data);
394}
395
396bool ByamlIter::tryGetInt64ByKey(s64* value, const char* key) const {
397 ByamlData data;
398 if (!getByamlDataByKey(data: &data, key))
399 return false;
400
401 if (data.getType() == ByamlDataType::TYPE_NULL)
402 return false;
403 return tryConvertInt64(val: value, data: &data);
404}
405
406bool ByamlIter::tryConvertInt64(s64* value, const ByamlData* data) const {
407 u32 val = data->getValue();
408 if (data->getType() == ByamlDataType::TYPE_INT) {
409 *value = *reinterpret_cast<s32*>(&val);
410 return true;
411 }
412 if (data->getType() == ByamlDataType::TYPE_UINT) {
413 *value = val;
414 return true;
415 }
416 if (data->getType() == ByamlDataType::TYPE_LONG) {
417 *value = alByamlLocalUtil::getData64Bit(data: mData, off: val, isRev: mHeader->isInvertOrder());
418 return true;
419 }
420
421 return false;
422}
423
424bool ByamlIter::tryGetUInt64ByIndex(u64* value, s32 index) const {
425 ByamlData data;
426 if (!getByamlDataByIndex(data: &data, index))
427 return false;
428
429 if (data.getType() == ByamlDataType::TYPE_NULL)
430 return false;
431 return tryConvertUInt64(val: value, data: &data);
432}
433
434bool ByamlIter::tryGetUInt64ByKey(u64* value, const char* key) const {
435 ByamlData data;
436 if (!getByamlDataByKey(data: &data, key))
437 return false;
438
439 if (data.getType() == ByamlDataType::TYPE_NULL)
440 return false;
441 return tryConvertUInt64(val: value, data: &data);
442}
443
444bool ByamlIter::tryConvertUInt64(u64* value, const ByamlData* data) const {
445 s32 val = data->getValue<s32>();
446 if (data->getType() == ByamlDataType::TYPE_INT) {
447 bool result = val >= 0;
448 *value = val > 0 ? val : 0;
449 return result;
450 }
451 if (data->getType() == ByamlDataType::TYPE_UINT) {
452 *value = *reinterpret_cast<u32*>(&val);
453 return true;
454 }
455
456 s64 realVal = alByamlLocalUtil::getData64Bit(data: mData, off: val, isRev: mHeader->isInvertOrder());
457 if (data->getType() == ByamlDataType::TYPE_LONG) {
458 bool result = realVal >= 0;
459 *value = realVal < 0 ? 0 : realVal;
460 return result;
461 }
462 if (data->getType() == ByamlDataType::TYPE_ULONG) {
463 *value = realVal;
464 return true;
465 }
466
467 return false;
468}
469
470bool ByamlIter::tryGetDoubleByIndex(f64* value, s32 index) const {
471 ByamlData data;
472 if (!getByamlDataByIndex(data: &data, index))
473 return false;
474
475 if (data.getType() == ByamlDataType::TYPE_NULL)
476 return false;
477 return tryConvertDouble(val: value, data: &data);
478}
479
480bool ByamlIter::tryGetDoubleByKey(f64* value, const char* key) const {
481 ByamlData data;
482 if (!getByamlDataByKey(data: &data, key))
483 return false;
484
485 if (data.getType() == ByamlDataType::TYPE_NULL)
486 return false;
487 return tryConvertDouble(val: value, data: &data);
488}
489
490bool ByamlIter::tryConvertDouble(f64* value, const ByamlData* data) const {
491 u32 val = data->getValue();
492 if (data->getType() == ByamlDataType::TYPE_FLOAT) {
493 *value = *reinterpret_cast<f32*>(&val);
494 return true;
495 }
496 if (data->getType() == ByamlDataType::TYPE_DOUBLE) {
497 u64 bigVal = alByamlLocalUtil::getData64Bit(data: mData, off: val, isRev: mHeader->isInvertOrder());
498 *value = *reinterpret_cast<f64*>(&bigVal);
499 return true;
500 }
501
502 return false;
503}
504
505bool ByamlIter::isEqualData(const ByamlIter& other) const {
506 if (!mData || !other.mData)
507 return false;
508
509 return mData == other.mData && mRootNode == other.mRootNode;
510}
511
512} // namespace al
513