2016-06-24 04:41:14 +00:00
|
|
|
/*
|
|
|
|
* nbt.c
|
|
|
|
*
|
|
|
|
* Created on: Mar 25, 2016
|
|
|
|
* Author: root
|
|
|
|
*/
|
|
|
|
|
2019-04-14 20:45:32 +00:00
|
|
|
#include <basin/nbt.h>
|
|
|
|
#include <basin/network.h>
|
|
|
|
#include <avuna/string.h>
|
2016-06-24 04:41:14 +00:00
|
|
|
#include <stdlib.h>
|
2016-12-25 04:59:02 +00:00
|
|
|
#include "util.h"
|
2016-12-24 23:09:16 +00:00
|
|
|
#include <zlib.h>
|
2016-12-25 04:59:02 +00:00
|
|
|
#include <stdio.h>
|
2016-06-24 04:41:14 +00:00
|
|
|
|
|
|
|
void freeNBT(struct nbt_tag* nbt) {
|
2016-12-25 04:59:02 +00:00
|
|
|
if (nbt->name != NULL) xfree(nbt->name);
|
2016-06-24 04:41:14 +00:00
|
|
|
if (nbt->children != NULL) {
|
|
|
|
for (size_t i = 0; i < nbt->children_count; i++) {
|
|
|
|
freeNBT(nbt->children[i]);
|
2016-12-25 04:59:02 +00:00
|
|
|
xfree(nbt->children[i]);
|
2016-06-24 04:41:14 +00:00
|
|
|
}
|
2016-12-25 04:59:02 +00:00
|
|
|
xfree(nbt->children);
|
2016-06-24 04:41:14 +00:00
|
|
|
}
|
|
|
|
if (nbt->id == NBT_TAG_BYTEARRAY) {
|
2016-12-25 04:59:02 +00:00
|
|
|
xfree(nbt->data.nbt_bytearray.data);
|
2016-06-24 04:41:14 +00:00
|
|
|
} else if (nbt->id == NBT_TAG_STRING) {
|
2016-12-25 04:59:02 +00:00
|
|
|
xfree(nbt->data.nbt_string);
|
2016-06-24 04:41:14 +00:00
|
|
|
} else if (nbt->id == NBT_TAG_INTARRAY) {
|
2016-12-25 04:59:02 +00:00
|
|
|
xfree(nbt->data.nbt_intarray.ints);
|
2016-06-24 04:41:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-16 07:18:30 +00:00
|
|
|
struct nbt_tag* getNBTChild(struct nbt_tag* nbt, char* name) {
|
|
|
|
for (size_t i = 0; i < nbt->children_count; i++) {
|
|
|
|
if (streq_nocase(nbt->children[i]->name, name)) return nbt->children[i];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-24 04:41:14 +00:00
|
|
|
struct nbt_tag* cloneNBT(struct nbt_tag* nbt) {
|
2016-12-25 04:59:02 +00:00
|
|
|
struct nbt_tag* nt = xmalloc(sizeof(struct nbt_tag));
|
|
|
|
nt->name = nbt->name == NULL ? NULL : xstrdup(nbt->name, 0);
|
2016-06-24 04:41:14 +00:00
|
|
|
nt->id = nbt->id;
|
|
|
|
nt->children_count = nbt->children_count;
|
2016-12-25 04:59:02 +00:00
|
|
|
nt->children = nt->children_count == 0 ? NULL : xmalloc(sizeof(struct nbt_tag*) * nt->children_count);
|
2016-06-24 04:41:14 +00:00
|
|
|
memcpy(&nt->data, &nbt->data, sizeof(union nbt_data));
|
|
|
|
if (nbt->id == NBT_TAG_BYTEARRAY) {
|
2016-12-25 04:59:02 +00:00
|
|
|
nt->data.nbt_bytearray.data = xmalloc(nt->data.nbt_bytearray.len);
|
2016-06-24 04:41:14 +00:00
|
|
|
memcpy(nt->data.nbt_bytearray.data, nbt->data.nbt_bytearray.data, nt->data.nbt_bytearray.len);
|
|
|
|
} else if (nbt->id == NBT_TAG_STRING) {
|
2016-12-25 04:59:02 +00:00
|
|
|
nt->data.nbt_string = xstrdup(nbt->data.nbt_string, 0);
|
2016-06-24 04:41:14 +00:00
|
|
|
} else if (nbt->id == NBT_TAG_INTARRAY) {
|
2016-12-25 04:59:02 +00:00
|
|
|
nt->data.nbt_intarray.ints = xmalloc(nt->data.nbt_intarray.count * 4);
|
2016-06-24 04:41:14 +00:00
|
|
|
memcpy(nt->data.nbt_intarray.ints, nbt->data.nbt_intarray.ints, nt->data.nbt_intarray.count * 4);
|
|
|
|
}
|
|
|
|
for (size_t i = 0; i < nt->children_count; i++) {
|
|
|
|
nt->children[i] = cloneNBT(nbt->children[i]);
|
|
|
|
}
|
|
|
|
return nt;
|
|
|
|
}
|
|
|
|
|
|
|
|
int __recurReadNBT(struct nbt_tag** root, unsigned char* buffer, size_t buflen, int list) {
|
2016-12-25 04:59:02 +00:00
|
|
|
struct nbt_tag* cur = xmalloc(sizeof(struct nbt_tag));
|
2016-06-24 04:41:14 +00:00
|
|
|
cur->name = NULL;
|
|
|
|
cur->children = NULL;
|
|
|
|
cur->children_count = 0;
|
|
|
|
size_t r = 0;
|
|
|
|
if (list) {
|
|
|
|
cur->id = list;
|
|
|
|
} else {
|
|
|
|
if (buflen < 1) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
cur->id = buffer[0];
|
|
|
|
buffer++;
|
|
|
|
r++;
|
|
|
|
buflen--;
|
2017-01-04 05:46:10 +00:00
|
|
|
if (cur->id) {
|
2016-06-24 04:41:14 +00:00
|
|
|
uint16_t sl;
|
|
|
|
if (buflen < 2) {
|
|
|
|
free(cur);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&sl, buffer, 2);
|
|
|
|
swapEndian(&sl, 2);
|
|
|
|
buffer += 2;
|
|
|
|
r += 2;
|
|
|
|
buflen -= 2;
|
|
|
|
if (buflen < sl) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-12-26 09:03:48 +00:00
|
|
|
cur->name = xmalloc(sl + 1);
|
2016-06-24 04:41:14 +00:00
|
|
|
cur->name[sl] = 0;
|
|
|
|
memcpy(cur->name, buffer, sl);
|
|
|
|
buffer += sl;
|
|
|
|
r += sl;
|
|
|
|
buflen -= sl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cur->id == NBT_TAG_BYTE) {
|
|
|
|
if (buflen < 1) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&cur->data.nbt_byte, buffer, 1);
|
|
|
|
buffer++;
|
|
|
|
buflen--;
|
|
|
|
r++;
|
|
|
|
} else if (cur->id == NBT_TAG_SHORT) {
|
|
|
|
if (buflen < 2) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&cur->data.nbt_short, buffer, 2);
|
|
|
|
swapEndian(&cur->data.nbt_short, 2);
|
|
|
|
buffer += 2;
|
|
|
|
buflen -= 2;
|
|
|
|
r += 2;
|
|
|
|
} else if (cur->id == NBT_TAG_INT) {
|
|
|
|
if (buflen < 4) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&cur->data.nbt_int, buffer, 4);
|
|
|
|
swapEndian(&cur->data.nbt_int, 4);
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
r += 4;
|
|
|
|
} else if (cur->id == NBT_TAG_LONG) {
|
|
|
|
if (buflen < 8) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&cur->data.nbt_long, buffer, 8);
|
|
|
|
swapEndian(&cur->data.nbt_long, 8);
|
|
|
|
buffer += 8;
|
|
|
|
buflen -= 8;
|
|
|
|
r += 8;
|
|
|
|
} else if (cur->id == NBT_TAG_FLOAT) {
|
|
|
|
if (buflen < 4) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&cur->data.nbt_float, buffer, 4);
|
|
|
|
swapEndian(&cur->data.nbt_float, 4);
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
r += 4;
|
|
|
|
} else if (cur->id == NBT_TAG_DOUBLE) {
|
|
|
|
if (buflen < 8) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&cur->data.nbt_double, buffer, 8);
|
|
|
|
swapEndian(&cur->data.nbt_double, 8);
|
|
|
|
buffer += 8;
|
|
|
|
buflen -= 8;
|
|
|
|
r += 8;
|
|
|
|
} else if (cur->id == NBT_TAG_BYTEARRAY) {
|
|
|
|
if (buflen < 4) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&cur->data.nbt_bytearray.len, buffer, 4);
|
|
|
|
swapEndian(&cur->data.nbt_bytearray.len, 4);
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
r += 4;
|
|
|
|
if (buflen < cur->data.nbt_bytearray.len || cur->data.nbt_bytearray.len <= 0) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
cur->data.nbt_bytearray.data = malloc(cur->data.nbt_bytearray.len);
|
|
|
|
memcpy(cur->data.nbt_bytearray.data, buffer, cur->data.nbt_bytearray.len);
|
|
|
|
buffer += cur->data.nbt_bytearray.len;
|
|
|
|
buflen -= cur->data.nbt_bytearray.len;
|
|
|
|
r += cur->data.nbt_bytearray.len;
|
|
|
|
} else if (cur->id == NBT_TAG_STRING) {
|
|
|
|
uint16_t sl;
|
|
|
|
if (buflen < 2) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&sl, buffer, 2);
|
|
|
|
swapEndian(&sl, 2);
|
|
|
|
buffer += 2;
|
|
|
|
r += 2;
|
|
|
|
buflen -= 2;
|
|
|
|
if (buflen < sl) {
|
2016-12-26 09:03:48 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-12-26 09:03:48 +00:00
|
|
|
cur->data.nbt_string = xmalloc(sl + 1);
|
2016-06-24 04:41:14 +00:00
|
|
|
cur->data.nbt_string[sl] = 0;
|
|
|
|
memcpy(cur->data.nbt_string, buffer, sl);
|
|
|
|
buffer += sl;
|
|
|
|
r += sl;
|
|
|
|
buflen -= sl;
|
|
|
|
} else if (cur->id == NBT_TAG_LIST) {
|
|
|
|
if (buflen < 5) {
|
|
|
|
free(cur->name);
|
|
|
|
free(cur);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
unsigned char lt = 0;
|
|
|
|
int32_t count;
|
|
|
|
memcpy(<, buffer, 1);
|
|
|
|
memcpy(&count, buffer + 1, 4);
|
|
|
|
swapEndian(&count, 4);
|
|
|
|
buffer += 5;
|
|
|
|
buflen -= 5;
|
|
|
|
r += 5;
|
|
|
|
struct nbt_tag *st = NULL;
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
st = NULL;
|
|
|
|
int nr = __recurReadNBT(&st, buffer, buflen, lt);
|
|
|
|
if (nr == 0) continue;
|
|
|
|
buffer += nr;
|
|
|
|
buflen -= nr;
|
|
|
|
r += nr;
|
2016-12-26 09:03:48 +00:00
|
|
|
if (!(st != NULL && st->id != NBT_TAG_END && buflen > 0)) {
|
|
|
|
if (st != NULL) freeNBT(st);
|
|
|
|
xfree(st);
|
|
|
|
st = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
2016-06-24 04:41:14 +00:00
|
|
|
if (cur->children == NULL) {
|
2016-12-26 09:03:48 +00:00
|
|
|
cur->children = xmalloc(sizeof(struct nbt_tag*));
|
2016-06-24 04:41:14 +00:00
|
|
|
cur->children_count = 0;
|
|
|
|
} else {
|
2016-12-26 09:03:48 +00:00
|
|
|
cur->children = xrealloc(cur->children, sizeof(struct nbt_tag*) * (cur->children_count + 1));
|
2016-06-24 04:41:14 +00:00
|
|
|
}
|
|
|
|
cur->children[cur->children_count++] = st;
|
|
|
|
}
|
|
|
|
} else if (cur->id == NBT_TAG_COMPOUND) {
|
|
|
|
struct nbt_tag *st = NULL;
|
|
|
|
do {
|
|
|
|
st = NULL;
|
|
|
|
int nr = __recurReadNBT(&st, buffer, buflen, 0);
|
|
|
|
buffer += nr;
|
|
|
|
buflen -= nr;
|
|
|
|
r += nr;
|
2016-12-26 09:03:48 +00:00
|
|
|
if (!(st != NULL && st->id != NBT_TAG_END && buflen > 0)) {
|
|
|
|
if (st != NULL) freeNBT(st);
|
|
|
|
xfree(st);
|
|
|
|
st = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
2016-06-24 04:41:14 +00:00
|
|
|
if (cur->children == NULL) {
|
2016-12-25 04:59:02 +00:00
|
|
|
cur->children = xmalloc(sizeof(struct nbt_tag*));
|
2016-06-24 04:41:14 +00:00
|
|
|
cur->children_count = 0;
|
|
|
|
} else {
|
2016-12-25 04:59:02 +00:00
|
|
|
cur->children = xrealloc(cur->children, sizeof(struct nbt_tag*) * (cur->children_count + 1));
|
2016-06-24 04:41:14 +00:00
|
|
|
}
|
|
|
|
cur->children[cur->children_count++] = st;
|
|
|
|
} while (st != NULL && st->id != NBT_TAG_END && buflen > 0);
|
|
|
|
} else if (cur->id == NBT_TAG_INTARRAY) {
|
|
|
|
if (buflen < 4) {
|
2016-12-25 04:59:02 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&cur->data.nbt_intarray.count, buffer, 4);
|
|
|
|
swapEndian(&cur->data.nbt_intarray.count, 4);
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
r += 4;
|
|
|
|
if (buflen < (cur->data.nbt_intarray.count * 4) || cur->data.nbt_intarray.count <= 0) {
|
2016-12-25 04:59:02 +00:00
|
|
|
xfree(cur->name);
|
|
|
|
xfree(cur);
|
2016-06-24 04:41:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-12-25 04:59:02 +00:00
|
|
|
cur->data.nbt_intarray.ints = xmalloc(cur->data.nbt_intarray.count * 4);
|
2016-06-24 04:41:14 +00:00
|
|
|
memcpy(cur->data.nbt_intarray.ints, buffer, cur->data.nbt_intarray.count * 4);
|
|
|
|
buffer += cur->data.nbt_intarray.count * 4;
|
|
|
|
buflen -= cur->data.nbt_intarray.count * 4;
|
|
|
|
r += cur->data.nbt_intarray.count * 4;
|
|
|
|
}
|
|
|
|
*root = cur;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-01-04 05:46:10 +00:00
|
|
|
#define DECOMPRESS_BUF_SIZE 16384
|
2016-12-24 23:09:16 +00:00
|
|
|
ssize_t decompressNBT(void* data, size_t size, void** dest) {
|
2017-01-04 05:46:10 +00:00
|
|
|
void* rtbuf = xmalloc(DECOMPRESS_BUF_SIZE);
|
|
|
|
size_t rtc = DECOMPRESS_BUF_SIZE;
|
2016-12-24 23:09:16 +00:00
|
|
|
z_stream strm;
|
|
|
|
strm.zalloc = Z_NULL;
|
|
|
|
strm.zfree = Z_NULL;
|
|
|
|
strm.opaque = Z_NULL;
|
2017-01-04 05:46:10 +00:00
|
|
|
strm.avail_in = 0;
|
|
|
|
strm.next_in = Z_NULL;
|
2016-12-24 23:09:16 +00:00
|
|
|
int dr = 0;
|
2017-01-04 05:46:10 +00:00
|
|
|
if ((dr = inflateInit2(&strm, (32 + MAX_WBITS))) != Z_OK) {
|
|
|
|
printf("Compression initialization error!\n");
|
2016-12-24 23:09:16 +00:00
|
|
|
xfree(rtbuf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
strm.avail_in = size;
|
|
|
|
strm.next_in = data;
|
|
|
|
strm.avail_out = rtc;
|
|
|
|
strm.next_out = rtbuf;
|
|
|
|
do {
|
2017-01-04 05:46:10 +00:00
|
|
|
if (rtc - strm.total_out < DECOMPRESS_BUF_SIZE / 2) {
|
|
|
|
rtc += DECOMPRESS_BUF_SIZE;
|
2016-12-24 23:09:16 +00:00
|
|
|
rtbuf = realloc(rtbuf, rtc);
|
|
|
|
}
|
|
|
|
strm.avail_out = rtc - strm.total_out;
|
|
|
|
strm.next_out = rtbuf + strm.total_out;
|
|
|
|
dr = inflate(&strm, Z_FINISH);
|
|
|
|
if (dr == Z_STREAM_ERROR) {
|
2017-01-04 05:46:10 +00:00
|
|
|
printf("Compression Read Error!\n");
|
2016-12-24 23:09:16 +00:00
|
|
|
inflateEnd(&strm);
|
|
|
|
xfree(rtbuf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} while (strm.avail_out == 0);
|
|
|
|
inflateEnd(&strm);
|
|
|
|
*dest = rtbuf;
|
|
|
|
return strm.total_out;
|
|
|
|
}
|
|
|
|
|
2016-06-24 04:41:14 +00:00
|
|
|
int readNBT(struct nbt_tag** root, unsigned char* buffer, size_t buflen) {
|
|
|
|
if (buflen == 0) return 0;
|
2016-12-25 04:59:02 +00:00
|
|
|
int x = __recurReadNBT(root, buffer, buflen, 0);
|
|
|
|
return x;
|
2016-06-24 04:41:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int __recurWriteNBT(struct nbt_tag* root, unsigned char* buffer, size_t buflen, int list) {
|
|
|
|
size_t r = 0;
|
|
|
|
if (list) {
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (buflen < 1) return 0;
|
|
|
|
buffer[0] = root->id;
|
|
|
|
r++;
|
|
|
|
buffer++;
|
|
|
|
buflen--;
|
|
|
|
if (root->id > 0) {
|
2016-12-28 10:18:41 +00:00
|
|
|
int16_t sl = root->name == NULL ? 0 : strlen(root->name);
|
2016-06-24 04:41:14 +00:00
|
|
|
memcpy(buffer, &sl, 2);
|
2016-12-25 04:59:02 +00:00
|
|
|
swapEndian(buffer, 2);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 2;
|
|
|
|
buffer += 2;
|
|
|
|
buflen -= 2;
|
|
|
|
if (buflen < sl) return 0;
|
2016-12-28 10:18:41 +00:00
|
|
|
if (root->name != NULL) memcpy(buffer, root->name, sl);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += sl;
|
|
|
|
buffer += sl;
|
|
|
|
buflen -= sl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (root->id == NBT_TAG_BYTE) {
|
|
|
|
if (buflen < 1) return 0;
|
|
|
|
buffer[0] = root->data.nbt_byte;
|
|
|
|
r++;
|
|
|
|
buffer++;
|
|
|
|
buflen--;
|
|
|
|
} else if (root->id == NBT_TAG_SHORT) {
|
|
|
|
if (buflen < 2) return 0;
|
|
|
|
memcpy(buffer, &root->data.nbt_short, 2);
|
2016-12-25 04:59:02 +00:00
|
|
|
swapEndian(buffer, 2);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 2;
|
|
|
|
buffer += 2;
|
|
|
|
buflen -= 2;
|
|
|
|
} else if (root->id == NBT_TAG_INT) {
|
|
|
|
if (buflen < 4) return 0;
|
|
|
|
memcpy(buffer, &root->data.nbt_int, 4);
|
2016-12-25 04:59:02 +00:00
|
|
|
swapEndian(buffer, 4);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 4;
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
} else if (root->id == NBT_TAG_LONG) {
|
|
|
|
if (buflen < 8) return 0;
|
|
|
|
memcpy(buffer, &root->data.nbt_short, 8);
|
2016-12-25 04:59:02 +00:00
|
|
|
swapEndian(buffer, 8);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 8;
|
|
|
|
buffer += 8;
|
|
|
|
buflen -= 8;
|
|
|
|
} else if (root->id == NBT_TAG_FLOAT) {
|
|
|
|
if (buflen < 4) return 0;
|
|
|
|
memcpy(buffer, &root->data.nbt_float, 4);
|
2016-12-25 04:59:02 +00:00
|
|
|
swapEndian(buffer, 4);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 4;
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
} else if (root->id == NBT_TAG_DOUBLE) {
|
|
|
|
if (buflen < 8) return 0;
|
|
|
|
memcpy(buffer, &root->data.nbt_double, 8);
|
2016-12-25 04:59:02 +00:00
|
|
|
swapEndian(buffer, 8);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 8;
|
|
|
|
buffer += 8;
|
|
|
|
buflen -= 8;
|
|
|
|
} else if (root->id == NBT_TAG_BYTEARRAY) {
|
|
|
|
if (buflen < 4) return 0;
|
|
|
|
memcpy(buffer, &root->data.nbt_bytearray.len, 4);
|
|
|
|
r += 4;
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
if (buflen < root->data.nbt_bytearray.len) return 0;
|
|
|
|
memcpy(buffer, root->data.nbt_bytearray.data, root->data.nbt_bytearray.len);
|
|
|
|
r += root->data.nbt_bytearray.len;
|
|
|
|
buffer += root->data.nbt_bytearray.len;
|
|
|
|
buflen -= root->data.nbt_bytearray.len;
|
|
|
|
} else if (root->id == NBT_TAG_STRING) {
|
|
|
|
if (buflen < 2) return 0;
|
|
|
|
uint16_t sl = strlen(root->data.nbt_string);
|
|
|
|
memcpy(buffer, &sl, 2);
|
2016-12-25 04:59:02 +00:00
|
|
|
swapEndian(buffer, 2);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 2;
|
|
|
|
buffer += 2;
|
|
|
|
buflen -= 2;
|
|
|
|
if (buflen < sl) return 0;
|
|
|
|
memcpy(buffer, root->data.nbt_string, sl);
|
|
|
|
r += sl;
|
|
|
|
buffer += sl;
|
|
|
|
buflen -= sl;
|
|
|
|
} else if (root->id == NBT_TAG_LIST) {
|
|
|
|
if (buflen < 5) return 0;
|
|
|
|
buffer[0] = root->data.nbt_list.type;
|
2016-12-28 10:18:41 +00:00
|
|
|
memcpy(buffer + 1, &root->data.nbt_list.count, 4);
|
|
|
|
swapEndian(buffer + 1, 4);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 5;
|
|
|
|
buffer += 5;
|
|
|
|
buflen -= 5;
|
|
|
|
for (size_t i = 0; i < root->children_count; i++) {
|
|
|
|
int x = __recurWriteNBT(root->children[i], buffer, buflen, 1);
|
|
|
|
r += x;
|
|
|
|
buffer += x;
|
|
|
|
buflen -= x;
|
|
|
|
if (buflen <= 0) break;
|
|
|
|
}
|
|
|
|
} else if (root->id == NBT_TAG_COMPOUND) {
|
|
|
|
for (size_t i = 0; i < root->children_count; i++) {
|
2016-12-25 04:59:02 +00:00
|
|
|
int x = __recurWriteNBT(root->children[i], buffer, buflen, 0);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += x;
|
|
|
|
buffer += x;
|
|
|
|
buflen -= x;
|
2016-12-25 04:59:02 +00:00
|
|
|
if (buflen <= 0) break;
|
2016-06-24 04:41:14 +00:00
|
|
|
}
|
2016-12-25 04:59:02 +00:00
|
|
|
if (buflen <= 1) return 0;
|
|
|
|
buffer[0] = 0;
|
|
|
|
buffer++;
|
|
|
|
buflen--;
|
|
|
|
r++;
|
2016-06-24 04:41:14 +00:00
|
|
|
} else if (root->id == NBT_TAG_INTARRAY) {
|
|
|
|
if (buflen < 4) return 0;
|
|
|
|
memcpy(buffer, &root->data.nbt_intarray.count, 4);
|
2016-12-25 04:59:02 +00:00
|
|
|
swapEndian(buffer, 4);
|
2016-06-24 04:41:14 +00:00
|
|
|
r += 4;
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
if (buflen < root->data.nbt_intarray.count * 4) return 0;
|
|
|
|
memcpy(buffer, root->data.nbt_intarray.ints, root->data.nbt_intarray.count * 4);
|
|
|
|
r += root->data.nbt_intarray.count * 4;
|
|
|
|
buffer += root->data.nbt_intarray.count * 4;
|
|
|
|
buflen -= root->data.nbt_intarray.count * 4;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int writeNBT(struct nbt_tag* root, unsigned char* buffer, size_t buflen) {
|
|
|
|
if (buflen == 0) return 0;
|
|
|
|
return __recurWriteNBT(root, buffer, buflen, 0);
|
|
|
|
}
|