Compare commits

..

2 Commits

Author SHA1 Message Date
6c2f51929b write a function for skipping to the next NBT tag
including a function for acquireing the array size, and bytesize of a
tag.
2025-07-18 10:29:08 +02:00
ee1811a3a5 rewrite endian header to not interfere with the endian system header.
the system header is inconsistently available across platforms.
This header provides the same functionality for less of the cost,
overriding the system macros.
2025-07-18 10:29:08 +02:00
2 changed files with 54 additions and 14 deletions

View File

@@ -11,6 +11,11 @@ static inline u16 nbt_strlen(u8 const *restrict buf) {
return be16toh(*(u16 *)(buf));
}
/* returns the length of an array from a specific location in the buffer */
static inline i32 nbt_arrlen(u8 const *restrict buf) {
return be32toh(*(i32 *)(buf));
}
/* compares the string in `buf` to `matstr`.
* returns `=0` if equal, `>0` if buf is greater, `<0` if matstr is greater. */
static int nbt_cmpstr(char const *restrict matstr, u8 const *restrict buf) {
@@ -24,29 +29,60 @@ static int nbt_cmpstr(char const *restrict matstr, u8 const *restrict buf) {
return strncmp(str, matstr, len);
}
/* gets the tag size of primitive types, returns `>0` on success, `<0` on failure */
int nbt_prim_tagsize(u8 tag) {
switch (tag) {
case NBT_I8: return 1;
case NBT_I16: return 2;
case NBT_I32: return 4;
case NBT_I64: return 8;
case NBT_F32: return 4;
case NBT_F64: return 8;
default: return -1;
}
}
/* 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 *buf) {
u8 const *nxt = NULL;
static u8 const *nbt_nexttag(u8 const *restrict buf) {
u8 const *nxt = buf + 1;
nxt += nbt_strlen(nxt) + 2;
uint mems = 0;
switch (*buf) {
case NBT_I8: nxt = buf + 1 + 1; break; // add 1 for the tag size here, since the constant can be precomputed
case NBT_I16: nxt = buf + 1 + 2; break;
case NBT_I32: nxt = buf + 1 + 4; break;
case NBT_I64: nxt = buf + 1 + 8; break;
case NBT_F32: nxt = buf + 1 + 4; break;
case NBT_F64: nxt = buf + 1 + 8; break;
case NBT_I8:
case NBT_I16:
case NBT_I32:
case NBT_I64:
case NBT_F32:
case NBT_F64:
nxt += nbt_prim_tagsize(*buf);
return nxt;
case NBT_ARR_I64:
mems += sizeof(i64) - sizeof(i32);
case NBT_ARR_I32:
mems += sizeof(i32) - sizeof(i8);
case NBT_ARR_I8:
case NBT_STR: break;
case NBT_LIST: break;
case NBT_ARR_I32: break;
case NBT_ARR_I64: break;
mems += 1;
nxt += mems * nbt_arrlen(nxt);
return nxt;
case NBT_STR:
nxt += nbt_strlen(nxt);
return nxt;
case NBT_LIST:
mems = nbt_prim_tagsize(*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
}
return nxt + nbt_strlen(buf + 1);
}
int nbt_proc(void **restrict datout, u8 const *restrict buf, size_t len) {

View File

@@ -2,6 +2,9 @@
// Licensed under the MIT Licence. See LICENSE for details
#pragma once
#if __has_include(<endian.h>)
#include <endian.h>
#else
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define le16toh(x) __uint16_identity(x)
#define le32toh(x) __uint32_identity(x)
@@ -31,3 +34,4 @@
#else
#error machine architecture unsupported! Expected either big-endian or little-endian, make sure to use a compiler which defines __BYTE_ORDER__ (like clang or gcc)
#endif
#endif