ox 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ox might be problematic. Click here for more details.

Files changed (52) hide show
  1. data/LICENSE +27 -0
  2. data/README +153 -0
  3. data/ext/ox/base64.c +123 -0
  4. data/ext/ox/base64.h +44 -0
  5. data/ext/ox/cache.c +148 -0
  6. data/ext/ox/cache.h +43 -0
  7. data/ext/ox/cache8.c +80 -0
  8. data/ext/ox/cache8.h +43 -0
  9. data/ext/ox/cache8_test.c +69 -0
  10. data/ext/ox/cache_test.c +69 -0
  11. data/ext/ox/dump.c +901 -0
  12. data/ext/ox/extconf.rb +7 -0
  13. data/ext/ox/gen_load.c +196 -0
  14. data/ext/ox/obj_load.c +802 -0
  15. data/ext/ox/ox.c +456 -0
  16. data/ext/ox/ox.h +190 -0
  17. data/ext/ox/parse.c +629 -0
  18. data/lib/ox.rb +97 -0
  19. data/lib/ox/cdata.rb +12 -0
  20. data/lib/ox/comment.rb +13 -0
  21. data/lib/ox/doctype.rb +13 -0
  22. data/lib/ox/document.rb +20 -0
  23. data/lib/ox/element.rb +67 -0
  24. data/lib/ox/node.rb +24 -0
  25. data/test/Sample.graffle +2318 -0
  26. data/test/cache16_test.rb +17 -0
  27. data/test/cache8_test.rb +17 -0
  28. data/test/cache_test.rb +17 -0
  29. data/test/files.rb +34 -0
  30. data/test/func.rb +228 -0
  31. data/test/gen_sample.rb +22 -0
  32. data/test/obj_sample.rb +19 -0
  33. data/test/ox/change.rb +16 -0
  34. data/test/ox/dir.rb +21 -0
  35. data/test/ox/doc.rb +39 -0
  36. data/test/ox/file.rb +33 -0
  37. data/test/ox/group.rb +18 -0
  38. data/test/ox/hasprops.rb +18 -0
  39. data/test/ox/layer.rb +14 -0
  40. data/test/ox/line.rb +22 -0
  41. data/test/ox/oval.rb +12 -0
  42. data/test/ox/rect.rb +12 -0
  43. data/test/ox/shape.rb +37 -0
  44. data/test/ox/text.rb +23 -0
  45. data/test/perf_gen.rb +193 -0
  46. data/test/perf_mars.rb +97 -0
  47. data/test/perf_obj.rb +201 -0
  48. data/test/perf_pod.rb +88 -0
  49. data/test/perf_write.rb +80 -0
  50. data/test/sample.rb +62 -0
  51. data/test/test.rb +70 -0
  52. metadata +106 -0
