Ilya Moiseenko | c115fba | 2011-08-01 10:53:18 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * ccn_coding.cc |
| 3 | * Abstraction |
| 4 | * |
| 5 | * Created by Ilya on 7/29/11. |
| 6 | * Copyright 2011 __MyCompanyName__. All rights reserved. |
| 7 | * |
| 8 | */ |
| 9 | |
| 10 | #include "ccn_coding.h" |
| 11 | |
| 12 | /** |
| 13 | * @file ccn_coding.c |
| 14 | * @brief Support for scanning and parsing ccnb-encoded data. |
| 15 | * |
| 16 | * Part of the CCNx C Library. |
| 17 | * |
| 18 | * Copyright (C) 2008, 2009 Palo Alto Research Center, Inc. |
| 19 | * |
| 20 | * This library is free software; you can redistribute it and/or modify it |
| 21 | * under the terms of the GNU Lesser General Public License version 2.1 |
| 22 | * as published by the Free Software Foundation. |
| 23 | * This library is distributed in the hope that it will be useful, |
| 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 26 | * Lesser General Public License for more details. You should have received |
| 27 | * a copy of the GNU Lesser General Public License along with this library; |
| 28 | * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, |
| 29 | * Fifth Floor, Boston, MA 02110-1301 USA. |
| 30 | */ |
| 31 | //#include <ccn/coding.h> |
| 32 | |
| 33 | /** |
| 34 | * This macro documents what's happening in the state machine by |
| 35 | * hinting at the XML syntax would be emitted in a re-encoder. |
| 36 | * But it actually does nothing. |
| 37 | */ |
| 38 | #define XML(goop) ((void)0) |
| 39 | |
| 40 | /** |
| 41 | * Decodes ccnb decoded data |
| 42 | * |
| 43 | * @param d holds the current state of the decoder. |
| 44 | * @param p points to a new block of ccnb data to feed to the decoder. |
| 45 | * @param n is the size of the input, in bytes. |
| 46 | * @returns the number of bytes consumed. |
| 47 | * |
| 48 | * The client should ensure that the decoder is initialized to all zero |
| 49 | * before the first call. In the default mode, the decoder will return |
| 50 | * only when it runs out of data, encounters an error, or reaches the end |
| 51 | * of the element that it started at. This is a good way to pull |
| 52 | * ccnb-encoded objects from a byte stream. |
| 53 | * |
| 54 | * By setting the CCN_DSTATE_PAUSE bit is set in the decoder state, the |
| 55 | * decoder will additionally return just after recognizing each token. |
| 56 | * In this instance, use CCN_GET_TT_FROM_DSTATE() to extract |
| 57 | * the token type from the decoder state; |
| 58 | * CCN_CLOSE will be reported as CCN_NO_TOKEN. |
| 59 | * |
| 60 | * The pause bit persists, so the end test should take that into account |
| 61 | * by using the CCN_FINAL_DSTATE() macro instead of testing for state 0. |
| 62 | * |
| 63 | * Once an error state is entered, no addition input is processed. |
| 64 | * |
| 65 | * @see ccn_buf_decoder_start(), ccn_buf_advance(), ccn_buf_check_close() |
| 66 | */ |
| 67 | ssize_t |
| 68 | ccn_skeleton_decode(struct ccn_skeleton_decoder *d, |
| 69 | const unsigned char *p, size_t n) |
| 70 | { |
| 71 | enum ccn_decoder_state state = (ccn_decoder_state)(d->state); |
| 72 | int tagstate = 0; |
| 73 | size_t numval = d->numval; |
| 74 | ssize_t i = 0; |
| 75 | unsigned char c; |
| 76 | size_t chunk; |
| 77 | int pause = 0; |
| 78 | if (d->state >= 0) { |
| 79 | pause = d->state & CCN_DSTATE_PAUSE; |
| 80 | tagstate = (d->state >> 8) & 3; |
| 81 | state = (ccn_decoder_state)(d->state & 0xFF); |
| 82 | } |
| 83 | while (i < (ssize_t)n) { |
| 84 | switch (state) { |
| 85 | case CCN_DSTATE_INITIAL: |
| 86 | case CCN_DSTATE_NEWTOKEN: /* start new thing */ |
| 87 | d->token_index = i + d->index; |
| 88 | if (tagstate > 1 && tagstate-- == 2) { |
| 89 | XML("\""); /* close off the attribute value */ |
| 90 | } |
| 91 | if (p[i] == CCN_CLOSE) { |
| 92 | i++; |
| 93 | if (d->nest <= 0 || tagstate > 1) { |
| 94 | state = CCN_DSTATE_ERR_NEST; |
| 95 | break; |
| 96 | } |
| 97 | if (tagstate == 1) { |
| 98 | tagstate = 0; |
| 99 | XML("/>"); |
| 100 | } |
| 101 | else { |
| 102 | XML("</%s>"); |
| 103 | } |
| 104 | d->nest -= 1; |
| 105 | if (d->nest == 0) { |
| 106 | state = CCN_DSTATE_INITIAL; |
| 107 | n = i; |
| 108 | } |
| 109 | if (pause) { |
| 110 | int temp = (int)state; |
| 111 | //state |= (((int)CCN_NO_TOKEN) << 16); |
| 112 | temp |= (((int)CCN_NO_TOKEN) << 16); |
| 113 | state = (ccn_decoder_state)temp; |
| 114 | n = i; |
| 115 | } |
| 116 | break; |
| 117 | } |
| 118 | numval = 0; |
| 119 | state = CCN_DSTATE_NUMVAL; |
| 120 | /* FALLTHRU */ |
| 121 | case CCN_DSTATE_NUMVAL: /* parsing numval */ |
| 122 | c = p[i++]; |
| 123 | if ((c & CCN_TT_HBIT) == CCN_CLOSE) { |
| 124 | if (numval > ((~(size_t)0U) >> (7 + CCN_TT_BITS))) |
| 125 | state = CCN_DSTATE_ERR_OVERFLOW; |
| 126 | numval = (numval << 7) + (c & 127); |
| 127 | } |
| 128 | else { |
| 129 | numval = (numval << (7-CCN_TT_BITS)) + |
| 130 | ((c >> CCN_TT_BITS) & CCN_MAX_TINY); |
| 131 | c &= CCN_TT_MASK; |
| 132 | switch (c) { |
| 133 | case CCN_EXT: |
| 134 | if (tagstate == 1) { |
| 135 | tagstate = 0; |
| 136 | XML(">"); |
| 137 | } |
| 138 | d->nest += 1; |
| 139 | d->element_index = d->token_index; |
| 140 | state = CCN_DSTATE_NEWTOKEN; |
| 141 | break; |
| 142 | case CCN_DTAG: |
| 143 | if (tagstate == 1) { |
| 144 | tagstate = 0; |
| 145 | XML(">"); |
| 146 | } |
| 147 | d->nest += 1; |
| 148 | d->element_index = d->token_index; |
| 149 | XML("<%s"); |
| 150 | tagstate = 1; |
| 151 | state = CCN_DSTATE_NEWTOKEN; |
| 152 | break; |
| 153 | case CCN_BLOB: |
| 154 | if (tagstate == 1) { |
| 155 | tagstate = 0; |
| 156 | XML(" ccnbencoding=\"base64Binary\">"); |
| 157 | } |
| 158 | state = CCN_DSTATE_BLOB; |
| 159 | if (numval == 0) |
| 160 | state = CCN_DSTATE_NEWTOKEN; |
| 161 | break; |
| 162 | case CCN_UDATA: |
| 163 | if (tagstate == 1) { |
| 164 | tagstate = 0; |
| 165 | XML(">"); |
| 166 | } |
| 167 | state = CCN_DSTATE_UDATA; |
| 168 | if (numval == 0) |
| 169 | state = CCN_DSTATE_NEWTOKEN; |
| 170 | break; |
| 171 | case CCN_DATTR: |
| 172 | if (tagstate != 1) { |
| 173 | state = CCN_DSTATE_ERR_ATTR; |
| 174 | break; |
| 175 | } |
| 176 | tagstate = 3; |
| 177 | state = CCN_DSTATE_NEWTOKEN; |
| 178 | break; |
| 179 | case CCN_ATTR: |
| 180 | if (tagstate != 1) { |
| 181 | state = CCN_DSTATE_ERR_ATTR; |
| 182 | break; |
| 183 | } |
| 184 | numval += 1; /* encoded as length-1 */ |
| 185 | state = CCN_DSTATE_ATTRNAME; |
| 186 | break; |
| 187 | case CCN_TAG: |
| 188 | if (tagstate == 1) { |
| 189 | tagstate = 0; |
| 190 | XML(">"); |
| 191 | } |
| 192 | numval += 1; /* encoded as length-1 */ |
| 193 | d->nest += 1; |
| 194 | d->element_index = d->token_index; |
| 195 | state = CCN_DSTATE_TAGNAME; |
| 196 | break; |
| 197 | default: |
| 198 | state = CCN_DSTATE_ERR_CODING; |
| 199 | } |
| 200 | if (pause) { |
| 201 | int temp = (int)state; |
| 202 | //state |= (c << 16); |
| 203 | temp |= (c << 16); |
| 204 | state = (ccn_decoder_state)temp; |
| 205 | n = i; |
| 206 | } |
| 207 | } |
| 208 | break; |
| 209 | case CCN_DSTATE_TAGNAME: /* parsing tag name */ |
| 210 | chunk = n - i; |
| 211 | if (chunk > numval) |
| 212 | chunk = numval; |
| 213 | if (chunk == 0) { |
| 214 | state = CCN_DSTATE_ERR_BUG; |
| 215 | break; |
| 216 | } |
| 217 | numval -= chunk; |
| 218 | i += chunk; |
| 219 | if (numval == 0) { |
| 220 | if (d->nest == 0) { |
| 221 | state = CCN_DSTATE_ERR_NEST; |
| 222 | break; |
| 223 | } |
| 224 | XML("<%s"); |
| 225 | tagstate = 1; |
| 226 | state = CCN_DSTATE_NEWTOKEN; |
| 227 | } |
| 228 | break; |
| 229 | case CCN_DSTATE_ATTRNAME: /* parsing attribute name */ |
| 230 | chunk = n - i; |
| 231 | if (chunk > numval) |
| 232 | chunk = numval; |
| 233 | if (chunk == 0) { |
| 234 | state = CCN_DSTATE_ERR_BUG; |
| 235 | break; |
| 236 | } |
| 237 | numval -= chunk; |
| 238 | i += chunk; |
| 239 | if (numval == 0) { |
| 240 | if (d->nest == 0) { |
| 241 | state = CCN_DSTATE_ERR_ATTR; |
| 242 | break; |
| 243 | } |
| 244 | XML(" %s=\""); |
| 245 | tagstate = 3; |
| 246 | state = CCN_DSTATE_NEWTOKEN; |
| 247 | } |
| 248 | break; |
| 249 | case CCN_DSTATE_UDATA: /* utf-8 data */ |
| 250 | case CCN_DSTATE_BLOB: /* BLOB */ |
| 251 | chunk = n - i; |
| 252 | if (chunk > numval) |
| 253 | chunk = numval; |
| 254 | if (chunk == 0) { |
| 255 | state = CCN_DSTATE_ERR_BUG; |
| 256 | break; |
| 257 | } |
| 258 | numval -= chunk; |
| 259 | i += chunk; |
| 260 | if (numval == 0) |
| 261 | state = CCN_DSTATE_NEWTOKEN; |
| 262 | break; |
| 263 | default: |
| 264 | n = i; |
| 265 | } |
| 266 | } |
| 267 | if (state < 0) |
| 268 | tagstate = pause = 0; |
| 269 | d->state = state | pause | (tagstate << 8); |
| 270 | d->numval = numval; |
| 271 | d->index += i; |
| 272 | return(i); |
| 273 | } |