add a function to get an NBT array bytelength

This commit is contained in:
2025-07-23 14:37:23 +02:00
parent 4e1cd68c38
commit 2daeb9823c

View File

@@ -29,6 +29,26 @@ static int nbt_cmpstr(char const *restrict matstr, u8 const *restrict buf) {
return strncmp(str, matstr, len); return strncmp(str, matstr, len);
} }
/* acquires the array's byte size (excluding name + size spec)
* returns `0` upon failure */
static size_t nbt_arrbsize(u8 const *restrict buf) {
i32 mems = 0;
switch (*buf) {
case NBT_ARR_I64: mems += sizeof(i64) - sizeof(i32); __attribute__((fallthrough));
case NBT_ARR_I32: mems += sizeof(i32) - sizeof(i8); __attribute__((fallthrough));
case NBT_ARR_I8: return +mems * nbt_arrlen(buf); // mems+1 multiplied by the array length
case NBT_STR: return nbt_strlen(buf);
case NBT_LIST:
mems = nbt_primsize(*buf);
if (mems > 0) return mems * nbt_arrlen(buf + 1);
return 0;
default: return 0;
}
}
/* returns the (expected) pointer of the tag following this one. /* returns the (expected) pointer of the tag following this one.
* `NBT_COMPOUND` and `NBT_END` tags are not valid for this function and should be handled separately. * `NBT_COMPOUND` and `NBT_END` tags are not valid for this function and should be handled separately.
* `NULL` is returned if anything went wrong. */ * `NULL` is returned if anything went wrong. */
@@ -36,7 +56,7 @@ static u8 const *nbt_nexttag(u8 const *restrict buf) {
u8 const *nxt = buf + 1; u8 const *nxt = buf + 1;
nxt += nbt_strlen(nxt) + 2; nxt += nbt_strlen(nxt) + 2;
uint mems = 0; i32 tmp;
switch (*buf) { switch (*buf) {
case NBT_I8: __attribute__((fallthrough)); case NBT_I8: __attribute__((fallthrough));
case NBT_I16: __attribute__((fallthrough)); case NBT_I16: __attribute__((fallthrough));
@@ -44,29 +64,22 @@ static u8 const *nbt_nexttag(u8 const *restrict buf) {
case NBT_I64: __attribute__((fallthrough)); case NBT_I64: __attribute__((fallthrough));
case NBT_F32: __attribute__((fallthrough)); case NBT_F32: __attribute__((fallthrough));
case NBT_F64: case NBT_F64:
nxt += nbt_primsize(*buf); tmp = nbt_primsize(*buf);
return nxt; return (tmp >= 0) ? (nxt + tmp) : 0;
case NBT_ARR_I64: case NBT_LIST: nxt += 5; break;
mems += sizeof(i64) - sizeof(i32); case NBT_STR: nxt += 2; break;
case NBT_ARR_I32: case NBT_ARR_I8: __attribute__((fallthrough));
mems += sizeof(i32) - sizeof(i8); case NBT_ARR_I32: __attribute__((fallthrough));
case NBT_ARR_I8: case NBT_ARR_I64: nxt += 4; break;
mems += 1;
nxt += mems * nbt_arrlen(nxt);
return nxt;
case NBT_STR:
nxt += nbt_strlen(nxt);
return nxt;
case NBT_LIST: default: return NULL; // failure on compound/end tags; these require more nuanced logic
mems = nbt_primsize(*nxt);
if (mems > 0) {
nxt += 1;
nxt += mems * nbt_arrlen(nxt);
return nxt;
} }
// let case escape to `default` when `mems` `≤0`
tmp = nbt_arrbsize(buf);
return (tmp >= 0) ? (nxt + tmp) : NULL;
}
default: return NULL; // failure on compound/end tags; these require more nuanced logic default: return NULL; // failure on compound/end tags; these require more nuanced logic
} }