librtree 0.9.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -0
  3. data/COPYING +21 -0
  4. data/README.md +87 -0
  5. data/ext/rtree/extconf.rb +37 -19
  6. data/ext/rtree/lib/README.md +9 -0
  7. data/ext/rtree/lib/bindex.c +157 -0
  8. data/ext/rtree/lib/bindex.h +31 -0
  9. data/ext/rtree/lib/bounds.h +21 -0
  10. data/ext/rtree/lib/branch.c +51 -0
  11. data/ext/rtree/lib/branches.c +17 -0
  12. data/ext/rtree/lib/bsrt.c +704 -0
  13. data/ext/rtree/lib/bsrt.h +16 -0
  14. data/ext/rtree/lib/constants.h +19 -0
  15. data/ext/rtree/lib/csv.c +81 -0
  16. data/ext/rtree/lib/csv.h +16 -0
  17. data/ext/rtree/lib/endianness.h +83 -0
  18. data/ext/rtree/lib/error.c +47 -0
  19. data/ext/rtree/lib/json.c +491 -0
  20. data/ext/rtree/lib/json.h +16 -0
  21. data/ext/rtree/lib/mk/Hdr.mk +3 -0
  22. data/ext/rtree/lib/mk/MakeDepend +25 -0
  23. data/ext/rtree/lib/mk/Obj.mk +3 -0
  24. data/ext/rtree/lib/node.c +736 -0
  25. data/ext/rtree/lib/package.c +11 -0
  26. data/ext/rtree/lib/page.c +47 -0
  27. data/ext/rtree/lib/page.h +13 -0
  28. data/ext/rtree/lib/postscript.c +543 -0
  29. data/ext/rtree/lib/rect.c +139 -0
  30. data/ext/rtree/lib/rectf.c +219 -0
  31. data/ext/rtree/lib/rtree/branch.h +105 -0
  32. data/ext/rtree/lib/rtree/branches.h +38 -0
  33. data/ext/rtree/lib/rtree/error.h +42 -0
  34. data/ext/rtree/lib/rtree/extent.h +20 -0
  35. data/ext/rtree/lib/rtree/node.h +96 -0
  36. data/ext/rtree/lib/rtree/package.h +14 -0
  37. data/ext/rtree/lib/rtree/postscript.h +66 -0
  38. data/ext/rtree/lib/rtree/rect.h +38 -0
  39. data/ext/rtree/lib/rtree/rectf.h +34 -0
  40. data/ext/rtree/lib/rtree/search.h +27 -0
  41. data/ext/rtree/lib/rtree/state.h +113 -0
  42. data/ext/rtree/lib/rtree/types.h +14 -0
  43. data/ext/rtree/lib/rtree-base.c +197 -0
  44. data/ext/rtree/lib/rtree.h +62 -0
  45. data/ext/rtree/lib/search.c +54 -0
  46. data/ext/rtree/lib/split.c +710 -0
  47. data/ext/rtree/lib/split.h +15 -0
  48. data/ext/rtree/lib/spvol.c +48 -0
  49. data/ext/rtree/lib/spvol.h +13 -0
  50. data/ext/rtree/lib/state.c +169 -0
  51. data/ext/rtree/rtree.c +11 -0
  52. data/lib/rtree.rb +4 -4
  53. metadata +65 -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