diff --git a/src/dat/nbt.c b/src/dat/nbt.c index 161a104..083cdba 100644 --- a/src/dat/nbt.c +++ b/src/dat/nbt.c @@ -29,60 +29,12 @@ 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. */ -static u8 const *nbt_nexttag(u8 const *restrict buf) { - u8 const *nxt = buf + 1; - nxt += nbt_strlen(nxt) + 2; - - i32 tmp; - switch (*buf) { - case NBT_I8: __attribute__((fallthrough)); - case NBT_I16: __attribute__((fallthrough)); - case NBT_I32: __attribute__((fallthrough)); - case NBT_I64: __attribute__((fallthrough)); - case NBT_F32: __attribute__((fallthrough)); - case NBT_F64: - tmp = nbt_primsize(*buf); - return (tmp >= 0) ? (nxt + tmp) : 0; - - 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; -} - - - default: return NULL; // failure on compound/end tags; these require more nuanced logic - } +static u8 const *nbt_nexttag(u8 const *restrict buf, u16 naml) { + size_t len = nbt_tagdatlen(buf); + if (!len) return NULL; // TODO: compound tags should be handled here + return buf + naml + len + 3; } int nbt_proc(void **restrict datout, u8 const *restrict buf, size_t len) { @@ -112,6 +64,33 @@ int nbt_primsize(u8 tag) { } } +size_t nbt_tagdatlen(u8 const *restrict buf) { + size_t mems = 0; + + switch (*buf) { + case NBT_I8: __attribute__((fallthrough)); + case NBT_I16: __attribute__((fallthrough)); + case NBT_I32: __attribute__((fallthrough)); + case NBT_F32: __attribute__((fallthrough)); + case NBT_I64: __attribute__((fallthrough)); + case NBT_F64: + mems = nbt_primsize(*buf); + return -(mems >= 0) & mems; + + 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) + 4; + + case NBT_STR: return nbt_strlen(buf) + 2; + + case NBT_LIST: + mems = nbt_primsize(*buf); + if (mems > 0) return mems * nbt_arrlen(buf + 1) + 5; + return 0; + default: return 0; + } +} + int nbt_isprim(u8 tag) { switch (tag) { case NBT_I8: __attribute__((fallthrough)); diff --git a/src/dat/nbt.h b/src/dat/nbt.h index 2bba880..d13122b 100644 --- a/src/dat/nbt.h +++ b/src/dat/nbt.h @@ -40,6 +40,8 @@ int nbt_proc(void **restrict datout, u8 const *restrict buf, size_t len); * returns a boolean value. */ atrb_const int nbt_isprim(u8 tag); +/* gets the byte size of an NBT tag's data (excluding id and name), returns `0` upon error. */ +atrb_const size_t nbt_tagdatlen(u8 const *buf); /* gets the tag size of primitive types, returns `>0` on success, `<0` on failure */ atrb_const int nbt_primsize(u8 tag);