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