Branch data Line data Source code
1 : : /* zxns.c - Namespace manipulation functions for generated (and other) code
2 : : * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 : : * Copyright (c) 2006-2008 Symlabs (symlabs@symlabs.com), All Rights Reserved.
4 : : * Author: Sampo Kellomaki (sampo@iki.fi)
5 : : * This is confidential unpublished proprietary source code of the author.
6 : : * NO WARRANTY, not even implied warranties. Contains trade secrets.
7 : : * Distribution prohibited unless authorized in writing.
8 : : * Licensed under Apache License 2.0, see file COPYING.
9 : : * $Id: zxns.c,v 1.7 2009-08-22 13:56:34 sampo Exp $
10 : : *
11 : : * 28.5.2006, created --Sampo
12 : : * 8.8.2006, moved lookup functions to generated code --Sampo
13 : : * 12.8.2006, added special scanning of xmlns to avoid backtracking elem recognition --Sampo
14 : : * 26.8.2006, significant Common Subexpression Elimination (CSE) --Sampo
15 : : * 30.9.2007, rework namespaces, esp. previously unknown namespaces --Sampo
16 : : * 7.10.2008, added documentation --Sampo
17 : : * 27.10.2010, re-engineered namespace handling --Sampo
18 : : */
19 : :
20 : : #include <string.h>
21 : :
22 : : #include "errmac.h"
23 : : #include "zx.h"
24 : : #include "c/zx-data.h"
25 : : #include "c/zx-ns.h"
26 : :
27 : : /* ------------- All the manner namespace management ------------- */
28 : :
29 : : #if 0
30 : : /* Called by: */
31 : : void zx_fix_any_elem_dec(struct zx_ctx* c, struct zx_elem_s* x, const char* nam, int namlen)
32 : : {
33 : : char* p = memchr(nam, ':', namlen);
34 : : if (p) {
35 : : x->gg.g.ns = zx_locate_ns_by_prefix(c, p-nam, nam);
36 : : ++p;
37 : : namlen -= p-nam;
38 : : nam = p;
39 : : }
40 : : x->name = (char*)nam;
41 : : x->name_len = namlen;
42 : : }
43 : :
44 : : /*() Given known namespace, does the prefix refer to it, either natively or through an alias. */
45 : :
46 : : /* Called by: */
47 : : int zx_is_ns_prefix(struct zx_ns_s* ns, int len, const char* prefix)
48 : : {
49 : : struct zx_ns_s* alias;
50 : : if (!ns)
51 : : return 0;
52 : : if (ns->prefix_len == len && (!len || !memcmp(ns->prefix, prefix, len)))
53 : : return 1;
54 : : for (alias = ns->n; alias; alias = alias->n)
55 : : if (alias->prefix_len == len && (!len || !memcmp(alias->prefix, prefix, len)))
56 : : return 1;
57 : : return 0;
58 : : }
59 : : #endif
60 : :
61 : : /*() Debugging function. You can say in gdb: print zx_dump_ns_tab(c,0) */
62 : :
63 : : /* Called by: */
64 : : int zx_dump_ns_tab(struct zx_ctx* c, int flags)
65 : 2 : {
66 : : struct zx_ns_s* ns;
67 : : struct zx_ns_s* alias;
68 : 2 : int n_ns = c->n_ns;
69 : 2 : int n=0;
70 [ - + ]: 2 : for (ns = c->ns_tab; n < n_ns; ++ns) {
71 : 0 : printf("%3d NS %8.*s %.*s\n", ++n, ns->prefix_len, ns->prefix, ns->url_len, ns->url);
72 [ # # ]: 0 : for (alias = ns->n; alias; alias = alias->n)
73 : 0 : printf("%3d A %8.*s %.*s\n", ++n, alias->prefix_len, alias->prefix, alias->url_len, alias->url);
74 : : }
75 [ - + ]: 2 : for (alias = c->unknown_ns; alias; alias = alias->n) {
76 : 0 : printf("%3d UNK %8.*s %.*s\n", ++n, alias->prefix_len, alias->prefix, alias->url_len, alias->url);
77 : : }
78 : 2 : return n;
79 : : }
80 : :
81 : : /* Profiling of 0.69 on 20101024 shows that 31% of the enc-dec time is spent here.
82 : : * Surprisingly, the namespace is never found! The only return that executes is 0.
83 : : * Input was t/azrq1.xml, where in our understanding all prefixes are known.
84 : : * After fixing a bug related to xmlns declarations being fed to here, the function
85 : : * was never called. Could we safely delete this? */
86 : :
87 : : /* Called by: zx_fix_any_elem_dec, zx_init_tok_tab, zx_prefix_seen_whine, zx_xmlns_decl */
88 : : static struct zx_ns_s* zx_locate_ns_by_prefix(struct zx_ctx* c, int len, const char* prefix)
89 : 12359 : {
90 : : struct zx_ns_s* ns;
91 : : struct zx_ns_s* alias;
92 [ + + ]: 14008 : for (ns = c->unknown_ns; ns; ns = ns->n)
93 [ + + + + : 7720 : if (ns->prefix_len == len && (!len || !memcmp(ns->prefix, prefix, len)))
+ + ]
94 : 6071 : return ns;
95 [ - + ]: 6288 : for (ns = c->ns_tab; ns->url_len; ++ns) {
96 [ # # # # : 0 : if (ns->prefix_len == len && (!len || !memcmp(ns->prefix, prefix, len)))
# # ]
97 : 0 : return ns;
98 [ # # ]: 0 : for (alias = ns->n; alias; alias = alias->n)
99 [ # # # # : 0 : if (alias->prefix_len == len && (!len || !memcmp(alias->prefix, prefix, len)))
# # ]
100 : 0 : return ns;
101 : : }
102 : 6288 : return 0;
103 : : }
104 : :
105 : : /* Profiling of 0.69 on 20101024 shows that 64% of the enc-dec time is spent here.
106 : : * Here the namespace is always found via return ns, but not before searching through
107 : : * oodles of aliases. After bug fix, this consumes 95% of the zxencdectest run time!
108 : : * After further bug fixing eliminating scanning (and accumulation) of aliases, the run time went
109 : : * down by two orders of magnitude. Final solution is the namespace hash lookup. */
110 : :
111 : : /* Called by: zx_xmlns_decl */
112 : : static struct zx_ns_s* zx_locate_ns_by_url(struct zx_ctx* c, int len, const char* url)
113 : 722460 : {
114 : : struct zx_ns_s* ns;
115 [ + + ]: 987256 : for (ns = c->unknown_ns; ns; ns = ns->n)
116 [ + + + - : 293087 : if (ns->url_len == len && (!len || !memcmp(ns->url, url, len)))
+ + ]
117 : 28291 : return ns;
118 : 694169 : return zx_url2ns(url, len); /* lookup in perfect hash generated by xsd2sg and gperf */
119 : : }
120 : :
121 : : /* Called by: zx_xmlns_decl */
122 : : static struct zx_ns_s* zx_new_known_ns(struct zx_ctx* c, int prefix_len, const char* prefix, struct zx_ns_s* known_ns)
123 : 718370 : {
124 : 718370 : struct zx_ns_s* ns = ZX_ZALLOC(c, struct zx_ns_s);
125 : 718370 : ns->prefix_len = prefix_len;
126 : 718370 : ns->prefix = prefix;
127 : 718370 : ns->url_len = known_ns->url_len;
128 : 718370 : ns->url = known_ns->url;
129 : 718370 : ns->master = known_ns;
130 : 718370 : return ns;
131 : : }
132 : :
133 : : /* Called by: zx_prefix_seen_whine, zx_xmlns_decl */
134 : : static struct zx_ns_s* zx_new_unknown_ns(struct zx_ctx* c, int prefix_len, const char* prefix, int url_len, const char* url)
135 : 6288 : {
136 : 6288 : struct zx_ns_s* ns = ZX_ZALLOC(c, struct zx_ns_s);
137 : 6288 : ns->prefix_len = prefix_len;
138 : 6288 : ns->url_len = url_len;
139 : : /* Reallocating these is necessary for unknown namespaces */
140 : 6288 : ns->prefix = ZX_ALLOC(c, prefix_len+1);
141 [ + + ]: 6288 : if (prefix_len)
142 : 2142 : memcpy((char*)ns->prefix, prefix, prefix_len);
143 : 6288 : *((char*)ns->prefix+prefix_len) = 0;
144 : 6288 : ns->url = ZX_ALLOC(c, url_len+1);
145 [ + - ]: 6288 : if (url_len)
146 : 6288 : memcpy((char*)ns->url, url, url_len);
147 : 6288 : *((char*)ns->url+url_len) = 0;
148 : 6288 : return ns;
149 : : }
150 : :
151 : : /*() Process XML namespace declaration, trying to match it by its declared namespace URI.
152 : : * Should this fail, we will attempt to match by customary (at least in our opinion)
153 : : * namespace prefixes. If duplicate namespaces are detected, they are handled as aliases. */
154 : :
155 : : /* Called by: zx_push_seen x2 */
156 : : static struct zx_ns_s* zx_xmlns_decl(struct zx_ctx* c, int prefix_len, const char* prefix, int url_len, const char* url)
157 : 722460 : {
158 : : struct zx_ns_s* alias;
159 : : struct zx_ns_s* new_ns;
160 : : struct zx_ns_s* ns;
161 : :
162 : 722460 : ns = zx_locate_ns_by_url(c, url_len, url);
163 [ + + ]: 722460 : if (!ns) {
164 [ + + - + ]: 4090 : D("Namespace(%.*s) not found by URL(%.*s) (probably unknown or wrong namespace URL)", prefix_len, prefix, url_len, url);
165 : 4090 : zx_xml_parse_dbg(c, '-', __FUNCTION__, "Namespace here");
166 : 4090 : ns = zx_locate_ns_by_prefix(c, prefix_len, prefix);
167 [ + - ]: 4090 : if (!ns) {
168 : : /* Namespace not known by compiled in schemata. */
169 [ + + - + ]: 4090 : D("Namespace not found by prefix(%.*s) or URL(%.*s) (probably unknown or wrong namespace URL)", prefix_len, prefix, url_len, url);
170 : 4090 : new_ns = zx_new_unknown_ns(c, prefix_len, prefix, url_len, url);
171 : 4090 : new_ns->n = c->unknown_ns;
172 : 4090 : c->unknown_ns = new_ns;
173 : 4090 : return new_ns;
174 : : }
175 : : }
176 : : /* Always alloc a new one because we may need to push to stack multiple instances of same ns. */
177 : 718370 : new_ns = zx_new_known_ns(c, prefix_len, prefix, ns);
178 : :
179 : : /* Avoid adding to alias list if prefix is already known. */
180 [ + + + + : 718370 : if (ns->prefix_len == prefix_len && (!prefix_len || !memcmp(ns->prefix, prefix, prefix_len)))
+ + ]
181 : : goto known_prefix;
182 [ - + ]: 1752 : for (alias = ns->n; alias; alias = alias->n)
183 [ # # # # : 0 : if (alias->prefix_len == prefix_len && (!prefix_len || !memcmp(alias->prefix, prefix, prefix_len)))
# # ]
184 : : goto known_prefix;
185 : :
186 [ + + - + ]: 1752 : D("New prefix(%.*s) known URL(%.*s)", prefix_len, prefix, url_len, url);
187 : 1752 : ns->n = new_ns->n;
188 : 1752 : new_ns->n = ns;
189 : 718370 : known_prefix:
190 : 718370 : return new_ns;
191 : : }
192 : :
193 : : /*() Scan the seen list (expected to be relatively short so scan
194 : : * is not a perfomance issue). The scan walks the doubly linked
195 : : * list of currently active seen prefixes (as opposed to seen_pop). */
196 : :
197 : : /* Called by: zx_prefix_seen_whine, zx_push_seen, zxsig_validate */
198 : : struct zx_ns_s* zx_prefix_seen(struct zx_ctx* c, int len, const char* prefix)
199 : 3116687 : {
200 : : struct zx_ns_s* ns;
201 [ + + + + ]: 3116687 : if (len == 3 && !memcmp(prefix, "xml", 3))
202 : 1503 : return zx_ns_tab + (zx_xml_NS >> ZX_TOK_NS_SHIFT);
203 [ + + ]: 5426537 : for (ns = c->guard_seen_n.seen_n; ns->seen_n; ns = ns->seen_n)
204 [ + + + + : 4695810 : if (ns->prefix_len == len && (!len || !memcmp(ns->prefix, prefix, len)))
+ + ]
205 : 2384457 : return ns;
206 : 730727 : return 0;
207 : : }
208 : :
209 : : #define zx_unknown_prefix "urn:zxid:unknown-ns-prefix"
210 : :
211 : : /*() zx_prefix_seen_whine() is a good place to detect, and add stub for,
212 : : * wholly unknown prefixes. Seldom returns NULL, just always makes something up. */
213 : :
214 : : /* Called by: zx_attr_lookup, zx_el_lookup */
215 : : struct zx_ns_s* zx_prefix_seen_whine(struct zx_ctx* c, int len, const char* prefix, const char* logkey, int mk_dummy_ns)
216 : 839465 : {
217 : : struct zx_str* url;
218 : 839465 : struct zx_ns_s* ns = zx_prefix_seen(c, len, prefix);
219 [ + + ]: 839465 : if (!ns) {
220 : : /* Try to locate the namespace by the prefix from among the namespaces
221 : : * naturally known to zxid. */
222 : 8269 : ns = zx_locate_ns_by_prefix(c, len, prefix);
223 [ + + ]: 8269 : if (!ns) {
224 [ + - ]: 2198 : if (mk_dummy_ns) {
225 [ + + ]: 2198 : url = zx_strf(c, "%s:%s:%.*s", zx_unknown_prefix, logkey, len, STRNULLCHK(prefix));
226 : 2198 : ns = zx_new_unknown_ns(c, len, prefix, url->len, url->s);
227 : 2198 : ns->n = c->unknown_ns;
228 : 2198 : c->unknown_ns = ns;
229 [ + + - + ]: 2198 : D("Undefined namespace prefix(%.*s). NS not known from any context. Creating dummy ns(%.*s).", len, prefix, url->len, url->s);
230 : 2198 : ZX_FREE(c, url);
231 : : } else {
232 [ # # # # ]: 0 : D("Undefined namespace prefix(%.*s) at(%s). NS not known from any context.", len, prefix, logkey);
233 : 0 : return 0;
234 : : }
235 : : } else {
236 [ - + # # ]: 6071 : if (len != 3 || memcmp(prefix, "xml", 3)) {
237 [ + + - + ]: 6071 : D("Undefined namespace prefix(%.*s) at(%s) mapped to uri(%.*s) by built-in table.", len, prefix, logkey, ns->url_len, ns->url);
238 : : }
239 : : }
240 : : }
241 : 839465 : return ns;
242 : : }
243 : :
244 : : /*() See if prefix has been seen, and in the same meaning. If not, allocate
245 : : * a new node and push or add it to the doubly linked list as well as to the
246 : : * pop_seen list. Returns 0 if no addition was done (i.e. ns had been seen already). */
247 : :
248 : : /* Called by: zx_add_xmlns_if_not_seen, zx_len_xmlns_if_not_seen, zx_scan_xmlns */
249 : : static struct zx_ns_s* zx_push_seen(struct zx_ctx* c, int prefix_len, const char* prefix, int url_len, const char* url, struct zx_ns_s** pop_seen)
250 : 2277221 : {
251 : : struct zx_ns_s* old_ns;
252 : : struct zx_ns_s* ns;
253 : 2277221 : old_ns = zx_prefix_seen(c, prefix_len, prefix);
254 [ + + ]: 2277221 : if (old_ns) {
255 [ + + + - : 1554763 : if (old_ns->url_len == url_len && (!url_len || !memcmp(old_ns->url, url, url_len)))
+ - ]
256 : 1554761 : return 0;
257 : 2 : ns = zx_xmlns_decl(c, prefix_len, prefix, url_len, url);
258 : 2 : ns->seen = old_ns; /* Push */
259 : 2 : ns->seen_n = old_ns->seen_n; /* Replace old_ns in middle of the list */
260 : 2 : ns->seen_p = old_ns->seen_p;
261 : 2 : old_ns->seen_n->seen_p = ns;
262 : 2 : old_ns->seen_p->seen_n = ns;
263 : : } else {
264 : 722458 : ns = zx_xmlns_decl(c, prefix_len, prefix, url_len, url);
265 : 722458 : ns->seen_n = c->guard_seen_n.seen_n; /* Add to beginning of seen_n list. */
266 : 722458 : c->guard_seen_n.seen_n = ns;
267 : 722458 : ns->seen_n->seen_p = ns;
268 : 722458 : ns->seen_p = &c->guard_seen_n;
269 : : }
270 : 722460 : ns->seen_pop = *pop_seen;
271 : 722460 : *pop_seen = ns;
272 : 722460 : return ns;
273 : : }
274 : :
275 : : /* Called by: TXENC_SO_ELNAME, TXLEN_SO_ELNAME, zx_DEC_elem, zx_ENC_WO_any_elem, zx_LEN_WO_any_elem, zxsig_validate */
276 : : void zx_pop_seen(struct zx_ns_s* ns)
277 : 2837107 : {
278 [ + + ]: 3559715 : for (; ns; ns = ns->seen_pop) {
279 [ + + ]: 722608 : if (ns->seen) {
280 : 2 : ns->seen->seen_n = ns->seen_n; /* Replace ns with old_ns (ns->seen) in middle of list */
281 : 2 : ns->seen->seen_p = ns->seen_p;
282 : 2 : ns->seen_n->seen_p = ns->seen;
283 : 2 : ns->seen_p->seen_n = ns->seen;
284 : : } else {
285 : 722606 : ns->seen_n->seen_p = ns->seen_p; /* Remove ns from middle of the seen_n list. */
286 : 722606 : ns->seen_p->seen_n = ns->seen_n;
287 : : }
288 : : }
289 : 2837107 : }
290 : :
291 : : /*() Collect namespaces from element */
292 : :
293 : : /* Called by: sig_validate x3, zxid_chk_sig, zxid_sp_dig_sso_a7n, zxid_sp_sso_finalize */
294 : : void zx_see_elem_ns(struct zx_ctx* c, struct zx_ns_s** pop_seen, struct zx_elem_s* el)
295 : 145 : {
296 : : struct zx_ns_s* ns;
297 [ + + ]: 293 : for (ns = el->xmlns; ns; ns = ns->n) {
298 : : /*zx_push_seen(c, xmlns->);*/
299 : 148 : ns->seen_n = c->guard_seen_n.seen_n; /* Add to beginning of seen_n list. */
300 : 148 : c->guard_seen_n.seen_n = ns;
301 : 148 : ns->seen_n->seen_p = ns;
302 : 148 : ns->seen_p = &c->guard_seen_n;
303 : 148 : ns->seen_pop = *pop_seen;
304 : 148 : *pop_seen = ns;
305 : : }
306 : 145 : }
307 : :
308 : : /*() When trying to scan an element, an annoying feature of XML namespaces is that the
309 : : * namespace may be declared in a xmlns attribute within the element itself. Thus
310 : : * at the time of scanning the <ns:element part we can't know its namespace. What
311 : : * a lousy design. In order to handle this we need to either backtrack or
312 : : * make a special case forward scan for xmlns attributes (which is redundant with
313 : : * normal attribute scanning). It seems simpler to do the latter, so here goes...
314 : : * (besides, the forward scan will prime the cache)
315 : : *
316 : : * The return value represents the list of namespaces that were newly declared
317 : : * at this level, i.e. pushed to the seen stacks. This list is used to pop the
318 : : * seen stacks after we are through with the element. */
319 : :
320 : : /* Called by: zx_el_lookup */
321 : : struct zx_ns_s* zx_scan_xmlns(struct zx_ctx* c)
322 : 730174 : {
323 : 730174 : struct zx_ns_s* pop_seen = 0; /* build a list of namespaces declared here */
324 : : const char* prefix;
325 : : const char* url;
326 : 730174 : const char* p = c->p; /* We need to keep the original c->p so normal attrs can be scanned. */
327 : : char quote;
328 : : int prefix_len, url_len;
329 : :
330 : : /* The tag name has already been detected. Process attributes until '>' */
331 : :
332 : 717120 : for ( ; 1; ++p) {
333 [ - + ]: 1447294 : ZX_SKIP_WS_P(c, p, pop_seen);
334 [ + + + + ]: 1447294 : if (ONE_OF_2(*p, '>', '/'))
335 : : break;
336 [ + + ]: 717120 : if (!memcmp(p, "xmlns", sizeof("xmlns")-1)) {
337 [ + + - ]: 219503 : switch (p[5]) {
338 : : case '=': /* Default namespace decl. */
339 : 2017 : prefix = p += 5;
340 : 2017 : goto scan_URL;
341 : : case ':': /* Qualified namespace decl. */
342 : 217486 : prefix = p += 6;
343 : 217486 : quote = '=';
344 [ + - ]: 217486 : ZX_LOOK_FOR_P(c,'=',p);
345 : 219503 : scan_URL:
346 : 219503 : ++p;
347 [ + + - + ]: 219503 : if (!ONE_OF_2(*p, '"', '\''))
348 : 0 : return pop_seen;
349 : 219503 : quote = *p;
350 : 219503 : url = ++p;
351 [ + - ]: 219503 : ZX_LOOK_FOR_P(c, quote, p);
352 : :
353 : 219503 : prefix_len = (url - 2) - prefix;
354 : 219503 : url_len = p - url;
355 : 219503 : zx_push_seen(c, prefix_len, prefix, url_len, url, &pop_seen);
356 : 219503 : goto next;
357 : : default:
358 : 0 : zx_xml_parse_err(c, p[5], (const char*)__FUNCTION__, "Illformed attributes. Bad char");
359 : 0 : return pop_seen;
360 : : }
361 : : }
362 : :
363 : : /* Skip over any other attributes. */
364 : :
365 : 497617 : quote = '=';
366 [ + - ]: 497617 : ZX_LOOK_FOR_P(c,'=',p);
367 : 497617 : ++p;
368 [ - + # # ]: 497617 : if (!ONE_OF_2(*p, '"', '\''))
369 : 0 : return pop_seen;
370 : 497617 : quote = *p;
371 : 497617 : ++p;
372 [ + - ]: 497617 : ZX_LOOK_FOR_P(c,quote,p);
373 : 717120 : next:
374 : : continue;
375 : 717120 : }
376 : 730174 : return pop_seen;
377 : :
378 : 0 : look_for_not_found:
379 : 0 : zx_xml_parse_err(c, quote, (const char*)__FUNCTION__, "char not found");
380 : 0 : return pop_seen;
381 : : }
382 : :
383 : : #if 0 /* *** schedule to remove */
384 : : /*() Disambiguate token by considering its namespace.
385 : : * See zx_attr_lookup(), zx_elem_lookup()
386 : : * For attributes the namespaceless case is considered. */
387 : :
388 : : /* Called by: */
389 : : const struct zx_tok* zx_tok_by_ns(const struct zx_tok* zt, const struct zx_tok* lim, int len, const char* name, struct zx_ns_s* ns)
390 : : {
391 : : struct zx_ns_s* alias;
392 : : const struct zx_tok* ztt;
393 : :
394 : : /* First find token whose name matches. The token table CAN have duplicate entries,
395 : : * see -D flag to gperf. */
396 : : for (; zt < lim && (memcmp(zt->name, name, len) || zt->name[len]); ++zt) ;
397 : : if (zt >= lim)
398 : : return 0; /* Not found! */
399 : : ztt = zt; /* Remember first "hit" in case we fail. */
400 : :
401 : : /* If no namespace was specified, then token must also be namespaceless */
402 : : if (!ns) {
403 : : if (!zt->ns)
404 : : return zt;
405 : : for (; zt < lim && (!memcmp(zt->name, name, len) && !zt->name[len]); ++zt)
406 : : if (!zt->ns)
407 : : return zt;
408 : : return ztt;
409 : : }
410 : : /* Now check for namespace match. */
411 : : for (; zt < lim && (!memcmp(zt->name, name, len) && !zt->name[len]); ++zt)
412 : : for (alias = zt->ns; alias; alias = alias->n)
413 : : if (alias == ns)
414 : : return zt;
415 : : return ztt;
416 : : }
417 : : #endif
418 : :
419 : : #if 0
420 : : /*(-) N.B. Generally this function is not needed since tokens can be arranged
421 : : * to point to respective struct zx_ns_s at compile time using static
422 : : * initialization. This is handled by xsd2sg.pl */
423 : :
424 : : /* Called by: */
425 : : int zx_init_tok_tab(struct zx_ctx* c, struct zx_tok* tok_tab, struct zx_tok* tok_tab_lim)
426 : : {
427 : : for (; tok_tab < tok_tab_lim; ++tok_tab)
428 : : if (!(tok_tab->ns = zx_locate_ns_by_prefix(c, strlen(tok_tab->prefix), (char*)tok_tab->prefix)))
429 : : return 0;
430 : : return 1;
431 : :
432 : : /*if (!zx_init_tok_tab(&ctx, zx_elems, zx_elems + sizeof(zx_elems) / sizeof(struct zx_tok))) DIE("Inconsistency between tokens and namespaces");*/
433 : : }
434 : : #endif
435 : :
436 : : /* Called by: zx_LEN_WO_any_elem x2, zx_len_inc_ns */
437 : : int zx_len_xmlns_if_not_seen(struct zx_ctx* c, struct zx_ns_s* ns, struct zx_ns_s** pop_seenp)
438 : 1511632 : {
439 [ + + ]: 1511632 : if (!ns)
440 : 482773 : return 0;
441 [ + + ]: 1028859 : if (!zx_push_seen(c, ns->prefix_len, ns->prefix, ns->url_len, ns->url, pop_seenp))
442 : 776945 : return 0;
443 : : /* Check for undeclared empty prefix, as seen in namespaceless XML */
444 [ + - + + : 251914 : if ((!ns->prefix || !*ns->prefix)
+ - ]
445 : : && !memcmp(ns->url, zx_unknown_prefix, sizeof(zx_unknown_prefix))-1)
446 : 11434 : return 0;
447 [ + + ]: 240480 : return sizeof(" xmlns")-1
448 : : + (ns->prefix_len ? ns->prefix_len+1 : 0) + 2 + ns->url_len + 1;
449 : : }
450 : :
451 : : /*() For WO encoder the order of xmlns declarations is not known at compile
452 : : * time. Thus we first add them to the pop_seen list using insertion
453 : : * sort (pop_seen is smallest and prefixes grow from there) and
454 : : * then later render the list using zx_enc_seen(). */
455 : :
456 : : /* Called by: zx_ENC_WO_any_elem, zx_add_inc_ns, zx_see_attr_ns */
457 : : void zx_add_xmlns_if_not_seen(struct zx_ctx* c, struct zx_ns_s* ns, struct zx_ns_s** pop_seenp)
458 : 1511632 : {
459 : 1511632 : struct zx_ns_s* pop_seen_dummy=0;
460 : : struct zx_ns_s* new_ns;
461 : : int res;
462 [ + + ]: 1511632 : if (!ns)
463 : 482773 : return;
464 : 1028859 : new_ns = zx_push_seen(c, ns->prefix_len, ns->prefix, ns->url_len, ns->url, &pop_seen_dummy);
465 [ + + ]: 1028859 : if (!new_ns)
466 : 776945 : return;
467 [ + + ]: 251914 : if (!*pop_seenp) {
468 : 213531 : *pop_seenp = new_ns;
469 : 213531 : return;
470 : : }
471 [ - + ]: 38383 : if (!new_ns->prefix_len) { /* Default namespace (empty prefix) sorts first. */
472 : 247 : first:
473 : 247 : new_ns->seen_pop = *pop_seenp;
474 : 247 : *pop_seenp = new_ns;
475 : 247 : return;
476 : : }
477 : :
478 : 38383 : ns = *pop_seenp;
479 [ + - ]: 38383 : if (ns->prefix_len) {
480 : 38383 : res = memcmp(ns->prefix, new_ns->prefix, MIN(ns->prefix_len, new_ns->prefix_len));
481 [ + + - + : 38383 : if (res > 0 || !res && ns->prefix_len >= new_ns->prefix_len)
# # ]
482 : : goto first;
483 : : }
484 [ + + ]: 38136 : for (; ns->seen_pop; ns = ns->seen_pop) {
485 : 943 : res = memcmp(ns->seen_pop->prefix, new_ns->prefix,
486 : : MIN(ns->seen_pop->prefix_len, new_ns->prefix_len));
487 [ - + # # : 943 : if (res > 0 || !res && ns->seen_pop->prefix_len >= new_ns->prefix_len)
# # ]
488 : : break;
489 : : }
490 : 38136 : new_ns->seen_pop = ns->seen_pop;
491 : 38136 : ns->seen_pop = new_ns;
492 : : }
493 : :
494 : : /*() Render the namespaces that have been seen. The list is assumed to be already sorted. */
495 : :
496 : : /* Called by: TXENC_SO_ELNAME, zx_ENC_WO_any_elem x2 */
497 : : char* zx_enc_seen(char* p, struct zx_ns_s* ns)
498 : 933745 : {
499 [ + + ]: 1185659 : for (; ns; ns = ns->seen_pop) {
500 : : /* Check for undeclared empty prefix, as seen in namespaceless XML */
501 [ + - + + : 251914 : if ((!ns->prefix || !*ns->prefix)
+ - ]
502 : : && !memcmp(ns->url, zx_unknown_prefix, sizeof(zx_unknown_prefix))-1)
503 : 11434 : continue;
504 : 240480 : ZX_OUT_MEM(p, " xmlns", sizeof(" xmlns")-1);
505 [ + + ]: 240480 : if (ns->prefix_len) {
506 : 240470 : ZX_OUT_CH(p, ':');
507 : 240470 : ZX_OUT_MEM(p, ns->prefix, ns->prefix_len);
508 : : }
509 : 240480 : ZX_OUT_CH(p, '=');
510 : 240480 : ZX_OUT_CH(p, '"');
511 : 240480 : ZX_OUT_MEM(p, ns->url, ns->url_len);
512 : 240480 : ZX_OUT_CH(p, '"');
513 : : }
514 : 933745 : return p;
515 : : }
516 : :
517 : : /*() dec-templ.c CSE elimination. */
518 : :
519 : : /* Called by: zx_attr_lookup x2 */
520 : : struct zx_ns_s* zx_xmlns_detected(struct zx_ctx* c, struct zx_elem_s* x, const char* url)
521 : 219503 : {
522 : : struct zx_ns_s* ns;
523 : : const char* prefix;
524 : : /* Scan backwards to find beginning of name. Already cached. Scan is cheaper than arg. */
525 [ + + + + : 219503 : for (prefix = url-2; !ONE_OF_5(*prefix, ':', ' ', '\n', '\r', '\t'); --prefix) ;
+ - + - +
- ]
526 : 219503 : ++prefix;
527 : : DD("xmlns detected(%.*s)", url-2-prefix, prefix);
528 : 219503 : ns = ZX_ZALLOC(c, struct zx_ns_s);
529 : 219503 : ns->url = url;
530 : 219503 : ns->url_len = c->p - url;
531 : 219503 : ns->prefix_len = url-2-prefix;
532 : 219503 : ns->prefix = prefix;
533 : 219503 : ns->n = x->xmlns;
534 : 219503 : x->xmlns = ns;
535 : 219503 : return ns;
536 : : }
537 : :
538 : : /* EOF -- zxns.c */
|