Add ARM files
[dh-make-perl] / dev / arm / libhtml-parser-perl / libhtml-parser-perl-3.56 / util.c
1 /* $Id: util.c,v 2.30 2006/03/22 09:15:17 gisle Exp $
2  *
3  * Copyright 1999-2006, Gisle Aas.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the same terms as Perl itself.
7  */
8
9 #ifndef EXTERN
10 #define EXTERN extern
11 #endif
12
13
14 EXTERN SV*
15 sv_lower(pTHX_ SV* sv)
16 {
17     STRLEN len;
18     char *s = SvPV_force(sv, len);
19     for (; len--; s++)
20         *s = toLOWER(*s);
21     return sv;
22 }
23
24 EXTERN int
25 strnEQx(const char* s1, const char* s2, STRLEN n, int ignore_case)
26 {
27     while (n--) {
28         if (ignore_case) {
29             if (toLOWER(*s1) != toLOWER(*s2))
30                 return 0;
31         }
32         else {
33             if (*s1 != *s2)
34                 return 0;
35         }
36         s1++;
37         s2++;
38     }
39     return 1;
40 }
41
42 static void
43 grow_gap(pTHX_ SV* sv, STRLEN grow, char** t, char** s, char** e)
44 {
45     /*
46      SvPVX ---> AAAAAA...BBBBBB
47                      ^   ^     ^
48                      t   s     e
49     */
50     STRLEN t_offset = *t - SvPVX(sv);
51     STRLEN s_offset = *s - SvPVX(sv);
52     STRLEN e_offset = *e - SvPVX(sv);
53
54     SvGROW(sv, e_offset + grow + 1);
55
56     *t = SvPVX(sv) + t_offset;
57     *s = SvPVX(sv) + s_offset;
58     *e = SvPVX(sv) + e_offset;
59
60     Move(*s, *s+grow, *e - *s, char);
61     *s += grow;
62     *e += grow;
63 }
64
65 EXTERN SV*
66 decode_entities(pTHX_ SV* sv, HV* entity2char, bool expand_prefix)
67 {
68     STRLEN len;
69     char *s = SvPV_force(sv, len);
70     char *t = s;
71     char *end = s + len;
72     char *ent_start;
73
74     char *repl;
75     STRLEN repl_len;
76 #ifdef UNICODE_HTML_PARSER
77     char buf[UTF8_MAXLEN];
78     int repl_utf8;
79     int high_surrogate = 0;
80 #else
81     char buf[1];
82 #endif
83
84 #if defined(__GNUC__) && defined(UNICODE_HTML_PARSER)
85     /* gcc -Wall reports this variable as possibly used uninitialized */
86     repl_utf8 = 0;
87 #endif
88
89     while (s < end) {
90         assert(t <= s);
91
92         if ((*t++ = *s++) != '&')
93             continue;
94
95         ent_start = s;
96         repl = 0;
97
98         if (s < end && *s == '#') {
99             UV num = 0;
100             UV prev = 0;
101             int ok = 0;
102             s++;
103             if (s < end && (*s == 'x' || *s == 'X')) {
104                 s++;
105                 while (s < end) {
106                     char *tmp = strchr(PL_hexdigit, *s);
107                     if (!tmp)
108                         break;
109                     num = num << 4 | ((tmp - PL_hexdigit) & 15);
110                     if (prev && num <= prev) {
111                         /* overflow */
112                         ok = 0;
113                         break;
114                     }
115                     prev = num;
116                     s++;
117                     ok = 1;
118                 }
119             }
120             else {
121                 while (s < end && isDIGIT(*s)) {
122                     num = num * 10 + (*s - '0');
123                     if (prev && num < prev) {
124                         /* overflow */
125                         ok = 0;
126                         break;
127                     }
128                     prev = num;
129                     s++;
130                     ok = 1;
131                 }
132             }
133             if (ok) {
134 #ifdef UNICODE_HTML_PARSER
135                 if (!SvUTF8(sv) && num <= 255) {
136                     buf[0] = (char) num;
137                     repl = buf;
138                     repl_len = 1;
139                     repl_utf8 = 0;
140                 }
141                 else {
142                     char *tmp;
143                     if ((num & 0xFFFFFC00) == 0xDC00) {  /* low-surrogate */
144                         if (high_surrogate != 0) {
145                             t -= 3; /* Back up past 0xFFFD */
146                             num = ((high_surrogate - 0xD800) << 10) +
147                                 (num - 0xDC00) + 0x10000;
148                             high_surrogate = 0;
149                         } else {
150                             num = 0xFFFD;
151                         }
152                     }
153                     else if ((num & 0xFFFFFC00) == 0xD800) { /* high-surrogate */
154                         high_surrogate = num;
155                         num = 0xFFFD;
156                     }
157                     else {
158                         high_surrogate = 0;
159                         /* otherwise invalid? */
160                         if ((num >= 0xFDD0 && num <= 0xFDEF) ||
161                             ((num & 0xFFFE) == 0xFFFE) ||
162                             num > 0x10FFFF)
163                         {
164                             num = 0xFFFD;
165                         }
166                     }
167
168                     tmp = (char*)uvuni_to_utf8((U8*)buf, num);
169                     repl = buf;
170                     repl_len = tmp - buf;
171                     repl_utf8 = 1;
172                 }
173 #else
174                 if (num <= 255) {
175                     buf[0] = (char) num & 0xFF;
176                     repl = buf;
177                     repl_len = 1;
178                 }
179 #endif
180             }
181         }
182         else {
183             char *ent_name = s;
184             while (s < end && isALNUM(*s))
185                 s++;
186             if (ent_name != s && entity2char) {
187                 SV** svp;
188                 if (              (svp = hv_fetch(entity2char, ent_name, s - ent_name, 0)) ||
189                     (*s == ';' && (svp = hv_fetch(entity2char, ent_name, s - ent_name + 1, 0)))
190                    )
191                 {
192                     repl = SvPV(*svp, repl_len);
193 #ifdef UNICODE_HTML_PARSER
194                     repl_utf8 = SvUTF8(*svp);
195 #endif
196                 }
197                 else if (expand_prefix) {
198                     char *ss = s - 1;
199                     while (ss > ent_name) {
200                         svp = hv_fetch(entity2char, ent_name, ss - ent_name, 0);
201                         if (svp) {
202                             repl = SvPV(*svp, repl_len);
203 #ifdef UNICODE_HTML_PARSER
204                             repl_utf8 = SvUTF8(*svp);
205 #endif
206                             s = ss;
207                             break;
208                         }
209                         ss--;
210                     }
211                 }
212             }
213 #ifdef UNICODE_HTML_PARSER
214             high_surrogate = 0;
215 #endif
216         }
217
218         if (repl) {
219             char *repl_allocated = 0;
220             if (s < end && *s == ';')
221                 s++;
222             t--;  /* '&' already copied, undo it */
223
224 #ifdef UNICODE_HTML_PARSER
225             if (*s != '&') {
226                 high_surrogate = 0;
227             }
228
229             if (!SvUTF8(sv) && repl_utf8) {
230                 /* need to upgrade sv before we continue */
231                 STRLEN before_gap_len = t - SvPVX(sv);
232                 char *before_gap = (char*)bytes_to_utf8((U8*)SvPVX(sv), &before_gap_len);
233                 STRLEN after_gap_len = end - s;
234                 char *after_gap = (char*)bytes_to_utf8((U8*)s, &after_gap_len);
235
236                 sv_setpvn(sv, before_gap, before_gap_len);
237                 sv_catpvn(sv, after_gap, after_gap_len);
238                 SvUTF8_on(sv);
239
240                 Safefree(before_gap);
241                 Safefree(after_gap);
242
243                 s = t = SvPVX(sv) + before_gap_len;
244                 end = SvPVX(sv) + before_gap_len + after_gap_len;
245             }
246             else if (SvUTF8(sv) && !repl_utf8) {
247                 repl = (char*)bytes_to_utf8((U8*)repl, &repl_len);
248                 repl_allocated = repl;
249             }
250 #endif
251
252             if (t + repl_len > s) {
253                 /* need to grow the string */
254                 grow_gap(aTHX_ sv, repl_len - (s - t), &t, &s, &end);
255             }
256
257             /* copy replacement string into string */
258             while (repl_len--)
259                 *t++ = *repl++;
260
261             if (repl_allocated)
262                 Safefree(repl_allocated);
263         }
264         else {
265             while (ent_start < s)
266                 *t++ = *ent_start++;
267         }
268     }
269
270     *t = '\0';
271     SvCUR_set(sv, t - SvPVX(sv));
272
273     return sv;
274 }
275
276 #ifdef UNICODE_HTML_PARSER
277 static bool
278 has_hibit(char *s, char *e)
279 {
280     while (s < e) {
281         U8 ch = *s++;
282         if (!UTF8_IS_INVARIANT(ch)) {
283             return 1;
284         }
285     }
286     return 0;
287 }
288
289
290 EXTERN bool
291 probably_utf8_chunk(pTHX_ char *s, STRLEN len)
292 {
293     char *e = s + len;
294     STRLEN clen;
295
296     /* ignore partial utf8 char at end of buffer */
297     while (s < e && UTF8_IS_CONTINUATION((U8)*(e - 1)))
298         e--;
299     if (s < e && UTF8_IS_START((U8)*(e - 1)))
300         e--;
301     clen = len - (e - s);
302     if (clen && UTF8SKIP(e) == clen) {
303         /* all promised continuation bytes are present */
304         e = s + len;
305     }
306
307     if (!has_hibit(s, e))
308         return 0;
309
310     return is_utf8_string((U8*)s, e - s);
311 }
312 #endif