File Coverage

Easy.xs
Criterion Covered Total %
statement 833 857 97.2
branch 639 796 80.2
condition n/a
subroutine n/a
pod n/a
total 1472 1653 89.0


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT 1
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #ifndef PERL_VERSION_DECIMAL
7             # define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
8             #endif
9             #ifndef PERL_DECIMAL_VERSION
10             # define PERL_DECIMAL_VERSION \
11             PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
12             #endif
13             #ifndef PERL_VERSION_GE
14             # define PERL_VERSION_GE(r,v,s) \
15             (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
16             #endif
17              
18             #if PERL_VERSION_GE(5,19,4)
19             typedef SSize_t array_ix_t;
20             #else /* <5.19.4 */
21             typedef I32 array_ix_t;
22             #endif /* <5.19.4 */
23              
24             #ifndef newSVpvs
25             # define newSVpvs(string) newSVpvn(""string"", sizeof(string)-1)
26             #endif /* !newSVpvs */
27              
28             #ifndef sv_catpvs_nomg
29             # define sv_catpvs_nomg(sv, string) \
30             sv_catpvn_nomg(sv, ""string"", sizeof(string)-1)
31             #endif /* !sv_catpvs_nomg */
32              
33             #ifndef gv_stashpvs
34             # define gv_stashpvs(name, flags) gv_stashpvn(""name"", sizeof(name)-1, flags)
35             #endif /* !gv_stashpvs */
36              
37             /* stashed stashes */
38              
39             static HV *stash_content, *stash_element;
40              
41             /* stashed constant content */
42              
43             static SV *empty_contentobject;
44              
45             /* parameter classification */
46              
47             #define sv_is_glob(sv) (SvTYPE(sv) == SVt_PVGV)
48              
49             #if PERL_VERSION_GE(5,11,0)
50             # define sv_is_regexp(sv) (SvTYPE(sv) == SVt_REGEXP)
51             #else /* <5.11.0 */
52             # define sv_is_regexp(sv) 0
53             #endif /* <5.11.0 */
54              
55             #define sv_is_string(sv) \
56             (!sv_is_glob(sv) && !sv_is_regexp(sv) && \
57             (SvFLAGS(sv) & (SVf_IOK|SVf_NOK|SVf_POK|SVp_IOK|SVp_NOK|SVp_POK)))
58              
59             #ifndef uvchr_to_utf8_flags
60             #define uvchr_to_utf8_flags(d, uv, flags) uvuni_to_utf8_flags(d, uv, flags);
61             #endif
62              
63             /* exceptions */
64              
65             #define throw_utf8_error() croak("broken internal UTF-8 encoding\n")
66             #define throw_syntax_error(p) croak("XML syntax error\n")
67             #define throw_wfc_error(MSG) croak("XML constraint error: "MSG"\n")
68             #define throw_data_error(MSG) croak("invalid XML data: "MSG"\n")
69              
70             /*
71             * string walking
72             *
73             * The parser deals with strings that are internally encoded using Perl's
74             * extended form of UTF-8. It is not assumed that the encoding is
75             * well-formed; encoding errors will result in an exception. The encoding
76             * octets are treated as U8 type.
77             *
78             * Characters that are known to be in the ASCII range are in some places
79             * processed as U8. General Unicode characters are processed as U32, with
80             * the intent that the entire ISO-10646 31-bit range be handleable. Any
81             * codepoint is accepted for processing, even the surrogates (which are
82             * not legal in true UTF-8 encoding). Perl's extended UTF-8 extends to
83             * 72-bit codepoints; encodings beyond the 31-bit range are translated to
84             * codepoint U+7fffffff, which is equally invalid in the XML syntax.
85             *
86             * char_unicode() returns the codepoint represented by the character being
87             * pointed at, or throws an exception if the encoding is malformed.
88             *
89             * To move on to the character following the one pointed at, use the core
90             * macro UTF8SKIP(), as in (p + UTF8SKIP(p)). It assumes that the character
91             * is properly encoded, so it is essential that char_unicode() has been
92             * called on it first.
93             *
94             * Given an input SV (that is meant to be a string), pass it through
95             * upgrade_sv() to return an SV that contains the string in UTF-8. This
96             * could be either the same SV (if it is already UTF-8-encoded or contains
97             * no non-ASCII characters) or a mortal upgraded copy.
98             *
99             * Given an unboxed Latin-1 string, upgrade_latin1_pvn() returns details of
100             * an equivalent UTF-8 string, either the same string (if it's ASCII) or a
101             * mortal SV.
102             */
103              
104             #define char_unicode(p) THX_char_unicode(aTHX_ p)
105 31053125           static U32 THX_char_unicode(pTHX_ U8 *p)
106             {
107 31053125           U32 val = *p;
108             U8 req_c1;
109             int ncont;
110             int i;
111 31053125 50         if(!(val & 0x80)) return val;
112 31053125 50         if(!(val & 0x40)) throw_utf8_error();
113 31053125 100         if(!(val & 0x20)) {
114 9442077 50         if(!(val & 0x1e)) throw_utf8_error();
115 9442077           val &= 0x1f;
116 9442077           ncont = 1;
117 9442077           req_c1 = 0x00;
118 21611048 100         } else if(!(val & 0x10)) {
119 7205210           val &= 0x0f;
120 7205210           ncont = 2;
121 7205210           req_c1 = 0x20;
122 14405838 100         } else if(!(val & 0x08)) {
123 14404378           val &= 0x07;
124 14404378           ncont = 3;
125 14404378           req_c1 = 0x30;
126 1460 50         } else if(!(val & 0x04)) {
127 0           val &= 0x03;
128 0           ncont = 4;
129 0           req_c1 = 0x38;
130 1460 100         } else if(!(val & 0x02)) {
131 730           val &= 0x01;
132 730           ncont = 5;
133 730           req_c1 = 0x3c;
134 730 50         } else if(!(val & 0x01)) {
135 0 0         if(!(p[1] & 0x3e)) throw_utf8_error();
136 0 0         for(i = 6; i--; )
137 0 0         if((*++p & 0xc0) != 0x80)
138 0           throw_utf8_error();
139 0           return 0x7fffffff;
140             } else {
141 730           U8 first_six = 0;
142 5110 100         for(i = 6; i--; ) {
143 4380           U8 ext = *++p;
144 4380 50         if((ext & 0xc0) != 0x80)
145 0           throw_utf8_error();
146 4380           first_six |= ext;
147             }
148 730 50         if(!(first_six & 0x3f))
149 0           throw_utf8_error();
150 5110 100         for(i = 6; i--; )
151 4380 50         if((*++p & 0xc0) != 0x80)
152 0           throw_utf8_error();
153 730           return 0x7fffffff;
154             }
155 31052395 100         if(val == 0 && !(p[1] & req_c1))
    50          
156 0           throw_utf8_error();
157 98121676 100         for(i = ncont; i--; ) {
158 67069281           U8 ext = *++p;
159 67069281 50         if((ext & 0xc0) != 0x80)
160 0           throw_utf8_error();
161 67069281           val = UTF8_ACCUMULATE(val, ext);
162             }
163 31052395           return val;
164             }
165              
166             #define upgrade_sv(input) THX_upgrade_sv(aTHX_ input)
167 721408           static SV *THX_upgrade_sv(pTHX_ SV *input)
168             {
169             U8 *p, *end;
170             STRLEN len;
171 721408 100         if(SvUTF8(input)) return input;
172 352003           p = (U8*)SvPV(input, len);
173 58989455 100         for(end = p + len; p != end; p++) {
174 58637871 100         if(*p & 0x80) {
175 419           SV *output = sv_mortalcopy(input);
176 419           sv_utf8_upgrade(output);
177 419           return output;
178             }
179             }
180 351584           return input;
181             }
182              
183             #define upgrade_latin1_pvn(ptrp, lenp) THX_upgrade_latin1_pvn(aTHX_ ptrp, lenp)
184 3496           static void THX_upgrade_latin1_pvn(pTHX_ U8 **ptrp, STRLEN *lenp)
185             {
186 3496           U8 *ptr = *ptrp;
187 3496           STRLEN len = *lenp;
188 3496           U8 *p = ptr, *end = ptr + len;
189 27008363 100         for(; p != end; p++) {
190 27005236 100         if(*p & 0x80) {
191 369           SV *output = sv_2mortal(newSVpvn((char*)ptr, len));
192 369           sv_utf8_upgrade(output);
193 369           ptr = (U8*)SvPV(output, len);
194 369           *ptrp = ptr;
195 369           *lenp = len;
196 369           return;
197             }
198             }
199             }
200              
201             /*
202             * character classification
203             *
204             * The full Unicode range of characters is subjected to fairly arbitrary
205             * classification. To avoid having enormous bitmaps, the ranges to match
206             * against are stored in lists, which are binary-searched. For speed,
207             * the ASCII range is classified by a bitmap.
208             *
209             * nona_codepoint_is_in_set() checks whether a non-ASCII codepoint is in
210             * a specified character set identified by a Unicode range table.
211             *
212             * The char_is_*() functions each check whether the character being
213             * pointed at is of a particular type.
214             *
215             * The codepoint_is_*() functions each check whether a codepoint is of
216             * a particular type.
217             *
218             * The ascii_codepoint_is_*() functions each check whether an ASCII
219             * codepoint is of a particular type.
220             */
221              
222             struct unicode_range {
223             U32 first;
224             U32 last;
225             };
226              
227             static struct unicode_range const uniset_namestart[] = {
228             { 0x003a, 0x003a },
229             { 0x0041, 0x005a },
230             { 0x005f, 0x005f },
231             { 0x0061, 0x007a },
232             { 0x00c0, 0x00d6 },
233             { 0x00d8, 0x00f6 },
234             { 0x00f8, 0x0131 },
235             { 0x0134, 0x013e },
236             { 0x0141, 0x0148 },
237             { 0x014a, 0x017e },
238             { 0x0180, 0x01c3 },
239             { 0x01cd, 0x01f0 },
240             { 0x01f4, 0x01f5 },
241             { 0x01fa, 0x0217 },
242             { 0x0250, 0x02a8 },
243             { 0x02bb, 0x02c1 },
244             { 0x0386, 0x0386 },
245             { 0x0388, 0x038a },
246             { 0x038c, 0x038c },
247             { 0x038e, 0x03a1 },
248             { 0x03a3, 0x03ce },
249             { 0x03d0, 0x03d6 },
250             { 0x03da, 0x03da },
251             { 0x03dc, 0x03dc },
252             { 0x03de, 0x03de },
253             { 0x03e0, 0x03e0 },
254             { 0x03e2, 0x03f3 },
255             { 0x0401, 0x040c },
256             { 0x040e, 0x044f },
257             { 0x0451, 0x045c },
258             { 0x045e, 0x0481 },
259             { 0x0490, 0x04c4 },
260             { 0x04c7, 0x04c8 },
261             { 0x04cb, 0x04cc },
262             { 0x04d0, 0x04eb },
263             { 0x04ee, 0x04f5 },
264             { 0x04f8, 0x04f9 },
265             { 0x0531, 0x0556 },
266             { 0x0559, 0x0559 },
267             { 0x0561, 0x0586 },
268             { 0x05d0, 0x05ea },
269             { 0x05f0, 0x05f2 },
270             { 0x0621, 0x063a },
271             { 0x0641, 0x064a },
272             { 0x0671, 0x06b7 },
273             { 0x06ba, 0x06be },
274             { 0x06c0, 0x06ce },
275             { 0x06d0, 0x06d3 },
276             { 0x06d5, 0x06d5 },
277             { 0x06e5, 0x06e6 },
278             { 0x0905, 0x0939 },
279             { 0x093d, 0x093d },
280             { 0x0958, 0x0961 },
281             { 0x0985, 0x098c },
282             { 0x098f, 0x0990 },
283             { 0x0993, 0x09a8 },
284             { 0x09aa, 0x09b0 },
285             { 0x09b2, 0x09b2 },
286             { 0x09b6, 0x09b9 },
287             { 0x09dc, 0x09dd },
288             { 0x09df, 0x09e1 },
289             { 0x09f0, 0x09f1 },
290             { 0x0a05, 0x0a0a },
291             { 0x0a0f, 0x0a10 },
292             { 0x0a13, 0x0a28 },
293             { 0x0a2a, 0x0a30 },
294             { 0x0a32, 0x0a33 },
295             { 0x0a35, 0x0a36 },
296             { 0x0a38, 0x0a39 },
297             { 0x0a59, 0x0a5c },
298             { 0x0a5e, 0x0a5e },
299             { 0x0a72, 0x0a74 },
300             { 0x0a85, 0x0a8b },
301             { 0x0a8d, 0x0a8d },
302             { 0x0a8f, 0x0a91 },
303             { 0x0a93, 0x0aa8 },
304             { 0x0aaa, 0x0ab0 },
305             { 0x0ab2, 0x0ab3 },
306             { 0x0ab5, 0x0ab9 },
307             { 0x0abd, 0x0abd },
308             { 0x0ae0, 0x0ae0 },
309             { 0x0b05, 0x0b0c },
310             { 0x0b0f, 0x0b10 },
311             { 0x0b13, 0x0b28 },
312             { 0x0b2a, 0x0b30 },
313             { 0x0b32, 0x0b33 },
314             { 0x0b36, 0x0b39 },
315             { 0x0b3d, 0x0b3d },
316             { 0x0b5c, 0x0b5d },
317             { 0x0b5f, 0x0b61 },
318             { 0x0b85, 0x0b8a },
319             { 0x0b8e, 0x0b90 },
320             { 0x0b92, 0x0b95 },
321             { 0x0b99, 0x0b9a },
322             { 0x0b9c, 0x0b9c },
323             { 0x0b9e, 0x0b9f },
324             { 0x0ba3, 0x0ba4 },
325             { 0x0ba8, 0x0baa },
326             { 0x0bae, 0x0bb5 },
327             { 0x0bb7, 0x0bb9 },
328             { 0x0c05, 0x0c0c },
329             { 0x0c0e, 0x0c10 },
330             { 0x0c12, 0x0c28 },
331             { 0x0c2a, 0x0c33 },
332             { 0x0c35, 0x0c39 },
333             { 0x0c60, 0x0c61 },
334             { 0x0c85, 0x0c8c },
335             { 0x0c8e, 0x0c90 },
336             { 0x0c92, 0x0ca8 },
337             { 0x0caa, 0x0cb3 },
338             { 0x0cb5, 0x0cb9 },
339             { 0x0cde, 0x0cde },
340             { 0x0ce0, 0x0ce1 },
341             { 0x0d05, 0x0d0c },
342             { 0x0d0e, 0x0d10 },
343             { 0x0d12, 0x0d28 },
344             { 0x0d2a, 0x0d39 },
345             { 0x0d60, 0x0d61 },
346             { 0x0e01, 0x0e2e },
347             { 0x0e30, 0x0e30 },
348             { 0x0e32, 0x0e33 },
349             { 0x0e40, 0x0e45 },
350             { 0x0e81, 0x0e82 },
351             { 0x0e84, 0x0e84 },
352             { 0x0e87, 0x0e88 },
353             { 0x0e8a, 0x0e8a },
354             { 0x0e8d, 0x0e8d },
355             { 0x0e94, 0x0e97 },
356             { 0x0e99, 0x0e9f },
357             { 0x0ea1, 0x0ea3 },
358             { 0x0ea5, 0x0ea5 },
359             { 0x0ea7, 0x0ea7 },
360             { 0x0eaa, 0x0eab },
361             { 0x0ead, 0x0eae },
362             { 0x0eb0, 0x0eb0 },
363             { 0x0eb2, 0x0eb3 },
364             { 0x0ebd, 0x0ebd },
365             { 0x0ec0, 0x0ec4 },
366             { 0x0f40, 0x0f47 },
367             { 0x0f49, 0x0f69 },
368             { 0x10a0, 0x10c5 },
369             { 0x10d0, 0x10f6 },
370             { 0x1100, 0x1100 },
371             { 0x1102, 0x1103 },
372             { 0x1105, 0x1107 },
373             { 0x1109, 0x1109 },
374             { 0x110b, 0x110c },
375             { 0x110e, 0x1112 },
376             { 0x113c, 0x113c },
377             { 0x113e, 0x113e },
378             { 0x1140, 0x1140 },
379             { 0x114c, 0x114c },
380             { 0x114e, 0x114e },
381             { 0x1150, 0x1150 },
382             { 0x1154, 0x1155 },
383             { 0x1159, 0x1159 },
384             { 0x115f, 0x1161 },
385             { 0x1163, 0x1163 },
386             { 0x1165, 0x1165 },
387             { 0x1167, 0x1167 },
388             { 0x1169, 0x1169 },
389             { 0x116d, 0x116e },
390             { 0x1172, 0x1173 },
391             { 0x1175, 0x1175 },
392             { 0x119e, 0x119e },
393             { 0x11a8, 0x11a8 },
394             { 0x11ab, 0x11ab },
395             { 0x11ae, 0x11af },
396             { 0x11b7, 0x11b8 },
397             { 0x11ba, 0x11ba },
398             { 0x11bc, 0x11c2 },
399             { 0x11eb, 0x11eb },
400             { 0x11f0, 0x11f0 },
401             { 0x11f9, 0x11f9 },
402             { 0x1e00, 0x1e9b },
403             { 0x1ea0, 0x1ef9 },
404             { 0x1f00, 0x1f15 },
405             { 0x1f18, 0x1f1d },
406             { 0x1f20, 0x1f45 },
407             { 0x1f48, 0x1f4d },
408             { 0x1f50, 0x1f57 },
409             { 0x1f59, 0x1f59 },
410             { 0x1f5b, 0x1f5b },
411             { 0x1f5d, 0x1f5d },
412             { 0x1f5f, 0x1f7d },
413             { 0x1f80, 0x1fb4 },
414             { 0x1fb6, 0x1fbc },
415             { 0x1fbe, 0x1fbe },
416             { 0x1fc2, 0x1fc4 },
417             { 0x1fc6, 0x1fcc },
418             { 0x1fd0, 0x1fd3 },
419             { 0x1fd6, 0x1fdb },
420             { 0x1fe0, 0x1fec },
421             { 0x1ff2, 0x1ff4 },
422             { 0x1ff6, 0x1ffc },
423             { 0x2126, 0x2126 },
424             { 0x212a, 0x212b },
425             { 0x212e, 0x212e },
426             { 0x2180, 0x2182 },
427             { 0x3007, 0x3007 },
428             { 0x3021, 0x3029 },
429             { 0x3041, 0x3094 },
430             { 0x30a1, 0x30fa },
431             { 0x3105, 0x312c },
432             { 0x4e00, 0x9fa5 },
433             { 0xac00, 0xd7a3 },
434             };
435              
436             static struct unicode_range const uniset_name[] = {
437             { 0x002d, 0x002e },
438             { 0x0030, 0x003a },
439             { 0x0041, 0x005a },
440             { 0x005f, 0x005f },
441             { 0x0061, 0x007a },
442             { 0x00b7, 0x00b7 },
443             { 0x00c0, 0x00d6 },
444             { 0x00d8, 0x00f6 },
445             { 0x00f8, 0x0131 },
446             { 0x0134, 0x013e },
447             { 0x0141, 0x0148 },
448             { 0x014a, 0x017e },
449             { 0x0180, 0x01c3 },
450             { 0x01cd, 0x01f0 },
451             { 0x01f4, 0x01f5 },
452             { 0x01fa, 0x0217 },
453             { 0x0250, 0x02a8 },
454             { 0x02bb, 0x02c1 },
455             { 0x02d0, 0x02d1 },
456             { 0x0300, 0x0345 },
457             { 0x0360, 0x0361 },
458             { 0x0387, 0x038a },
459             { 0x038c, 0x038c },
460             { 0x038e, 0x03a1 },
461             { 0x03a3, 0x03ce },
462             { 0x03d0, 0x03d6 },
463             { 0x03da, 0x03da },
464             { 0x03dc, 0x03dc },
465             { 0x03de, 0x03de },
466             { 0x03e0, 0x03e0 },
467             { 0x03e2, 0x03f3 },
468             { 0x0401, 0x040c },
469             { 0x040e, 0x044f },
470             { 0x0451, 0x045c },
471             { 0x045e, 0x0481 },
472             { 0x0483, 0x0486 },
473             { 0x0490, 0x04c4 },
474             { 0x04c7, 0x04c8 },
475             { 0x04cb, 0x04cc },
476             { 0x04d0, 0x04eb },
477             { 0x04ee, 0x04f5 },
478             { 0x04f8, 0x04f9 },
479             { 0x0531, 0x0556 },
480             { 0x0559, 0x0559 },
481             { 0x0561, 0x0586 },
482             { 0x0591, 0x05a1 },
483             { 0x05a3, 0x05b9 },
484             { 0x05bb, 0x05bd },
485             { 0x05bf, 0x05bf },
486             { 0x05c1, 0x05c2 },
487             { 0x05c4, 0x05c4 },
488             { 0x05d0, 0x05ea },
489             { 0x05f0, 0x05f2 },
490             { 0x0621, 0x063a },
491             { 0x0641, 0x0652 },
492             { 0x0660, 0x0669 },
493             { 0x0670, 0x06b7 },
494             { 0x06ba, 0x06be },
495             { 0x06c0, 0x06ce },
496             { 0x06d0, 0x06d3 },
497             { 0x06e5, 0x06e8 },
498             { 0x06ea, 0x06ed },
499             { 0x06f0, 0x06f9 },
500             { 0x0901, 0x0903 },
501             { 0x0905, 0x0939 },
502             { 0x093e, 0x094d },
503             { 0x0951, 0x0954 },
504             { 0x0958, 0x0963 },
505             { 0x0966, 0x096f },
506             { 0x0981, 0x0983 },
507             { 0x0985, 0x098c },
508             { 0x098f, 0x0990 },
509             { 0x0993, 0x09a8 },
510             { 0x09aa, 0x09b0 },
511             { 0x09b2, 0x09b2 },
512             { 0x09b6, 0x09b9 },
513             { 0x09bc, 0x09bc },
514             { 0x09bf, 0x09c4 },
515             { 0x09c7, 0x09c8 },
516             { 0x09cb, 0x09cd },
517             { 0x09d7, 0x09d7 },
518             { 0x09dc, 0x09dd },
519             { 0x09df, 0x09e3 },
520             { 0x09e6, 0x09f1 },
521             { 0x0a02, 0x0a02 },
522             { 0x0a05, 0x0a0a },
523             { 0x0a0f, 0x0a10 },
524             { 0x0a13, 0x0a28 },
525             { 0x0a2a, 0x0a30 },
526             { 0x0a32, 0x0a33 },
527             { 0x0a35, 0x0a36 },
528             { 0x0a38, 0x0a39 },
529             { 0x0a3c, 0x0a3c },
530             { 0x0a3f, 0x0a42 },
531             { 0x0a47, 0x0a48 },
532             { 0x0a4b, 0x0a4d },
533             { 0x0a59, 0x0a5c },
534             { 0x0a5e, 0x0a5e },
535             { 0x0a70, 0x0a74 },
536             { 0x0a81, 0x0a83 },
537             { 0x0a85, 0x0a8b },
538             { 0x0a8d, 0x0a8d },
539             { 0x0a8f, 0x0a91 },
540             { 0x0a93, 0x0aa8 },
541             { 0x0aaa, 0x0ab0 },
542             { 0x0ab2, 0x0ab3 },
543             { 0x0ab5, 0x0ab9 },
544             { 0x0abd, 0x0ac5 },
545             { 0x0ac7, 0x0ac9 },
546             { 0x0acb, 0x0acd },
547             { 0x0ae0, 0x0ae0 },
548             { 0x0ae6, 0x0aef },
549             { 0x0b01, 0x0b03 },
550             { 0x0b05, 0x0b0c },
551             { 0x0b0f, 0x0b10 },
552             { 0x0b13, 0x0b28 },
553             { 0x0b2a, 0x0b30 },
554             { 0x0b32, 0x0b33 },
555             { 0x0b36, 0x0b39 },
556             { 0x0b3d, 0x0b43 },
557             { 0x0b47, 0x0b48 },
558             { 0x0b4b, 0x0b4d },
559             { 0x0b56, 0x0b57 },
560             { 0x0b5c, 0x0b5d },
561             { 0x0b5f, 0x0b61 },
562             { 0x0b66, 0x0b6f },
563             { 0x0b82, 0x0b83 },
564             { 0x0b85, 0x0b8a },
565             { 0x0b8e, 0x0b90 },
566             { 0x0b92, 0x0b95 },
567             { 0x0b99, 0x0b9a },
568             { 0x0b9c, 0x0b9c },
569             { 0x0b9e, 0x0b9f },
570             { 0x0ba3, 0x0ba4 },
571             { 0x0ba8, 0x0baa },
572             { 0x0bae, 0x0bb5 },
573             { 0x0bb7, 0x0bb9 },
574             { 0x0bbe, 0x0bc2 },
575             { 0x0bc6, 0x0bc8 },
576             { 0x0bca, 0x0bcd },
577             { 0x0bd7, 0x0bd7 },
578             { 0x0be7, 0x0bef },
579             { 0x0c01, 0x0c03 },
580             { 0x0c05, 0x0c0c },
581             { 0x0c0e, 0x0c10 },
582             { 0x0c12, 0x0c28 },
583             { 0x0c2a, 0x0c33 },
584             { 0x0c35, 0x0c39 },
585             { 0x0c3e, 0x0c44 },
586             { 0x0c46, 0x0c48 },
587             { 0x0c4a, 0x0c4d },
588             { 0x0c55, 0x0c56 },
589             { 0x0c60, 0x0c61 },
590             { 0x0c66, 0x0c6f },
591             { 0x0c82, 0x0c83 },
592             { 0x0c85, 0x0c8c },
593             { 0x0c8e, 0x0c90 },
594             { 0x0c92, 0x0ca8 },
595             { 0x0caa, 0x0cb3 },
596             { 0x0cb5, 0x0cb9 },
597             { 0x0cbe, 0x0cc4 },
598             { 0x0cc6, 0x0cc8 },
599             { 0x0cca, 0x0ccd },
600             { 0x0cd5, 0x0cd6 },
601             { 0x0cde, 0x0cde },
602             { 0x0ce0, 0x0ce1 },
603             { 0x0ce6, 0x0cef },
604             { 0x0d02, 0x0d03 },
605             { 0x0d05, 0x0d0c },
606             { 0x0d0e, 0x0d10 },
607             { 0x0d12, 0x0d28 },
608             { 0x0d2a, 0x0d39 },
609             { 0x0d3e, 0x0d43 },
610             { 0x0d46, 0x0d48 },
611             { 0x0d4a, 0x0d4d },
612             { 0x0d57, 0x0d57 },
613             { 0x0d60, 0x0d61 },
614             { 0x0d66, 0x0d6f },
615             { 0x0e01, 0x0e2e },
616             { 0x0e32, 0x0e3a },
617             { 0x0e46, 0x0e4e },
618             { 0x0e50, 0x0e59 },
619             { 0x0e81, 0x0e82 },
620             { 0x0e84, 0x0e84 },
621             { 0x0e87, 0x0e88 },
622             { 0x0e8a, 0x0e8a },
623             { 0x0e8d, 0x0e8d },
624             { 0x0e94, 0x0e97 },
625             { 0x0e99, 0x0e9f },
626             { 0x0ea1, 0x0ea3 },
627             { 0x0ea5, 0x0ea5 },
628             { 0x0ea7, 0x0ea7 },
629             { 0x0eaa, 0x0eab },
630             { 0x0ead, 0x0eae },
631             { 0x0eb2, 0x0eb9 },
632             { 0x0ebb, 0x0ebd },
633             { 0x0ec0, 0x0ec4 },
634             { 0x0ec6, 0x0ec6 },
635             { 0x0ec8, 0x0ecd },
636             { 0x0ed0, 0x0ed9 },
637             { 0x0f18, 0x0f19 },
638             { 0x0f20, 0x0f29 },
639             { 0x0f35, 0x0f35 },
640             { 0x0f37, 0x0f37 },
641             { 0x0f39, 0x0f39 },
642             { 0x0f3f, 0x0f47 },
643             { 0x0f49, 0x0f69 },
644             { 0x0f71, 0x0f84 },
645             { 0x0f86, 0x0f8b },
646             { 0x0f90, 0x0f95 },
647             { 0x0f97, 0x0f97 },
648             { 0x0f99, 0x0fad },
649             { 0x0fb1, 0x0fb7 },
650             { 0x0fb9, 0x0fb9 },
651             { 0x10a0, 0x10c5 },
652             { 0x10d0, 0x10f6 },
653             { 0x1100, 0x1100 },
654             { 0x1102, 0x1103 },
655             { 0x1105, 0x1107 },
656             { 0x1109, 0x1109 },
657             { 0x110b, 0x110c },
658             { 0x110e, 0x1112 },
659             { 0x113c, 0x113c },
660             { 0x113e, 0x113e },
661             { 0x1140, 0x1140 },
662             { 0x114c, 0x114c },
663             { 0x114e, 0x114e },
664             { 0x1150, 0x1150 },
665             { 0x1154, 0x1155 },
666             { 0x1159, 0x1159 },
667             { 0x115f, 0x1161 },
668             { 0x1163, 0x1163 },
669             { 0x1165, 0x1165 },
670             { 0x1167, 0x1167 },
671             { 0x1169, 0x1169 },
672             { 0x116d, 0x116e },
673             { 0x1172, 0x1173 },
674             { 0x1175, 0x1175 },
675             { 0x119e, 0x119e },
676             { 0x11a8, 0x11a8 },
677             { 0x11ab, 0x11ab },
678             { 0x11ae, 0x11af },
679             { 0x11b7, 0x11b8 },
680             { 0x11ba, 0x11ba },
681             { 0x11bc, 0x11c2 },
682             { 0x11eb, 0x11eb },
683             { 0x11f0, 0x11f0 },
684             { 0x11f9, 0x11f9 },
685             { 0x1e00, 0x1e9b },
686             { 0x1ea0, 0x1ef9 },
687             { 0x1f00, 0x1f15 },
688             { 0x1f18, 0x1f1d },
689             { 0x1f20, 0x1f45 },
690             { 0x1f48, 0x1f4d },
691             { 0x1f50, 0x1f57 },
692             { 0x1f59, 0x1f59 },
693             { 0x1f5b, 0x1f5b },
694             { 0x1f5d, 0x1f5d },
695             { 0x1f5f, 0x1f7d },
696             { 0x1f80, 0x1fb4 },
697             { 0x1fb6, 0x1fbc },
698             { 0x1fbe, 0x1fbe },
699             { 0x1fc2, 0x1fc4 },
700             { 0x1fc6, 0x1fcc },
701             { 0x1fd0, 0x1fd3 },
702             { 0x1fd6, 0x1fdb },
703             { 0x1fe0, 0x1fec },
704             { 0x1ff2, 0x1ff4 },
705             { 0x1ff6, 0x1ffc },
706             { 0x20d0, 0x20dc },
707             { 0x20e1, 0x20e1 },
708             { 0x2126, 0x2126 },
709             { 0x212a, 0x212b },
710             { 0x212e, 0x212e },
711             { 0x2180, 0x2182 },
712             { 0x3005, 0x3005 },
713             { 0x3007, 0x3007 },
714             { 0x3021, 0x302f },
715             { 0x3031, 0x3035 },
716             { 0x3041, 0x3094 },
717             { 0x3099, 0x309a },
718             { 0x309d, 0x309e },
719             { 0x30a1, 0x30fa },
720             { 0x30fc, 0x30fe },
721             { 0x3105, 0x312c },
722             { 0x4e00, 0x9fa5 },
723             { 0xac00, 0xd7a3 },
724             };
725              
726             #define ARRAY_END(a) ((a) + sizeof((a))/sizeof(*(a)))
727              
728 1124965           static int nona_codepoint_is_in_set(U32 c, struct unicode_range const *rl,
729             struct unicode_range const *rr)
730             {
731 1124965           rr--;
732 10125952 100         while(rl != rr) {
733             /* invariant: c >= rl->first && c < rr[1].first */
734 9000987           struct unicode_range const *rt = rl + ((rr-rl+1) >> 1);
735 9000987 100         if(c >= rt->first) {
736 2274196           rl = rt;
737             } else {
738 6726791           rr = rt-1;
739             }
740             }
741 1124965           return c <= rl->last;
742             }
743              
744             #define CHARATTR_NAMESTART 0x01
745             #define CHARATTR_NAME 0x02
746             #define CHARATTR_S 0x04
747             #define CHARATTR_ENCSTART 0x10
748             #define CHARATTR_ENC 0x20
749             #define CHARATTR_CHAR 0x80
750              
751             static U8 const asciichar_attr[128] = {
752             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* NUL to BEL */
753             0x00, 0x84, 0x84, 0x00, 0x00, 0x84, 0x00, 0x00, /* BS to SI */
754             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* DLE to ETB */
755             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CAN to US */
756             0x84, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, /* SP to ' */
757             0x80, 0x80, 0x80, 0x80, 0x80, 0xa2, 0xa2, 0x80, /* ( to / */
758             0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, /* 0 to 7 */
759             0xa2, 0xa2, 0x83, 0x80, 0x80, 0x80, 0x80, 0x80, /* 8 to ? */
760             0x80, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, /* @ to G */
761             0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, /* H to O */
762             0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, /* P to W */
763             0xb3, 0xb3, 0xb3, 0x80, 0x80, 0x80, 0x80, 0xa3, /* X to _ */
764             0x80, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, /* ` to g */
765             0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, /* h to o */
766             0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, /* p to w */
767             0xb3, 0xb3, 0xb3, 0x80, 0x80, 0x80, 0x80, 0x80, /* x to DEL */
768             };
769              
770             #define char_is_namestart(p) THX_char_is_namestart(aTHX_ p)
771 505203           static int THX_char_is_namestart(pTHX_ U8 *p)
772             {
773 505203           U8 c0 = *p;
774 505203 100         if(!(c0 & 0x80)) return asciichar_attr[c0] & CHARATTR_NAMESTART;
775 2775           return nona_codepoint_is_in_set(char_unicode(p),
776             uniset_namestart, ARRAY_END(uniset_namestart));
777             }
778              
779             #define char_is_name(p) THX_char_is_name(aTHX_ p)
780 77628286           static int THX_char_is_name(pTHX_ U8 *p)
781             {
782 77628286           U8 c0 = *p;
783 77628286 100         if(!(c0 & 0x80)) return asciichar_attr[c0] & CHARATTR_NAME;
784 1122190           return nona_codepoint_is_in_set(char_unicode(p),
785             uniset_name, ARRAY_END(uniset_name));
786             }
787              
788 1522160           static int char_is_s(U8 *p)
789             {
790 1522160           U8 c0 = *p;
791 1522160 50         if(!(c0 & 0x80)) return asciichar_attr[c0] & CHARATTR_S;
792 0           return 0;
793             }
794              
795             #if 0 /* unused */
796             static int ascii_codepoint_is_s(U8 c)
797             {
798             return asciichar_attr[c] & CHARATTR_S;
799             }
800             #endif
801              
802 4025           static int char_is_encstart(U8 *p)
803             {
804 4025           U8 c0 = *p;
805 4025 100         if(!(c0 & 0x80)) return asciichar_attr[c0] & CHARATTR_ENCSTART;
806 276           return 0;
807             }
808              
809 7212476           static int char_is_enc(U8 *p)
810             {
811 7212476           U8 c0 = *p;
812 7212476 100         if(!(c0 & 0x80)) return asciichar_attr[c0] & CHARATTR_ENC;
813 184           return 0;
814             }
815              
816 29928296           static int nona_codepoint_is_char(U32 c)
817             {
818 29928296 100         if(c <= 0xd7ff) return 1;
819 19806906 100         return c >= 0xe000 && c <= 0x10ffff && (c & ~1) != 0xfffe;
    100          
    100          
820             }
821              
822 242           static int codepoint_is_char(U32 c)
823             {
824 378 100         return (c < 0x80) ? asciichar_attr[c] & CHARATTR_CHAR :
825 136           nona_codepoint_is_char(c);
826             }
827              
828             #define char_is_char(p) THX_char_is_char(aTHX_ p)
829 178523885           static int THX_char_is_char(pTHX_ U8 *p)
830             {
831 178523885           U8 c0 = *p;
832 178523885 100         if(!(c0 & 0x80)) return asciichar_attr[c0] & CHARATTR_CHAR;
833 29928160           return nona_codepoint_is_char(char_unicode(p));
834             }
835              
836             /*
837             * XML node handling
838             */
839              
840             #define contentobject_twine(cobj) THX_contentobject_twine(aTHX_ cobj)
841 172127           static SV *THX_contentobject_twine(pTHX_ SV *cobj)
842             {
843             AV *twine;
844             SV **item_ptr;
845 172127 100         if(!SvROK(cobj))
846 36           throw_data_error("content data isn't a content chunk");
847 172091           twine = (AV*)SvRV(cobj);
848 172091 100         if(SvTYPE((SV*)twine) != SVt_PVAV || av_len(twine) != 0)
    100          
849 51           throw_data_error("content data isn't a content chunk");
850 172040 100         if(!SvOBJECT((SV*)twine) || SvSTASH((SV*)twine) != stash_content)
    50          
851 3           throw_data_error("content data isn't a content chunk");
852 172037           item_ptr = av_fetch(twine, 0, 0);
853 172037 50         if(!item_ptr) throw_data_error("content array isn't an array");
854 172037           return *item_ptr;
855             }
856              
857             #define twine_contentobject(tref) THX_twine_contentobject(aTHX_ tref)
858 168812           static SV *THX_twine_contentobject(pTHX_ SV *tref)
859             {
860 168812           AV *content = newAV();
861 168812           SV *cref = sv_2mortal(newRV_noinc((SV*)content));
862 168812           av_push(content, SvREFCNT_inc(tref));
863 168812           sv_bless(cref, stash_content);
864 168812           SvREADONLY_on((SV*)content);
865 168812           SvREADONLY_on(cref);
866 168812           return cref;
867             }
868              
869             #define element_nodearray(eref) THX_element_nodearray(aTHX_ eref)
870 172738           static AV *THX_element_nodearray(pTHX_ SV *eref)
871             {
872             AV *earr;
873 172738 100         if(!SvROK(eref)) throw_data_error("element data isn't an element");
874 172648           earr = (AV*)SvRV(eref);
875 172648 100         if(SvTYPE((SV*)earr) != SVt_PVAV || av_len(earr) != 2)
    100          
876 150           throw_data_error("element data isn't an element");
877 172498 50         if(!SvOBJECT((SV*)earr) || SvSTASH((SV*)earr) != stash_element)
    50          
878 0           throw_data_error("element data isn't an element");
879 172498           return earr;
880             }
881              
882             #define userchardata_chardata(idata) THX_userchardata_chardata(aTHX_ idata)
883 19976           static SV *THX_userchardata_chardata(pTHX_ SV *idata)
884             {
885             SV *odata;
886             U8 *p, *end;
887             STRLEN len;
888 19976 100         if(!sv_is_string(idata))
    50          
    100          
889 52           throw_data_error("character data isn't a string");
890 19924           odata = sv_mortalcopy(idata);
891 19924           sv_utf8_upgrade(odata);
892 19924           SvREADONLY_on(odata);
893 19924           p = (U8*)SvPV(odata, len);
894 19924           end = p + len;
895 159680401 100         while(*p != 0) {
896 159665053 100         if(!char_is_char(p))
897 4576           throw_data_error("character data "
898             "contains illegal character");
899 159660477           p += UTF8SKIP(p);
900             }
901 15348 100         if(p != end)
902 352           throw_data_error("character data contains illegal character");
903 14996           return odata;
904             }
905              
906             #define usertwine_twine(itref) THX_usertwine_twine(aTHX_ itref)
907 14087           static SV *THX_usertwine_twine(pTHX_ SV *itref)
908             {
909             SV *otref;
910             AV *itwine, *otwine;
911             array_ix_t clen, i;
912 14087 100         if(!SvROK(itref)) throw_data_error("content array isn't an array");
913 14081           itwine = (AV*)SvRV(itref);
914 14081 100         if(SvTYPE((SV*)itwine) != SVt_PVAV || SvOBJECT((SV*)itwine))
    100          
915 9           throw_data_error("content array isn't an array");
916 14072           clen = av_len(itwine);
917 14072 100         if(clen & 1) throw_data_error("content array has even length");
918 13992           otwine = newAV();
919 13992           otref = sv_2mortal(newRV_noinc((SV*)otwine));
920 13992           SvREADONLY_on(otref);
921 13992           av_extend(otwine, clen);
922 19001           for(i = 0; ; i++) {
923             SV **item_ptr, *iitem, *oitem, *elem;
924 19001           item_ptr = av_fetch(itwine, i, 0);
925 19001 50         if(!item_ptr)
926 0           throw_data_error("character data isn't a string");
927 19001           iitem = *item_ptr;
928 19001 100         if(!sv_is_string(iitem))
    50          
    100          
929 520           throw_data_error("character data isn't a string");
930 18481           oitem = userchardata_chardata(iitem);
931 14001           av_push(otwine, SvREFCNT_inc(oitem));
932 14001 100         if(i++ == clen) break;
933 5649           item_ptr = av_fetch(itwine, i, 0);
934 5649 50         if(!item_ptr)
935 0           throw_data_error("element data isn't an element");
936 5649           iitem = *item_ptr;
937 5649 100         if(!SvROK(iitem))
938 240           throw_data_error("element data isn't an element");
939 5409           elem = SvRV(iitem);
940 5409 100         if(!SvOBJECT(elem) || SvSTASH(elem) != stash_element)
    100          
941 400           throw_data_error("element data isn't an element");
942 5009           oitem = newRV_inc(elem);
943 5009           SvREADONLY_on(oitem);
944 5009           av_push(otwine, oitem);
945             }
946 8352           SvREADONLY_on((SV*)otwine);
947 8352           return otref;
948             }
949              
950             /*
951             * parsing
952             *
953             * The parse_*() functions each parse some syntactic construct within the
954             * XML grammar. Their main input is the pointer to the start of that
955             * construct in the input. Generally they can be pointed at anything,
956             * however malformed, and they will detect a syntax error if it is not the
957             * item they are meant to parse. Upon a successful parse they return, in
958             * one way or another, a pointer to the end of the parsed construct and
959             * any details required of the item's content. Upon syntax error or UTF-8
960             * encoding error, they throw an exception.
961             *
962             * The end of the input string is not explicitly indicated to the parser
963             * functions. They detect the end of input by means of the NUL terminator.
964             * A NUL can also be embedded in the string, in which case parsing will
965             * initially return a successful result (if that's a valid place to end),
966             * and the outermost code (which has access to the SV) will detect that it
967             * was an embedded NUL rather than end of input and throw an exception.
968             *
969             * Unlike the regular expressions in XML::Easy::Syntax, these parser
970             * functions won't match their grammar production in absolutely any context.
971             * They are specialised to work in the context of the complete XML grammar,
972             * and are permitted to detect XML syntax errors that strictly fall outside
973             * the construct being parsed. For example, parse_contentobject() will
974             * complain if it faces "]]>", rather than matching "]]" and then returning.
975             *
976             * All objects created by parsing are initially mortal, and have their
977             * reference counts later increased when a persistent reference is made.
978             * Thus on exception all the partial results are cleaned up.
979             */
980              
981             /* parse_s(), parse_opt_s(), parse_eq(): return the updated pointer */
982              
983             #define parse_s(p) THX_parse_s(aTHX_ p)
984 488           static U8 *THX_parse_s(pTHX_ U8 *p)
985             {
986 488 100         if(!char_is_s(p)) throw_syntax_error(p);
987             do {
988 640464           p++;
989 640464 100         } while(char_is_s(p));
990 472           return p;
991             }
992              
993 161168           static U8 *parse_opt_s(U8 *p)
994             {
995 881186 100         while(char_is_s(p))
996 720018           p++;
997 161168           return p;
998             }
999              
1000             #define parse_eq(p) THX_parse_eq(aTHX_ p)
1001 384           static U8 *THX_parse_eq(pTHX_ U8 *p)
1002             {
1003 384           p = parse_opt_s(p);
1004 384 100         if(*p != '=') throw_syntax_error(p);
1005 382           return parse_opt_s(p+1);
1006             }
1007              
1008             /* parse_name(): returns the number of octets encoding the name */
1009              
1010             #define parse_name(p) THX_parse_name(aTHX_ p)
1011 321752           static STRLEN THX_parse_name(pTHX_ U8 *p)
1012             {
1013 321752           U8 *start = p;
1014 321752 100         if(!char_is_namestart(p)) throw_syntax_error(p);
1015             do {
1016 1522046           p += UTF8SKIP(p);
1017 1522046 100         } while(char_is_name(p));
1018 321720           return p - start;
1019             }
1020              
1021             /* parse_reference(): updates pointer in place and returns codepoint of
1022             referenced character */
1023              
1024             static U8 const digit_value[256] = {
1025             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1026             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1027             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1028             0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99, 77, 99, 99, 99, 99,
1029             99, 10, 11, 12, 13, 14, 15, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1030             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1031             99, 10, 11, 12, 13, 14, 15, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1032             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1033             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1034             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1035             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1036             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1037             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1038             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1039             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1040             99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1041             };
1042              
1043             #define parse_reference(pp) THX_parse_reference(aTHX_ pp)
1044 160358           static U32 THX_parse_reference(pTHX_ U8 **pp)
1045             {
1046 160358           U8 *p = *pp;
1047             U8 c;
1048             U32 val;
1049 160358 50         if(*p != '&') throw_syntax_error(p);
1050 160358           c = *++p;
1051 160358 100         if(c == '#') {
1052 250           c = *++p;
1053 250 100         if(c == 'x') {
1054 122           val = digit_value[*++p];
1055 122 50         if(val > 15) throw_syntax_error(p);
1056             while(1) {
1057 432           c = digit_value[*++p];
1058 432 100         if(c > 15) break;
1059 316 100         if(val & 0xf0000000)
1060 6           throw_wfc_error("invalid character "
1061             "in character reference");
1062 310           val = (val<<4) + c;
1063             }
1064             } else {
1065 128           val = digit_value[c];
1066 128 50         if(val > 9) throw_syntax_error(p);
1067             while(1) {
1068 502           c = digit_value[*++p];
1069 502 100         if(c > 9) break;
1070 376 100         if(val >= 100000000)
1071 2           throw_wfc_error("invalid character "
1072             "in character reference");
1073 374           val = val*10 + c;
1074             }
1075             }
1076 242 50         if(c != 77) throw_syntax_error(p);
1077 242           p++;
1078 242 100         if(!codepoint_is_char(val))
1079 98           throw_wfc_error("invalid character "
1080             "in character reference");
1081 160108 100         } else if(c == 'l' && p[1] == 't' && p[2] == ';') {
    50          
    50          
1082 30           p += 3;
1083 30           val = '<';
1084 160078 100         } else if(c == 'g' && p[1] == 't' && p[2] == ';') {
    50          
    50          
1085 28           p += 3;
1086 28           val = '>';
1087 160050 100         } else if(c == 'a' && p[1] == 'm' && p[2] == 'p' && p[3] == ';') {
    100          
    50          
    50          
1088 22           p += 4;
1089 22           val = '&';
1090 160028 100         } else if(c == 'q' && p[1] == 'u' && p[2] == 'o' && p[3] == 't' &&
    50          
    50          
    50          
1091 4 50         p[4] == ';') {
1092 4           p += 5;
1093 4           val = '"';
1094 160024 100         } else if(c == 'a' && p[1] == 'p' && p[2] == 'o' && p[3] == 's' &&
    50          
    50          
    50          
1095 160004 50         p[4] == ';') {
1096 160004           p += 5;
1097 160004           val = '\'';
1098             } else {
1099 20           p += parse_name(p);
1100 20 100         if(*p != ';') throw_syntax_error(p);
1101 16           throw_wfc_error("reference to undeclared entity");
1102             }
1103 160232           *pp = p;
1104 160232           return val;
1105             }
1106              
1107             /* parse_chars(): parses literal characters and references, for use in
1108             ordinary content, CDATA, and attribute values; guarantees to return only
1109             when facing correct terminator; returns updated pointer, appends
1110             characters to supplied SV */
1111              
1112             #define CHARDATA_AMP_REF 0x01
1113             #define CHARDATA_LT_ERR 0x02
1114             #define CHARDATA_S_LINEAR 0x04
1115             #define CHARDATA_RBRBGT_ERR 0x08
1116             #define CHARDATA_NUL_END 0x10
1117              
1118             #define parse_chars(p, value, endc, flags) \
1119             THX_parse_chars(aTHX_ p, value, endc, flags)
1120 320830           static U8 *THX_parse_chars(pTHX_ U8 *p, SV *value, U8 endc, U32 flags)
1121             {
1122 320830           U8 *lstart = p;
1123 3415668           while(1) {
1124 3736498           U8 c = *p;
1125 3736498 100         if(c < 0x80) {
1126 3256484           U8 *lend = p;
1127             U32 val;
1128 3256484 100         if(c == endc && (c != ']' ||
    100          
1129 38 50         (p[1] == ']' && p[2] == '>')))
    50          
1130             break;
1131 2935864 100         if(c < 0x20) {
1132 480198 100         if(c == 0 && (flags & CHARDATA_NUL_END)) {
    100          
1133             break;
1134 480152 100         } else if(c == 0x9 || c == 0xa) {
    100          
1135 46           val = (flags & CHARDATA_S_LINEAR) ?
1136 46           0x20 : 0;
1137 480106 100         } else if(c == 0xd) {
1138 480092 100         if(p[1] == 0xa) p++;
1139 480092           val = (flags & CHARDATA_S_LINEAR) ?
1140 480092 100         0x20 : 0xa;
1141             } else
1142 14           throw_syntax_error(p);
1143 480138           p++;
1144 2455666 100         } else if(c == '&' && (flags & CHARDATA_AMP_REF)) {
    100          
1145 160358           val = parse_reference(&p);
1146 2295308 100         } else if((c == '<' && (flags & CHARDATA_LT_ERR)) ||
    100          
    100          
1147 112           (c == ']' &&
1148 112 100         (flags & CHARDATA_RBRBGT_ERR) &&
1149 80 100         p[1] == ']' && p[2] == '>')) {
    100          
1150 24           throw_syntax_error(p);
1151             } else {
1152 2295284           val = 0;
1153 2295284           p++;
1154             }
1155 2935654 100         if(val) {
1156             STRLEN vlen;
1157             U8 *vstart, *voldend, *vnewend;
1158 640332 100         if(lstart != lend)
1159 224           sv_catpvn_nomg(value, (char*)lstart,
1160             lend-lstart);
1161 640332           vlen = SvCUR(value);
1162 640332 50         vstart = (U8*)SvGROW(value, vlen+4+1);
    100          
1163 640332           voldend = vstart + vlen;
1164 640332           vnewend = uvchr_to_utf8_flags(voldend, val,
1165             UNICODE_ALLOW_ANY);
1166 640332           *vnewend = 0;
1167 640332           SvCUR_set(value, vnewend - vstart);
1168 640332           lstart = p;
1169             }
1170             } else {
1171 480014 50         if(!char_is_char(p)) throw_syntax_error(p);
1172 480014           p += UTF8SKIP(p);
1173             }
1174             }
1175 320666 100         if(lstart != p) sv_catpvn_nomg(value, (char*)lstart, p-lstart);
1176 320666           return p;
1177             }
1178              
1179             /* parse_comment(), parse_pi(): return updated pointer */
1180              
1181             #define parse_comment(p) THX_parse_comment(aTHX_ p)
1182 160048           static U8 *THX_parse_comment(pTHX_ U8 *p)
1183             {
1184 160048 50         if(!(p[0] == '<' && p[1] == '!' && p[2] == '-' && p[3] == '-'))
    50          
    100          
    50          
1185 6           throw_syntax_error(p);
1186 160042           p += 4;
1187             while(1) {
1188 1200174 100         if(*p == '-') {
1189 160044 100         if(*++p == '-') break;
1190             }
1191 1040134 100         if(!char_is_char(p)) throw_syntax_error(p);
1192 1040132           p += UTF8SKIP(p);
1193             }
1194 160040 100         if(p[1] != '>') throw_syntax_error(p);
1195 160032           return p + 2;
1196             }
1197              
1198             #define parse_pi(p) THX_parse_pi(aTHX_ p)
1199 60           static U8 *THX_parse_pi(pTHX_ U8 *p)
1200             {
1201             STRLEN tgtlen;
1202 60 50         if(!(p[0] == '<' && p[1] == '?')) throw_syntax_error(p);
    50          
1203 60           p += 2;
1204 60           tgtlen = parse_name(p);
1205 60 100         if(tgtlen == 3 && (p[0] & ~0x20) == 'X' &&
    50          
1206 6 50         (p[1] & ~0x20) == 'M' &&
1207 6 50         (p[2] & ~0x20) == 'L')
1208 6           throw_syntax_error(p);
1209 54           p += tgtlen;
1210 54 100         if(!(p[0] == '?' && p[1] == '>')) {
    50          
1211 22 100         if(!char_is_s(p)) throw_syntax_error(p);
1212 20           p++;
1213 880054 100         while(!(p[0] == '?' && p[1] == '>')) {
    50          
1214 880036 100         if(!char_is_char(p)) throw_syntax_error(p);
1215 880034           p += UTF8SKIP(p);
1216             }
1217             }
1218 50           return p + 2;
1219             }
1220              
1221             /* parse_twine(): parses content, guarantees to return only when
1222             facing the correct terminator ("
1223             returns reference to AV which alternates character data and element
1224             objects */
1225              
1226             #define CONTENT_TOPLEVEL (CHARDATA_AMP_REF|CHARDATA_RBRBGT_ERR| \
1227             CHARDATA_NUL_END)
1228             #define CONTENT_INSIDE (CHARDATA_AMP_REF|CHARDATA_RBRBGT_ERR)
1229              
1230             #define parse_element(pp) THX_parse_element(aTHX_ pp)
1231             static SV *THX_parse_element(pTHX_ U8 **pp);
1232              
1233             #define parse_twine(pp, chardata_flags) \
1234             THX_parse_twine(aTHX_ pp, chardata_flags)
1235 160572           static SV *THX_parse_twine(pTHX_ U8 **pp, U32 chardata_flags)
1236             {
1237 160572           U8 *p = *pp;
1238 160572           SV *chardata = newSVpvs("");
1239 160572           AV *twine = newAV();
1240 160572           SV *tref = sv_2mortal(newRV_noinc((SV*)twine));
1241 160572           SvUTF8_on(chardata);
1242 160572           av_push(twine, chardata);
1243 160572           SvREADONLY_on(tref);
1244 320156           while(1) {
1245 480728           U8 c = *p;
1246 480728 100         if(c != '<') {
1247 320520           p = parse_chars(p, chardata, '<', chardata_flags);
1248 320436 100         if((chardata_flags & CHARDATA_NUL_END) && *p == 0)
    100          
1249 46           break;
1250             }
1251 480598           c = p[1];
1252 480598 100         if(c == '/' && !(chardata_flags & CHARDATA_NUL_END)) break;
    50          
1253 320182 100         if(c == '!') {
1254 160076           c = p[2];
1255 160076 100         if(c == '-') {
1256 160036           p = parse_comment(p);
1257 40 50         } else if(c == '[' && p[3] == 'C' &&
    50          
1258 40 50         p[4] == 'D' && p[5] == 'A' &&
    50          
1259 40 50         p[6] == 'T' && p[7] == 'A' &&
    50          
1260 40 50         p[8] == '[') {
1261 40           p = parse_chars(p+9, chardata, ']', 0) + 3;
1262             } else
1263 0           throw_syntax_error(p);
1264 160106 100         } else if(c == '?') {
1265 52           p = parse_pi(p);
1266             } else {
1267 160054           SvREADONLY_on(chardata);
1268 160054           av_push(twine, SvREFCNT_inc(parse_element(&p)));
1269 160048           chardata = newSVpvs("");
1270 160048           SvUTF8_on(chardata);
1271 160048           av_push(twine, chardata);
1272             }
1273             }
1274 160462           *pp = p;
1275 160462           SvREADONLY_on(chardata);
1276 160462           SvREADONLY_on((SV*)twine);
1277 160462           return tref;
1278             }
1279              
1280             /* parse_contentobject(): parses content, guarantees to return only when
1281             facing the correct terminator ("
1282             returns reference to AV blessed into XML::Easy::Content (sole element
1283             is a reference to an AV which alternates character data and element
1284             objects) */
1285              
1286             #define parse_contentobject(p, chardata_flags) \
1287             THX_parse_contentobject(aTHX_ p, chardata_flags)
1288 160570           static SV *THX_parse_contentobject(pTHX_ U8 **pp, U32 chardata_flags)
1289             {
1290 160570           return twine_contentobject(parse_twine(pp, chardata_flags));
1291             }
1292              
1293             /* parse_element(): updates pointer in place, returns reference to AV blessed
1294             into XML::Easy::Element (first element is an SV containing the element
1295             type name, the second element is a reference to an HV containing the
1296             attributes, and the third element is a reference to the content object) */
1297              
1298 160992           static SV *THX_parse_element(pTHX_ U8 **pp)
1299             {
1300 160992           U8 *p = *pp;
1301             U8 *typename_start, *namestart;
1302             STRLEN typename_len, namelen;
1303             SV *typename;
1304             HV *attrs;
1305             SV *aref;
1306             AV *element;
1307             SV *eref;
1308             U8 c;
1309 160992 100         if(*p != '<') throw_syntax_error(p);
1310 160978           typename_start = ++p;
1311 160978           typename_len = parse_name(p);
1312 160948           p += typename_len;
1313 160948           typename = newSVpvn((char*)typename_start, typename_len);
1314 160948           SvUTF8_on(typename);
1315 160948           SvREADONLY_on(typename);
1316 160948           element = newAV();
1317 160948           av_extend(element, 2);
1318 160948           eref = sv_2mortal(newRV_noinc((SV*)element));
1319 160948           av_push(element, typename);
1320 160948           attrs = newHV();
1321 160948           aref = newRV_noinc((SV*)attrs);
1322 160948           SvREADONLY_on(aref);
1323 160948           av_push(element, aref);
1324 192           while(1) {
1325             SV *attval;
1326 161140           c = *p;
1327 161140 100         if(c == '>' || c == '/') break;
    100          
1328 302           p = parse_s(p);
1329 294           c = *p;
1330 294 100         if(c == '>' || c == '/') break;
    100          
1331 278           namelen = parse_name(p);
1332 278           namestart = p;
1333 278           p += namelen;
1334 278 100         if(hv_exists(attrs, (char*)namestart, -namelen))
1335 6           throw_wfc_error("duplicate attribute");
1336 272           p = parse_eq(p);
1337 270           c = *p;
1338 270 100         if(c != '"' && c != '\'') throw_syntax_error(p);
    50          
1339 270           attval = sv_2mortal(newSVpvs(""));
1340 270           SvUTF8_on(attval);
1341 270           p = parse_chars(p+1, attval, c,
1342             CHARDATA_AMP_REF|CHARDATA_LT_ERR|CHARDATA_S_LINEAR)
1343 192           + 1;
1344 192           SvREADONLY_on(attval);
1345 192 50         if(!hv_store(attrs, (char*)namestart, -namelen,
1346             SvREFCNT_inc(attval), 0))
1347 0           SvREFCNT_dec(attval);
1348             }
1349 160854           SvREADONLY_on((SV*)attrs);
1350 160854 100         if(c == '/') {
1351 332 100         if(*++p != '>') throw_syntax_error(p);
1352 320           av_push(element, SvREFCNT_inc(empty_contentobject));
1353             } else {
1354 160522           p++;
1355 160522           av_push(element,
1356             SvREFCNT_inc(
1357             parse_contentobject(&p, CONTENT_INSIDE)));
1358 160416           p += 2;
1359 160416           namelen = parse_name(p);
1360 160414 100         if(namelen != typename_len ||
1361 160410 100         memcmp(p, typename_start, namelen))
1362 12           throw_wfc_error("mismatched tags");
1363 160402           p += namelen;
1364 160402           p = parse_opt_s(p);
1365 160402 50         if(*p != '>') throw_syntax_error(p);
1366             }
1367 160722           *pp = p + 1;
1368 160722           sv_bless(eref, stash_element);
1369 160722           SvREADONLY_on((SV*)element);
1370 160722           SvREADONLY_on(eref);
1371 160722           return eref;
1372             }
1373              
1374             /* parse_opt_xmldecl(): parses optional XML declaration or text declaration,
1375             returns updated pointer */
1376              
1377             #define XMLDECL_VERSION 0x01
1378             #define XMLDECL_ENCODING 0x02
1379             #define XMLDECL_STANDALONE 0x03
1380              
1381             #define parse_opt_xmldecl(p, allow, require) \
1382             THX_parse_opt_xmldecl(aTHX_ p, allow, require)
1383 942           static U8 *THX_parse_opt_xmldecl(pTHX_ U8 *p, U32 allow, U32 require)
1384             {
1385             #if 0 /* unused, because throw_syntax_error() ignores its argument */
1386             U8 *start = p;
1387             #endif
1388 942           U32 found = 0;
1389 942 100         if(!(p[0] == '<' && p[1] == '?' && p[2] == 'x' && p[3] == 'm' &&
    100          
    100          
    50          
1390 74 50         p[4] == 'l' && p[5] <= 0x20))
    100          
1391 870           return p;
1392 72           p += 5;
1393 72 50         if(*p == '?') goto enddecl;
1394 72           p = parse_s(p);
1395 72 100         if(*p == '?') goto enddecl;
1396 70 100         if(p[0] == 'v' && p[1] == 'e' && p[2] == 'r' && p[3] == 's' &&
    50          
    50          
    50          
1397 68 50         p[4] == 'i' && p[5] == 'o' && p[6] == 'n') {
    50          
    50          
1398             U8 q;
1399 68           p = parse_eq(p + 7);
1400 68           q = p[0];
1401 68 100         if(q != '"' && q != '\'') throw_syntax_error(start);
    50          
1402 68 50         if(!(p[1] == '1' && p[2] == '.' && p[3] == '0' && p[4] == q))
    50          
    100          
    50          
1403 2           throw_syntax_error(start);
1404 66           p += 5;
1405 66           found |= XMLDECL_VERSION;
1406 66 100         if(*p == '?') goto enddecl;
1407 48           p = parse_s(p);
1408 48 100         if(*p == '?') goto enddecl;
1409             }
1410 46 100         if(p[0] == 'e' && p[1] == 'n' && p[2] == 'c' && p[3] == 'o' &&
    50          
    50          
    50          
1411 24 50         p[4] == 'd' && p[5] == 'i' && p[6] == 'n' &&
    50          
    50          
1412 24 50         p[7] == 'g') {
1413             U8 q;
1414 24           p = parse_eq(p + 8);
1415 24           q = *p;
1416 24 100         if(q != '"' && q != '\'') throw_syntax_error(start);
    50          
1417 24           p++;
1418 24 50         if(!char_is_encstart(p)) throw_syntax_error(start);
1419             do {
1420 132           p++;
1421 132 100         } while(char_is_enc(p));
1422 24 50         if(*p != q) throw_syntax_error(start);
1423 24           p++;
1424 24           found |= XMLDECL_ENCODING;
1425 24 100         if(*p == '?') goto enddecl;
1426 4           p = parse_s(p);
1427 4 50         if(*p == '?') goto enddecl;
1428             }
1429 22 100         if(p[0] == 's' && p[1] == 't' && p[2] == 'a' && p[3] == 'n' &&
    50          
    50          
    50          
1430 20 50         p[4] == 'd' && p[5] == 'a' && p[6] == 'l' &&
    50          
    50          
1431 20 50         p[7] == 'o' && p[8] == 'n' && p[9] == 'e') {
    50          
    50          
1432             U8 q;
1433 20           p = parse_eq(p + 10);
1434 20           q = p[0];
1435 20 100         if(q != '"' && q != '\'') throw_syntax_error(start);
    50          
1436 20 100         if(!((p[1] == 'y' && p[2] == 'e' && p[3] == 's' && p[4] == q)
    50          
    50          
    50          
1437 4 100         || (p[1] == 'n' && p[2] == 'o' && p[3] == q)))
    50          
    50          
1438 2           throw_syntax_error(start);
1439 18 100         p += p[1] == 'y' ? 5 : 4;
1440 18           found |= XMLDECL_STANDALONE;
1441 18 100         if(*p == '?') goto enddecl;
1442 4           p = parse_s(p);
1443 4 50         if(*p == '?') goto enddecl;
1444             }
1445 2           throw_syntax_error(start);
1446 66           enddecl:
1447 66 50         if(!(p[1] == '>' && !(found & ~allow) && !(require & ~found)))
    50          
    100          
1448 6           throw_syntax_error(start);
1449 60           return p + 2;
1450             }
1451              
1452             /* parse_misc_seq(): returns updated pointer */
1453              
1454             #define parse_misc_seq(p) THX_parse_misc_seq(aTHX_ p)
1455 1556           static U8 *THX_parse_misc_seq(pTHX_ U8 *p)
1456             {
1457 62           while(1) {
1458 1618           U8 c = p[0];
1459 1618 100         if(c == 0) break;
1460 968 100         if(c == '<') {
1461 910           c = p[1];
1462 910 100         if(c == '!') {
1463 12           p = parse_comment(p);
1464 898 100         } else if(c == '?') {
1465 8           p = parse_pi(p);
1466             } else {
1467 890           break;
1468             }
1469             } else {
1470 58           p = parse_s(p);
1471             }
1472             }
1473 1540           return p;
1474             }
1475              
1476             /*
1477             * serialisation
1478             *
1479             * The serialise_*() functions each serialise some syntactic construct
1480             * within the XML grammar. Their main input is an SV to which they append
1481             * the textual form of the item in question.
1482             */
1483              
1484             #define check_encname(enc) THX_check_encname(aTHX_ enc)
1485 4053           static void THX_check_encname(pTHX_ SV *enc)
1486             {
1487             U8 *p, *end;
1488             STRLEN len;
1489 4053 100         if(!sv_is_string(enc))
    50          
    100          
1490 48           throw_data_error("encoding name isn't a string");
1491 4005           p = (U8*)SvPV(enc, len);
1492 4005 100         if(len == 0) throw_data_error("illegal encoding name");
1493 4001           end = p + len;
1494 4001 100         if(!char_is_encstart(p)) throw_data_error("illegal encoding name");
1495             while(1) {
1496 7215385           p++;
1497 7215385 100         if(p == end) return;
1498 7212344 100         if(!char_is_enc(p)) throw_data_error("illegal encoding name");
1499             }
1500             }
1501              
1502             #define is_name(p, len) THX_is_name(aTHX_ p, len)
1503 183451           static int THX_is_name(pTHX_ U8 *p, STRLEN len)
1504             {
1505 183451           U8 *end = p + len;
1506 183451 100         if(!char_is_namestart(p)) return 0;
1507             do {
1508 76281057           p += UTF8SKIP(p);
1509 76281057 100         if(p == end) return 1;
1510 76106240 100         } while(char_is_name(p));
1511 3528           return 0;
1512             }
1513              
1514             static U8 const hexdig[16] = "0123456789abcdef";
1515              
1516             #define serialise_chardata(out, data) THX_serialise_chardata(aTHX_ out, data)
1517 321972           static void THX_serialise_chardata(pTHX_ SV *out, SV *data)
1518             {
1519             STRLEN datalen;
1520             U8 *datastart, *dataend, *p, *lstart;
1521 321972 100         if(!sv_is_string(data))
    50          
    100          
1522 156           throw_data_error("character data isn't a string");
1523 321816           data = upgrade_sv(data);
1524 321816           datastart = (U8*)SvPV(data, datalen);
1525 321816           dataend = datastart + datalen;
1526 321816           lstart = p = datastart;
1527 9073138           while(1) {
1528 9394954           U8 c = *p;
1529 9394954 100         if(c == 0) break;
1530 9074386 100         if(c == 0xd || c == '<' || c == '&' ||
    100          
    100          
    100          
1531 70 100         (c == '>' && p-lstart >= 2 &&
1532 32 100         p[-1] == ']' && p[-2] == ']')) {
    100          
1533 80066           U8 refbuf[6] = "&#xXX;";
1534 80066 100         if(lstart != p)
1535 46           sv_catpvn_nomg(out, (char*)lstart, p-lstart);
1536 80066           refbuf[3] = hexdig[c >> 4];
1537 80066           refbuf[4] = hexdig[c & 0xf];
1538 80066           sv_catpvn(out, (char*)refbuf, 6);
1539 80066           lstart = ++p;
1540             } else {
1541 8994320 100         if(!char_is_char(p))
1542 1248           throw_data_error("character data contains "
1543             "illegal character");
1544 8993072           p += UTF8SKIP(p);
1545             }
1546             }
1547 320568 100         if(p != dataend)
1548 96           throw_data_error("character data contains illegal character");
1549 320472 100         if(lstart != p) sv_catpvn_nomg(out, (char*)lstart, p-lstart);
1550 320472           }
1551              
1552             #define serialise_element(out, elem) THX_serialise_element(aTHX_ out, elem)
1553             static void THX_serialise_element(pTHX_ SV *out, SV *elem);
1554              
1555             #define serialise_twine(out, tref) THX_serialise_twine(aTHX_ out, tref)
1556 162019           static void THX_serialise_twine(pTHX_ SV *out, SV *tref)
1557             {
1558             AV *twine;
1559             array_ix_t clen, i;
1560             SV **item_ptr;
1561 162019 100         if(!SvROK(tref)) throw_data_error("content array isn't an array");
1562 162001           twine = (AV*)SvRV(tref);
1563 162001 100         if(SvTYPE((SV*)twine) != SVt_PVAV || SvOBJECT((SV*)twine))
    100          
1564 27           throw_data_error("content array isn't an array");
1565 161974           clen = av_len(twine);
1566 161974 100         if(clen & 1) throw_data_error("content array has even length");
1567 161950           item_ptr = av_fetch(twine, 0, 0);
1568 161950 50         if(!item_ptr) throw_data_error("character data isn't a string");
1569 161950           serialise_chardata(out, *item_ptr);
1570 320472 100         for(i = 0; i != clen; ) {
1571 160214           item_ptr = av_fetch(twine, ++i, 0);
1572 160214 50         if(!item_ptr)
1573 0           throw_data_error("element data isn't an element");
1574 160214           serialise_element(out, *item_ptr);
1575 160022           item_ptr = av_fetch(twine, ++i, 0);
1576 160022 50         if(!item_ptr)
1577 0           throw_data_error("character data isn't a string");
1578 160022           serialise_chardata(out, *item_ptr);
1579             }
1580 160258           }
1581              
1582             #define serialise_contentobject(out, cref) \
1583             THX_serialise_contentobject(aTHX_ out, cref)
1584 161249           static void THX_serialise_contentobject(pTHX_ SV *out, SV *cref)
1585             {
1586 161249           serialise_twine(out, contentobject_twine(cref));
1587 160256           }
1588              
1589             #define serialise_eithercontent(out, cref) \
1590             THX_serialise_eithercontent(aTHX_ out, cref)
1591 1827           static void THX_serialise_eithercontent(pTHX_ SV *out, SV *cref)
1592             {
1593             SV *tgt;
1594 1827 100         if(SvROK(cref) && (tgt = SvRV(cref), SvTYPE(tgt) == SVt_PVAV) &&
    100          
1595 1794 100         !SvOBJECT(tgt)) {
1596 860           serialise_twine(out, cref);
1597             } else {
1598 967           serialise_contentobject(out, cref);
1599             }
1600 24           }
1601              
1602             #define twine_is_empty(tref) THX_twine_is_empty(aTHX_ tref)
1603 160344           static int THX_twine_is_empty(pTHX_ SV *tref)
1604             {
1605             AV *twine;
1606             SV **item_ptr;
1607             SV *item;
1608 160344 50         if(!SvROK(tref)) return 0;
1609 160344           twine = (AV*)SvRV(tref);
1610 160344 50         if(SvTYPE((SV*)twine) != SVt_PVAV || SvOBJECT((SV*)twine)) return 0;
    50          
1611 160344 100         if(av_len(twine) != 0) return 0;
1612 160334           item_ptr = av_fetch(twine, 0, 0);
1613 160334 50         if(!item_ptr) return 0;
1614 160334           item = *item_ptr;
1615 160334 50         if(!SvOK(item) || SvROK(item)) return 0;
    50          
1616 160334 50         return SvPOK(item) && SvCUR(item) == 0;
    100          
1617             }
1618              
1619             #define content_is_empty(cref) THX_content_is_empty(aTHX_ cref)
1620 160392           static int THX_content_is_empty(pTHX_ SV *cref)
1621             {
1622             AV *twine;
1623             SV **item_ptr;
1624 160392 100         if(!SvROK(cref)) return 0;
1625 160374           twine = (AV*)SvRV(cref);
1626 160374 100         if(SvTYPE((SV*)twine) != SVt_PVAV || av_len(twine) != 0) return 0;
    100          
1627 160347 100         if(!SvOBJECT((SV*)twine) || SvSTASH((SV*)twine) != stash_content)
    50          
1628 3           return 0;
1629 160344           item_ptr = av_fetch(twine, 0, 0);
1630 160344 50         if(!item_ptr) return 0;
1631 160344           return twine_is_empty(*item_ptr);
1632             }
1633              
1634             #define serialise_attvalue(out, data) THX_serialise_attvalue(aTHX_ out, data)
1635 1632           static void THX_serialise_attvalue(pTHX_ SV *out, SV *data)
1636             {
1637             STRLEN datalen;
1638             U8 *datastart, *dataend, *p, *lstart;
1639 1632 100         if(!sv_is_string(data))
    50          
    100          
1640 156           throw_data_error("character data isn't a string");
1641 1476           data = upgrade_sv(data);
1642 1476           datastart = (U8*)SvPV(data, datalen);
1643 1476           dataend = datastart + datalen;
1644 1476           lstart = p = datastart;
1645 7543094           while(1) {
1646 7544570           U8 c = *p;
1647 7544570 100         if(c == 0) break;
1648 7544342 100         if(c == 0x9 || c == 0xa || c == 0xd || c == '<' || c == '&' ||
    100          
    100          
    100          
    100          
    100          
1649 80014           c == '"') {
1650 80014           U8 refbuf[6] = "&#xXX;";
1651 80014 100         if(lstart != p)
1652 16           sv_catpvn_nomg(out, (char*)lstart, p-lstart);
1653 80014           refbuf[3] = hexdig[c >> 4];
1654 80014           refbuf[4] = hexdig[c & 0xf];
1655 80014           sv_catpvn(out, (char*)refbuf, 6);
1656 80014           lstart = ++p;
1657             } else {
1658 7464328 100         if(!char_is_char(p))
1659 1248           throw_data_error("character data contains "
1660             "illegal character");
1661 7463080           p += UTF8SKIP(p);
1662             }
1663             }
1664 228 100         if(p != dataend)
1665 96           throw_data_error("character data contains illegal character");
1666 132 50         if(lstart != p) sv_catpvn_nomg(out, (char*)lstart, p-lstart);
1667 132           }
1668              
1669 167844           static void THX_serialise_element(pTHX_ SV *out, SV *eref)
1670             {
1671             AV *earr;
1672             SV **item_ptr;
1673             SV *typename, *attrs, *content;
1674             HV *ahash;
1675             U8 *typename_start;
1676             STRLEN typename_len;
1677             U32 nattrs;
1678 167844           earr = element_nodearray(eref);
1679 167604           sv_catpvs_nomg(out, "<");
1680 167604           item_ptr = av_fetch(earr, 0, 0);
1681 167604 50         if(!item_ptr) throw_data_error("element type name isn't a string");
1682 167604           typename = *item_ptr;
1683 167604 100         if(!sv_is_string(typename))
    50          
    100          
1684 117           throw_data_error("element type name isn't a string");
1685 167487           typename = upgrade_sv(typename);
1686 167487           typename_start = (U8*)SvPV(typename, typename_len);
1687 167487 100         if(!is_name(typename_start, typename_len))
1688 1953           throw_data_error("illegal element type name");
1689 165534           sv_catpvn_nomg(out, (char*)typename_start, typename_len);
1690 165534           item_ptr = av_fetch(earr, 1, 0);
1691 165534 50         if(!item_ptr) throw_data_error("attribute hash isn't a hash");
1692 165534           attrs = *item_ptr;
1693 165534 100         if(!SvROK(attrs)) throw_data_error("attribute hash isn't a hash");
1694 165498           ahash = (HV*)SvRV(attrs);
1695 165498 100         if(SvTYPE((SV*)ahash) != SVt_PVHV || SvOBJECT((SV*)ahash))
    100          
1696 60           throw_data_error("attribute hash isn't a hash");
1697 165438           nattrs = hv_iterinit(ahash);
1698 165438 100         if(nattrs != 0) {
1699 5126 100         if(nattrs == 1) {
1700             STRLEN klen;
1701             U8 *key;
1702 3430           HE *ent = hv_iternext(ahash);
1703 3430           sv_catpvs_nomg(out, " ");
1704 3430 50         key = (U8*)HePV(ent, klen);
1705 3430 100         if(!HeKUTF8(ent)) upgrade_latin1_pvn(&key, &klen);
1706 3430 100         if(!is_name(key, klen))
1707 2604           throw_data_error("illegal attribute name");
1708 826           sv_catpvn_nomg(out, (char*)key, klen);
1709 826           sv_catpvs_nomg(out, "=\"");
1710 826           serialise_attvalue(out, HeVAL(ent));
1711 76           sv_catpvs_nomg(out, "\"");
1712             } else {
1713             U32 i;
1714 1696           AV *keys = newAV();
1715 1696           sv_2mortal((SV*)keys);
1716 1696           av_extend(keys, nattrs-1);
1717 172644 100         for(i = nattrs; i--; ) {
1718 170948           SV *keysv = upgrade_sv(
1719             hv_iterkeysv(hv_iternext(ahash)));
1720 170948           SvREFCNT_inc(keysv);
1721 170948           av_push(keys, keysv);
1722             }
1723 1696           sortsv(AvARRAY(keys), nattrs, Perl_sv_cmp);
1724 1752 100         for(i = 0; i != nattrs; i++) {
1725             SV *keysv;
1726             STRLEN klen;
1727             U8 *key;
1728 1748           sv_catpvs_nomg(out, " ");
1729 1748           keysv = *av_fetch(keys, i, 0);
1730 1748           key = (U8*)SvPV(keysv, klen);
1731 1748 100         if(!is_name(key, klen))
1732 942           throw_data_error("illegal attribute "
1733             "name");
1734 806           sv_catpvn_nomg(out, (char*)key, klen);
1735 806           sv_catpvs_nomg(out, "=\"");
1736 806           serialise_attvalue(out,
1737             *hv_fetch(ahash, (char*)key, -klen,
1738             0));
1739 56           sv_catpvs_nomg(out, "\"");
1740             }
1741             }
1742             }
1743 160392           item_ptr = av_fetch(earr, 2, 0);
1744 160392 50         if(!item_ptr) throw_data_error("content data isn't a content chunk");
1745 160392           content = *item_ptr;
1746 160392 100         if(content_is_empty(content)) {
1747 110           sv_catpvs_nomg(out, "/>");
1748             } else {
1749 160282           sv_catpvs_nomg(out, ">");
1750 160282           serialise_contentobject(out, content);
1751 160234           sv_catpvs_nomg(out, "
1752 160234           sv_catpvn_nomg(out, (char*)typename_start, typename_len);
1753 160234           sv_catpvs_nomg(out, ">");
1754             }
1755 160344           }
1756              
1757             MODULE = XML::Easy PACKAGE = XML::Easy::Content
1758              
1759             PROTOTYPES: DISABLE
1760              
1761             BOOT:
1762             /* stash stashes */
1763 7           stash_content = gv_stashpvs("XML::Easy::Content", 1);
1764 7           stash_element = gv_stashpvs("XML::Easy::Element", 1);
1765             /* stash shared empty-content object */
1766             {
1767             SV *chardata;
1768             AV *twine;
1769             SV *tref;
1770             AV *content;
1771             SV *cref;
1772 7           chardata = newSVpvs("");
1773 7           SvREADONLY_on(chardata);
1774 7           twine = newAV();
1775 7           av_push(twine, chardata);
1776 7           SvREADONLY_on((SV*)twine);
1777 7           tref = newRV_noinc((SV*)twine);
1778 7           SvREADONLY_on(tref);
1779 7           content = newAV();
1780 7           av_push(content, tref);
1781 7           cref = newRV_noinc((SV*)content);
1782 7           sv_bless(cref, stash_content);
1783 7           SvREADONLY_on((SV*)content);
1784 7           SvREADONLY_on(cref);
1785 7           empty_contentobject = cref;
1786             }
1787              
1788             SV *
1789             new(SV *classname, SV *tref)
1790             CODE:
1791             PERL_UNUSED_VAR(classname);
1792 12754           RETVAL = twine_contentobject(usertwine_twine(tref));
1793 7305           SvREFCNT_inc(RETVAL);
1794             OUTPUT:
1795             RETVAL
1796              
1797             SV *
1798             twine(SV *cref)
1799             CODE:
1800 9260           RETVAL = contentobject_twine(cref);
1801 9260           SvREFCNT_inc(RETVAL);
1802             OUTPUT:
1803             RETVAL
1804              
1805             MODULE = XML::Easy PACKAGE = XML::Easy::Element
1806              
1807             SV *
1808             new(SV *classname, SV *type_name, SV *attrs, SV *content)
1809             PREINIT:
1810             U8 *p;
1811             STRLEN len;
1812             HV *iahash, *oahash;
1813             U32 nattrs;
1814             SV *tgt;
1815             AV *earr;
1816             CODE:
1817             PERL_UNUSED_VAR(classname);
1818 6828 100         if(!sv_is_string(type_name))
    50          
    100          
1819 91           throw_data_error("element type name isn't a string");
1820 6737           type_name = sv_mortalcopy(type_name);
1821 6737           sv_utf8_upgrade(type_name);
1822 6737           SvREADONLY_on(type_name);
1823 6737           p = (U8*)SvPV(type_name, len);
1824 6737 100         if(!is_name(p, len)) throw_data_error("illegal element type name");
1825 5218 100         if(!SvROK(attrs)) throw_data_error("attribute hash isn't a hash");
1826 5206           iahash = (HV*)SvRV(attrs);
1827 5206 100         if(SvTYPE((SV*)iahash) != SVt_PVHV || SvOBJECT((SV*)iahash))
    100          
1828 20           throw_data_error("attribute hash isn't a hash");
1829 5186           oahash = newHV();
1830 5186           attrs = sv_2mortal(newRV_noinc((SV*)oahash));
1831 5186           SvREADONLY_on(attrs);
1832 5186           nattrs = hv_iterinit(iahash);
1833 5186 100         if(nattrs != 0) {
1834 2363 100         if(nattrs == 1) {
1835             STRLEN klen;
1836             U8 *key;
1837 1780           HE *ent = hv_iternext(iahash);
1838 1780 50         key = (U8*)HePV(ent, klen);
1839 1780 100         if(!HeKUTF8(ent)) upgrade_latin1_pvn(&key, &klen);
1840 1780 100         if(!is_name(key, klen))
1841 868           throw_data_error("illegal attribute name");
1842 912           tgt = userchardata_chardata(HeVAL(ent));
1843 662 50         if(!hv_store(oahash, (char *)key, -klen,
1844             SvREFCNT_inc(tgt), 0))
1845 0           SvREFCNT_dec(tgt);
1846             } else {
1847             U32 i;
1848 583           AV *keys = newAV();
1849 583           sv_2mortal((SV*)keys);
1850 583           av_extend(keys, nattrs-1);
1851 57880 100         for(i = nattrs; i--; ) {
1852 57297           SV *keysv = upgrade_sv(
1853             hv_iterkeysv(hv_iternext(iahash)));
1854 57297           SvREFCNT_inc(keysv);
1855 57297           av_push(keys, keysv);
1856             }
1857 583           sortsv(AvARRAY(keys), nattrs, Perl_sv_cmp);
1858 916 100         for(i = 0; i != nattrs; i++) {
1859             SV *keysv;
1860             STRLEN klen;
1861             U8 *key;
1862 897           keysv = *av_fetch(keys, i, 0);
1863 897           key = (U8*)SvPV(keysv, klen);
1864 897 100         if(!is_name(key, klen))
1865 314           throw_data_error("illegal attribute "
1866             "name");
1867 583           tgt = *hv_fetch(iahash, (char*)key, -klen, 0);
1868 583           tgt = userchardata_chardata(tgt);
1869 333 50         if(!hv_store(oahash, (char *)key, -klen,
1870             SvREFCNT_inc(tgt), 0))
1871 0           SvREFCNT_dec(tgt);
1872             }
1873             }
1874             }
1875 3504           SvREADONLY_on((SV*)oahash);
1876 3504 100         if(!SvROK(content))
1877 6           throw_data_error("content data isn't a content chunk");
1878 3498           tgt = SvRV(content);
1879 3498 100         if(!SvOBJECT(tgt) && SvTYPE(tgt) == SVt_PVAV) {
    100          
1880 1333           content = twine_contentobject(usertwine_twine(content));
1881 2165 100         } else if(SvOBJECT(tgt) && SvSTASH(tgt) == stash_content) {
    100          
1882 2157           content = sv_2mortal(newRV_inc(tgt));
1883 2157           SvREADONLY_on(content);
1884             } else {
1885 8           throw_data_error("content data isn't a content chunk");
1886             }
1887 3204           earr = newAV();
1888 3204           av_extend(earr, 2);
1889 3204           av_push(earr, SvREFCNT_inc(type_name));
1890 3204           av_push(earr, SvREFCNT_inc(attrs));
1891 3204           av_push(earr, SvREFCNT_inc(content));
1892 3204           RETVAL = newRV_noinc((SV*)earr);
1893 3204           sv_bless(RETVAL, stash_element);
1894 3204           SvREADONLY_on(earr);
1895 3204           SvREADONLY_on(RETVAL);
1896             OUTPUT:
1897             RETVAL
1898              
1899             SV *
1900             type_name(SV *eref)
1901             PREINIT:
1902             AV *earr;
1903             SV **item_ptr;
1904             CODE:
1905 218           earr = element_nodearray(eref);
1906 218           item_ptr = av_fetch(earr, 0, 0);
1907 218 50         if(!item_ptr) throw_data_error("element type name isn't a string");
1908 218           RETVAL = SvREFCNT_inc(*item_ptr);
1909             OUTPUT:
1910             RETVAL
1911              
1912             SV *
1913             attributes(SV *eref)
1914             PREINIT:
1915             AV *earr;
1916             SV **item_ptr;
1917             CODE:
1918 534           earr = element_nodearray(eref);
1919 534           item_ptr = av_fetch(earr, 1, 0);
1920 534 50         if(!item_ptr) throw_data_error("attribute hash isn't a hash");
1921 534           RETVAL = SvREFCNT_inc(*item_ptr);
1922             OUTPUT:
1923             RETVAL
1924              
1925             SV *
1926             attribute(SV *eref, SV *attrname_sv)
1927             PREINIT:
1928             U8 *attrname;
1929             STRLEN attrname_len;
1930             AV *earr;
1931             HV *ahash;
1932             SV **item_ptr, *attrs;
1933             CODE:
1934 1398 100         if(!sv_is_string(attrname_sv))
    50          
    100          
1935 26           throw_data_error("attribute name isn't a string");
1936 1372           attrname_sv = upgrade_sv(attrname_sv);
1937 1372           attrname = (U8*)SvPV(attrname_sv, attrname_len);
1938 1372 100         if(!is_name(attrname, attrname_len))
1939 434           throw_data_error("illegal attribute name");
1940 938           earr = element_nodearray(eref);
1941 938           item_ptr = av_fetch(earr, 1, 0);
1942 938 50         if(!item_ptr) throw_data_error("attribute hash isn't a hash");
1943 938           attrs = *item_ptr;
1944 938 50         if(!SvROK(attrs)) throw_data_error("attribute hash isn't a hash");
1945 938           ahash = (HV*)SvRV(attrs);
1946 938 50         if(SvTYPE((SV*)ahash) != SVt_PVHV || SvOBJECT((SV*)ahash))
    50          
1947 0           throw_data_error("attribute hash isn't a hash");
1948 938 100         if(hv_exists(ahash, (char *)attrname, -attrname_len)) {
1949 354           item_ptr = hv_fetch(ahash, (char *)attrname, -attrname_len, 0);
1950 354 50         RETVAL = item_ptr ? SvREFCNT_inc(*item_ptr) : &PL_sv_undef;
1951             } else {
1952 584           RETVAL = &PL_sv_undef;
1953             }
1954             OUTPUT:
1955             RETVAL
1956              
1957             SV *
1958             content_object(SV *eref)
1959             PREINIT:
1960             AV *earr;
1961             SV **item_ptr;
1962             CODE:
1963 1586           earr = element_nodearray(eref);
1964 1586           item_ptr = av_fetch(earr, 2, 0);
1965 1586 50         if(!item_ptr) throw_data_error("content data isn't a content chunk");
1966 1586           RETVAL = SvREFCNT_inc(*item_ptr);
1967             OUTPUT:
1968             RETVAL
1969              
1970             SV *
1971             content_twine(SV *eref)
1972             PREINIT:
1973             AV *earr;
1974             SV **item_ptr;
1975             CODE:
1976 1618           earr = element_nodearray(eref);
1977 1618           item_ptr = av_fetch(earr, 2, 0);
1978 1618 50         if(!item_ptr) throw_data_error("content data isn't a content chunk");
1979 1618           RETVAL = contentobject_twine(*item_ptr);
1980 1618           SvREFCNT_inc(RETVAL);
1981             OUTPUT:
1982             RETVAL
1983              
1984             MODULE = XML::Easy PACKAGE = XML::Easy::Text
1985              
1986             SV *
1987             xml10_read_content_object(SV *text_sv)
1988             PROTOTYPE: $
1989             PREINIT:
1990             STRLEN text_len;
1991             U8 *p, *end;
1992             CODE:
1993 38 100         if(!sv_is_string(text_sv)) throw_data_error("text isn't a string");
    50          
    100          
1994 25           text_sv = upgrade_sv(text_sv);
1995 25           p = (U8*)SvPV(text_sv, text_len);
1996 25           end = p + text_len;
1997 25           RETVAL = parse_contentobject(&p, CONTENT_TOPLEVEL);
1998 21 50         if(p != end) throw_syntax_error(p);
1999 21           SvREFCNT_inc(RETVAL);
2000             OUTPUT:
2001             RETVAL
2002              
2003             SV *
2004             xml10_read_content_twine(SV *text_sv)
2005             PROTOTYPE: $
2006             PREINIT:
2007             STRLEN text_len;
2008             U8 *p, *end;
2009             CODE:
2010 14 100         if(!sv_is_string(text_sv)) throw_data_error("text isn't a string");
    50          
    100          
2011 1           text_sv = upgrade_sv(text_sv);
2012 1           p = (U8*)SvPV(text_sv, text_len);
2013 1           end = p + text_len;
2014 1           RETVAL = parse_twine(&p, CONTENT_TOPLEVEL);
2015 1 50         if(p != end) throw_syntax_error(p);
2016 1           SvREFCNT_inc(RETVAL);
2017             OUTPUT:
2018             RETVAL
2019              
2020             SV *
2021             xml10_read_element(SV *text_sv)
2022             PROTOTYPE: $
2023             PREINIT:
2024             STRLEN text_len;
2025             U8 *p, *end;
2026             CODE:
2027 57 100         if(!sv_is_string(text_sv)) throw_data_error("text isn't a string");
    50          
    100          
2028 44           text_sv = upgrade_sv(text_sv);
2029 44           p = (U8*)SvPV(text_sv, text_len);
2030 44           end = p + text_len;
2031 44           RETVAL = parse_element(&p);
2032 24 100         if(p != end) throw_syntax_error(p);
2033 16           SvREFCNT_inc(RETVAL);
2034             OUTPUT:
2035             RETVAL
2036              
2037             SV *
2038             xml10_read_document(SV *text_sv)
2039             PROTOTYPE: $
2040             PREINIT:
2041             STRLEN text_len;
2042             U8 *p, *end;
2043             CODE:
2044 929 100         if(!sv_is_string(text_sv)) throw_data_error("text isn't a string");
    50          
    100          
2045 916           text_sv = upgrade_sv(text_sv);
2046 916           p = (U8*)SvPV(text_sv, text_len);
2047 916           end = p + text_len;
2048 916           p = parse_opt_xmldecl(p,
2049             XMLDECL_VERSION|XMLDECL_ENCODING|XMLDECL_STANDALONE,
2050             XMLDECL_VERSION);
2051 906           p = parse_misc_seq(p);
2052 894           RETVAL = parse_element(&p);
2053 650           p = parse_misc_seq(p);
2054 646 100         if(p != end) throw_syntax_error(p);
2055 644           SvREFCNT_inc(RETVAL);
2056             OUTPUT:
2057             RETVAL
2058              
2059             SV *
2060             xml10_read_extparsedent_object(SV *text_sv)
2061             PROTOTYPE: $
2062             PREINIT:
2063             STRLEN text_len;
2064             U8 *p, *end;
2065             CODE:
2066 38 100         if(!sv_is_string(text_sv)) throw_data_error("text isn't a string");
    50          
    100          
2067 25           text_sv = upgrade_sv(text_sv);
2068 25           p = (U8*)SvPV(text_sv, text_len);
2069 25           end = p + text_len;
2070 25           p = parse_opt_xmldecl(p, XMLDECL_VERSION|XMLDECL_ENCODING,
2071             XMLDECL_ENCODING);
2072 23           RETVAL = parse_contentobject(&p, CONTENT_TOPLEVEL);
2073 23 50         if(p != end) throw_syntax_error(p);
2074 23           SvREFCNT_inc(RETVAL);
2075             OUTPUT:
2076             RETVAL
2077              
2078             SV *
2079             xml10_read_extparsedent_twine(SV *text_sv)
2080             PROTOTYPE: $
2081             PREINIT:
2082             STRLEN text_len;
2083             U8 *p, *end;
2084             CODE:
2085 14 100         if(!sv_is_string(text_sv)) throw_data_error("text isn't a string");
    50          
    100          
2086 1           text_sv = upgrade_sv(text_sv);
2087 1           p = (U8*)SvPV(text_sv, text_len);
2088 1           end = p + text_len;
2089 1           p = parse_opt_xmldecl(p, XMLDECL_VERSION|XMLDECL_ENCODING,
2090             XMLDECL_ENCODING);
2091 1           RETVAL = parse_twine(&p, CONTENT_TOPLEVEL);
2092 1 50         if(p != end) throw_syntax_error(p);
2093 1           SvREFCNT_inc(RETVAL);
2094             OUTPUT:
2095             RETVAL
2096              
2097             SV *
2098             xml10_write_content(SV *cont)
2099             PROTOTYPE: $
2100             CODE:
2101 619           RETVAL = sv_2mortal(newSVpvs(""));
2102 619           SvUTF8_on(RETVAL);
2103 619           serialise_eithercontent(RETVAL, cont);
2104 18           SvREFCNT_inc(RETVAL);
2105             OUTPUT:
2106             RETVAL
2107              
2108             SV *
2109             xml10_write_element(SV *elem)
2110             PROTOTYPE: $
2111             CODE:
2112 2754           RETVAL = sv_2mortal(newSVpvs(""));
2113 2754           SvUTF8_on(RETVAL);
2114 2754           serialise_element(RETVAL, elem);
2115 318           SvREFCNT_inc(RETVAL);
2116             OUTPUT:
2117             RETVAL
2118              
2119             SV *
2120             xml10_write_document(SV *elem, SV *enc = &PL_sv_undef)
2121             PROTOTYPE: $;$
2122             CODE:
2123 5382           RETVAL = sv_2mortal(newSVpvs("
2124 5382           SvUTF8_on(RETVAL);
2125 5382 100         if(SvOK(enc) || SvTYPE(enc) == SVt_PVGV) {
    50          
2126 2944           check_encname(enc);
2127 2438           sv_catpvs_nomg(RETVAL, " encoding=\"");
2128 2438           sv_catsv_nomg(RETVAL, enc);
2129 2438           sv_catpvs_nomg(RETVAL, "\" standalone=\"yes\"?>\n");
2130             } else {
2131 2438           sv_catpvs_nomg(RETVAL, " standalone=\"yes\"?>\n");
2132             }
2133 4876           serialise_element(RETVAL, elem);
2134 4           sv_catpvs_nomg(RETVAL, "\n");
2135 4           SvREFCNT_inc(RETVAL);
2136             OUTPUT:
2137             RETVAL
2138              
2139             SV *
2140             xml10_write_extparsedent(SV *cont, SV *enc = &PL_sv_undef)
2141             PROTOTYPE: $;$
2142             CODE:
2143 1714           RETVAL = sv_2mortal(newSVpvs(""));
2144 1714           SvUTF8_on(RETVAL);
2145 1714 100         if(SvOK(enc) || SvTYPE(enc) == SVt_PVGV) {
    50          
2146 1109           check_encname(enc);
2147 603           sv_catpvs_nomg(RETVAL, "
2148 603           sv_catsv_nomg(RETVAL, enc);
2149 603           sv_catpvs_nomg(RETVAL, "\"?>");
2150             }
2151 1208           serialise_eithercontent(RETVAL, cont);
2152 6           SvREFCNT_inc(RETVAL);
2153             OUTPUT:
2154             RETVAL