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);
}
/* 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.
* `NBT_COMPOUND` and `NBT_END` tags are not valid for this function and should be handled separately.
* `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;
nxt += nbt_strlen(nxt) + 2;
uint mems = 0;
i32 tmp;
switch (*buf) {
case NBT_I8: __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_F32: __attribute__((fallthrough));
case NBT_F64:
nxt += nbt_primsize(*buf);
return nxt;
tmp = nbt_primsize(*buf);
return (tmp >= 0) ? (nxt + tmp) : 0;
case NBT_ARR_I64:
mems += sizeof(i64) - sizeof(i32);
case NBT_ARR_I32:
mems += sizeof(i32) - sizeof(i8);
case NBT_ARR_I8:
mems += 1;
nxt += mems * nbt_arrlen(nxt);
return nxt;
case NBT_STR:
nxt += nbt_strlen(nxt);
return nxt;
case NBT_LIST: nxt += 5; break;
case NBT_STR: nxt += 2; break;
case NBT_ARR_I8: __attribute__((fallthrough));
case NBT_ARR_I32: __attribute__((fallthrough));
case NBT_ARR_I64: nxt += 4; break;
default: return NULL; // failure on compound/end tags; these require more nuanced logic
}
tmp = nbt_arrbsize(buf);
return (tmp >= 0) ? (nxt + tmp) : NULL;
}
case NBT_LIST:
mems = nbt_primsize(*nxt);
if (mems > 0) {
nxt += 1;
nxt += mems * nbt_arrlen(nxt);
return nxt;
}
// let case escape to `default` when `mems` `≤0`
default: return NULL; // failure on compound/end tags; these require more nuanced logic
}