ccn_coding.c

Go to the documentation of this file.
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 }
Generated on Fri May 13 16:27:02 2011 for Content-Centric Networking in C by  doxygen 1.6.3