fast-xml 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,105 @@
1
+ #ifndef _XH_STRING_H_
2
+ #define _XH_STRING_H_
3
+
4
+ #include "xh_config.h"
5
+ #include "xh_core.h"
6
+
7
+ #define xh_str_equal2(p, c0, c1) \
8
+ ((((uint32_t *) (p))[0] & 0xffff) == ((c1 << 8) | c0))
9
+
10
+ #define xh_str_equal3(p, c0, c1, c2) \
11
+ ((((uint32_t *) (p))[0] & 0xffffff) == ((c2 << 16) | (c1 << 8) | c0))
12
+
13
+ #define xh_str_equal4(p, c0, c1, c2, c3) \
14
+ (*(uint32_t *) (p) == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0))
15
+
16
+ #define xh_str_equal5(p, c0, c1, c2, c3, c4) \
17
+ (xh_str_equal4(p, c0, c1, c2, c3) && (p)[4] == c4)
18
+
19
+ #define xh_str_equal6(p, c0, c1, c2, c3, c4, c5) \
20
+ (xh_str_equal4(p, c0, c1, c2, c3) && xh_str_equal2(&p[4], c4, c5))
21
+
22
+ #define xh_str_equal7(p, c0, c1, c2, c3, c4, c5, c6) \
23
+ (xh_str_equal4(p, c0, c1, c2, c3) && xh_str_equal3(&p[4], c4, c5, c6))
24
+
25
+ #define xh_str_equal8(p, c0, c1, c2, c3, c4, c5, c6, c7) \
26
+ (xh_str_equal4(p, c0, c1, c2, c3) && xh_str_equal4(&p[4], c4, c5, c6, c7))
27
+
28
+ #define xh_str_equal9(p, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
29
+ (xh_str_equal8(p, c0, c1, c2, c3, c4, c5, c6, c7) && (p)[8] == c8)
30
+
31
+ #define xh_str_equal10(p, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \
32
+ (xh_str_equal8(p, c0, c1, c2, c3, c4, c5, c6, c7) && xh_str_equal2(&p[8], c8, c9))
33
+
34
+ #define xh_str_equal11(p, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \
35
+ (xh_str_equal8(p, c0, c1, c2, c3, c4, c5, c6, c7) && xh_str_equal3(&p[8], c8, c9, c10))
36
+
37
+ #define xh_str_equal12(p, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11)\
38
+ (xh_str_equal8(p, c0, c1, c2, c3, c4, c5, c6, c7) && xh_str_equal4(&p[8], c8, c9, c10, c11))
39
+
40
+ #define xh_str_equal13(p, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12)\
41
+ (xh_str_equal8(p, c0, c1, c2, c3, c4, c5, c6, c7) && xh_str_equal5(&p[8], c8, c9, c10, c11, c12))
42
+
43
+
44
+ #define xh_strcmp(s1, s2) strcmp((const char *) (s1), (const char *) (s2))
45
+ #define xh_strcasecmp(s1, s2) strcasecmp((const char *) (s1), (const char *) (s2))
46
+ #define xh_strncmp(s1, s2, n) strncmp((const char *) (s1), (const char *) (s2), (n))
47
+ #define xh_strlen(s) strlen((const char *) (s))
48
+ #define xh_strcpy(d, s) strcpy((char *) (d), (const char *) (s))
49
+ #define xh_strncpy(d, s, n) strncpy((char *) (d), (const char *) (s), (n))
50
+
51
+ XH_INLINE xh_char_t *
52
+ xh_str_trim(xh_char_t *s, size_t *len)
53
+ {
54
+ xh_char_t *end, ch;
55
+
56
+ end = s + *len;
57
+
58
+ while ((ch = *s++) == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
59
+ if (ch == '\0') {
60
+ *len = 0;
61
+ return s - 1;
62
+ }
63
+
64
+ s--;
65
+
66
+ while (--end != s && ((ch = *end) == ' ' || ch == '\t' || ch == '\n' || ch == '\r'));
67
+
68
+ *len = end - s + 1;
69
+
70
+ return s;
71
+ }
72
+
73
+ XH_INLINE xh_char_t *
74
+ xh_str_copy(xh_char_t *dest, const xh_char_t *src, size_t n)
75
+ {
76
+ dest[--n] = '\0';
77
+ return XH_CHAR_CAST strncpy((char *) dest, (const char *) src, n);
78
+ }
79
+
80
+ XH_INLINE xh_char_t *
81
+ xh_str_range_copy(xh_char_t *dest, const xh_char_t *src, size_t l, size_t n)
82
+ {
83
+ if (l < n) n = l + 1;
84
+ dest[--n] = '\0';
85
+ return XH_CHAR_CAST strncpy((char *) dest, (const char *) src, n);
86
+ }
87
+
88
+ XH_INLINE void
89
+ xh_memmove(xh_char_t *dest, const xh_char_t *src, size_t n)
90
+ {
91
+ while (n--) *dest++ = *src++;
92
+ }
93
+
94
+ XH_INLINE xh_bool_t
95
+ xh_str_is_xml(xh_char_t *s)
96
+ {
97
+ xh_char_t ch;
98
+
99
+ while ((ch = *s++) == ' ' || ch =='\t' || ch == '\n' || ch == '\r');
100
+ if (ch == '<') return TRUE;
101
+
102
+ return FALSE;
103
+ }
104
+
105
+ #endif /* _XH_STRING_H_ */
@@ -0,0 +1,94 @@
1
+ #include "xh_config.h"
2
+ #include "xh_core.h"
3
+
4
+ void
5
+ xh_writer_resize_buffer(xh_writer_t *writer, size_t inc)
6
+ {
7
+ (void) xh_writer_flush(writer);
8
+
9
+ xh_ruby_buffer_grow(&writer->main_buf, inc);
10
+ }
11
+
12
+ VALUE
13
+ xh_writer_flush_buffer(xh_writer_t *writer, xh_ruby_buffer_t *buf)
14
+ {
15
+ size_t use = xh_writer_flush_ruby_buffer(buf);
16
+
17
+ if (writer->ruby_io != Qnil) {
18
+ if (use > 0) xh_writer_flush_ruby_io(buf, writer->ruby_io, use);
19
+ return Qnil;
20
+ }
21
+
22
+ return buf->scalar;
23
+ }
24
+
25
+ #ifdef XH_HAVE_ENCODER
26
+ void
27
+ xh_writer_encode_buffer(xh_writer_t *writer, xh_ruby_buffer_t *main_buf, xh_ruby_buffer_t *enc_buf)
28
+ {
29
+ size_t len;
30
+
31
+ /* 1 char -> 4 chars and '\0' */
32
+ len = xh_buffer_use(main_buf) * 4 + 1;
33
+
34
+ if (len > (size_t) (enc_buf->end - enc_buf->cur)) {
35
+ xh_writer_flush_buffer(writer, enc_buf);
36
+
37
+ xh_ruby_buffer_grow(enc_buf, len);
38
+ }
39
+
40
+ xh_encoder_encode_ruby_buffer(writer->encoder, main_buf, enc_buf);
41
+ }
42
+ #endif
43
+
44
+ VALUE
45
+ xh_writer_flush(xh_writer_t *writer)
46
+ {
47
+ xh_ruby_buffer_t *buf;
48
+
49
+ #ifdef XH_HAVE_ENCODER
50
+ if (writer->encoder != NULL) {
51
+ xh_writer_encode_buffer(writer, &writer->main_buf, &writer->enc_buf);
52
+ buf = &writer->enc_buf;
53
+ }
54
+ else {
55
+ buf = &writer->main_buf;
56
+ }
57
+ #else
58
+ buf = &writer->main_buf;
59
+ #endif
60
+
61
+ return xh_writer_flush_buffer(writer, buf);
62
+ }
63
+
64
+ void
65
+ xh_writer_destroy(xh_writer_t *writer)
66
+ {
67
+ #ifdef XH_HAVE_ENCODER
68
+ xh_encoder_destroy(writer->encoder);
69
+ #endif
70
+ }
71
+
72
+ void
73
+ xh_writer_init(xh_writer_t *writer, xh_char_t *encoding, VALUE output, size_t size, xh_uint_t indent, xh_bool_t trim)
74
+ {
75
+ writer->indent = indent;
76
+ writer->trim = trim;
77
+
78
+ xh_ruby_buffer_init(&writer->main_buf, size);
79
+
80
+ if (encoding[0] != '\0' && xh_strcasecmp(encoding, XH_INTERNAL_ENCODING) != 0) {
81
+ #ifdef XH_HAVE_ENCODER
82
+ writer->encoder = xh_encoder_create(encoding, XH_CHAR_CAST XH_INTERNAL_ENCODING);
83
+ if (writer->encoder == NULL) {
84
+ rb_raise(xh_parse_error_class, "Can't create encoder for '%s'", encoding);
85
+ }
86
+
87
+ xh_ruby_buffer_init(&writer->enc_buf, size * 4);
88
+ #else
89
+ rb_raise(xh_parse_error_class, "Can't create encoder for '%s'", encoding);
90
+ #endif
91
+ }
92
+
93
+ writer->ruby_io = output;
94
+ }
@@ -0,0 +1,49 @@
1
+ #ifndef _XH_WRITER_H_
2
+ #define _XH_WRITER_H_
3
+
4
+ #include "xh_config.h"
5
+ #include "xh_core.h"
6
+
7
+ #define XH_WRITER_RESIZE_BUFFER(w, b, l) \
8
+ if (((l) + 1) > (size_t) xh_buffer_avail(b)) { \
9
+ xh_writer_resize_buffer(w, (l) + 1); \
10
+ }
11
+
12
+ typedef struct _xh_writer_t xh_writer_t;
13
+ struct _xh_writer_t {
14
+ #ifdef XH_HAVE_ENCODER
15
+ xh_encoder_t *encoder;
16
+ xh_ruby_buffer_t enc_buf;
17
+ #endif
18
+ VALUE ruby_io;
19
+ xh_ruby_buffer_t main_buf;
20
+ xh_int_t indent;
21
+ xh_int_t indent_count;
22
+ xh_bool_t trim;
23
+ };
24
+
25
+ VALUE xh_writer_flush_buffer(xh_writer_t *writer, xh_ruby_buffer_t *buf);
26
+ VALUE xh_writer_flush(xh_writer_t *writer);
27
+ void xh_writer_resize_buffer(xh_writer_t *writer, size_t inc);
28
+ void xh_writer_destroy(xh_writer_t *writer);
29
+ void xh_writer_init(xh_writer_t *writer, xh_char_t *encoding, VALUE output, size_t size, xh_uint_t indent, xh_bool_t trim);
30
+
31
+ XH_INLINE void
32
+ xh_writer_flush_ruby_io(xh_ruby_buffer_t *buf, VALUE ruby_io, size_t use)
33
+ {
34
+ rb_io_write(ruby_io, buf->scalar);
35
+ xh_buffer_reset(buf);
36
+ }
37
+
38
+ XH_INLINE size_t
39
+ xh_writer_flush_ruby_buffer(xh_ruby_buffer_t *buf)
40
+ {
41
+ size_t use = xh_buffer_use(buf);
42
+
43
+ *buf->cur = '\0';
44
+ rb_str_set_len(buf->scalar, use);
45
+
46
+ return use;
47
+ }
48
+
49
+ #endif /* _XH_WRITER_H_ */
@@ -0,0 +1,453 @@
1
+ #ifndef _XH_XML_H_
2
+ #define _XH_XML_H_
3
+
4
+ #include "xh_config.h"
5
+ #include "xh_core.h"
6
+
7
+ static const xh_char_t indent_string[60] = " ";
8
+
9
+ XH_INLINE void
10
+ xh_xml_write_xml_declaration(xh_writer_t *writer, xh_char_t *version, xh_char_t *encoding)
11
+ {
12
+ xh_ruby_buffer_t *buf;
13
+ size_t ver_len, enc_len;
14
+
15
+ buf = &writer->main_buf;
16
+ ver_len = xh_strlen(version);
17
+ if (encoding[0] == '\0')
18
+ encoding = XH_CHAR_CAST XH_INTERNAL_ENCODING;
19
+ enc_len = xh_strlen(encoding);
20
+
21
+ XH_WRITER_RESIZE_BUFFER(writer, buf, sizeof("<?xml version=\"\" encoding=\"\"?>\n") - 1 + ver_len * 6 + enc_len * 6)
22
+
23
+ XH_BUFFER_WRITE_CONSTANT(buf, "<?xml version=\"")
24
+ XH_BUFFER_WRITE_ESCAPE_ATTR(buf, version, ver_len);
25
+ XH_BUFFER_WRITE_CONSTANT(buf, "\" encoding=\"")
26
+ XH_BUFFER_WRITE_ESCAPE_ATTR(buf, encoding, enc_len);
27
+ XH_BUFFER_WRITE_CHAR4(buf, "\"?>\n");
28
+
29
+ }
30
+
31
+ XH_INLINE void
32
+ xh_xml_write_node(xh_writer_t *writer, xh_char_t *name, size_t name_len, VALUE value, xh_bool_t raw)
33
+ {
34
+ size_t indent_len;
35
+ xh_ruby_buffer_t *buf;
36
+ xh_char_t *content;
37
+ size_t content_len;
38
+
39
+ buf = &writer->main_buf;
40
+ value = rb_obj_as_string(value);
41
+ content = XH_CHAR_CAST RSTRING_PTR(value);
42
+ content_len = RSTRING_LEN(value);
43
+
44
+ if (writer->trim && content_len) {
45
+ content = xh_str_trim(content, &content_len);
46
+ }
47
+
48
+ if (writer->indent) {
49
+ indent_len = writer->indent_count * writer->indent;
50
+ if (indent_len > sizeof(indent_string)) {
51
+ indent_len = sizeof(indent_string);
52
+ }
53
+
54
+ /* "</" + "_" + ">" + "\n" */
55
+ XH_WRITER_RESIZE_BUFFER(writer, buf, indent_len + name_len * 2 + 10 + (raw ? content_len : content_len * 5))
56
+
57
+ XH_BUFFER_WRITE_LONG_STRING(buf, indent_string, indent_len);
58
+ }
59
+ else {
60
+ /* "</" + "_" + ">" + "\n" */
61
+ XH_WRITER_RESIZE_BUFFER(writer, buf, name_len * 2 + 10 + (raw ? content_len : content_len * 5))
62
+ }
63
+
64
+ XH_BUFFER_WRITE_CHAR(buf, '<')
65
+
66
+ if (name[0] >= '0' && name[0] <= '9') {
67
+ XH_BUFFER_WRITE_CHAR(buf, '_')
68
+ }
69
+
70
+ XH_BUFFER_WRITE_LONG_STRING(buf, name, name_len)
71
+
72
+ XH_BUFFER_WRITE_CHAR(buf, '>')
73
+
74
+ if (raw) {
75
+ XH_BUFFER_WRITE_LONG_STRING(buf, content, content_len)
76
+ }
77
+ else {
78
+ XH_BUFFER_WRITE_ESCAPE_STRING(buf, content, content_len)
79
+ }
80
+
81
+ XH_BUFFER_WRITE_CHAR2(buf, "</")
82
+
83
+ if (name[0] >= '0' && name[0] <= '9') {
84
+ XH_BUFFER_WRITE_CHAR(buf, '_')
85
+ }
86
+
87
+ XH_BUFFER_WRITE_LONG_STRING(buf, name, name_len)
88
+
89
+ XH_BUFFER_WRITE_CHAR(buf, '>')
90
+
91
+ if (writer->indent) {
92
+ XH_BUFFER_WRITE_CHAR(buf, '\n')
93
+ }
94
+ }
95
+
96
+ XH_INLINE void
97
+ xh_xml_write_empty_node(xh_writer_t *writer, xh_char_t *name, size_t name_len)
98
+ {
99
+ size_t indent_len;
100
+ xh_ruby_buffer_t *buf;
101
+
102
+ buf = &writer->main_buf;
103
+
104
+ if (writer->indent) {
105
+ indent_len = writer->indent_count * writer->indent;
106
+ if (indent_len > sizeof(indent_string)) {
107
+ indent_len = sizeof(indent_string);
108
+ }
109
+
110
+ /* "</" + "_" + ">" + "\n" */
111
+ XH_WRITER_RESIZE_BUFFER(writer, buf, indent_len + name_len + 5)
112
+
113
+ XH_BUFFER_WRITE_LONG_STRING(buf, indent_string, indent_len);
114
+ }
115
+ else {
116
+ /* "</" + "_" + ">" + "\n" */
117
+ XH_WRITER_RESIZE_BUFFER(writer, buf, name_len + 5)
118
+ }
119
+
120
+ XH_BUFFER_WRITE_CHAR(buf, '<')
121
+
122
+ if (name[0] >= '0' && name[0] <= '9') {
123
+ XH_BUFFER_WRITE_CHAR(buf, '_')
124
+ }
125
+
126
+ XH_BUFFER_WRITE_LONG_STRING(buf, name, name_len)
127
+
128
+ XH_BUFFER_WRITE_CHAR2(buf, "/>")
129
+
130
+ if (writer->indent) {
131
+ XH_BUFFER_WRITE_CHAR(buf, '\n')
132
+ }
133
+ }
134
+
135
+ XH_INLINE void
136
+ xh_xml_write_start_node(xh_writer_t *writer, xh_char_t *name, size_t name_len)
137
+ {
138
+ size_t indent_len;
139
+ xh_ruby_buffer_t *buf;
140
+
141
+ buf = &writer->main_buf;
142
+
143
+ if (writer->indent) {
144
+ indent_len = writer->indent_count++ * writer->indent;
145
+ if (indent_len > sizeof(indent_string)) {
146
+ indent_len = sizeof(indent_string);
147
+ }
148
+
149
+ /* "</" + "_" + ">" + "\n" */
150
+ XH_WRITER_RESIZE_BUFFER(writer, buf, indent_len + name_len + 5)
151
+
152
+ XH_BUFFER_WRITE_LONG_STRING(buf, indent_string, indent_len);
153
+ }
154
+ else {
155
+ /* "</" + "_" + ">" + "\n" */
156
+ XH_WRITER_RESIZE_BUFFER(writer, buf, name_len + 5)
157
+ }
158
+
159
+ XH_BUFFER_WRITE_CHAR(buf, '<')
160
+
161
+ if (name[0] >= '0' && name[0] <= '9') {
162
+ XH_BUFFER_WRITE_CHAR(buf, '_')
163
+ }
164
+
165
+ XH_BUFFER_WRITE_LONG_STRING(buf, name, name_len)
166
+
167
+ XH_BUFFER_WRITE_CHAR(buf, '>')
168
+
169
+ if (writer->indent) {
170
+ XH_BUFFER_WRITE_CHAR(buf, '\n')
171
+ }
172
+ }
173
+
174
+ XH_INLINE void
175
+ xh_xml_write_end_node(xh_writer_t *writer, xh_char_t *name, size_t name_len)
176
+ {
177
+ size_t indent_len;
178
+ xh_ruby_buffer_t *buf;
179
+
180
+ buf = &writer->main_buf;
181
+
182
+ if (writer->indent) {
183
+ indent_len = --writer->indent_count * writer->indent;
184
+ if (indent_len > sizeof(indent_string)) {
185
+ indent_len = sizeof(indent_string);
186
+ }
187
+
188
+ /* "</" + "_" + ">" + "\n" */
189
+ XH_WRITER_RESIZE_BUFFER(writer, buf, indent_len + name_len + 5)
190
+
191
+ XH_BUFFER_WRITE_LONG_STRING(buf, indent_string, indent_len);
192
+ }
193
+ else {
194
+ /* "</" + "_" + ">" + "\n" */
195
+ XH_WRITER_RESIZE_BUFFER(writer, buf, name_len + 5)
196
+ }
197
+
198
+ XH_BUFFER_WRITE_CHAR2(buf, "</")
199
+
200
+ if (name[0] >= '0' && name[0] <= '9') {
201
+ XH_BUFFER_WRITE_CHAR(buf, '_')
202
+ }
203
+
204
+ XH_BUFFER_WRITE_LONG_STRING(buf, name, name_len)
205
+
206
+ XH_BUFFER_WRITE_CHAR(buf, '>')
207
+
208
+ if (writer->indent) {
209
+ XH_BUFFER_WRITE_CHAR(buf, '\n')
210
+ }
211
+ }
212
+
213
+ XH_INLINE void
214
+ xh_xml_write_content(xh_writer_t *writer, VALUE value)
215
+ {
216
+ size_t indent_len;
217
+ xh_ruby_buffer_t *buf;
218
+ xh_char_t *content;
219
+ size_t content_len;
220
+
221
+ buf = &writer->main_buf;
222
+ value = rb_obj_as_string(value);
223
+ content = XH_CHAR_CAST RSTRING_PTR(value);
224
+ content_len = RSTRING_LEN(value);
225
+
226
+ if (writer->trim) {
227
+ content = xh_str_trim(content, &content_len);
228
+ }
229
+
230
+ if (writer->indent) {
231
+ indent_len = writer->indent_count * writer->indent;
232
+ if (indent_len > sizeof(indent_string)) {
233
+ indent_len = sizeof(indent_string);
234
+ }
235
+
236
+ XH_WRITER_RESIZE_BUFFER(writer, buf, indent_len + content_len * 5)
237
+
238
+ XH_BUFFER_WRITE_LONG_STRING(buf, indent_string, indent_len);
239
+ }
240
+ else {
241
+ XH_WRITER_RESIZE_BUFFER(writer, buf, content_len * 5)
242
+ }
243
+
244
+ XH_BUFFER_WRITE_ESCAPE_STRING(buf, content, content_len);
245
+
246
+ if (writer->indent) {
247
+ XH_BUFFER_WRITE_CHAR(buf, '\n')
248
+ }
249
+ }
250
+
251
+ XH_INLINE void
252
+ xh_xml_write_comment(xh_writer_t *writer, VALUE value)
253
+ {
254
+ size_t indent_len;
255
+ xh_ruby_buffer_t *buf;
256
+ xh_char_t *content;
257
+ size_t content_len;
258
+
259
+ buf = &writer->main_buf;
260
+
261
+ if (value == Qnil) {
262
+ content = XH_EMPTY_STRING;
263
+ content_len = 0;
264
+ }
265
+ else {
266
+ value = rb_obj_as_string(value);
267
+ content = XH_CHAR_CAST RSTRING_PTR(value);
268
+ content_len = RSTRING_LEN(value);
269
+ }
270
+
271
+ if (writer->trim && content_len) {
272
+ content = xh_str_trim(content, &content_len);
273
+ }
274
+
275
+ if (writer->indent) {
276
+ indent_len = writer->indent_count * writer->indent;
277
+ if (indent_len > sizeof(indent_string)) {
278
+ indent_len = sizeof(indent_string);
279
+ }
280
+
281
+ /* "<!--" + "-->" */
282
+ XH_WRITER_RESIZE_BUFFER(writer, buf, indent_len + content_len + 7)
283
+
284
+ XH_BUFFER_WRITE_LONG_STRING(buf, indent_string, indent_len);
285
+ }
286
+ else {
287
+ /* "<!--" + "-->" */
288
+ XH_WRITER_RESIZE_BUFFER(writer, buf, content_len + 7)
289
+ }
290
+
291
+ XH_BUFFER_WRITE_CHAR4(buf, "<!--")
292
+ XH_BUFFER_WRITE_LONG_STRING(buf, content, content_len);
293
+ XH_BUFFER_WRITE_CHAR3(buf, "-->")
294
+
295
+ if (writer->indent) {
296
+ XH_BUFFER_WRITE_CHAR(buf, '\n')
297
+ }
298
+ }
299
+
300
+ XH_INLINE void
301
+ xh_xml_write_cdata(xh_writer_t *writer, VALUE value)
302
+ {
303
+ size_t indent_len;
304
+ xh_ruby_buffer_t *buf;
305
+ xh_char_t *content;
306
+ size_t content_len;
307
+
308
+ buf = &writer->main_buf;
309
+
310
+ if (value == Qnil) {
311
+ content = XH_EMPTY_STRING;
312
+ content_len = 0;
313
+ }
314
+ else {
315
+ value = rb_obj_as_string(value);
316
+ content = XH_CHAR_CAST RSTRING_PTR(value);
317
+ content_len = RSTRING_LEN(value);
318
+ }
319
+
320
+ if (writer->trim && content_len) {
321
+ content = xh_str_trim(content, &content_len);
322
+ }
323
+
324
+ if (writer->indent) {
325
+ indent_len = writer->indent_count * writer->indent;
326
+ if (indent_len > sizeof(indent_string)) {
327
+ indent_len = sizeof(indent_string);
328
+ }
329
+
330
+ /* "<![CDATA[" + "]]>" */
331
+ XH_WRITER_RESIZE_BUFFER(writer, buf, indent_len + content_len + 12)
332
+
333
+ XH_BUFFER_WRITE_LONG_STRING(buf, indent_string, indent_len);
334
+ }
335
+ else {
336
+ /* "<![CDATA[" + "]]>" */
337
+ XH_WRITER_RESIZE_BUFFER(writer, buf, content_len + 12)
338
+ }
339
+
340
+ XH_BUFFER_WRITE_CHAR9(buf, "<![CDATA[")
341
+ XH_BUFFER_WRITE_LONG_STRING(buf, content, content_len);
342
+ XH_BUFFER_WRITE_CHAR3(buf, "]]>")
343
+
344
+ if (writer->indent) {
345
+ XH_BUFFER_WRITE_CHAR(buf, '\n')
346
+ }
347
+ }
348
+
349
+ XH_INLINE void
350
+ xh_xml_write_start_tag(xh_writer_t *writer, xh_char_t *name, size_t name_len)
351
+ {
352
+ size_t indent_len;
353
+ xh_ruby_buffer_t *buf;
354
+
355
+ buf = &writer->main_buf;
356
+
357
+ if (writer->indent) {
358
+ indent_len = writer->indent_count * writer->indent;
359
+ if (indent_len > sizeof(indent_string)) {
360
+ indent_len = sizeof(indent_string);
361
+ }
362
+
363
+ /* "<" + "_" */
364
+ XH_WRITER_RESIZE_BUFFER(writer, buf, indent_len + name_len + 2)
365
+
366
+ XH_BUFFER_WRITE_LONG_STRING(buf, indent_string, indent_len);
367
+ }
368
+ else {
369
+ /* "<" + "_" */
370
+ XH_WRITER_RESIZE_BUFFER(writer, buf, name_len + 2)
371
+ }
372
+
373
+ XH_BUFFER_WRITE_CHAR(buf, '<')
374
+
375
+ if (name[0] >= '0' && name[0] <= '9') {
376
+ XH_BUFFER_WRITE_CHAR(buf, '_')
377
+ }
378
+
379
+ XH_BUFFER_WRITE_LONG_STRING(buf, name, name_len)
380
+ }
381
+
382
+ XH_INLINE void
383
+ xh_xml_write_end_tag(xh_writer_t *writer)
384
+ {
385
+ xh_ruby_buffer_t *buf;
386
+
387
+ buf = &writer->main_buf;
388
+
389
+ XH_WRITER_RESIZE_BUFFER(writer, buf, 2)
390
+
391
+ if (writer->indent) {
392
+ XH_BUFFER_WRITE_CHAR2(buf, ">\n");
393
+ writer->indent_count++;
394
+ }
395
+ else {
396
+ XH_BUFFER_WRITE_CHAR(buf, '>')
397
+ }
398
+ }
399
+
400
+ XH_INLINE void
401
+ xh_xml_write_closed_end_tag(xh_writer_t *writer)
402
+ {
403
+ xh_ruby_buffer_t *buf;
404
+
405
+ buf = &writer->main_buf;
406
+
407
+ XH_WRITER_RESIZE_BUFFER(writer, buf, 3)
408
+
409
+ if (writer->indent) {
410
+ XH_BUFFER_WRITE_CHAR3(buf, "/>\n");
411
+ }
412
+ else {
413
+ XH_BUFFER_WRITE_CHAR2(buf, "/>");
414
+ }
415
+ }
416
+
417
+ XH_INLINE void
418
+ xh_xml_write_attribute(xh_writer_t *writer, xh_char_t *name, size_t name_len, VALUE value)
419
+ {
420
+ xh_ruby_buffer_t *buf;
421
+ xh_char_t *content;
422
+ size_t content_len;
423
+
424
+ buf = &writer->main_buf;
425
+
426
+ if (value == Qnil) {
427
+ content = XH_EMPTY_STRING;
428
+ content_len = 0;
429
+ }
430
+ else {
431
+ value = rb_obj_as_string(value);
432
+ content = XH_CHAR_CAST RSTRING_PTR(value);
433
+ content_len = RSTRING_LEN(value);
434
+ }
435
+
436
+ /* ' =""' */
437
+ XH_WRITER_RESIZE_BUFFER(writer, buf, name_len + content_len * 6 + 4)
438
+
439
+ XH_BUFFER_WRITE_CHAR(buf, ' ')
440
+
441
+ XH_BUFFER_WRITE_LONG_STRING(buf, name, name_len)
442
+
443
+ if (content_len == 0) {
444
+ XH_BUFFER_WRITE_CHAR3(buf, "=\"\"");
445
+ }
446
+ else {
447
+ XH_BUFFER_WRITE_CHAR2(buf, "=\"");
448
+ XH_BUFFER_WRITE_ESCAPE_ATTR(buf, content, content_len);
449
+ XH_BUFFER_WRITE_CHAR(buf, '"');
450
+ }
451
+ }
452
+
453
+ #endif /* _XH_XML_H_ */