fast-xml 1.0.0

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.
@@ -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_ */