1967b350ae3b047699608b5da1a178e4737816f0
[strongswan.git] / src / libstrongswan / chunk.c
1 /**
2 * @file chunk.c
3 *
4 * @brief Pointer/lenght abstraction and its functions.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <stdio.h>
25
26 #include "chunk.h"
27
28 #include <printf_hook.h>
29
30 /**
31 * Empty chunk.
32 */
33 chunk_t chunk_empty = { NULL, 0 };
34
35 /**
36 * Described in header.
37 */
38 chunk_t chunk_create(u_char *ptr, size_t len)
39 {
40 chunk_t chunk = {ptr, len};
41 return chunk;
42 }
43
44 /**
45 * Described in header.
46 */
47 chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
48 {
49 chunk_t clone = chunk_empty;
50
51 if (chunk.ptr && chunk.len > 0)
52 {
53 clone.ptr = ptr;
54 clone.len = chunk.len;
55 memcpy(clone.ptr, chunk.ptr, chunk.len);
56 }
57
58 return clone;
59 }
60
61 /**
62 * Decribed in header.
63 */
64 size_t chunk_length(const char* mode, ...)
65 {
66 va_list chunks;
67 size_t length = 0;
68
69 va_start(chunks, mode);
70 while (TRUE)
71 {
72 switch (*mode++)
73 {
74 case 'm':
75 case 'c':
76 {
77 chunk_t ch = va_arg(chunks, chunk_t);
78 length += ch.len;
79 continue;
80 }
81 default:
82 break;
83 }
84 break;
85 }
86 va_end(chunks);
87 return length;
88 }
89
90 /**
91 * Decribed in header.
92 */
93 chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
94 {
95 va_list chunks;
96 chunk_t construct = chunk_create(ptr, 0);
97
98 va_start(chunks, mode);
99 while (TRUE)
100 {
101 bool free_chunk = FALSE;
102 switch (*mode++)
103 {
104 case 'm':
105 {
106 free_chunk = TRUE;
107 }
108 case 'c':
109 {
110 chunk_t ch = va_arg(chunks, chunk_t);
111 memcpy(ptr, ch.ptr, ch.len);
112 ptr += ch.len;
113 construct.len += ch.len;
114 if (free_chunk)
115 {
116 free(ch.ptr);
117 }
118 continue;
119 }
120 default:
121 break;
122 }
123 break;
124 }
125 va_end(chunks);
126
127 return construct;
128 }
129
130 /**
131 * Decribed in header.
132 */
133 void chunk_split(chunk_t chunk, const char *mode, ...)
134 {
135 va_list chunks;
136 size_t len;
137 chunk_t *ch;
138
139 va_start(chunks, mode);
140 while (TRUE)
141 {
142 if (*mode == '\0')
143 {
144 break;
145 }
146 len = va_arg(chunks, size_t);
147 ch = va_arg(chunks, chunk_t*);
148 /* a null chunk means skip len bytes */
149 if (ch == NULL)
150 {
151 chunk = chunk_skip(chunk, len);
152 continue;
153 }
154 switch (*mode++)
155 {
156 case 'm':
157 {
158 ch->len = min(chunk.len, len);
159 if (ch->len)
160 {
161 ch->ptr = chunk.ptr;
162 }
163 else
164 {
165 ch->ptr = NULL;
166 }
167 chunk = chunk_skip(chunk, ch->len);
168 continue;
169 }
170 case 'a':
171 {
172 ch->len = min(chunk.len, len);
173 if (ch->len)
174 {
175 ch->ptr = malloc(ch->len);
176 memcpy(ch->ptr, chunk.ptr, ch->len);
177 }
178 else
179 {
180 ch->ptr = NULL;
181 }
182 chunk = chunk_skip(chunk, ch->len);
183 continue;
184 }
185 case 'c':
186 {
187 ch->len = min(ch->len, chunk.len);
188 ch->len = min(ch->len, len);
189 if (ch->len)
190 {
191 memcpy(ch->ptr, chunk.ptr, ch->len);
192 }
193 else
194 {
195 ch->ptr = NULL;
196 }
197 chunk = chunk_skip(chunk, ch->len);
198 continue;
199 }
200 default:
201 break;
202 }
203 break;
204 }
205 va_end(chunks);
206 }
207
208
209 /**
210 * Described in header.
211 */
212 void chunk_free(chunk_t *chunk)
213 {
214 free(chunk->ptr);
215 chunk->ptr = NULL;
216 chunk->len = 0;
217 }
218
219 /**
220 * Described in header.
221 */
222 chunk_t chunk_skip(chunk_t chunk, size_t bytes)
223 {
224 if (chunk.len > bytes)
225 {
226 chunk.ptr += bytes;
227 chunk.len -= bytes;
228 return chunk;
229 }
230 return chunk_empty;
231 }
232
233 /**
234 * Described in header.
235 */
236 int chunk_compare(chunk_t a, chunk_t b)
237 {
238 int compare_len = a.len - b.len;
239 int len = (compare_len < 0)? a.len : b.len;
240
241 if (compare_len != 0 || len == 0)
242 {
243 return compare_len;
244 }
245 return memcmp(a.ptr, b.ptr, len);
246 };
247
248 /**
249 * Described in header.
250 */
251 bool chunk_equals(chunk_t a, chunk_t b)
252 {
253 return a.ptr != NULL && b.ptr != NULL &&
254 a.len == b.len && memeq(a.ptr, b.ptr, a.len);
255 }
256
257 /**
258 * Described in header.
259 */
260 bool chunk_equals_or_null(chunk_t a, chunk_t b)
261 {
262 if (a.ptr == NULL || b.ptr == NULL)
263 return TRUE;
264 return a.len == b.len && memeq(a.ptr, b.ptr, a.len);
265 }
266
267 /**
268 * Number of bytes per line to dump raw data
269 */
270 #define BYTES_PER_LINE 16
271
272 /**
273 * output handler in printf() for byte ranges
274 */
275 static int print_bytes(FILE *stream, const struct printf_info *info,
276 const void *const *args)
277 {
278 char *bytes = *((void**)(args[0]));
279 int len = *((size_t*)(args[1]));
280
281 char buffer[BYTES_PER_LINE * 3];
282 char ascii_buffer[BYTES_PER_LINE + 1];
283 char *buffer_pos = buffer;
284 char *bytes_pos = bytes;
285 char *bytes_roof = bytes + len;
286 int line_start = 0;
287 int i = 0;
288 int written = 0;
289
290 written += fprintf(stream, "=> %d bytes @ %p", len, bytes);
291
292 while (bytes_pos < bytes_roof)
293 {
294 static char hexdig[] = "0123456789ABCDEF";
295
296 *buffer_pos++ = hexdig[(*bytes_pos >> 4) & 0xF];
297 *buffer_pos++ = hexdig[ *bytes_pos & 0xF];
298
299 ascii_buffer[i++] =
300 (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.';
301
302 if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE)
303 {
304 int padding = 3 * (BYTES_PER_LINE - i);
305 int written;
306
307 while (padding--)
308 {
309 *buffer_pos++ = ' ';
310 }
311 *buffer_pos++ = '\0';
312 ascii_buffer[i] = '\0';
313
314 written += fprintf(stream, "\n%4d: %s %s",
315 line_start, buffer, ascii_buffer);
316
317
318 buffer_pos = buffer;
319 line_start += BYTES_PER_LINE;
320 i = 0;
321 }
322 else
323 {
324 *buffer_pos++ = ' ';
325 }
326 }
327 return written;
328 }
329
330 /**
331 * output handler in printf() for chunks
332 */
333 static int print_chunk(FILE *stream, const struct printf_info *info,
334 const void *const *args)
335 {
336 chunk_t *chunk = *((chunk_t**)(args[0]));
337 bool first = TRUE;
338 chunk_t copy = *chunk;
339 int written = 0;
340
341 if (!info->alt)
342 {
343 const void *new_args[] = {&chunk->ptr, &chunk->len};
344 return print_bytes(stream, info, new_args);
345 }
346
347 while (copy.len > 0)
348 {
349 if (first)
350 {
351 first = FALSE;
352 }
353 else
354 {
355 written += fprintf(stream, ":");
356 }
357 written += fprintf(stream, "%02x", *copy.ptr++);
358 copy.len--;
359 }
360 return written;
361 }
362
363 /**
364 * register printf() handlers
365 */
366 static void __attribute__ ((constructor))print_register()
367 {
368 register_printf_function(PRINTF_CHUNK, print_chunk, arginfo_ptr);
369 register_printf_function(PRINTF_BYTES, print_bytes, arginfo_ptr_int);
370 }