6constexpr size_t payload_zero_sizes[] = {
11 [CLOD_NBT_FLOAT32] = 4,
12 [CLOD_NBT_FLOAT64] = 8,
13 [CLOD_NBT_INT8_ARRAY] = 4,
14 [CLOD_NBT_INT32_ARRAY] = 4,
15 [CLOD_NBT_INT64_ARRAY] = 4,
16 [CLOD_NBT_STRING] = 2,
18 [CLOD_NBT_COMPOUND] = 1
20constexpr char payload_zero_sizes_len =
sizeof(payload_zero_sizes) /
sizeof(payload_zero_sizes[0]);
22#define type_zero_size(type) (0 <= (type) && (type) < payload_zero_sizes_len ? payload_zero_sizes[(unsigned)type] : 0)
23#define type_valid(type) (type_zero_size(type))
24#define available(ptr, end) ((ptr) <= (char*)(end) ? (size_t)((char*)(end) - (ptr)) : 0)
27 const char *restrict
const payload,
28 const void *
const end,
29 const char payload_type
31 switch (payload_type) {
33 case CLOD_NBT_INT8:
return 1;
34 case CLOD_NBT_INT16:
return 2;
35 case CLOD_NBT_INT32:
return 4;
36 case CLOD_NBT_INT64:
return 8;
37 case CLOD_NBT_FLOAT32:
return 4;
38 case CLOD_NBT_FLOAT64:
return 8;
39 case CLOD_NBT_INT8_ARRAY: {
40 if (available(payload, end) < 4)
return 0;
41 const size_t size = (size_t)
bei32_dec(payload);
42 if (available(payload, end) < 4 + size)
return 0;
45 case CLOD_NBT_INT32_ARRAY: {
46 if (available(payload, end) < 4)
return 0;
47 const size_t size = (size_t)
bei32_dec(payload) * 4;
48 if (available(payload, end) < 4 + size)
return 0;
51 case CLOD_NBT_INT64_ARRAY: {
52 if (available(payload, end) < 4)
return 0;
53 const size_t size = (size_t)
bei32_dec(payload) * 8;
54 if (available(payload, end) < 4 + size)
return 0;
57 case CLOD_NBT_STRING: {
58 if (available(payload, end) < 2)
return 0;
59 const size_t size = (size_t)
beu16_dec(payload);
60 if (available(payload, end) < 2 + size)
return 0;
64 if (available(payload, end) < 5)
return 0;
65 if (payload[0] == CLOD_NBT_ZERO)
return 5;
66 if (!type_valid(payload[0]))
return 0;
67 const size_t length = (size_t)
bei32_dec(payload + 1);
69 for (
size_t i = 0; i < length; i++) {
71 if (elem_size == 0)
return 0;
76 case CLOD_NBT_COMPOUND: {
79 while (available(payload, end) >= size + 3) {
80 if (!type_valid(payload[size]))
break;
81 const size_t name_size =
beu16_dec(payload + size + 1);
82 if (available(payload, end) < size + 3 + name_size)
return 0;
86 if (available(payload, end) < size + 1)
return 0;
87 if (payload[size] == CLOD_NBT_ZERO)
return size + 1;
95 if (available(tag, end) < 3)
return 0;
96 if (!type_valid(tag[0]))
return 0;
97 const size_t name_size =
beu16_dec(tag + 1);
98 if (available(tag, end) < 3 + name_size)
return 0;
103 if (available(tag, end) < 3)
return nullptr;
104 if (!type_valid(tag[0]))
return nullptr;
105 const size_t name_size =
beu16_dec(tag + 1);
106 if (available(tag, end) < 3 + name_size)
return nullptr;
107 return (
char*)tag + 3 + name_size;
111 if (available(tag, end) < 3)
return CLOD_SSTR_NULL;
112 if (!type_valid(tag[0]))
return CLOD_SSTR_NULL;
113 const size_t name_size =
beu16_dec(tag + 1);
114 if (available(tag, end) < 3 + name_size)
return CLOD_SSTR_NULL;
115 return clod_sstr(tag + 3, name_size);
119 const char *
const restrict payload,
120 const void *
const end,
121 const char payload_type,
124 switch (payload_type) {
125 case CLOD_NBT_COMPOUND: {
126 if (iter->
payload ==
nullptr) {
127 memset(iter, 0,
sizeof(*iter));
128 iter->
tag = (
char*)payload;
134 if (available(iter->
tag, end) < 1)
goto iter_fail;
135 if (iter->
tag[0] == CLOD_NBT_ZERO) {
139 iter->
type = CLOD_NBT_ZERO;
144 if (!tag_payload)
goto iter_fail;
146 if (payload_size == 0)
goto iter_fail;
149 iter->
size = (size_t)(tag_payload - iter->
tag) + payload_size;
153 case CLOD_NBT_LIST: {
154 if (iter->
payload ==
nullptr) {
155 if (available(payload, end) < 5)
goto iter_fail;
156 memset(iter, 0,
sizeof(*iter));
157 iter->
payload = (
char*)payload;
158 iter->
type = payload[0];
168 iter->
type = CLOD_NBT_ZERO;
173 if (payload_size == 0)
goto iter_fail;
174 iter->
size = payload_size;
177 case CLOD_NBT_STRING: {
178 if (iter->
payload ==
nullptr) {
179 if (available(payload, end) < 2)
goto iter_fail;
180 memset(iter, 0,
sizeof(*iter));
181 iter->
payload = (
char*)payload;
183 iter->
type = CLOD_NBT_INT8;
193 iter->
type = CLOD_NBT_ZERO;
198 case CLOD_NBT_INT8_ARRAY: {
199 if (iter->
payload ==
nullptr) {
200 if (available(payload, end) < 4)
goto iter_fail;
201 memset(iter, 0,
sizeof(*iter));
202 iter->
payload = (
char*)payload;
204 iter->
type = CLOD_NBT_INT8;
214 iter->
type = CLOD_NBT_ZERO;
219 case CLOD_NBT_INT32_ARRAY: {
220 if (iter->
payload ==
nullptr) {
221 if (available(payload, end) < 4)
goto iter_fail;
222 memset(iter, 0,
sizeof(*iter));
223 iter->
payload = (
char*)payload;
225 iter->
type = CLOD_NBT_INT32;
235 iter->
type = CLOD_NBT_ZERO;
240 case CLOD_NBT_INT64_ARRAY: {
241 if (iter->
payload ==
nullptr) {
242 if (available(payload, end) < 4)
goto iter_fail;
243 memset(iter, 0,
sizeof(*iter));
244 iter->
payload = (
char*)payload;
246 iter->
type = CLOD_NBT_INT64;
256 iter->
type = CLOD_NBT_ZERO;
261 default:
return false;
265 memset(iter, 0,
sizeof(*iter));
270 const char *restrict compound,
282 char *restrict compound,
285 const clod_sstr name,
288 if (!type_valid(
type))
return nullptr;
289 const size_t elem_size = 3 + name.
size + type_zero_size(
type);
291 *free -= (ptrdiff_t)elem_size;
300 if (!iter.
tag)
return nullptr;
301 *free -= (ptrdiff_t)elem_size;
307 memmove(iter.
tag + elem_size, iter.
tag, available(iter.
tag, *end) - elem_size);
312 memset(iter.
tag + 3 + name.
size, 0, type_zero_size(
type));
314 *end = *(
char**)end + elem_size;
319 char *restrict compound,
328 *end = *(
char**)end - iter.
size;
329 *free += (ptrdiff_t)iter.
size;
341 const uint32_t length
344 *free -= (ptrdiff_t)(length * type_zero_size(
type));
347 if (available(list, *end) < 5)
return false;
349 if (list[0] !=
type) {
351 const size_t new_size = 5 + length * type_zero_size(
type);
352 if (old_size == 0)
return false;
354 const ptrdiff_t delta = (ptrdiff_t)new_size - (ptrdiff_t)old_size;
356 if (*free < 0)
return false;
358 memmove(list + new_size, list + old_size, available(list, *end) - old_size);
359 memset(list, 0, new_size);
362 *end = *(
char**)end + delta;
366 const uint32_t old_length = (uint32_t)
bei32_dec(list + 1);
368 if (old_length < length) {
370 const size_t append_size = type_zero_size(list[0]) * (length - old_length);
372 *free -= (ptrdiff_t)append_size;
373 if (*free < 0)
return false;
375 memmove(list + old_size + append_size, list + old_size, available(list, *end) - old_size - append_size);
376 memset(list + old_size, 0, append_size);
379 *end = *(
char**)end + append_size;
383 if (old_length > length) {
385 char *truncate =
nullptr;
389 if (!iter.
tag || !truncate)
return false;
391 memmove(truncate, iter.
tag, available(iter.
tag, *end));
393 *free += iter.
tag - truncate;
394 *end = *(
char**)end - (iter.
tag - truncate);
static int32_t bei32_dec(const char ptr[4])
Decode a 32-bit signed integer in big-endian format.
static void bei32_enc(char ptr[4], const int32_t val)
Encode a 32-bit signed integer into big-endian format.
static uint16_t beu16_dec(const char ptr[2])
Decode a 16-bit unsigned integer in big-endian format.
static void beu16_enc(char ptr[2], const uint16_t val)
Encode a 16-bit unsigned integer into big-endian format.
char * clod_nbt_compound_get(const char *restrict compound, const void *end, const clod_sstr name)
bool clod_nbt_iter_next(const char *const restrict payload, const void *const end, const char payload_type, struct clod_nbt_iter *iter)
bool clod_nbt_list_resize(char *restrict list, const char **end, ptrdiff_t *free, char type, const uint32_t length)
bool clod_nbt_compound_del(char *restrict compound, const void **end, ptrdiff_t *free, const clod_sstr name)
char * clod_nbt_compound_add(char *restrict compound, const void **end, ptrdiff_t *free, const clod_sstr name, const char type)
clod_sstr clod_nbt_tag_name(const char *tag, const void *end)
size_t clod_nbt_payload_size(const char *restrict const payload, const void *const end, const char payload_type)
char * clod_nbt_tag_payload(const char *restrict tag, const void *end)
size_t clod_nbt_tag_size(const char *restrict tag, const void *end)
static bool clod_sstr_eq(const clod_sstr str1, const clod_sstr str2)