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