Branch data Line data Source code
1 : : /* zxlibenc.c - XML encoder
2 : : * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 : : * Copyright (c) 2006-2009 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: zxlib.c,v 1.41 2009-11-24 23:53:40 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, more CSE --Sampo
16 : : * 7.10.2008, added documentation --Sampo
17 : : * 26.5.2010, added XML parse error reporting --Sampo
18 : : * 27.10.2010, re-engineered namespace handling --Sampo
19 : : */
20 : :
21 : : #include "platform.h" /* needed on Win32 for snprintf(), va_copy() et al. */
22 : :
23 : : #include <memory.h>
24 : : #include <string.h>
25 : : #include <stdarg.h>
26 : : #include <stdio.h>
27 : : #include <stdlib.h>
28 : :
29 : : #include "errmac.h"
30 : : #include "zx.h"
31 : : #include "c/zx-ns.h"
32 : : #include "c/zx-data.h"
33 : :
34 : : /* Add inclusive namespaces. */
35 : :
36 : : /* Called by: TXLEN_SO_ELNAME, zx_LEN_WO_any_elem x2 */
37 : : static int zx_len_inc_ns(struct zx_ctx* c, struct zx_ns_s** pop_seenp)
38 : 248 : {
39 : 248 : int len = 0;
40 : : struct zx_ns_s* ns;
41 [ + + ]: 496 : for (ns = c->inc_ns; ns; ns = ns->inc_n)
42 : 248 : len += zx_len_xmlns_if_not_seen(c, ns, pop_seenp);
43 : : /*c->inc_ns_len = 0; needs to be processed at every level */
44 : 248 : return len;
45 : : }
46 : :
47 : : /* Called by: TXENC_SO_ELNAME, zx_ENC_WO_any_elem x2 */
48 : : static void zx_add_inc_ns(struct zx_ctx* c, struct zx_ns_s** pop_seenp)
49 : 248 : {
50 : : struct zx_ns_s* ns;
51 [ + + ]: 496 : for (ns = c->inc_ns; ns; ns = ns->inc_n)
52 : 248 : zx_add_xmlns_if_not_seen(c, ns, pop_seenp);
53 : : /*c->inc_ns = 0; needs to be processed at every level */
54 : 248 : }
55 : :
56 : : /* Called by: TXENC_SO_ELNAME, zx_ENC_WO_any_elem */
57 : : static void zx_see_attr_ns(struct zx_ctx* c, struct zx_attr_s* aa, struct zx_ns_s** pop_seenp)
58 : 915624 : {
59 [ + + ]: 1511384 : for (; aa; aa = (struct zx_attr_s*)aa->g.n)
60 : 595760 : zx_add_xmlns_if_not_seen(c, aa->ns, pop_seenp);
61 : 915624 : }
62 : :
63 : : /*() Check if a namespace is already in inclusive namespaces so we do not need to add it again. */
64 : :
65 : : /* Called by: zxsig_validate */
66 : : int zx_in_inc_ns(struct zx_ctx* c, struct zx_ns_s* new_ns)
67 : 1 : {
68 : : struct zx_ns_s* ns;
69 [ - + ]: 1 : for (ns = c->inc_ns; ns; ns = ns->inc_n)
70 [ # # ]: 0 : if (new_ns == ns)
71 : 0 : return 1;
72 : 1 : return 0;
73 : : }
74 : :
75 : : #define D_LEN_ENA 0
76 : : #if D_LEN_ENA
77 : : #define D_LEN(f,t,l) D(f,t,l)
78 : : #else
79 : : #define D_LEN(f,t,l)
80 : : #endif
81 : :
82 : : /*() Compute length of an element (and its subelements). The XML attributes
83 : : * and elements are processed in wire order and no assumptions
84 : : * are made about namespace prefixes. */
85 : :
86 : : /* Called by: main x2, zx_EASY_ENC_elem, zx_LEN_WO_any_elem x2 */
87 : : int zx_LEN_WO_any_elem(struct zx_ctx* c, struct zx_elem_s* x)
88 : 1173131 : {
89 : : //const struct zx_el_desc* ed;
90 : : struct zx_at_tok* at_tok;
91 : : struct zx_el_tok* el_tok;
92 : 1173131 : struct zx_ns_s* pop_seen = 0;
93 : : struct zx_attr_s* attr;
94 : : struct zx_elem_s* kid;
95 : : int ix;
96 : : int len;
97 : : //struct zx_elem_s* kid;
98 [ + + + + ]: 1173131 : switch (x->g.tok) {
99 : : case zx_root_ELEM:
100 : 18121 : len = 0;
101 [ - + ]: 18121 : if (c->inc_ns_len)
102 : 0 : len += zx_len_inc_ns(c, &pop_seen);
103 [ + + ]: 36242 : for (kid = x->kids; kid; kid = ((struct zx_elem_s*)(kid->g.n)))
104 : 18121 : len += zx_LEN_WO_any_elem(c, kid);
105 : 18121 : break;
106 : : case ZX_TOK_DATA:
107 : 239225 : return x->g.len;
108 : : case zx_ds_Signature_ELEM:
109 [ + + ]: 11299 : if (x == c->exclude_sig)
110 : 161 : return 0;
111 : : /* fall thru */
112 : : default:
113 [ + + ]: 915624 : if (x->g.s) {
114 : : /* < ns:elem > </ ns:elem > / */
115 [ + + + + ]: 756651 : len = 1 + x->g.len + 1 + ((x->kids || !c->enc_tail_opt) ? (2 + x->g.len + 1) : 1);
116 : : } else { /* Construct elem string from tok */
117 : 158973 : ix = (x->g.tok >> ZX_TOK_NS_SHIFT)&(ZX_TOK_NS_MASK >> ZX_TOK_NS_SHIFT);
118 [ - + ]: 158973 : if (ix >= zx__NS_MAX) {
119 : 0 : ERR("Namespace index of token(0x%06x) out of range(0x%02x)", x->g.tok, zx__NS_MAX);
120 : 0 : return 0;
121 : : }
122 : 158973 : x->ns = zx_ns_tab + ix;
123 : : //ed = zx_el_desc_lookup(tok);
124 : 158973 : ix = x->g.tok & ZX_TOK_TOK_MASK;
125 [ - + ]: 158973 : if (ix >= zx__ELEM_MAX) {
126 : 0 : ERR("Element token(0x%06x) out of range(0x%04x)", x->g.tok, zx__ELEM_MAX);
127 : 0 : return 0;
128 : : }
129 : 158973 : el_tok = zx_el_tab + ix;
130 : 158973 : len = strlen(el_tok->name);
131 : : DD("ns prefix_len=%d el_len=%d", x->ns->prefix_len, len);
132 : : /* < ns : elem > </ ns : elem > / */
133 [ + + + + ]: 158973 : len = 1 + x->ns->prefix_len + 1 + len + 1 + ((x->kids || !c->enc_tail_opt) ? (2 + x->ns->prefix_len + 1 + len + 1) : 1);
134 : : }
135 : : D_LEN("%06x ** tag start: %d", x->g.tok, len);
136 : 915624 : len += zx_len_xmlns_if_not_seen(c, x->ns, &pop_seen);
137 : : D_LEN("%06x after xmlns: %d", x->g.tok, len);
138 : :
139 [ + + ]: 915624 : if (c->inc_ns_len)
140 : 248 : len += zx_len_inc_ns(c, &pop_seen);
141 : : D_LEN("%06x after inc_ns: %d", x->g.tok, len);
142 : :
143 [ + + ]: 1511384 : for (attr = x->attr; attr; attr = (struct zx_attr_s*)attr->g.n) {
144 [ + + ]: 595760 : if (attr->name) {
145 : : /* sp name =" " */
146 : 490805 : len += 1 + attr->name_len + 2 + attr->g.len + 1;
147 : : } else { /* Construct elem string from tok */
148 [ + + + + : 104955 : if (!attr->ns && IN_RANGE((attr->g.tok & ZX_TOK_NS_MASK) >> ZX_TOK_NS_SHIFT, 1, zx__NS_MAX))
+ - ]
149 : 1124 : attr->ns = zx_ns_tab + ((attr->g.tok & ZX_TOK_NS_MASK) >> ZX_TOK_NS_SHIFT);
150 [ + + ]: 104955 : if (attr->ns)
151 : 6283 : len += attr->ns->prefix_len + 1;
152 : 104955 : ix = attr->g.tok & ZX_TOK_TOK_MASK;
153 [ - + ]: 104955 : if (ix >= zx__ATTR_MAX) {
154 : 0 : ERR("Attribute token(0x%06x) out of range(0x%04x)", attr->g.tok, zx__ATTR_MAX);
155 : 0 : return 0;
156 : : }
157 : 104955 : at_tok = zx_at_tab + ix;
158 : 104955 : len += strlen(at_tok->name);
159 : : /* sp =" " */
160 : 104955 : len += 1+ 2 + attr->g.len + 1;
161 : : }
162 : 595760 : len += zx_len_xmlns_if_not_seen(c, attr->ns, &pop_seen);
163 : : }
164 : : D_LEN("%06x after attrs: %d", x->g.tok, len);
165 : :
166 [ + + ]: 2045029 : for (kid = x->kids; kid; kid = ((struct zx_elem_s*)(kid->g.n)))
167 : 1129405 : len += zx_LEN_WO_any_elem(c, kid);
168 : :
169 : : break;
170 : : }
171 : 933745 : zx_pop_seen(pop_seen);
172 : : D_LEN("%06x final: %d", x->g.tok, len);
173 : 933745 : return len;
174 : : }
175 : :
176 : : /* Called by: TXENC_SO_ELNAME, zx_ENC_WO_any_elem */
177 : : static char* zx_attr_wo_enc(char* p, struct zx_attr_s* attr)
178 : 595760 : {
179 : : struct zx_at_tok* at_tok;
180 : : int ix;
181 : 595760 : ZX_OUT_CH(p, ' ');
182 [ + + ]: 595760 : if (attr->name) {
183 : 490805 : ZX_OUT_MEM(p, attr->name, attr->name_len);
184 : : } else { /* Construct elem string from tok */
185 [ + + - + : 104955 : if (!attr->ns && IN_RANGE((attr->g.tok & ZX_TOK_NS_MASK) >> ZX_TOK_NS_SHIFT, 1, zx__NS_MAX))
# # ]
186 : 0 : attr->ns = zx_ns_tab + ((attr->g.tok & ZX_TOK_NS_MASK) >> ZX_TOK_NS_SHIFT);
187 [ + + ]: 104955 : if (attr->ns) {
188 : 6283 : ZX_OUT_MEM(p, attr->ns->prefix, attr->ns->prefix_len);
189 : 6283 : ZX_OUT_CH(p, ':');
190 : : }
191 : 104955 : ix = attr->g.tok & ZX_TOK_TOK_MASK;
192 [ - + ]: 104955 : if (ix >= zx__ATTR_MAX) {
193 : 0 : ERR("Attribute token(0x%06x) out of range(0x%04x)", attr->g.tok, zx__ATTR_MAX);
194 : 0 : return p;
195 : : }
196 : 104955 : at_tok = zx_at_tab + ix;
197 : 104955 : ZX_OUT_MEM(p, at_tok->name, strlen(at_tok->name));
198 : : }
199 : 595760 : ZX_OUT_CH(p, '=');
200 : 595760 : ZX_OUT_CH(p, '"');
201 : 595760 : ZX_OUT_MEM(p, attr->g.s, attr->g.len);
202 : 595760 : ZX_OUT_CH(p, '"');
203 : 595760 : return p;
204 : : }
205 : :
206 : : /*() Render element into string. The XML attributes and elements are
207 : : * processed in wire order by chasing wo pointers. This is what you want for
208 : : * validating signatures on other people's XML documents. */
209 : :
210 : : /* Called by: main x2, zx_EASY_ENC_elem, zx_ENC_WO_any_elem x2 */
211 : : char* zx_ENC_WO_any_elem(struct zx_ctx* c, struct zx_elem_s* x, char* p)
212 : 1173131 : {
213 : : //const struct zx_el_desc* ed;
214 : : struct zx_el_tok* el_tok;
215 : 1173131 : struct zx_ns_s* pop_seen = 0;
216 : : struct zx_attr_s* attr;
217 : : struct zx_elem_s* kid;
218 : : int ix;
219 : : #if D_LEN_ENA
220 : : char* b = p;
221 : : #endif
222 [ + + + + ]: 1173131 : switch (x->g.tok) {
223 : : case zx_root_ELEM:
224 [ - + ]: 18121 : if (c->inc_ns)
225 : 0 : zx_add_inc_ns(c, &pop_seen);
226 : 18121 : p = zx_enc_seen(p, pop_seen);
227 [ + + ]: 36242 : for (kid = x->kids; kid; kid = (struct zx_elem_s*)kid->g.n)
228 : 18121 : p = zx_ENC_WO_any_elem(c, kid, p);
229 : 18121 : break;
230 : : case ZX_TOK_DATA:
231 : 239225 : ZX_OUT_STR(p, x);
232 : 239225 : break;
233 : : case zx_ds_Signature_ELEM:
234 [ + + ]: 11299 : if (x == c->exclude_sig)
235 : 161 : return p;
236 : : /* fall thru */
237 : : default:
238 : 915624 : ZX_OUT_CH(p, '<');
239 [ + + ]: 915624 : if (x->g.s) {
240 : 756651 : ZX_OUT_MEM(p, x->g.s, x->g.len);
241 : : } else { /* Construct elem string from tok */
242 [ - + ]: 158973 : if (!x->ns) {
243 : 0 : ix = (x->g.tok >> ZX_TOK_NS_SHIFT)&(ZX_TOK_NS_MASK >> ZX_TOK_NS_SHIFT);
244 [ # # ]: 0 : if (ix >= zx__NS_MAX) {
245 : 0 : ERR("Namespace index of token(0x%06x) out of range(0x%02x)", x->g.tok, zx__NS_MAX);
246 : 0 : return p;
247 : : }
248 : 0 : x->ns = zx_ns_tab + ix;
249 : : }
250 : : //ed = zx_el_desc_lookup(tok);
251 : 158973 : ix = x->g.tok & ZX_TOK_TOK_MASK;
252 [ - + ]: 158973 : if (ix >= zx__ELEM_MAX) {
253 : 0 : ERR("Element token(0x%06x) out of range(0x%04x)", x->g.tok, zx__ELEM_MAX);
254 : 0 : return p;
255 : : }
256 : 158973 : el_tok = zx_el_tab + ix;
257 : 158973 : ZX_OUT_MEM(p, x->ns->prefix, x->ns->prefix_len);
258 : 158973 : ZX_OUT_CH(p, ':');
259 : 158973 : ZX_OUT_MEM(p, el_tok->name, strlen(el_tok->name));
260 : : }
261 : : D_LEN("%06x ** tag start: %d", x->g.tok, p-b);
262 : 915624 : zx_add_xmlns_if_not_seen(c, x->ns, &pop_seen);
263 [ + + ]: 915624 : if (c->inc_ns)
264 : 248 : zx_add_inc_ns(c, &pop_seen);
265 : : D_LEN("%06x after inc_ns: %d", x->g.tok, p-b);
266 : 915624 : zx_see_attr_ns(c, x->attr, &pop_seen);
267 : 915624 : p = zx_enc_seen(p, pop_seen);
268 : : D_LEN("%06x after seen ns: %d", x->g.tok, p-b);
269 : :
270 [ + + ]: 1511384 : for (attr = x->attr; attr; attr = (struct zx_attr_s*)attr->g.n)
271 : 595760 : p = zx_attr_wo_enc(p, attr);
272 : :
273 [ + + + + ]: 1808455 : if (x->kids || !c->enc_tail_opt) {
274 : 892831 : ZX_OUT_CH(p, '>');
275 : : D_LEN("%06x after attrs: %d", x->g.tok, p-b);
276 : :
277 [ + + ]: 2022236 : for (kid = x->kids; kid; kid = (struct zx_elem_s*)kid->g.n)
278 : 1129405 : p = zx_ENC_WO_any_elem(c, kid, p);
279 : : D_LEN("%06x after kids: %d", x->g.tok, p-b);
280 : :
281 : 892831 : ZX_OUT_CH(p, '<');
282 : 892831 : ZX_OUT_CH(p, '/');
283 [ + + ]: 892831 : if (x->g.s) {
284 : 747068 : ZX_OUT_MEM(p, x->g.s, x->g.len);
285 : : } else { /* Construct elem string from tok */
286 : 145763 : ZX_OUT_MEM(p, x->ns->prefix, x->ns->prefix_len);
287 : 145763 : ZX_OUT_CH(p, ':');
288 : 145763 : ZX_OUT_MEM(p, el_tok->name, strlen(el_tok->name));
289 : : }
290 : : } else {
291 : 22793 : ZX_OUT_CH(p, '/'); /* Also an XML legal way to terminate an empty tag, e.g. <ns:foo/> */
292 : : }
293 : 915624 : ZX_OUT_CH(p, '>');
294 : : }
295 : 1172970 : zx_pop_seen(pop_seen);
296 : : D_LEN("%06x final: %d", x->g.tok, p-b);
297 : 1172970 : return p;
298 : : }
299 : :
300 : : /*(i) Render any element in wire order, as often needed in validating canonicalizations.
301 : : * See also: zx_easy_enc_elem_opt() */
302 : :
303 : : /* Called by: zx_easy_enc_elem_opt, zx_easy_enc_elem_sig, zxsig_sign, zxsig_validate x2 */
304 : : struct zx_str* zx_EASY_ENC_elem(struct zx_ctx* c, struct zx_elem_s* x)
305 : 7484 : {
306 : 7484 : int len = zx_LEN_WO_any_elem(c, x);
307 : 7484 : char* buf = ZX_ALLOC(c, len+1);
308 : 7484 : char* p = zx_ENC_WO_any_elem(c, x, buf);
309 [ - + ]: 7484 : if (p != buf+len) {
310 : 0 : ERR("Encoded length(%d) does not match computed length(%d). ED(%.*s)", p-buf, len, p-buf, buf);
311 : 0 : len = p-buf;
312 : : }
313 : 7484 : buf[len] = 0;
314 : 7484 : return zx_ref_len_str(c, len, buf);
315 : : }
316 : :
317 : : /* EOF -- zxlibenc.c */
|