blob: cbb53457286cdc4913295e4daee12e776dd0ff4f [file] [log] [blame]
Ilya Moiseenkoc115fba2011-08-01 10:53:18 -07001/*
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 */
67ssize_t
68ccn_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}