librtree 0.9.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -0
  3. data/COPYING +21 -0
  4. data/README.md +86 -0
  5. data/ext/rtree/extconf.rb +37 -19
  6. data/ext/rtree/lib/bindex.c +157 -0
  7. data/ext/rtree/lib/bindex.h +31 -0
  8. data/ext/rtree/lib/bounds.h +21 -0
  9. data/ext/rtree/lib/branch.c +51 -0
  10. data/ext/rtree/lib/branches.c +17 -0
  11. data/ext/rtree/lib/bsrt.c +704 -0
  12. data/ext/rtree/lib/bsrt.h +16 -0
  13. data/ext/rtree/lib/constants.h +19 -0
  14. data/ext/rtree/lib/csv.c +81 -0
  15. data/ext/rtree/lib/csv.h +16 -0
  16. data/ext/rtree/lib/endianness.h +83 -0
  17. data/ext/rtree/lib/error.c +47 -0
  18. data/ext/rtree/lib/json.c +491 -0
  19. data/ext/rtree/lib/json.h +16 -0
  20. data/ext/rtree/lib/mk/Hdr.mk +3 -0
  21. data/ext/rtree/lib/mk/MakeDepend +25 -0
  22. data/ext/rtree/lib/mk/Obj.mk +3 -0
  23. data/ext/rtree/lib/node.c +708 -0
  24. data/ext/rtree/lib/package.c +11 -0
  25. data/ext/rtree/lib/page.c +47 -0
  26. data/ext/rtree/lib/page.h +13 -0
  27. data/ext/rtree/lib/postscript.c +543 -0
  28. data/ext/rtree/lib/rect.c +139 -0
  29. data/ext/rtree/lib/rectf.c +219 -0
  30. data/ext/rtree/lib/rtree/branch.h +105 -0
  31. data/ext/rtree/lib/rtree/branches.h +38 -0
  32. data/ext/rtree/lib/rtree/error.h +42 -0
  33. data/ext/rtree/lib/rtree/extent.h +20 -0
  34. data/ext/rtree/lib/rtree/node.h +92 -0
  35. data/ext/rtree/lib/rtree/package.h +14 -0
  36. data/ext/rtree/lib/rtree/postscript.h +66 -0
  37. data/ext/rtree/lib/rtree/rect.h +38 -0
  38. data/ext/rtree/lib/rtree/rectf.h +34 -0
  39. data/ext/rtree/lib/rtree/search.h +27 -0
  40. data/ext/rtree/lib/rtree/state.h +113 -0
  41. data/ext/rtree/lib/rtree/types.h +14 -0
  42. data/ext/rtree/lib/rtree-base.c +190 -0
  43. data/ext/rtree/lib/rtree.h +61 -0
  44. data/ext/rtree/lib/search.c +54 -0
  45. data/ext/rtree/lib/split.c +710 -0
  46. data/ext/rtree/lib/split.h +15 -0
  47. data/ext/rtree/lib/spvol.c +48 -0
  48. data/ext/rtree/lib/spvol.h +13 -0
  49. data/ext/rtree/lib/state.c +169 -0
  50. metadata +50 -3
