blob: 18a30405ae3624a91654ebb301515a99bf37be35 [file] [log] [blame]
Ilya Moiseenkoc115fba2011-08-01 10:53:18 -07001/*
2 * ccn_name_util.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_name_util.h"
11#include "ccn_coding.h"
12#include "ccn_charbuf.h"
13#include "ccn_indexbuf.h"
14#include <string.h>
15#include <stdlib.h>
16#include "ccn_random.h"
17#include "ccn_ccn.h"
18
19/**
20 * @file ccn_name_util.c
21 * @brief Support for manipulating ccnb-encoded Names.
22 *
23 * Part of the CCNx C Library.
24 *
25 * Copyright (C) 2008-2010 Palo Alto Research Center, Inc.
26 *
27 * This library is free software; you can redistribute it and/or modify it
28 * under the terms of the GNU Lesser General Public License version 2.1
29 * as published by the Free Software Foundation.
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 * Lesser General Public License for more details. You should have received
34 * a copy of the GNU Lesser General Public License along with this library;
35 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
36 * Fifth Floor, Boston, MA 02110-1301 USA.
37 */
38
39//#include <ccn/ccn.h>
40
41/**
42 * Reset charbuf to represent an empty Name in binary format.
43 * @returns 0, or -1 for error.
44 */
45int
46ccn_name_init(struct ccn_charbuf *c)
47{
48 int res;
49 c->length = 0;
50 res = ccn_charbuf_append_tt(c, CCN_DTAG_Name, CCN_DTAG);
51 if (res == -1) return(res);
52 res = ccn_charbuf_append_closer(c);
53 return(res);
54}
55
56/**
57 * Add a Component to a Name.
58 *
59 * The component is an arbitrary string of n octets, no escaping required.
60 * @returns 0, or -1 for error.
61 */
62int
63ccn_name_append(struct ccn_charbuf *c, const void *component, size_t n)
64{
65 int res;
66 const unsigned char closer[2] = {CCN_CLOSE, CCN_CLOSE};
67 if (c->length < 2 || c->buf[c->length-1] != closer[1])
68 return(-1);
69 c->length -= 1;
70 ccn_charbuf_reserve(c, n + 8);
71 res = ccn_charbuf_append_tt(c, CCN_DTAG_Component, CCN_DTAG);
72 if (res == -1) return(res);
73 res = ccn_charbuf_append_tt(c, n, CCN_BLOB);
74 if (res == -1) return(res);
75 res = ccn_charbuf_append(c, component, n);
76 if (res == -1) return(res);
77 res = ccn_charbuf_append(c, closer, sizeof(closer));
78 return(res);
79}
80
81/**
82 * Add a Component that is a NUL-terminated string.
83 *
84 * The component added consists of the bytes of the string without the NUL.
85 * This function is convenient for those applications that construct
86 * component names from simple strings.
87 * @returns 0, or -1 for error.
88 */
89int
90ccn_name_append_str(struct ccn_charbuf *c, const char *s)
91{
92 return(ccn_name_append(c, s, strlen(s)));
93}
94
95/**
96 * Add a binary Component to a ccnb-encoded Name
97 *
98 * These are special components used for marking versions, fragments, etc.
99 * @returns 0, or -1 for error
100 * see doc/technical/NameConventions.html
101 */
102int
103ccn_name_append_numeric(struct ccn_charbuf *c,
104 enum ccn_marker marker, unsigned long long value)
105{
106 //uintmax_t v;
107 unsigned long long v;
108 int i;
109 char b[32];
110
111 for (v = value, i = sizeof(b); v != 0 && i > 0; i--, v >>= 8)
112 b[i-1] = v & 0xff;
113 if (i < 1)
114 return(-1);
115 if (marker >= 0)
116 b[--i] = marker;
117 return(ccn_name_append(c, b + i, sizeof(b) - i));
118}
119
120/**
121 * Add nonce Component to ccnb-encoded Name
122 *
123 * Uses %C1.N namespace.
124 * @returns 0, or -1 for error
125 * see doc/technical/NameConventions.html
126 */
127int
128ccn_name_append_nonce(struct ccn_charbuf *c)
129{
130 const unsigned char pre[4] = { CCN_MARKER_CONTROL, '.', 'N', 0 };
131 unsigned char b[15];
132
133 memcpy(b, pre, sizeof(pre));
134 ccn_random_bytes(b + sizeof(pre), sizeof(b) - sizeof(pre));
135 return(ccn_name_append(c, b, sizeof(b)));
136}
137
138/**
139 * Add sequence of ccnb-encoded Components to a ccnb-encoded Name.
140 *
141 * start and stop are offsets from ccnb
142 * @returns 0, or -1 for obvious error
143 */
144int
145ccn_name_append_components(struct ccn_charbuf *c,
146 const unsigned char *ccnb,
147 size_t start, size_t stop)
148{
149 int res;
150 if (c->length < 2 || start > stop)
151 return(-1);
152 c->length -= 1;
153 ccn_charbuf_reserve(c, stop - start + 1);
154 res = ccn_charbuf_append(c, ccnb + start, stop - start);
155 if (res == -1) return(res);
156 res = ccn_charbuf_append_closer(c);
157 return(res);
158}
159
160/**
161 * Extract a pointer to and size of component at
162 * given index i. The first component is index 0.
163 * @returns 0, or -1 for error.
164 */
165int
166ccn_name_comp_get(const unsigned char *data,
167 const struct ccn_indexbuf *indexbuf,
168 unsigned int i,
169 const unsigned char **comp, size_t *size)
170{
171 int len;
172 struct ccn_buf_decoder decoder;
173 struct ccn_buf_decoder *d;
174 /* indexbuf should have an extra value marking end of last component,
175 so we need to use last 2 values */
176 if (indexbuf->n < 2 || i > indexbuf->n - 2) {
177 /* There isn't a component at this index */
178 return(-1);
179 }
180 len = indexbuf->buf[i + 1]-indexbuf->buf[i];
181 d = ccn_buf_decoder_start(&decoder, data + indexbuf->buf[i], len);
182 if (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
183 ccn_buf_advance(d);
184 if (ccn_buf_match_blob(d, comp, size))
185 return(0);
186 *comp = d->buf + d->decoder.index;
187 *size = 0;
188 ccn_buf_check_close(d);
189 if (d->decoder.state >= 0)
190 return(0);
191 }
192 return(-1);
193}
194
195int
196ccn_name_comp_strcmp(const unsigned char *data,
197 const struct ccn_indexbuf *indexbuf,
198 unsigned int i, const char *val)
199{
200 const unsigned char *comp_ptr;
201 size_t comp_size;
202
203 // XXX - We probably want somewhat different semantics in the API -
204 // comparing a string against a longer string with a 0 byte should
205 // not claim equality.
206 if (ccn_name_comp_get(data, indexbuf, i, &comp_ptr, &comp_size) == 0)
207 return(strncmp(val, (const char *)comp_ptr, comp_size));
208 /* Probably no such component, say query is greater-than */
209 return(1);
210}
211
212/**
213 * Find Component boundaries in a ccnb-encoded Name.
214 *
215 * Thin veneer over ccn_parse_Name().
216 * components arg may be NULL to just do a validity check
217 *
218 * @returns -1 for error, otherwise the number of Components.
219 */
220int
221ccn_name_split(const struct ccn_charbuf *c, struct ccn_indexbuf *components)
222{
223 struct ccn_buf_decoder decoder;
224 struct ccn_buf_decoder *d;
225 d = ccn_buf_decoder_start(&decoder, c->buf, c->length);
226 return(ccn_parse_Name(d, components));
227}
228
229/**
230 * Chop the name down to n components.
231 * @param c contains a ccnb-encoded Name
232 * @param components may be NULL; if provided it must be consistent with
233 * some prefix of the name, and is updated accordingly.
234 * @param n is the number or components to leave, or, if negative, specifies
235 * how many components to remove,
236 e.g. -1 will remove just the last component.
237 * @returns -1 for error, otherwise the new number of Components
238 */
239int
240ccn_name_chop(struct ccn_charbuf *c, struct ccn_indexbuf *components, int n)
241{
242 if (components == NULL) {
243 int res;
244 components = ccn_indexbuf_create();
245 if (components == NULL)
246 return(-1);
247 res = ccn_name_split(c, components);
248 if (res >= 0)
249 res = ccn_name_chop(c, components, n);
250 ccn_indexbuf_destroy(&components);
251 return(res);
252 }
253 /* Fix up components if needed. We could be a little smarter about this. */
254 if (components->n == 0 || components->buf[components->n-1] + 1 != c->length)
255 if (ccn_name_split(c, components) < 0)
256 return(-1);
257 if (n < 0)
258 n += (components->n - 1); /* APL-style indexing */
259 if (n < 0)
260 return(-1);
261 if (n < (int)(components->n)) {
262 c->length = components->buf[n];
263 ccn_charbuf_append_value(c, CCN_CLOSE, 1);
264 components->n = n + 1;
265 return(n);
266 }
267 return(-1);
268}
269
270/**
271 * Advance the last Component of a Name to the next possible value.
272 * @param c contains a ccnb-encoded Name to be updated.
273 * @returns -1 for error, otherwise the number of Components
274 */
275int
276ccn_name_next_sibling(struct ccn_charbuf *c)
277{
278 int res = -1;
279 struct ccn_indexbuf *ndx;
280 unsigned char *lastcomp = NULL;
281 size_t lastcompsize = 0;
282 size_t i;
283 int carry;
284 struct ccn_charbuf *newcomp;
285
286 ndx = ccn_indexbuf_create();
287 if (ndx == NULL) goto Finish;
288 res = ccn_name_split(c, ndx);
289 if (res <= 0) {
290 res = -1;
291 goto Finish;
292 }
293 res = ccn_ref_tagged_BLOB(CCN_DTAG_Component, c->buf,
294 ndx->buf[res-1], ndx->buf[res],
295 (const unsigned char **)&lastcomp,
296 &lastcompsize);
297 if (res < 0) goto Finish;
298 for (carry = 1, i = lastcompsize; carry && i > 0; i--) {
299 carry = (((++lastcomp[i-1]) & 0xFF) == 0x00);
300 }
301 if (carry) {
302 newcomp = ccn_charbuf_create();
303 res |= ccn_charbuf_append_value(newcomp, 0, 1);
304 res |= ccn_charbuf_append(newcomp, lastcomp, lastcompsize);
305 res |= ccn_name_chop(c, ndx, ndx->n - 2);
306 res |= ccn_name_append(c, newcomp->buf, newcomp->length);
307 ccn_charbuf_destroy(&newcomp);
308 if (res < 0) goto Finish;
309 }
310 res = ndx->n - 1;
311Finish:
312 ccn_indexbuf_destroy(&ndx);
313 return(res);
314}
315