data/ext/ox/cache.h ADDED
@@ -0,0 +1,43 @@
1
+ /* cache.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * - Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
16
+ * used to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #ifndef __OX_CACHE_H__
32
+ #define __OX_CACHE_H__
33
+
34
+ #include "ruby.h"
35
+
36
+ typedef struct _Cache *Cache;
37
+
38
+ extern void ox_cache_new(Cache *cache);
39
+ extern VALUE ox_cache_get(Cache cache, const char *key, VALUE **slot);
40
+
41
+ extern void ox_cache_print(Cache cache);
42
+
43
+ #endif /* __OX_CACHE_H__ */
data/ext/ox/cache8.c ADDED
@@ -0,0 +1,80 @@
1
+
2
+ #include <stdlib.h>
3
+ #include <errno.h>
4
+ #include <stdio.h>
5
+ #include <string.h>
6
+ #include <stdarg.h>
7
+
8
+ #include "ruby.h"
9
+ #include "cache8.h"
10
+
11
+ #define BITS 4
12
+ #define MASK 0x000000000000000F
13
+ #define SLOT_CNT 16
14
+ #define DEPTH 16
15
+
16
+ struct _Cache8 {
17
+ union {
18
+ struct _Cache8 *slots[SLOT_CNT];
19
+ unsigned long values[SLOT_CNT];
20
+ };
21
+ };
22
+
23
+ static void slot_print(Cache8 cache, VALUE key, unsigned int depth);
24
+
25
+ void
26
+ ox_cache8_new(Cache8 *cache) {
27
+ Cache8 *cp;
28
+ int i;
29
+
30
+ if (0 == (*cache = (Cache8)malloc(sizeof(struct _Cache8)))) {
31
+ rb_raise(rb_eNoMemError, "not enough memory\n");
32
+ }
33
+ for (i = SLOT_CNT, cp = (*cache)->slots; 0 < i; i--, cp++) {
34
+ *cp = 0;
35
+ }
36
+ }
37
+
38
+ unsigned long
39
+ ox_cache8_get(Cache8 cache, VALUE key, unsigned long **slot) {
40
+ Cache8 *cp;
41
+ int i;
42
+ VALUE k;
43
+
44
+ for (i = 64 - BITS; 0 < i; i -= BITS) {
45
+ k = (key >> i) & MASK;
46
+ cp = cache->slots + k;
47
+ if (0 == *cp) {
48
+ ox_cache8_new(cp);
49
+ }
50
+ cache = *cp;
51
+ }
52
+ *slot = cache->values + (key & MASK);
53
+
54
+ return **slot;
55
+ }
56
+
57
+ void
58
+ ox_cache8_print(Cache8 cache) {
59
+ //printf("-------------------------------------------\n");
60
+ slot_print(cache, 0, 0);
61
+ }
62
+
63
+ static void
64
+ slot_print(Cache8 c, VALUE key, unsigned int depth) {
65
+ Cache8 *cp;
66
+ unsigned int i;
67
+ unsigned long k;
68
+
69
+ for (i = 0, cp = c->slots; i < SLOT_CNT; i++, cp++) {
70
+ if (0 != *cp) {
71
+ k = (key << BITS) | i;
72
+ //printf("*** key: 0x%016lx depth: %u i: %u\n", k, depth, i);
73
+ if (DEPTH - 1 == depth) {
74
+ printf("0x%016lx: %4lu\n", k, (unsigned long)*cp);
75
+ } else {
76
+ slot_print(*cp, k, depth + 1);
77
+ }
78
+ }
79
+ }
80
+ }
data/ext/ox/cache8.h ADDED
@@ -0,0 +1,43 @@
1
+ /* cache8.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * - Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
16
+ * used to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #ifndef __OX_CACHE8_H__
32
+ #define __OX_CACHE8_H__
33
+
34
+ #include "ruby.h"
35
+
36
+ typedef struct _Cache8 *Cache8;
37
+
38
+ extern void ox_cache8_new(Cache8 *cache);
39
+ extern unsigned long ox_cache8_get(Cache8 cache, VALUE key, unsigned long **slot);
40
+
41
+ extern void ox_cache8_print(Cache8 cache);
42
+
43
+ #endif /* __OX_CACHE8_H__ */
@@ -0,0 +1,69 @@
1
+ /* cache8_test.c
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * - Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
16
+ * used to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #include <stdio.h>
32
+ #include "cache8.h"
33
+
34
+ static unsigned long data[] = {
35
+ 0x000000A0A0A0A0A0,
36
+ 0x0000000000ABCDEF,
37
+ 0x0123456789ABCDEF,
38
+ 0x0000000000000001,
39
+ 0x0000000000000002,
40
+ 0x0000000000000003,
41
+ 0x0000000000000004,
42
+ 0
43
+ };
44
+
45
+ void
46
+ ox_cache8_test() {
47
+ Cache8 c;
48
+ unsigned long v;
49
+ unsigned long *d;
50
+ unsigned long cnt = 1;
51
+ unsigned long *slot = 0;
52
+
53
+ ox_cache8_new(&c);
54
+ for (d = data; 0 != *d; d++) {
55
+ v = ox_cache8_get(c, *d, &slot);
56
+ if (0 == v) {
57
+ if (0 == slot) {
58
+ printf("*** failed to get a slot for 0x%016lx\n", *d);
59
+ } else {
60
+ printf("*** adding 0x%016lx to cache with value %lu\n", *d, cnt);
61
+ *slot = cnt++;
62
+ }
63
+ } else {
64
+ printf("*** get on 0x%016lx returned %lu\n", *d, v);
65
+ }
66
+ //ox_cache8_print(c);
67
+ }
68
+ ox_cache8_print(c);
69
+ }
@@ -0,0 +1,69 @@
1
+ /* cache_test.c
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * - Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
16
+ * used to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #include "cache.h"
32
+
33
+ static const char *data[] = {
34
+ "one",
35
+ "two",
36
+ "one",
37
+ "onex",
38
+ "oney",
39
+ "one",
40
+ 0
41
+ };
42
+
43
+ void
44
+ ox_cache_test() {
45
+ Cache c;
46
+ const char **d;
47
+ VALUE v;
48
+ VALUE *slot = 0;;
49
+
50
+ ox_cache_new(&c);
51
+ for (d = data; 0 != *d; d++) {
52
+ v = ox_cache_get(c, *d, &slot);
53
+ if (Qundef == v) {
54
+ if (0 == slot) {
55
+ //printf("*** failed to get a slot for %s\n", *d);
56
+ } else {
57
+ //printf("*** added '%s' to cache\n", *d);
58
+ v = ID2SYM(rb_intern(*d));
59
+ *slot = v;
60
+ }
61
+ } else {
62
+ VALUE rs = rb_funcall2(v, rb_intern("to_s"), 0, 0);
63
+
64
+ printf("*** get on '%s' returned '%s' (%s)\n", *d, StringValuePtr(rs), rb_class2name(rb_obj_class(v)));
65
+ }
66
+ //ox_cache_print(c);
67
+ }
68
+ ox_cache_print(c);
69
+ }
data/ext/ox/dump.c ADDED
@@ -0,0 +1,901 @@
1
+ /* dump.c
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * - Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
16
+ * used to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #include <stdlib.h>
32
+ #include <errno.h>
33
+ #include <stdio.h>
34
+ #include <string.h>
35
+
36
+ #include "ruby.h"
37
+ #include "ruby/oniguruma.h"
38
+ #include "base64.h"
39
+ #include "cache8.h"
40
+ #include "ox.h"
41
+
42
+ typedef struct _Str {
43
+ const char *str;
44
+ size_t len;
45
+ } *Str;
46
+
47
+ typedef struct _Element {
48
+ struct _Str clas;
49
+ struct _Str attr;
50
+ unsigned long id;
51
+ int indent; // < 0 indicates no \n
52
+ int closed;
53
+ char type;
54
+ } *Element;
55
+
56
+ typedef struct _Out {
57
+ void (*w_start)(struct _Out *out, Element e);
58
+ void (*w_end)(struct _Out *out, Element e);
59
+ void (*w_time)(struct _Out *out, VALUE obj);
60
+ char *buf;
61
+ char *end;
62
+ char *cur;
63
+ Cache8 circ_cache;
64
+ unsigned long circ_cnt;
65
+ int indent;
66
+ int depth; // used by dumpHash
67
+ } *Out;
68
+
69
+ static void dump_obj_to_xml(VALUE obj, int indent, int xsd_date, int circular, Out out);
70
+
71
+ static void dump_obj(ID aid, VALUE obj, unsigned int depth, Out out);
72
+ static void dump_gen_doc(VALUE obj, unsigned int depth, Out out);
73
+ static void dump_gen_element(VALUE obj, unsigned int depth, Out out);
74
+ static int dump_gen_attr(VALUE key, VALUE value, Out out);
75
+ static int dump_gen_nodes(VALUE obj, unsigned int depth, Out out);
76
+ static void dump_gen_val_node(VALUE obj, unsigned int depth,
77
+ const char *pre, size_t plen,
78
+ const char *suf, size_t slen, Out out);
79
+
80
+ static void dump_start(Out out, Element e);
81
+ static void dump_end(Out out, Element e);
82
+
83
+ static void grow(Out out, size_t len);
84
+
85
+ static void dump_value(Out out, const char *value, size_t size);
86
+ static int dump_var(ID key, VALUE value, Out out);
87
+ static void dump_num(Out out, VALUE obj);
88
+ static void dump_time_thin(Out out, VALUE obj);
89
+ static void dump_time_xsd(Out out, VALUE obj);
90
+ static int dump_hash(VALUE key, VALUE value, Out out);
91
+
92
+ static int is_xml_friendly(const u_char *str, int len);
93
+
94
+
95
+ static char xml_friendly_chars[256] = "\
96
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
97
+ ooxoooxxooooooooooooooooooooxoxo\
98
+ oooooooooooooooooooooooooooooooo\
99
+ xoooooooooooooooooooooooooooooox\
100
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
101
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
102
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
103
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
104
+
105
+ inline static int
106
+ is_xml_friendly(const u_char *str, int len) {
107
+ for (; 0 < len; str++, len--) {
108
+ if ('x' == xml_friendly_chars[*str]) {
109
+ return 0;
110
+ }
111
+ }
112
+ return 1;
113
+ }
114
+
115
+ inline static void
116
+ fill_indent(Out out, int cnt) {
117
+ if (0 <= cnt) {
118
+ *out->cur++ = '\n';
119
+ for (; 0 < cnt; cnt--) {
120
+ *out->cur++ = ' ';
121
+ }
122
+ }
123
+ }
124
+
125
+ inline static void
126
+ fill_value(Out out, const char *value, size_t len) {
127
+ if (6 < len) {
128
+ memcpy(out->cur, value, len);
129
+ out->cur += len;
130
+ } else {
131
+ for (; '\0' != *value; value++) {
132
+ *out->cur++ = *value;
133
+ }
134
+ }
135
+ }
136
+
137
+ inline static void
138
+ fill_attr(Out out, char name, const char *value, size_t len) {
139
+ *out->cur++ = ' ';
140
+ *out->cur++ = name;
141
+ *out->cur++ = '=';
142
+ *out->cur++ = '"';
143
+ if (6 < len) {
144
+ memcpy(out->cur, value, len);
145
+ out->cur += len;
146
+ } else {
147
+ for (; '\0' != *value; value++) {
148
+ *out->cur++ = *value;
149
+ }
150
+ }
151
+ *out->cur++ = '"';
152
+ }
153
+
154
+ inline static const char*
155
+ ulong2str(unsigned long num, char *end) {
156
+ char *b;
157
+
158
+ *end-- = '\0';
159
+ for (b = end; 0 < num || b == end; num /= 10, b--) {
160
+ *b = (num % 10) + '0';
161
+ }
162
+ b++;
163
+
164
+ return b;
165
+ }
166
+
167
+ static int
168
+ check_circular(Out out, VALUE obj, Element e) {
169
+ unsigned long *slot;
170
+ unsigned long id;
171
+ int result;
172
+
173
+ if (0 == (id = ox_cache8_get(out->circ_cache, obj, &slot))) {
174
+ out->circ_cnt++;
175
+ id = out->circ_cnt;
176
+ *slot = id;
177
+ e->id = id;
178
+ result = 0;
179
+ } else {
180
+ e->type = RefCode; e->clas.len = 0; e->clas.str = 0;
181
+ e->closed = 1;
182
+ e->id = id;
183
+ out->w_start(out, e);
184
+ result = 1;
185
+ }
186
+ return result;
187
+ }
188
+
189
+ static void
190
+ grow(Out out, size_t len) {
191
+ size_t size = out->end - out->buf;
192
+ long pos = out->cur - out->buf;
193
+ char *buf;
194
+
195
+ size *= 2;
196
+ if (size < len + pos) {
197
+ size += len;
198
+ }
199
+ if (0 == (buf = (char*)realloc(out->buf, size))) {
200
+ rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
201
+ }
202
+ out->buf = buf;
203
+ out->end = buf + size;
204
+ out->cur = out->buf + pos;
205
+ }
206
+
207
+ static void
208
+ dump_start(Out out, Element e) {
209
+ size_t size = e->indent + 4;
210
+
211
+ if (0 < e->attr.len) { // a="attr"
212
+ size += e->attr.len + 5;
213
+ }
214
+ if (0 < e->clas.len) { // c="class"
215
+ size += e->clas.len + 5;
216
+ }
217
+ if (0 < e->id) { // i="id"
218
+ size += 24; // over estimate, 19 digits
219
+ }
220
+ if (out->end - out->cur < (long)size) {
221
+ grow(out, size);
222
+ }
223
+ fill_indent(out, e->indent);
224
+ *out->cur++ = '<';
225
+ *out->cur++ = e->type;
226
+ if (0 < e->attr.len) {
227
+ fill_attr(out, 'a', e->attr.str, e->attr.len);
228
+ }
229
+ if ((ObjectCode == e->type || StructCode == e->type || ClassCode == e->type) && 0 < e->clas.len) {
230
+ fill_attr(out, 'c', e->clas.str, e->clas.len);
231
+ }
232
+ if (0 < e->id) {
233
+ char buf[32];
234
+ char *end = buf + sizeof(buf);
235
+ const char *s = ulong2str(e->id, end);
236
+
237
+ fill_attr(out, 'i', s, end - s);
238
+ }
239
+ if (e->closed) {
240
+ *out->cur++ = '/';
241
+ }
242
+ *out->cur++ = '>';
243
+ *out->cur = '\0';
244
+ }
245
+
246
+ static void
247
+ dump_end(Out out, Element e) {
248
+ size_t size = e->indent + 5;
249
+
250
+ if (out->end - out->cur < (long)size) {
251
+ grow(out, size);
252
+ }
253
+ fill_indent(out, e->indent);
254
+ *out->cur++ = '<';
255
+ *out->cur++ = '/';
256
+ *out->cur++ = e->type;
257
+ *out->cur++ = '>';
258
+ *out->cur = '\0';
259
+ }
260
+
261
+ inline static void
262
+ dump_value(Out out, const char *value, size_t size) {
263
+ if (out->end - out->cur < (long)size) {
264
+ grow(out, size);
265
+ }
266
+ if (6 < size) {
267
+ memcpy(out->cur, value, size);
268
+ out->cur += size;
269
+ } else {
270
+ for (; '\0' != *value; value++) {
271
+ *out->cur++ = *value;
272
+ }
273
+ }
274
+ *out->cur = '\0';
275
+ }
276
+
277
+ inline static void
278
+ dump_num(Out out, VALUE obj) {
279
+ char buf[32];
280
+ char *b = buf + sizeof(buf) - 1;
281
+ long num = NUM2LONG(obj);
282
+ int neg = 0;
283
+
284
+ if (0 > num) {
285
+ neg = 1;
286
+ num = -num;
287
+ }
288
+ *b-- = '\0';
289
+ if (0 < num) {
290
+ for (; 0 < num; num /= 10, b--) {
291
+ *b = (num % 10) + '0';
292
+ }
293
+ if (neg) {
294
+ *b = '-';
295
+ } else {
296
+ b++;
297
+ }
298
+ } else {
299
+ *b = '0';
300
+ }
301
+ if (out->end - out->cur < (long)(sizeof(buf) - (b - buf))) {
302
+ grow(out, sizeof(buf) - (b - buf));
303
+ }
304
+ for (; '\0' != *b; b++) {
305
+ *out->cur++ = *b;
306
+ }
307
+ *out->cur = '\0';
308
+ }
309
+
310
+ static void
311
+ dump_time_thin(Out out, VALUE obj) {
312
+ char buf[64];
313
+ char *b = buf + sizeof(buf) - 1;
314
+ time_t sec = NUM2LONG(rb_funcall2(obj, tv_sec_id, 0, 0));
315
+ long usec = NUM2LONG(rb_funcall2(obj, tv_usec_id, 0, 0));
316
+ char *dot = b - 7;
317
+ long size;
318
+
319
+ *b-- = '\0';
320
+ for (; dot < b; b--, usec /= 10) {
321
+ *b = '0' + (usec % 10);
322
+ }
323
+ *b-- = '.';
324
+ for (; 0 < sec; b--, sec /= 10) {
325
+ *b = '0' + (sec % 10);
326
+ }
327
+ b++;
328
+ size = sizeof(buf) - (b - buf) - 1;
329
+ if (out->end - out->cur < size) {
330
+ grow(out, size);
331
+ }
332
+ memcpy(out->cur, b, size);
333
+ out->cur += size;
334
+ }
335
+
336
+ static void
337
+ dump_time_xsd(Out out, VALUE obj) {
338
+ struct tm *tm;
339
+ time_t sec = NUM2LONG(rb_funcall2(obj, tv_sec_id, 0, 0));
340
+ long usec = NUM2LONG(rb_funcall2(obj, tv_usec_id, 0, 0));
341
+ int tzhour, tzmin;
342
+ char tzsign = '+';
343
+
344
+ if (out->end - out->cur < 33) {
345
+ grow(out, 33);
346
+ }
347
+ // 2010-07-09T10:47:45.895826+09:00
348
+ tm = localtime(&sec);
349
+ if (0 > tm->tm_gmtoff) {
350
+ tzsign = '-';
351
+ tzhour = (int)(tm->tm_gmtoff / -3600);
352
+ tzmin = (int)(tm->tm_gmtoff / -60) - (tzhour * 60);
353
+ } else {
354
+ tzhour = (int)(tm->tm_gmtoff / 3600);
355
+ tzmin = (int)(tm->tm_gmtoff / 60) - (tzhour * 60);
356
+ }
357
+ sprintf(out->cur, "%04d-%02d-%02dT%02d:%02d:%02d.%06ld%c%02d:%02d",
358
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
359
+ tm->tm_hour, tm->tm_min, tm->tm_sec, usec,
360
+ tzsign, tzhour, tzmin);
361
+ }
362
+
363
+ static void
364
+ dump_obj(ID aid, VALUE obj, unsigned int depth, Out out) {
365
+ struct _Element e;
366
+ char value_buf[64];
367
+ int cnt;
368
+
369
+ if (0 == aid) {
370
+ //e.attr.str = 0;
371
+ e.attr.len = 0;
372
+ } else {
373
+ e.attr.str = rb_id2name(aid);
374
+ e.attr.len = strlen(e.attr.str);
375
+ }
376
+ e.closed = 0;
377
+ if (0 == depth) {
378
+ if (0 <= out->indent) {
379
+ e.indent = 0;
380
+ } else {
381
+ e.indent = -1;
382
+ }
383
+ dump_value(out, "<?xml version=\"1.0\"?>", 21);
384
+ } else if (0 > out->indent) {
385
+ e.indent = -1;
386
+ } else if (0 == out->indent) {
387
+ e.indent = 0;
388
+ } else {
389
+ e.indent = depth * out->indent;
390
+ }
391
+ e.id = 0;
392
+ switch (rb_type(obj)) {
393
+ case RUBY_T_NIL:
394
+ e.type = NilClassCode; e.clas.len = 0; e.clas.str = 0;
395
+ e.closed = 1;
396
+ out->w_start(out, &e);
397
+ break;
398
+ case RUBY_T_ARRAY:
399
+ if (0 != out->circ_cache && check_circular(out, obj, &e)) {
400
+ break;
401
+ }
402
+ cnt = (int)RARRAY_LEN(obj);
403
+ e.type = ArrayCode; e.clas.len = 5; e.clas.str = "Array";
404
+ e.closed = (0 >= cnt);
405
+ out->w_start(out, &e);
406
+ if (!e.closed) {
407
+ VALUE *np = RARRAY_PTR(obj);
408
+ int i;
409
+ int d2 = depth + 1;
410
+
411
+ for (i = cnt; 0 < i; i--, np++) {
412
+ dump_obj(0, *np, d2, out);
413
+ }
414
+ out->w_end(out, &e);
415
+ }
416
+ break;
417
+ case RUBY_T_HASH:
418
+ if (0 != out->circ_cache && check_circular(out, obj, &e)) {
419
+ break;
420
+ }
421
+ cnt = (int)RHASH_SIZE(obj);
422
+ e.type = HashCode; e.clas.len = 4; e.clas.str = "Hash";
423
+ e.closed = (0 >= cnt);
424
+ out->w_start(out, &e);
425
+ if (0 < cnt) {
426
+ unsigned int od = out->depth;
427
+
428
+ out->depth = depth + 1;
429
+ rb_hash_foreach(obj, dump_hash, (VALUE)out);
430
+ out->depth = od;
431
+ out->w_end(out, &e);
432
+ }
433
+ break;
434
+ case RUBY_T_TRUE:
435
+ e.type = TrueClassCode; e.clas.len = 9; e.clas.str = "TrueClass";
436
+ e.closed = 1;
437
+ out->w_start(out, &e);
438
+ break;
439
+ case RUBY_T_FALSE:
440
+ e.type = FalseClassCode; e.clas.len = 10; e.clas.str = "FalseClass";
441
+ e.closed = 1;
442
+ out->w_start(out, &e);
443
+ break;
444
+ case RUBY_T_FIXNUM:
445
+ e.type = FixnumCode; e.clas.len = 6; e.clas.str = "Fixnum";
446
+ out->w_start(out, &e);
447
+ dump_num(out, obj);
448
+ e.indent = -1;
449
+ out->w_end(out, &e);
450
+ break;
451
+ case RUBY_T_FLOAT:
452
+ e.type = FloatCode; e.clas.len = 5; e.clas.str = "Float";
453
+ cnt = sprintf(value_buf, "%0.16g", RFLOAT_VALUE(obj)); // used sprintf due to bug in snprintf
454
+ out->w_start(out, &e);
455
+ dump_value(out, value_buf, cnt);
456
+ e.indent = -1;
457
+ out->w_end(out, &e);
458
+ break;
459
+ case RUBY_T_STRING:
460
+ {
461
+ const char *str;
462
+
463
+ if (0 != out->circ_cache && check_circular(out, obj, &e)) {
464
+ break;
465
+ }
466
+ str = StringValuePtr(obj);
467
+ cnt = (int)RSTRING_LEN(obj);
468
+ if (is_xml_friendly((u_char*)str, cnt)) {
469
+ e.type = StringCode; e.clas.len = 6; e.clas.str = "String";
470
+ out->w_start(out, &e);
471
+ dump_value(out, str, cnt);
472
+ e.indent = -1;
473
+ out->w_end(out, &e);
474
+ } else {
475
+ char buf64[4096];
476
+ char *b64 = buf64;
477
+ unsigned long size = b64_size(cnt);
478
+
479
+ e.type = Base64Code; e.clas.len = 6; e.clas.str = "Base64";
480
+ if (sizeof(buf64) < size) {
481
+ if (0 == (b64 = (char*)malloc(size + 1))) {
482
+ rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
483
+ }
484
+ }
485
+ to_base64((u_char*)str, cnt, b64);
486
+ out->w_start(out, &e);
487
+ dump_value(out, b64, size);
488
+ e.indent = -1;
489
+ out->w_end(out, &e);
490
+ // TBD pass in flag to free if failure
491
+ if (sizeof(buf64) <= size) {
492
+ free(b64);
493
+ }
494
+ }
495
+ break;
496
+ }
497
+ case RUBY_T_SYMBOL:
498
+ {
499
+ const char *sym = rb_id2name(SYM2ID(obj));
500
+
501
+ e.type = SymbolCode; e.clas.len = 6; e.clas.str = "Symbol";
502
+ out->w_start(out, &e);
503
+ dump_value(out, sym, strlen(sym));
504
+ e.indent = -1;
505
+ out->w_end(out, &e);
506
+ break;
507
+ }
508
+ case RUBY_T_DATA:
509
+ {
510
+ VALUE clas;
511
+
512
+ clas = rb_obj_class(obj);
513
+ if (rb_cTime == clas) {
514
+ e.type = TimeCode; e.clas.len = 4; e.clas.str = "Time";
515
+ out->w_start(out, &e);
516
+ out->w_time(out, obj);
517
+ e.indent = -1;
518
+ out->w_end(out, &e);
519
+ } else {
520
+ printf("*** dumpAttr: RUBY_T_DATA class: %s\n", rb_class2name(clas));
521
+ }
522
+ break;
523
+ }
524
+ case RUBY_T_STRUCT:
525
+ {
526
+ VALUE clas;
527
+
528
+ if (0 != out->circ_cache && check_circular(out, obj, &e)) {
529
+ break;
530
+ }
531
+ clas = rb_obj_class(obj);
532
+ if (rb_cRange == clas) {
533
+ VALUE beg = RSTRUCT(obj)->as.ary[0];
534
+ VALUE end = RSTRUCT(obj)->as.ary[1];
535
+ VALUE excl = RSTRUCT(obj)->as.ary[2];
536
+ int d2 = depth + 1;
537
+
538
+ e.type = RangeCode; e.clas.len = 5; e.clas.str = "Range";
539
+ out->w_start(out, &e);
540
+ dump_obj(beg_id, beg, d2, out);
541
+ dump_obj(end_id, end, d2, out);
542
+ dump_obj(excl_id, excl, d2, out);
543
+ out->w_end(out, &e);
544
+ } else {
545
+ char num_buf[16];
546
+ VALUE *vp;
547
+ int i;
548
+ int d2 = depth + 1;
549
+
550
+ e.type = StructCode;
551
+ e.clas.str = rb_class2name(clas);
552
+ e.clas.len = strlen(e.clas.str);
553
+ out->w_start(out, &e);
554
+ cnt = (int)RSTRUCT_LEN(obj);
555
+ for (i = 0, vp = RSTRUCT_PTR(obj); i < cnt; i++, vp++) {
556
+ dump_obj(rb_intern(ulong2str(i, num_buf + sizeof(num_buf) - 1)), *vp, d2, out);
557
+ }
558
+ out->w_end(out, &e);
559
+ }
560
+ break;
561
+ }
562
+ case RUBY_T_OBJECT:
563
+ {
564
+ VALUE clas;
565
+
566
+ if (0 != out->circ_cache && check_circular(out, obj, &e)) {
567
+ break;
568
+ }
569
+ clas = rb_obj_class(obj);
570
+ e.clas.str = rb_class2name(clas);
571
+ e.clas.len = strlen(e.clas.str);
572
+ if (ox_document_clas == clas) {
573
+ e.type = RawCode;
574
+ out->w_start(out, &e);
575
+ dump_gen_doc(obj, depth + 1, out);
576
+ out->w_end(out, &e);
577
+ } else if (ox_element_clas == clas) {
578
+ e.type = RawCode;
579
+ out->w_start(out, &e);
580
+ dump_gen_element(obj, depth + 1, out);
581
+ out->w_end(out, &e);
582
+ } else { // Object
583
+ e.type = ObjectCode;
584
+ cnt = (int)rb_ivar_count(obj);
585
+ e.closed = (0 >= cnt);
586
+ out->w_start(out, &e);
587
+ if (0 < cnt) {
588
+ unsigned int od = out->depth;
589
+
590
+ out->depth = depth + 1;
591
+ rb_ivar_foreach(obj, dump_var, (VALUE)out);
592
+ out->depth = od;
593
+ out->w_end(out, &e);
594
+ }
595
+ }
596
+ break;
597
+ }
598
+ case RUBY_T_REGEXP:
599
+ {
600
+ #if 1
601
+ VALUE rs = rb_funcall2(obj, inspect_id, 0, 0);
602
+ const char *s = StringValuePtr(rs);
603
+
604
+ cnt = (int)RSTRING_LEN(rs);
605
+ #else
606
+ const char *s = RREGEXP_SRC_PTR(obj);
607
+ int options = rb_reg_options(obj);
608
+
609
+ cnt = (int)RREGEXP_SRC_LEN(obj);
610
+ #endif
611
+ e.type = RegexpCode; e.clas.len = 6; e.clas.str = "Regexp";
612
+ out->w_start(out, &e);
613
+ if (is_xml_friendly((u_char*)s, cnt)) {
614
+ //dump_value(out, "/", 1);
615
+ dump_value(out, s, cnt);
616
+ } else {
617
+ char buf64[4096];
618
+ char *b64 = buf64;
619
+ unsigned long size = b64_size(cnt);
620
+
621
+ if (sizeof(buf64) < size) {
622
+ if (0 == (b64 = (char*)malloc(size + 1))) {
623
+ rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
624
+ }
625
+ }
626
+ to_base64((u_char*)s, cnt, b64);
627
+ dump_value(out, b64, size);
628
+ if (sizeof(buf64) <= size) {
629
+ free(b64);
630
+ }
631
+ }
632
+ #if 0
633
+ dump_value(out, "/", 1);
634
+ if (0 != (ONIG_OPTION_MULTILINE & options)) {
635
+ dump_value(out, "m", 1);
636
+ }
637
+ if (0 != (ONIG_OPTION_IGNORECASE & options)) {
638
+ dump_value(out, "i", 1);
639
+ }
640
+ if (0 != (ONIG_OPTION_EXTEND & options)) {
641
+ dump_value(out, "x", 1);
642
+ }
643
+ #endif
644
+ e.indent = -1;
645
+ out->w_end(out, &e);
646
+ break;
647
+ }
648
+ case RUBY_T_BIGNUM:
649
+ {
650
+ VALUE rs = rb_big2str(obj, 10);
651
+
652
+ e.type = BignumCode; e.clas.len = 6; e.clas.str = "Bignum";
653
+ out->w_start(out, &e);
654
+ dump_value(out, StringValuePtr(rs), RSTRING_LEN(rs));
655
+ e.indent = -1;
656
+ out->w_end(out, &e);
657
+ break;
658
+ }
659
+ case RUBY_T_COMPLEX:
660
+ e.type = ComplexCode; e.clas.len = 7; e.clas.str = "Complex";
661
+ out->w_start(out, &e);
662
+ dump_obj(0, RCOMPLEX(obj)->real, depth + 1, out);
663
+ dump_obj(0, RCOMPLEX(obj)->imag, depth + 1, out);
664
+ out->w_end(out, &e);
665
+ break;
666
+ case RUBY_T_RATIONAL:
667
+ e.type = RationalCode; e.clas.len = 8; e.clas.str = "Rational";
668
+ out->w_start(out, &e);
669
+ dump_obj(0, RRATIONAL(obj)->num, depth + 1, out);
670
+ dump_obj(0, RRATIONAL(obj)->den, depth + 1, out);
671
+ out->w_end(out, &e);
672
+ break;
673
+ case RUBY_T_CLASS:
674
+ {
675
+ e.type = ClassCode;
676
+ e.clas.str = rb_class2name(obj);
677
+ e.clas.len = strlen(e.clas.str);
678
+ e.closed = 1;
679
+ out->w_start(out, &e);
680
+ break;
681
+ }
682
+ default:
683
+ rb_raise(rb_eNotImpError, "Failed to dump %s Object (%02x)\n", rb_class2name(rb_obj_class(obj)), rb_type(obj));
684
+ break;
685
+ }
686
+ }
687
+
688
+ static int
689
+ dump_var(ID key, VALUE value, Out out) {
690
+ dump_obj(key, value, out->depth, out);
691
+
692
+ return ST_CONTINUE;
693
+ }
694
+
695
+ static int
696
+ dump_hash(VALUE key, VALUE value, Out out) {
697
+ dump_obj(0, key, out->depth, out);
698
+ dump_obj(0, value, out->depth, out);
699
+
700
+ return ST_CONTINUE;
701
+ }
702
+
703
+ static void
704
+ dump_gen_doc(VALUE obj, unsigned int depth, Out out) {
705
+ VALUE attrs = rb_ivar_get(obj, attributes_id);
706
+ VALUE nodes = rb_ivar_get(obj, nodes_id);
707
+
708
+ dump_value(out, "<?xml", 5);
709
+ if (Qnil != attrs) {
710
+ rb_hash_foreach(attrs, dump_gen_attr, (VALUE)out);
711
+ }
712
+ dump_value(out, "?>", 2);
713
+ if (Qnil != nodes) {
714
+ dump_gen_nodes(nodes, depth, out);
715
+ }
716
+ }
717
+
718
+ static void
719
+ dump_gen_element(VALUE obj, unsigned int depth, Out out) {
720
+ VALUE rname = rb_ivar_get(obj, value_id);
721
+ VALUE attrs = rb_ivar_get(obj, attributes_id);
722
+ VALUE nodes = rb_ivar_get(obj, nodes_id);
723
+ const char *name = StringValuePtr(rname);
724
+ long nlen = RSTRING_LEN(rname);
725
+ size_t size;
726
+ int indent;
727
+
728
+ if (0 > out->indent) {
729
+ indent = -1;
730
+ } else if (0 == out->indent) {
731
+ indent = 0;
732
+ } else {
733
+ indent = depth * out->indent;
734
+ }
735
+ size = indent + 4 + nlen;
736
+ if (out->end - out->cur < (long)size) {
737
+ grow(out, size);
738
+ }
739
+ fill_indent(out, indent);
740
+ *out->cur++ = '<';
741
+ fill_value(out, name, nlen);
742
+ if (Qnil != attrs) {
743
+ rb_hash_foreach(attrs, dump_gen_attr, (VALUE)out);
744
+ }
745
+ if (Qnil != nodes) {
746
+ int do_indent;
747
+
748
+ *out->cur++ = '>';
749
+ do_indent = dump_gen_nodes(nodes, depth, out);
750
+ if (out->end - out->cur < (long)size) {
751
+ grow(out, size);
752
+ }
753
+ if (do_indent) {
754
+ fill_indent(out, indent);
755
+ }
756
+ *out->cur++ = '<';
757
+ *out->cur++ = '/';
758
+ fill_value(out, name, nlen);
759
+ } else {
760
+ *out->cur++ = '/';
761
+ }
762
+ *out->cur++ = '>';
763
+ *out->cur = '\0';
764
+ }
765
+
766
+ static int
767
+ dump_gen_nodes(VALUE obj, unsigned int depth, Out out) {
768
+ long cnt = RARRAY_LEN(obj);
769
+ int indent_needed = 1;
770
+
771
+ if (0 < cnt) {
772
+ VALUE *np = RARRAY_PTR(obj);
773
+ VALUE clas;
774
+ int d2 = depth + 1;
775
+
776
+ for (; 0 < cnt; cnt--, np++) {
777
+ clas = rb_obj_class(*np);
778
+ if (ox_element_clas == clas) {
779
+ dump_gen_element(*np, d2, out);
780
+ } else if (rb_cString == clas) {
781
+ dump_value(out, StringValuePtr(*np), RSTRING_LEN(*np));
782
+ indent_needed = (1 == cnt) ? 0 : 1;
783
+ } else if (ox_comment_clas == clas) {
784
+ dump_gen_val_node(*np, d2, "<!-- ", 5, " -->", 4, out);
785
+ } else if (ox_cdata_clas == clas) {
786
+ dump_gen_val_node(*np, d2, "<![CDATA[", 9, "]]>", 3, out);
787
+ } else if (ox_doctype_clas == clas) {
788
+ dump_gen_val_node(*np, d2, "<!DOCTYPE ", 10, " >", 2, out);
789
+ } else {
790
+ rb_raise(rb_eTypeError, "Unexpected class, %s, while dumping generic XML\n", rb_class2name(clas));
791
+ }
792
+ }
793
+ }
794
+ return indent_needed;
795
+ }
796
+
797
+ static int
798
+ dump_gen_attr(VALUE key, VALUE value, Out out) {
799
+ const char *ks = (RUBY_T_SYMBOL == rb_type(key)) ? rb_id2name(SYM2ID(key)) : StringValuePtr(key);
800
+ size_t klen = strlen(ks);
801
+ size_t size = 4 + klen + RSTRING_LEN(value);
802
+
803
+ if (out->end - out->cur < (long)size) {
804
+ grow(out, size);
805
+ }
806
+ *out->cur++ = ' ';
807
+ fill_value(out, ks, klen);
808
+ *out->cur++ = '=';
809
+ *out->cur++ = '"';
810
+ fill_value(out, StringValuePtr(value), RSTRING_LEN(value));
811
+ *out->cur++ = '"';
812
+
813
+ return ST_CONTINUE;
814
+ }
815
+
816
+ static void
817
+ dump_gen_val_node(VALUE obj, unsigned int depth,
818
+ const char *pre, size_t plen,
819
+ const char *suf, size_t slen, Out out) {
820
+ VALUE v = rb_ivar_get(obj, value_id);
821
+ const char *val;
822
+ size_t vlen;
823
+ size_t size;
824
+ int indent;
825
+
826
+ if (RUBY_T_STRING != rb_type(v)) {
827
+ return;
828
+ }
829
+ val = StringValuePtr(v);
830
+ vlen = RSTRING_LEN(v);
831
+ if (0 > out->indent) {
832
+ indent = -1;
833
+ } else if (0 == out->indent) {
834
+ indent = 0;
835
+ } else {
836
+ indent = depth * out->indent;
837
+ }
838
+ size = indent + plen + slen + vlen;
839
+ if (out->end - out->cur < (long)size) {
840
+ grow(out, size);
841
+ }
842
+ fill_indent(out, indent);
843
+ fill_value(out, pre, plen);
844
+ fill_value(out, val, vlen);
845
+ fill_value(out, suf, slen);
846
+ *out->cur = '\0';
847
+ }
848
+
849
+ static void
850
+ dump_obj_to_xml(VALUE obj, int indent, int xsd_date, int circular, Out out) {
851
+ VALUE clas = rb_obj_class(obj);
852
+
853
+ out->w_time = (xsd_date) ? dump_time_xsd : dump_time_thin;
854
+ out->buf = (char*)malloc(65336);
855
+ out->end = out->buf + 65336;
856
+ out->cur = out->buf;
857
+ out->circ_cache = 0;
858
+ out->circ_cnt = 0;
859
+ if (circular) {
860
+ ox_cache8_new(&out->circ_cache);
861
+ }
862
+ out->indent = indent;
863
+ if (ox_document_clas == clas) {
864
+ dump_gen_doc(obj, -1, out);
865
+ } else if (ox_element_clas == clas) {
866
+ dump_gen_element(obj, 0, out);
867
+ } else {
868
+ out->w_start = dump_start;
869
+ out->w_end = dump_end;
870
+ dump_obj(0, obj, 0, out);
871
+ }
872
+ dump_value(out, "\n", 1);
873
+ }
874
+
875
+ char*
876
+ write_obj_to_str(VALUE obj, int indent, int xsd_date, int circular) {
877
+ struct _Out out;
878
+
879
+ dump_obj_to_xml(obj, indent, xsd_date, circular, &out);
880
+
881
+ return out.buf;
882
+ }
883
+
884
+ void
885
+ write_obj_to_file(VALUE obj, const char *path, int indent, int xsd_date, int circular) {
886
+ struct _Out out;
887
+ size_t size;
888
+ FILE *f;
889
+
890
+ dump_obj_to_xml(obj, indent, xsd_date, circular, &out);
891
+ size = out.cur - out.buf;
892
+ if (0 == (f = fopen(path, "w"))) {
893
+ rb_raise(rb_eIOError, "%s\n", strerror(errno));
894
+ }
895
+ if (size != fwrite(out.buf, 1, size, f)) {
896
+ int err = ferror(f);
897
+ rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err));
898
+ }
899
+ free(out.buf);
900
+ fclose(f);
901
+ }