00001 /** 00002 * @file ccn_coding.c 00003 * @brief Support for scanning and parsing ccnb-encoded data. 00004 * 00005 * Part of the CCNx C Library. 00006 * 00007 * Copyright (C) 2008, 2009 Palo Alto Research Center, Inc. 00008 * 00009 * This library is free software; you can redistribute it and/or modify it 00010 * under the terms of the GNU Lesser General Public License version 2.1 00011 * as published by the Free Software Foundation. 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. You should have received 00016 * a copy of the GNU Lesser General Public License along with this library; 00017 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, 00018 * Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 #include <ccn/coding.h> 00021 00022 /** 00023 * This macro documents what's happening in the state machine by 00024 * hinting at the XML syntax would be emitted in a re-encoder. 00025 * But it actually does nothing. 00026 */ 00027 #define XML(goop) ((void)0) 00028 00029 /** 00030 * Decodes ccnb decoded data 00031 * 00032 * @param d holds the current state of the decoder. 00033 * @param p points to a new block of ccnb data to feed to the decoder. 00034 * @param n is the size of the input, in bytes. 00035 * @returns the number of bytes consumed. 00036 * 00037 * The client should ensure that the decoder is initialized to all zero 00038 * before the first call. In the default mode, the decoder will return 00039 * only when it runs out of data, encounters an error, or reaches the end 00040 * of the element that it started at. This is a good way to pull 00041 * ccnb-encoded objects from a byte stream. 00042 * 00043 * By setting the CCN_DSTATE_PAUSE bit is set in the decoder state, the 00044 * decoder will additionally return just after recognizing each token. 00045 * In this instance, use CCN_GET_TT_FROM_DSTATE() to extract 00046 * the token type from the decoder state; 00047 * CCN_CLOSE will be reported as CCN_NO_TOKEN. 00048 * 00049 * The pause bit persists, so the end test should take that into account 00050 * by using the CCN_FINAL_DSTATE() macro instead of testing for state 0. 00051 * 00052 * Once an error state is entered, no addition input is processed. 00053 * 00054 * @see ccn_buf_decoder_start(), ccn_buf_advance(), ccn_buf_check_close() 00055 */ 00056 ssize_t 00057 ccn_skeleton_decode(struct ccn_skeleton_decoder *d, 00058 const unsigned char *p, size_t n) 00059 { 00060 enum ccn_decoder_state state = d->state; 00061 int tagstate = 0; 00062 size_t numval = d->numval; 00063 ssize_t i = 0; 00064 unsigned char c; 00065 size_t chunk; 00066 int pause = 0; 00067 if (d->state >= 0) { 00068 pause = d->state & CCN_DSTATE_PAUSE; 00069 tagstate = (d->state >> 8) & 3; 00070 state = d->state & 0xFF; 00071 } 00072 while (i < n) { 00073 switch (state) { 00074 case CCN_DSTATE_INITIAL: 00075 case CCN_DSTATE_NEWTOKEN: /* start new thing */ 00076 d->token_index = i + d->index; 00077 if (tagstate > 1 && tagstate-- == 2) { 00078 XML("\""); /* close off the attribute value */ 00079 } 00080 if (p[i] == CCN_CLOSE) { 00081 i++; 00082 if (d->nest <= 0 || tagstate > 1) { 00083 state = CCN_DSTATE_ERR_NEST; 00084 break; 00085 } 00086 if (tagstate == 1) { 00087 tagstate = 0; 00088 XML("/>"); 00089 } 00090 else { 00091 XML("</%s>"); 00092 } 00093 d->nest -= 1; 00094 if (d->nest == 0) { 00095 state = CCN_DSTATE_INITIAL; 00096 n = i; 00097 } 00098 if (pause) { 00099 state |= (((int)CCN_NO_TOKEN) << 16); 00100 n = i; 00101 } 00102 break; 00103 } 00104 numval = 0; 00105 state = CCN_DSTATE_NUMVAL; 00106 /* FALLTHRU */ 00107 case CCN_DSTATE_NUMVAL: /* parsing numval */ 00108 c = p[i++]; 00109 if ((c & CCN_TT_HBIT) == CCN_CLOSE) { 00110 if (numval > ((~(size_t)0U) >> (7 + CCN_TT_BITS))) 00111 state = CCN_DSTATE_ERR_OVERFLOW; 00112 numval = (numval << 7) + (c & 127); 00113 } 00114 else { 00115 numval = (numval << (7-CCN_TT_BITS)) + 00116 ((c >> CCN_TT_BITS) & CCN_MAX_TINY); 00117 c &= CCN_TT_MASK; 00118 switch (c) { 00119 case CCN_EXT: 00120 if (tagstate == 1) { 00121 tagstate = 0; 00122 XML(">"); 00123 } 00124 d->nest += 1; 00125 d->element_index = d->token_index; 00126 state = CCN_DSTATE_NEWTOKEN; 00127 break; 00128 case CCN_DTAG: 00129 if (tagstate == 1) { 00130 tagstate = 0; 00131 XML(">"); 00132 } 00133 d->nest += 1; 00134 d->element_index = d->token_index; 00135 XML("<%s"); 00136 tagstate = 1; 00137 state = CCN_DSTATE_NEWTOKEN; 00138 break; 00139 case CCN_BLOB: 00140 if (tagstate == 1) { 00141 tagstate = 0; 00142 XML(" ccnbencoding=\"base64Binary\">"); 00143 } 00144 state = CCN_DSTATE_BLOB; 00145 if (numval == 0) 00146 state = CCN_DSTATE_NEWTOKEN; 00147 break; 00148 case CCN_UDATA: 00149 if (tagstate == 1) { 00150 tagstate = 0; 00151 XML(">"); 00152 } 00153 state = CCN_DSTATE_UDATA; 00154 if (numval == 0) 00155 state = CCN_DSTATE_NEWTOKEN; 00156 break; 00157 case CCN_DATTR: 00158 if (tagstate != 1) { 00159 state = CCN_DSTATE_ERR_ATTR; 00160 break; 00161 } 00162 tagstate = 3; 00163 state = CCN_DSTATE_NEWTOKEN; 00164 break; 00165 case CCN_ATTR: 00166 if (tagstate != 1) { 00167 state = CCN_DSTATE_ERR_ATTR; 00168 break; 00169 } 00170 numval += 1; /* encoded as length-1 */ 00171 state = CCN_DSTATE_ATTRNAME; 00172 break; 00173 case CCN_TAG: 00174 if (tagstate == 1) { 00175 tagstate = 0; 00176 XML(">"); 00177 } 00178 numval += 1; /* encoded as length-1 */ 00179 d->nest += 1; 00180 d->element_index = d->token_index; 00181 state = CCN_DSTATE_TAGNAME; 00182 break; 00183 default: 00184 state = CCN_DSTATE_ERR_CODING; 00185 } 00186 if (pause) { 00187 state |= (c << 16); 00188 n = i; 00189 } 00190 } 00191 break; 00192 case CCN_DSTATE_TAGNAME: /* parsing tag name */ 00193 chunk = n - i; 00194 if (chunk > numval) 00195 chunk = numval; 00196 if (chunk == 0) { 00197 state = CCN_DSTATE_ERR_BUG; 00198 break; 00199 } 00200 numval -= chunk; 00201 i += chunk; 00202 if (numval == 0) { 00203 if (d->nest == 0) { 00204 state = CCN_DSTATE_ERR_NEST; 00205 break; 00206 } 00207 XML("<%s"); 00208 tagstate = 1; 00209 state = CCN_DSTATE_NEWTOKEN; 00210 } 00211 break; 00212 case CCN_DSTATE_ATTRNAME: /* parsing attribute name */ 00213 chunk = n - i; 00214 if (chunk > numval) 00215 chunk = numval; 00216 if (chunk == 0) { 00217 state = CCN_DSTATE_ERR_BUG; 00218 break; 00219 } 00220 numval -= chunk; 00221 i += chunk; 00222 if (numval == 0) { 00223 if (d->nest == 0) { 00224 state = CCN_DSTATE_ERR_ATTR; 00225 break; 00226 } 00227 XML(" %s=\""); 00228 tagstate = 3; 00229 state = CCN_DSTATE_NEWTOKEN; 00230 } 00231 break; 00232 case CCN_DSTATE_UDATA: /* utf-8 data */ 00233 case CCN_DSTATE_BLOB: /* BLOB */ 00234 chunk = n - i; 00235 if (chunk > numval) 00236 chunk = numval; 00237 if (chunk == 0) { 00238 state = CCN_DSTATE_ERR_BUG; 00239 break; 00240 } 00241 numval -= chunk; 00242 i += chunk; 00243 if (numval == 0) 00244 state = CCN_DSTATE_NEWTOKEN; 00245 break; 00246 default: 00247 n = i; 00248 } 00249 } 00250 if (state < 0) 00251 tagstate = pause = 0; 00252 d->state = state | pause | (tagstate << 8); 00253 d->numval = numval; 00254 d->index += i; 00255 return(i); 00256 }