LCOV - code coverage report
Current view: top level - zxid - zxlibenc.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 125 147 85.0 %
Date: 2010-12-19 Functions: 8 8 100.0 %
Branches: 78 96 81.2 %

           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 */

Generated by: LCOV version 1.9