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