mcchunktools
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
nbt.h
Go to the documentation of this file.
1 /* * -----------------------------------------------------------------------------
2  * "THE BEER-WARE LICENSE" (Revision 42):
3  * Lukas Niederbremer <webmaster@flippeh.de> and Clark Gaebel <cg.wowus.cg@gmail.com>
4  * wrote this file. As long as you retain this notice you can do whatever you
5  * want with this stuff. If we meet some day, and you think this stuff is worth
6  * it, you can buy us a beer in return.
7  * -----------------------------------------------------------------------------
8  */
9 
10 #ifndef NBT_H
11 #define NBT_H
12 
13 #ifdef __cplusplus
14 #define restrict __restrict__
15 extern "C" {
16 #endif
17 
18 #include <stdbool.h>
19 #include <stddef.h> /* for size_t */
20 #include <stdint.h>
21 #include <stdio.h> /* for FILE* */
22 
23 #include "buffer.h" /* for struct buffer */
24 #include "list.h" /* For struct list_entry etc. */
25 
26 typedef enum {
27  NBT_OK = 0, /* No error. */
28  NBT_ERR = -1, /* Generic error, most likely of the parsing variety. */
29  NBT_EMEM = -2, /* Out of memory. */
30  NBT_EIO = -3, /* IO error. */
31  NBT_EZ = -4 /* Zlib compression/decompression error. */
32 } nbt_status;
33 
34 typedef enum {
35  TAG_INVALID = 0, /* tag_end, but we don't use it in the in-memory representation. */
36  TAG_BYTE = 1, /* char, 8 bits, signed */
37  TAG_SHORT = 2, /* short, 16 bits, signed */
38  TAG_INT = 3, /* long, 32 bits, signed */
39  TAG_LONG = 4, /* long long, 64 bits, signed */
40  TAG_FLOAT = 5, /* float, 32 bits, signed */
41  TAG_DOUBLE = 6, /* double, 64 bits, signed */
42  TAG_BYTE_ARRAY = 7, /* char *, 8 bits, unsigned, TAG_INT length */
43  TAG_STRING = 8, /* char *, 8 bits, signed, TAG_SHORT length */
44  TAG_LIST = 9, /* X *, X bits, TAG_INT length, no names inside */
45  TAG_COMPOUND = 10, /* nbt_tag * */
47 
48 } nbt_type;
49 
50 typedef enum {
51  STRAT_GZIP, /* Use a gzip header. Use this if you want your data to be
52  compressed like level.dat */
53 
54  STRAT_INFLATE /* Use a zlib header. Use this if you want your data to be
55  compressed like a chunk. */
57 
58 struct nbt_node;
59 
60 /*
61  * Represents a single node in the tree. You should switch on `type' and ONLY
62  * access the union member it signifies. tag_compound and tag_list contain
63  * recursive nbt_node entries, so those will have to be switched on too. I
64  * recommended being VERY comfortable with recursion before traversing this
65  * beast, or at least sticking to the library routines provided.
66  */
67 typedef struct nbt_node {
69  char* name; /* This may be NULL. Check your damn pointers. */
70 
71  union { /* payload */
72 
73  /* tag_end has no payload */
74  int8_t tag_byte;
75  int16_t tag_short;
76  int32_t tag_int;
77  int64_t tag_long;
78  float tag_float;
79  double tag_double;
80 
81  struct nbt_byte_array {
82  unsigned char* data;
83  int32_t length;
85 
86  struct nbt_int_array {
87  int32_t* data;
88  int32_t length;
89  } tag_int_array;
90 
91  char* tag_string; /* TODO: technically, this should be a UTF-8 string */
92 
93  /*
94  * Design addendum: we make tag_list a linked list instead of an array
95  * so that nbt_node can be a true recursive data structure. If we used
96  * an array, it would be incorrect to call free() on any element except
97  * the first one. By using a linked list, the context of the node is
98  * irrelevant. One tradeoff of this design is that we don't get tight
99  * list packing when memory is a concern and huge lists are created.
100  *
101  * For more information on using the linked list, see `list.h'. The API
102  * is well documented.
103  */
104  struct nbt_list {
105  struct nbt_node* data; /* A single node's data. */
106  struct list_head entry;
107  } * tag_list,
108  * tag_compound;
109 
110  /*
111  * The primary difference between a tag_list and a tag_compound is the
112  * use of the first (sentinel) node.
113  *
114  * In an nbt_list, the sentinel node contains a valid data pointer with
115  * only the type filled in. This is to deal with empty lists which
116  * still posess types. Therefore, the sentinel's data pointer must be
117  * deallocated.
118  *
119  * In the tag_compound, the only use of the sentinel is to get the
120  * beginning and end of the doubly linked list. The data pointer is
121  * unused and set to NULL.
122  */
123  } payload;
124 } nbt_node;
125 
126  /***** High Level Loading/Saving Functions *****/
127 
128 /*
129  * Loads a NBT tree from a compressed file. The file must have been opened with
130  * a mode of "rb". If an error occurs, NULL will be returned and errno will be
131  * set to the appropriate nbt_status. Check your danm pointers.
132  */
133 nbt_node* nbt_parse_file(FILE* fp);
134 
135 /*
136  * The same as nbt_parse_file, but opens and closes the file for you.
137  */
138 nbt_node* nbt_parse_path(const char* filename);
139 
140 /*
141  * Loads a NBT tree from a compressed block of memory (such as a chunk or a
142  * pre-loaded level.dat). If an error occurs, NULL will be returned and errno
143  * will be set to the appropriate nbt_status. Check your damn pointers.
144  *
145  * PROTIP: Memory map each individual region file, then call
146  * nbt_parse_compressed for chunks as needed.
147  */
148 nbt_node* nbt_parse_compressed(const void* chunk_start, size_t length);
149 
150 /*
151  * Dumps a tree into a file. Check your damn error codes. This function should
152  * return NBT_OK.
153  *
154  * @see nbt_compression_strategy
155  */
156 nbt_status nbt_dump_file(const nbt_node* tree,
157  FILE* fp, nbt_compression_strategy);
158 
159 /*
160  * Dumps a tree into a block of memory. If an error occurs, a buffer with a NULL
161  * `data' pointer will be returned, and errno will be set.
162  *
163  * 1) Check your damn pointers.
164  * 2) Don't forget to free buf->data. Memory leaks are bad, mkay?
165  *
166  * @see nbt_compression_strategy
167  */
168 struct buffer nbt_dump_compressed(const nbt_node* tree,
170 
171  /***** Low Level Loading/Saving Functions *****/
172 
173 /*
174  * Loads a NBT tree from memory. The tree MUST NOT be compressed. If an error
175  * occurs, NULL will be returned, and errno will be set to the appropriate
176  * nbt_status. Please check your damn pointers.
177  */
178 nbt_node* nbt_parse(const void* memory, size_t length);
179 
180 /*
181  * Returns a NULL-terminated string as the ascii representation of the tree. If
182  * an error occurs, NULL will be returned and errno will be set.
183  *
184  * 1) Check your damn pointers.
185  * 2) Don't forget to free the returned pointer. Memory leaks are bad, mkay?
186  */
187 char* nbt_dump_ascii(const nbt_node* tree);
188 
189 /*
190  * Returns a buffer representing the uncompressed tree in Notch's official
191  * binary format. Trees dumped with this function can be regenerated with
192  * nbt_parse. If an error occurs, a buffer with a NULL `data' pointer will be
193  * returned, and errno will be set.
194  *
195  * 1) Check your damn pointers.
196  * 2) Don't forget to free buf->data. Memory leaks are bad, mkay?
197  */
198 struct buffer nbt_dump_binary(const nbt_node* tree);
199 
200  /***** Tree Manipulation Functions *****/
201 
202 /*
203  * Clones an existing tree. Returns NULL on memory errors.
204  */
206 
207 /*
208  * Recursively deallocates a node and all its children. If this is used on a an
209  * entire tree, no memory will be leaked.
210  */
211 void nbt_free(nbt_node*);
212 
213 /*
214  * Recursively frees all the elements of a list, and then frees the list itself.
215  */
216 void nbt_free_list(struct nbt_list*);
217 
218 /*
219  * A visitor function to traverse the tree. Return true to keep going, false to
220  * stop. `aux' is an optional parameter which will be passed to your visitor
221  * from the parent function.
222  */
223 typedef bool (*nbt_visitor_t)(nbt_node* node, void* aux);
224 
225 /*
226  * A function which directs the overall algorithm with its return type.
227  * `aux' is an optional parameter which will be passed to your predicate from
228  * the parent function.
229  */
230 typedef bool (*nbt_predicate_t)(const nbt_node* node, void* aux);
231 
232 /*
233  * Traverses the tree until a visitor says stop or all elements are exhausted.
234  * Returns false if it was terminated by a visitor, true otherwise. In most
235  * cases this can be ignored.
236  *
237  * TODO: Is there a way to do this without expensive function pointers? Maybe
238  * something like list_for_each?
239  */
240 bool nbt_map(nbt_node* tree, nbt_visitor_t, void* aux);
241 
242 /*
243  * Returns a new tree, consisting of a copy of all the nodes the predicate
244  * returned `true' for. If the new tree is empty, this function will return
245  * NULL. If an out of memory error occured, errno will be set to NBT_EMEM.
246  *
247  * TODO: What if I want to keep a tree and all of its children? Do I need to
248  * augment nbt_node with parent pointers?
249  */
250 nbt_node* nbt_filter(const nbt_node* tree, nbt_predicate_t, void* aux);
251 
252 /*
253  * The exact same as nbt_filter, except instead of returning a new tree, the
254  * existing tree is modified in place, and then returned for convenience.
255  */
257 
258 /*
259  * Returns the first node which causes the predicate to return true. If all
260  * nodes are rejected, NULL is returned. If you want to find every instance of
261  * something, consider using nbt_map with a visitor that keeps track.
262  *
263  * Since const-ing `tree' would require me const-ing the return value, you'll
264  * just have to take my word for it that nbt_find DOES NOT modify the tree.
265  * Feel free to cast as necessary.
266  */
267 nbt_node* nbt_find(nbt_node* tree, nbt_predicate_t, void* aux);
268 
269 /*
270  * Returns the first node with the name `name'. If no node with that name is in
271  * the tree, returns NULL.
272  *
273  * If `name' is NULL, this function will find the first unnamed node.
274  *
275  * Since const-ing `tree' would require me const-ing the return value, you'll
276  * just have to take my word for it that nbt_find DOES NOT modify the tree.
277  * Feel free to cast as necessary.
278  */
279 nbt_node* nbt_find_by_name(nbt_node* tree, const char* name);
280 
281 /*
282  * Returns the first node with the "path" in the tree of `path'. If no such node
283  * exists, returns NULL. If an element has no name, something like:
284  *
285  * root.subelement..data == "root" -> "subelement" -> "" -> "data"
286  *
287  * Remember, if multiple elements exist in a sublist which share the same name
288  * (including ""), the first one will be chosen.
289  */
290 nbt_node* nbt_find_by_path(nbt_node* tree, const char* path);
291 
292 /* Returns the number of nodes in the tree. */
293 size_t nbt_size(const nbt_node* tree);
294 
295 /*
296  * Returns the Nth item of a list
297  * Don't use this to iterate through a list, it would be very inefficient
298  */
299 nbt_node* nbt_list_item(nbt_node* list, int n);
300 
301 /* TODO: More utilities as requests are made and patches contributed. */
302 
303  /***** Utility Functions *****/
304 
305 /* Returns true if the trees are identical. */
306 bool nbt_eq(const nbt_node* restrict a, const nbt_node* restrict b);
307 
308 /*
309  * Converts a type to a print-friendly string. The string is statically
310  * allocated, and therefore does not have to be freed by the user.
311 */
312 const char* nbt_type_to_string(nbt_type);
313 
314 /*
315  * Converts an error code into a print-friendly string. The string is statically
316  * allocated, and therefore does not have to be freed by the user.
317  */
318 const char* nbt_error_to_string(nbt_status);
319 
320 #ifdef __cplusplus
321 }
322 #endif
323 
324 #endif
325 
nbt_node * nbt_parse_compressed(const void *chunk_start, size_t length)
nbt_node * nbt_find_by_name(nbt_node *tree, const char *name)
int64_t tag_long
Definition: nbt.h:77
bool nbt_eq(const nbt_node *restrict a, const nbt_node *restrict b)
nbt_node * nbt_find_by_path(nbt_node *tree, const char *path)
Definition: nbt.h:43
struct nbt_node::@2::nbt_list * tag_compound
struct nbt_node::@2::nbt_int_array tag_int_array
void nbt_free_list(struct nbt_list *)
nbt_node * nbt_parse_path(const char *filename)
Definition: nbt.h:41
bool(* nbt_visitor_t)(nbt_node *node, void *aux)
Definition: nbt.h:223
struct nbt_node nbt_node
nbt_type type
Definition: nbt.h:68
Definition: nbt.h:29
Definition: nbt.h:31
nbt_type
Definition: nbt.h:34
char * nbt_dump_ascii(const nbt_node *tree)
double tag_double
Definition: nbt.h:79
bool nbt_map(nbt_node *tree, nbt_visitor_t, void *aux)
Definition: nbt.h:51
nbt_status
Definition: nbt.h:26
#define restrict
Definition: mcchunk.h:25
nbt_status nbt_dump_file(const nbt_node *tree, FILE *fp, nbt_compression_strategy)
Definition: nbt.h:44
Definition: list.h:10
int32_t * data
Definition: nbt.h:87
char * name
Definition: nbt.h:69
struct buffer nbt_dump_compressed(const nbt_node *tree, nbt_compression_strategy)
nbt_node * nbt_clone(nbt_node *)
Definition: nbt.h:38
Definition: nbt.h:36
nbt_node * nbt_find(nbt_node *tree, nbt_predicate_t, void *aux)
Definition: nbt.h:37
nbt_node * nbt_parse(const void *memory, size_t length)
size_t nbt_size(const nbt_node *tree)
struct nbt_node * data
Definition: nbt.h:105
Definition: nbt.h:30
int32_t tag_int
Definition: nbt.h:76
const char * nbt_type_to_string(nbt_type)
struct buffer nbt_dump_binary(const nbt_node *tree)
struct nbt_node::@2::nbt_byte_array tag_byte_array
struct list_head entry
Definition: nbt.h:106
float tag_float
Definition: nbt.h:78
nbt_node * nbt_parse_file(FILE *fp)
Definition: nbt.h:27
nbt_node * nbt_filter_inplace(nbt_node *tree, nbt_predicate_t, void *aux)
unsigned char * data
Definition: nbt.h:82
union nbt_node::@2 payload
int16_t tag_short
Definition: nbt.h:75
void nbt_free(nbt_node *)
int32_t length
Definition: nbt.h:83
Definition: nbt.h:28
bool(* nbt_predicate_t)(const nbt_node *node, void *aux)
Definition: nbt.h:230
Definition: buffer.h:20
nbt_compression_strategy
Definition: nbt.h:50
Definition: nbt.h:40
Definition: nbt.h:67
const char * nbt_error_to_string(nbt_status)
Definition: nbt.h:39
int8_t tag_byte
Definition: nbt.h:74
nbt_node * nbt_filter(const nbt_node *tree, nbt_predicate_t, void *aux)
nbt_node * nbt_list_item(nbt_node *list, int n)
char * tag_string
Definition: nbt.h:91
struct nbt_node::@2::nbt_list * tag_list