@@ -0,0 +1,81 @@
1
+ #ifdef HAVE_CONFIG_H
2
+ #include "config.h"
3
+ #endif
4
+
5
+ #include "csv.h"
6
+
7
+ #include "rtree/error.h"
8
+ #include "rtree/types.h"
9
+
10
+ #include <errno.h>
11
+ #include <string.h>
12
+ #include <stdlib.h>
13
+
14
+ #define LINE_LEN 0x1000
15
+
16
+ static int parse(FILE *stream, rtree_t *rtree)
17
+ {
18
+ const size_t dims = state_dims(rtree->state);
19
+ rtree_coord_t rect[2 * dims];
20
+ char line[LINE_LEN];
21
+
22
+ /*
23
+ Note that fgets(3) reads from the stream up to LINE_LEN - 1,
24
+ or if an EOF or line-ending \n is found. That's behaviour
25
+ required by the C standard. CSV files should really have
26
+ CRLF line semantics, i.e., each line is terminated by \r\n,
27
+ in that case, fgets will still read up to the \n, so the \r
28
+ will be the last character written to the buffer. That's OK.
29
+ But, a line with just \r line endings will not be handled
30
+ correctly by this code, fgets(3) will not see a line ending
31
+ and so will read multiple lines into the buffer. Such files
32
+ might be found as output from old Macs, they are pretty rare,
33
+ so probably not worth the hassle of handling this case.
34
+ */
35
+
36
+ while (fgets(line, LINE_LEN, stream) != NULL)
37
+ {
38
+ char *tok;
39
+
40
+ if ((tok = strtok(line, ",")) == NULL)
41
+ continue;
42
+
43
+ rtree_id_t id = strtoul(tok, NULL, 0);
44
+
45
+ for (size_t i = 0 ; i < 2 * dims - 1 ; i++)
46
+ {
47
+ if ((tok = strtok(NULL, ",")) == NULL)
48
+ return RTREE_ERR_CSVPARSE;
49
+ rect[i] = strtod(tok, NULL);
50
+ }
51
+
52
+ if ((tok = strtok(NULL, ",\n\r")) == NULL)
53
+ return RTREE_ERR_CSVPARSE;
54
+ rect[2 * dims - 1] = strtod(tok, NULL);
55
+
56
+ if (rtree_add_rect(rtree, id, rect) != 0)
57
+ return RTREE_ERR_CSVPARSE;
58
+ }
59
+
60
+ return RTREE_OK;
61
+ }
62
+
63
+ rtree_t* csv_rtree_read(FILE *stream, size_t dims, state_flags_t flags)
64
+ {
65
+ if (stream == NULL)
66
+ {
67
+ errno = EINVAL;
68
+ return NULL;
69
+ }
70
+
71
+ rtree_t *rtree;
72
+
73
+ if ((rtree = rtree_new(dims, flags)) != NULL)
74
+ {
75
+ if (parse(stream, rtree) == RTREE_OK)
76
+ return rtree;
77
+ rtree_destroy(rtree);
78
+ }
79
+
80
+ return NULL;
81
+ }
@@ -0,0 +1,16 @@
1
+ /*
2
+ csv.h
3
+ Copyright (c) J.J. Green 2020
4
+ */
5
+
6
+ #ifndef CSV_H
7
+ #define CSV_H
8
+
9
+ #include <stdio.h>
10
+
11
+ #include <rtree.h>
12
+ #include <rtree/state.h>
13
+
14
+ rtree_t* csv_rtree_read(FILE*, size_t, state_flags_t);
15
+
16
+ #endif
@@ -0,0 +1,83 @@
1
+ /*
2
+ endian.h
3
+
4
+ This is an "internal" header, it is not used by any public headers
5
+ and not installed; it handles the messing around that you need to
6
+ do to get endinannes functions even close to portable.
7
+
8
+ This is largely from https://github.com/mikepb/endian.h which is
9
+ based on a Gist by Mathias Panzenböck, those are both released into
10
+ the public domain. It differs in that
11
+
12
+ - it uses autoconf to determine the existence of headers and
13
+ declarations, rather than "OS sniffing"
14
+
15
+ - it is only interested in the little-endian versions of the macros
16
+ since that's the only ones we use (one could add those in a fairly
17
+ obvious fashion though)
18
+
19
+ Copyright (c) J.J. Green 2020
20
+ */
21
+
22
+ #ifndef ENDIANNESS_H
23
+ #define ENDIANNESS_H
24
+
25
+ #ifdef HAVE_CONFIG_H
26
+ #include "config.h"
27
+ #endif
28
+
29
+ #if defined HAVE_ENDIAN_H
30
+
31
+ #include <endian.h>
32
+
33
+ #elif defined HAVE_SYS_ENDIAN_H
34
+
35
+ #include <sys/endian.h>
36
+
37
+ #ifndef HAVE_DECL_LE16TOH
38
+ #define le16toh(x) letoh16(x)
39
+ #endif
40
+ #ifndef HAVE_DECL_LE32TOH
41
+ #define le32toh(x) letoh32(x)
42
+ #endif
43
+ #ifndef HAVE_DECL_LE64TOH
44
+ #define le64toh(x) letoh64(x)
45
+ #endif
46
+
47
+ #elif defined HAVE_LIBKERN_OSBYTEORDER_H
48
+
49
+ #include <libkern/OSByteOrder.h>
50
+ #define htole16(x) OSSwapHostToLittleInt16(x)
51
+ #define le16toh(x) OSSwapLittleToHostInt16(x)
52
+ #define htole32(x) OSSwapHostToLittleInt32(x)
53
+ #define le32toh(x) OSSwapLittleToHostInt32(x)
54
+ #define htole64(x) OSSwapHostToLittleInt64(x)
55
+ #define le64toh(x) OSSwapLittleToHostInt64(x)
56
+
57
+ #elif defined HAVE_WINSOCK2_H
58
+
59
+ #include <winsock2.h>
60
+ #include <sys/param.h>
61
+ #if BYTE_ORDER == LITTLE_ENDIAN
62
+ #define htole16(x) (x)
63
+ #define le16toh(x) (x)
64
+ #define htole32(x) (x)
65
+ #define le32toh(x) (x)
66
+ #define htole64(x) (x)
67
+ #define le64toh(x) (x)
68
+ #elif BYTE_ORDER == BIG_ENDIAN
69
+ #define htole16(x) __builtin_bswap16(x)
70
+ #define le16toh(x) __builtin_bswap16(x)
71
+ #define htole32(x) __builtin_bswap32(x)
72
+ #define le32toh(x) __builtin_bswap32(x)
73
+ #define htole64(x) __builtin_bswap64(x)
74
+ #define le64toh(x) __builtin_bswap64(x)
75
+ #endif
76
+
77
+ #else
78
+
79
+ #error No compatible endianness header available
80
+
81
+ #endif
82
+
83
+ #endif
@@ -0,0 +1,47 @@
1
+ #ifdef HAVE_CONFIG_H
2
+ #include "config.h"
3
+ #endif
4
+
5
+ #include <stdlib.h>
6
+
7
+ #include "rtree/error.h"
8
+
9
+ const char* strerror_rtree(int err)
10
+ {
11
+ static const char nomsg[] = "unimplemented message";
12
+ struct
13
+ {
14
+ int err;
15
+ const char *msg;
16
+ } *m, mtab[] =
17
+ {
18
+ { RTREE_OK, "Success" },
19
+ { RTREE_ERR_INVAL, "Invalid argument" },
20
+ { RTREE_ERR_DOM, "Argument outside domain" },
21
+ { RTREE_ERR_NOMEM, "Out of memory" },
22
+ { RTREE_ERR_CSVPARSE, "Error parsing CSV" },
23
+ { RTREE_ERR_NOCSV, "Compiled without CSV support" },
24
+ { RTREE_ERR_JANSSON, "Error from the Jansson library" },
25
+ { RTREE_ERR_NOJSON, "Compiled without JSON support" },
26
+ { RTREE_ERR_NOJSON, "Compiled without BSRT support" },
27
+ { RTREE_ERR_GETBRANCH, "Error getting branch" },
28
+ { RTREE_ERR_GETCHILD, "Error getting child node" },
29
+ { RTREE_ERR_NODECLONE, "Error cloning node" },
30
+ { RTREE_ERR_PICKBRANCH, "Error picking branch" },
31
+ { RTREE_ERR_ADDRECT, "Error adding rectangle" },
32
+ { RTREE_ERR_NOSUCHSPLIT, "No such splitting method" },
33
+ { RTREE_ERR_DIMS, "Bad R-tree dimension" },
34
+ { RTREE_ERR_EMPTY, "Empty R-tree" },
35
+ { RTREE_ERR_BUFFER, "Buffer to small" },
36
+ { RTREE_ERR_POSTSCRIPT, "Error generating PostScript" },
37
+ { RTREE_ERR_USER, "User abort" },
38
+ { RTREE_ERR_FWRITE, "Failed write" },
39
+ { RTREE_ERR_SPLIT, "Error in split" },
40
+ { -1, NULL }
41
+ };
42
+
43
+ for (m = mtab ; m->msg ; m++)
44
+ if (m->err == err) return m->msg;
45
+
46
+ return nomsg;
47
+ }
@@ -0,0 +1,491 @@
1
+ #ifdef HAVE_CONFIG_H
2
+ #include "config.h"
3
+ #endif
4
+
5
+ #include "json.h"
6
+ #include "bounds.h"
7
+
8
+ #include "rtree/error.h"
9
+ #include "rtree/branches.h"
10
+
11
+ #include <errno.h>
12
+
13
+ #ifdef WITH_JSON
14
+
15
+ #include <jansson.h>
16
+
17
+ /*
18
+ This module exports json_rtree_read(), json_rtree_write() but
19
+ we make a change in our usual naming conventions in having all
20
+ static functions prefixed "jr/w_" (for JSON reed/write) since
21
+ the Jansson library uses the "json_" prefix, so to avoid a clash
22
+ with that namespace
23
+ */
24
+
25
+ static json_t* jw_leaf(const state_t *state, const branch_t *branch)
26
+ {
27
+ json_t *jb = json_object(), *jr = json_array();
28
+ const rtree_coord_t *rect = branch_get_rect((branch_t*)branch);
29
+ const size_t dims = state_dims(state);
30
+ const unsigned long id = branch_get_id(branch);
31
+
32
+ for (size_t i = 0 ; i < 2 * dims ; i++)
33
+ json_array_append_new(jr, json_real(rect[i]));
34
+
35
+ json_object_set_new(jb, "rect", jr);
36
+ json_object_set_new(jb, "id", json_integer(id));
37
+
38
+ return jb;
39
+ }
40
+
41
+ static int jw_leaf_f(const state_t *state, const branch_t *branch, void *arg)
42
+ {
43
+ json_t *ja = (json_t*)arg, *jb;
44
+
45
+ if ((jb = jw_leaf(state, branch)) != NULL)
46
+ {
47
+ json_array_append_new(ja, jb);
48
+ return 0;
49
+ }
50
+
51
+ return 1;
52
+ }
53
+
54
+ static json_t* jw_node(const state_t*, const node_t*);
55
+
56
+ static int jw_branch_f(const state_t *state, const branch_t *branch, void *arg)
57
+ {
58
+ const size_t dims = state_dims(state);
59
+
60
+ json_t *jr;
61
+ if ((jr = json_array()) != NULL)
62
+ {
63
+ const rtree_coord_t *rect;
64
+ if ((rect = branch_get_rect((branch_t*)branch)) != NULL)
65
+ {
66
+ for (size_t i = 0 ; i < 2 * dims ; i++)
67
+ json_array_append_new(jr, json_real(rect[i]));
68
+
69
+ const node_t *child;
70
+ if ((child = branch_get_child(branch)) != NULL)
71
+ {
72
+ json_t *jb;
73
+ if ((jb = json_object()) != NULL)
74
+ {
75
+ json_t *jn;
76
+ if ((jn = jw_node(state, child)) != NULL)
77
+ {
78
+ json_object_set_new(jb, "rect", jr);
79
+ json_object_set_new(jb, "node", jn);
80
+ json_array_append_new((json_t*)arg, jb);
81
+
82
+ return 0;
83
+ }
84
+ json_decref(jb);
85
+ }
86
+ }
87
+ }
88
+ json_decref(jr);
89
+ }
90
+
91
+ return 1;
92
+ }
93
+
94
+ static json_t* jw_branch(const state_t *state, const node_t *node)
95
+ {
96
+ json_t *json;
97
+ nbe_cb_t *json_f;
98
+
99
+ if (node_level(node) == 0)
100
+ json_f = jw_leaf_f;
101
+ else
102
+ json_f = jw_branch_f;
103
+
104
+ if ((json = json_array()) != NULL)
105
+ {
106
+ if (node_branch_each(state, node, json_f, json) == 0)
107
+ return json;
108
+ json_decref(json);
109
+ }
110
+
111
+ return NULL;
112
+ }
113
+
114
+ static json_t* jw_node(const state_t *state, const node_t *node)
115
+ {
116
+ json_t *json;
117
+
118
+ if ((json = json_object()) == NULL)
119
+ return NULL;
120
+
121
+ json_object_set_new(json, "level", json_integer(node_level(node)));
122
+ json_object_set_new(json, "count", json_integer(node_count(node)));
123
+ json_object_set_new(json, "branches", jw_branch(state, node));
124
+
125
+ return json;
126
+ }
127
+
128
+ static json_t* jw_state(const state_t *state)
129
+ {
130
+ json_t *json;
131
+
132
+ if ((json = json_object()) == NULL)
133
+ return NULL;
134
+
135
+ const size_t
136
+ dims = state_dims(state),
137
+ page_size = state_page_size(state),
138
+ branch_size = state_branch_size(state),
139
+ node_size = state_node_size(state),
140
+ rect_size = state_rect_size(state),
141
+ float_size = sizeof(rtree_coord_t);
142
+
143
+ json_object_set_new(json, "dims", json_integer(dims));
144
+ json_object_set_new(json, "page_size", json_integer(page_size));
145
+ json_object_set_new(json, "float_size", json_integer(float_size));
146
+ json_object_set_new(json, "rect_size", json_integer(rect_size));
147
+ json_object_set_new(json, "branch_size", json_integer(branch_size));
148
+ json_object_set_new(json, "node_size", json_integer(node_size));
149
+
150
+ return json;
151
+ }
152
+
153
+ static json_t* jw_rtree(const rtree_t *rtree)
154
+ {
155
+ json_t *json;
156
+
157
+ if ((json = json_object()) == NULL)
158
+ return NULL;
159
+
160
+ json_object_set_new(json, "root", jw_node(rtree->state, rtree->root));
161
+ json_object_set_new(json, "state", jw_state(rtree->state));
162
+
163
+ return json;
164
+ }
165
+
166
+ int json_rtree_write(const rtree_t *rtree, FILE *stream)
167
+ {
168
+ json_t *json;
169
+ int err = 0;
170
+
171
+ if ((json = jw_rtree(rtree)) != NULL)
172
+ {
173
+ if (json_dumpf(json, stream, JSON_INDENT(2)) != 0)
174
+ err++;
175
+ json_decref(json);
176
+ }
177
+ else
178
+ err++;
179
+
180
+ return err ? RTREE_ERR_JANSSON : RTREE_OK;
181
+ }
182
+
183
+ /* reader */
184
+
185
+ static bool jr_value_equal(json_t *object, const char *key, size_t value)
186
+ {
187
+ json_t *json_value = json_object_get(object, key);
188
+
189
+ if ((json_value == NULL) || (json_is_integer(json_value) == false))
190
+ return false;
191
+
192
+ json_int_t int_value = json_integer_value(json_value);
193
+
194
+ return (int_value >= 0) && ((size_t)int_value == value);
195
+ }
196
+
197
+ static bool jr_state_is_consistent(json_t *json_state, state_t *state)
198
+ {
199
+ return
200
+ jr_value_equal(json_state, "dims", state_dims(state)) &&
201
+ jr_value_equal(json_state, "page_size", state_page_size(state)) &&
202
+ jr_value_equal(json_state, "float_size", sizeof(rtree_coord_t)) &&
203
+ jr_value_equal(json_state, "rect_size", state_rect_size(state)) &&
204
+ jr_value_equal(json_state, "branch_size", state_branch_size(state)) &&
205
+ jr_value_equal(json_state, "node_size", state_node_size(state));
206
+ }
207
+
208
+ static state_t* jr_state(json_t *json)
209
+ {
210
+ json_t *json_state;
211
+
212
+ if ((json_state = json_object_get(json, "state")) == NULL)
213
+ return NULL;
214
+
215
+ if (! json_is_object(json_state))
216
+ return NULL;
217
+
218
+ size_t dims;
219
+
220
+ {
221
+ json_t *json_dims;
222
+
223
+ if ((json_dims = json_object_get(json_state, "dims")) == NULL)
224
+ return NULL;
225
+
226
+ if (! json_is_integer(json_dims))
227
+ return NULL;
228
+
229
+ dims = json_integer_value(json_dims);
230
+
231
+ if (dims > RTREE_DIMS_MAX)
232
+ return NULL;
233
+ }
234
+
235
+ size_t page_size;
236
+
237
+ {
238
+ json_t *json_page_size;
239
+
240
+ if ((json_page_size = json_object_get(json_state, "page_size")) == NULL)
241
+ return NULL;
242
+
243
+ if (! json_is_integer(json_page_size))
244
+ return NULL;
245
+
246
+ page_size = json_integer_value(json_page_size);
247
+ }
248
+
249
+ size_t node_size;
250
+
251
+ {
252
+ json_t *json_node_size;
253
+
254
+ if ((json_node_size = json_object_get(json_state, "node_size")) == NULL)
255
+ return NULL;
256
+
257
+ if (! json_is_integer(json_node_size))
258
+ return NULL;
259
+
260
+ node_size = json_integer_value(json_node_size);
261
+ }
262
+
263
+ const size_t node_page = page_size / node_size;
264
+
265
+ state_t *state;
266
+
267
+ if ((state = state_new(dims, RTREE_NODE_PAGE(node_page))) != NULL)
268
+ {
269
+ if (jr_state_is_consistent(json_state, state))
270
+ return state;
271
+ else
272
+ errno = EINVAL;
273
+ state_destroy(state);
274
+ }
275
+
276
+ return NULL;
277
+ }
278
+
279
+ static node_t* jr_node(state_t*, json_t*);
280
+
281
+ static int jr_branch_leaf(json_t *json, branch_t *branch)
282
+ {
283
+ const json_t *json_id = json_object_get(json, "id");
284
+ if ((json_id == NULL) || (json_is_integer(json_id) == false))
285
+ return 1;
286
+
287
+ branch_set_id(branch, json_integer_value(json_id));
288
+
289
+ return 0;
290
+ }
291
+
292
+ static int jr_branch_internal(state_t *state, json_t *json, branch_t *branch)
293
+ {
294
+ json_t *json_node = json_object_get(json, "node");
295
+ if ((json_node == NULL) || (json_is_object(json_node) == false))
296
+ return RTREE_ERR_JANSSON;
297
+
298
+ node_t *node = jr_node(state, json_node);
299
+ if (node == NULL)
300
+ return RTREE_ERR_JANSSON;
301
+
302
+ branch_set_child(branch, node);
303
+
304
+ return RTREE_OK;
305
+ }
306
+
307
+ static int jr_node_recurse(state_t *state, node_t *node, json_t *json_branches)
308
+ {
309
+ const size_t dims = state_dims(state);
310
+ const node_level_t level = node_level(node);
311
+ size_t i;
312
+ void *branches = node_get_branches(node);
313
+ json_t *json_branch;
314
+
315
+ if (json_array_size(json_branches) > state_branching_factor(state))
316
+ return RTREE_ERR_INVAL;
317
+
318
+ json_array_foreach(json_branches, i, json_branch)
319
+ {
320
+ if (json_is_object(json_branch) == false)
321
+ return RTREE_ERR_JANSSON;
322
+
323
+ branch_t *branch = branches_get(state, branches, i);
324
+
325
+ {
326
+ int err = branch_init(state, branch);
327
+ if (err != RTREE_OK)
328
+ return err;
329
+ }
330
+
331
+ json_t *json_rect = json_object_get(json_branch, "rect");
332
+
333
+ if ( (json_rect == NULL) ||
334
+ (json_is_array(json_rect) == false) ||
335
+ (json_array_size(json_rect) != 2 * dims) )
336
+ return RTREE_ERR_JANSSON;
337
+
338
+ rtree_coord_t coord[2 * dims];
339
+ json_t *json_coord;
340
+ size_t j;
341
+
342
+ json_array_foreach(json_rect, j, json_coord)
343
+ {
344
+ if (json_is_real(json_coord) == false)
345
+ return RTREE_ERR_JANSSON;
346
+ coord[j] = json_real_value(json_coord);
347
+ }
348
+
349
+ branch_set_rect(state, branch, coord);
350
+ node_count_increment(node);
351
+
352
+ if (level == 0)
353
+ {
354
+ int err = jr_branch_leaf(json_branch, branch);
355
+ if (err != RTREE_OK)
356
+ return err;
357
+ }
358
+ else
359
+ {
360
+ int err = jr_branch_internal(state, json_branch, branch);
361
+ if (err != RTREE_OK)
362
+ return err;
363
+ }
364
+ }
365
+
366
+ return RTREE_OK;
367
+ }
368
+
369
+ static node_t* jr_node(state_t *state, json_t *json_node)
370
+ {
371
+ json_int_t count;
372
+ {
373
+ json_t *json = json_object_get(json_node, "count");
374
+ if ( (json == NULL) || (json_is_integer(json) == false) )
375
+ return NULL;
376
+ count = json_integer_value(json);
377
+ if ((count < 0) || (state_branching_factor(state) < (size_t)count))
378
+ return NULL;
379
+ }
380
+
381
+ json_int_t level;
382
+ {
383
+ json_t *json = json_object_get(json_node, "level");
384
+ if ( (json == NULL) || (json_is_integer(json) == false) )
385
+ return NULL;
386
+ level = json_integer_value(json);
387
+ if ((level < 0) || (NODE_LEVEL_MAX < level))
388
+ return NULL;
389
+ }
390
+
391
+ json_t *json_branches = json_object_get(json_node, "branches");
392
+
393
+ if ( (json_branches == NULL) ||
394
+ (json_is_array(json_branches) == false) ||
395
+ (json_array_size(json_branches) != (size_t)count) )
396
+ return NULL;
397
+
398
+ node_t *node;
399
+
400
+ if ((node = node_new(state)) != NULL)
401
+ {
402
+ node_set_level(node, level);
403
+
404
+ int err = jr_node_recurse(state, node, json_branches);
405
+ if (err == 0)
406
+ return node;
407
+
408
+ node_destroy(state, node);
409
+ }
410
+
411
+ return NULL;
412
+ }
413
+
414
+ static node_t* jr_root(state_t *state, json_t *json)
415
+ {
416
+ json_t *json_root;
417
+
418
+ if ((json_root = json_object_get(json, "root")) == NULL)
419
+ return NULL;
420
+
421
+ return jr_node(state, json_root);
422
+ }
423
+
424
+ static rtree_t* jr_rtree(json_t *json)
425
+ {
426
+ if (! json_is_object(json))
427
+ return NULL;
428
+
429
+ state_t *state;
430
+
431
+ if ((state = jr_state(json)) != NULL)
432
+ {
433
+ node_t *root;
434
+
435
+ if ((root = jr_root(state, json)) != NULL)
436
+ {
437
+ rtree_t *rtree;
438
+
439
+ if ((rtree = rtree_alloc()) == NULL)
440
+ errno = ENOMEM;
441
+ else
442
+ {
443
+ rtree->state = state;
444
+ rtree->root = root;
445
+
446
+ return rtree;
447
+ }
448
+ node_destroy(state, root);
449
+ }
450
+ state_destroy(state);
451
+ }
452
+
453
+ return NULL;
454
+ }
455
+
456
+ rtree_t* json_rtree_read(FILE *stream)
457
+ {
458
+ const size_t flags = JSON_REJECT_DUPLICATES;
459
+ json_t *json;
460
+
461
+ if ((json = json_loadf(stream, flags, NULL)) != NULL)
462
+ {
463
+ rtree_t *rtree = jr_rtree(json);
464
+ json_decref(json);
465
+ return rtree;
466
+ }
467
+
468
+ return NULL;
469
+ }
470
+
471
+ #else
472
+
473
+ #pragma GCC diagnostic push
474
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
475
+ int json_rtree_write(const rtree_t *rtree, FILE *stream)
476
+ {
477
+ errno = ENOSYS;
478
+ return RTREE_ERR_NOJSON;
479
+ }
480
+ #pragma GCC diagnostic pop
481
+
482
+ #pragma GCC diagnostic push
483
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
484
+ rtree_t* json_rtree_read(FILE *stream)
485
+ {
486
+ errno = ENOSYS;
487
+ return NULL;
488
+ }
489
+ #pragma GCC diagnostic pop
490
+
491
+ #endif