#include "nbt.h" #include "../lib.h" #include #include #include static bool nbt_read_data(tag_t *tag, const stream_t *stream); static bool nbt_read_header(tag_t *tag, const stream_t *stream, bool named) { bool ok = true; if (stream_read_i8(stream, &tag->type) == false) return false; if (tag->type == TAG_END) named = false; if (named) { if (stream_read_u16(stream, &tag->name_len) == false) return false; } else { tag->name_len = 0; } if (tag->name_len < 1) { tag->name = ""; } else { tag->name = xalloc(tag->name_len); ok = stream_read(stream, tag->name, tag->name_len); } if (!ok) return false; return true; } static bool nbt_read_byte_array(tagdata_t *data, const stream_t *stream) { if (stream_read_i32(stream, &data->b_arr.size) == false) return false; if (data->b_arr.size == 0) { data->b_arr.data = NULL; return true; } data->b_arr.data = xalloc(data->b_arr.size * sizeof(int8_t)); for (int32_t i = 0; i < data->b_arr.size; i++) if (stream_read_i8(stream, &data->b_arr.data[i]) == false) return false; return true; } static bool nbt_read_int_array(tagdata_t *data, const stream_t *stream) { if (stream_read_i32(stream, &data->i_arr.size) == false) return false; if (data->i_arr.size == 0) { data->i_arr.data = NULL; return true; } data->i_arr.data = xalloc(data->i_arr.size * sizeof(int32_t)); for (int32_t i = 0; i < data->i_arr.size; i++) if (stream_read_i32(stream, &data->i_arr.data[i]) == false) return false; return true; } static bool nbt_read_long_array(tagdata_t *data, const stream_t *stream) { if (stream_read_i32(stream, &data->l_arr.size) == false) return false; if (data->l_arr.size == 0) { data->l_arr.data = NULL; return true; } data->l_arr.data = xalloc(data->l_arr.size * sizeof(int64_t)); for (int32_t i = 0; i < data->l_arr.size; i++) if (stream_read_i64(stream, &data->l_arr.data[i]) == false) return false; return true; } static bool nbt_read_string(tagdata_t *data, const stream_t *stream) { if (stream_read_u16(stream, &data->string.size) == false) return false; if (data->string.size < 1) { data->string.data = NULL; return true; } data->string.data = xalloc(data->string.size); if (stream_read(stream, data->string.data, data->string.size) == false) return false; return true; } static bool nbt_read_list(tagdata_t *data, const stream_t *stream) { if (stream_read_i8(stream, &data->list.type) == false) return false; if (stream_read_i32(stream, &data->list.size) == false) return false; if (data->list.size <= 0) { data->list.tags = NULL; return true; } else if (data->list.type == 0) { // tag end is not allowed to be used with non empty list return false; } data->list.tags = xalloc(data->list.size * sizeof(tag_t)); for (int32_t i = 0; i < data->list.size; i++) { tag_t tag; tag.type = data->list.type; tag.name = ""; tag.name_len = 0; if (nbt_read_data(&tag, stream) == false) return false; data->list.tags[i] = tag; } return true; } static bool nbt_read_compound(tagdata_t *data, const stream_t *stream) { map_t map; map_init(&map); while (1) { tag_t tag; if (nbt_read_header(&tag, stream, true) == false) { map_free(&map); return false; } if (tag.type == TAG_END) break; if (tag.name_len < 1) { map_free(&map); return false; } if (nbt_read_data(&tag, stream) == false) { map_free(&map); return false; } map_put(&map, &tag); } data->compound = map; return true; } static bool nbt_read_data(tag_t *tag, const stream_t *stream) { bool ok = true; switch (tag->type) { case TAG_END: // tag has no data break; case TAG_BYTE: ok = stream_read_i8(stream, &tag->data.b); break; case TAG_SHORT: ok = stream_read_i16(stream, &tag->data.s); break; case TAG_FLOAT: case TAG_INT: ok = stream_read_i32(stream, &tag->data.i); break; case TAG_DOUBLE: case TAG_LONG: ok = stream_read_i64(stream, &tag->data.l); break; case TAG_BYTE_ARRAY: ok = nbt_read_byte_array(&tag->data, stream); break; case TAG_STRING: ok = nbt_read_string(&tag->data, stream); break; case TAG_LIST: ok = nbt_read_list(&tag->data, stream); break; case TAG_COMPOUND: ok = nbt_read_compound(&tag->data, stream); break; case TAG_INT_ARRAY: ok = nbt_read_int_array(&tag->data, stream); break; case TAG_LONG_ARRAY: ok = nbt_read_long_array(&tag->data, stream); break; break; }; return ok; } bool nbt_read(tag_t *tag, const stream_t *stream) { memset(tag, 0, sizeof(tag_t)); if (nbt_read_header(tag, stream, true) == false) return false; if (nbt_read_data(tag, stream) == false) return false; return true; }