added missing #include
[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 #include <sys/stat.h>
26
27 #include "chunk.h"
28
29 #include <debug.h>
30 #include <printf_hook.h>
31
32 /**
33 * Empty chunk.
34 */
35 chunk_t chunk_empty = { NULL, 0 };
36
37 /**
38 * Described in header.
39 */
40 chunk_t chunk_create(u_char *ptr, size_t len)
41 {
42 chunk_t chunk = {ptr, len};
43 return chunk;
44 }
45
46 /**
47 * Described in header.
48 */
49 chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
50 {
51 chunk_t clone = chunk_empty;
52
53 if (chunk.ptr && chunk.len > 0)
54 {
55 clone.ptr = ptr;
56 clone.len = chunk.len;
57 memcpy(clone.ptr, chunk.ptr, chunk.len);
58 }
59
60 return clone;
61 }
62
63 /**
64 * Decribed in header.
65 */
66 size_t chunk_length(const char* mode, ...)
67 {
68 va_list chunks;
69 size_t length = 0;
70
71 va_start(chunks, mode);
72 while (TRUE)
73 {
74 switch (*mode++)
75 {
76 case 'm':
77 case 'c':
78 {
79 chunk_t ch = va_arg(chunks, chunk_t);
80 length += ch.len;
81 continue;
82 }
83 default:
84 break;
85 }
86 break;
87 }
88 va_end(chunks);
89 return length;
90 }
91
92 /**
93 * Decribed in header.
94 */
95 chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
96 {
97 va_list chunks;
98 chunk_t construct = chunk_create(ptr, 0);
99
100 va_start(chunks, mode);
101 while (TRUE)
102 {
103 bool free_chunk = FALSE;
104 switch (*mode++)
105 {
106 case 'm':
107 {
108 free_chunk = TRUE;
109 }
110 case 'c':
111 {
112 chunk_t ch = va_arg(chunks, chunk_t);
113 memcpy(ptr, ch.ptr, ch.len);
114 ptr += ch.len;
115 construct.len += ch.len;
116 if (free_chunk)
117 {
118 free(ch.ptr);
119 }
120 continue;
121 }
122 default:
123 break;
124 }
125 break;
126 }
127 va_end(chunks);
128
129 return construct;
130 }
131
132 /**
133 * Decribed in header.
134 */
135 void chunk_split(chunk_t chunk, const char *mode, ...)
136 {
137 va_list chunks;
138 size_t len;
139 chunk_t *ch;
140
141 va_start(chunks, mode);
142 while (TRUE)
143 {
144 if (*mode == '\0')
145 {
146 break;
147 }
148 len = va_arg(chunks, size_t);
149 ch = va_arg(chunks, chunk_t*);
150 /* a null chunk means skip len bytes */
151 if (ch == NULL)
152 {
153 chunk = chunk_skip(chunk, len);
154 continue;
155 }
156 switch (*mode++)
157 {
158 case 'm':
159 {
160 ch->len = min(chunk.len, len);
161 if (ch->len)
162 {
163 ch->ptr = chunk.ptr;
164 }
165 else
166 {
167 ch->ptr = NULL;
168 }
169 chunk = chunk_skip(chunk, ch->len);
170 continue;
171 }
172 case 'a':
173 {
174 ch->len = min(chunk.len, len);
175 if (ch->len)
176 {
177 ch->ptr = malloc(ch->len);
178 memcpy(ch->ptr, chunk.ptr, ch->len);
179 }
180 else
181 {
182 ch->ptr = NULL;
183 }
184 chunk = chunk_skip(chunk, ch->len);
185 continue;
186 }
187 case 'c':
188 {
189 ch->len = min(ch->len, chunk.len);
190 ch->len = min(ch->len, len);
191 if (ch->len)
192 {
193 memcpy(ch->ptr, chunk.ptr, ch->len);
194 }
195 else
196 {
197 ch->ptr = NULL;
198 }
199 chunk = chunk_skip(chunk, ch->len);
200 continue;
201 }
202 default:
203 break;
204 }
205 break;
206 }
207 va_end(chunks);
208 }
209
210 /**
211 * Described in header.
212 */
213 bool chunk_write(chunk_t chunk, const char *path, const char *label, mode_t mask, bool force)
214 {
215 mode_t oldmask;
216 FILE *fd;
217
218 if (!force)
219 {
220 fd = fopen(path, "r");
221 if (fd)
222 {
223 fclose(fd);
224 DBG1(" %s file '%s' already exists", label, path);
225 return FALSE;
226 }
227 }
228
229 /* set umask */
230 oldmask = umask(mask);
231
232 fd = fopen(path, "w");
233
234 if (fd)
235 {
236 fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd);
237 fclose(fd);
238 DBG1(" written %s file '%s' (%u bytes)", label, path, chunk.len);
239 umask(oldmask);
240 return TRUE;
241 }
242 else
243 {
244 DBG1(" could not open %s file '%s' for writing", label, path);
245 umask(oldmask);
246 return FALSE;
247 }
248 }
249
250 /**
251 * Described in header.
252 */
253 void chunk_free(chunk_t *chunk)
254 {
255 free(chunk->ptr);
256 chunk->ptr = NULL;
257 chunk->len = 0;
258 }
259
260 /**
261 * Described in header.
262 */
263 chunk_t chunk_skip(chunk_t chunk, size_t bytes)
264 {
265 if (chunk.len > bytes)
266 {
267 chunk.ptr += bytes;
268 chunk.len -= bytes;
269 return chunk;
270 }
271 return chunk_empty;
272 }
273
274 /**
275 * Described in header.
276 */
277 int chunk_compare(chunk_t a, chunk_t b)
278 {
279 int compare_len = a.len - b.len;
280 int len = (compare_len < 0)? a.len : b.len;
281
282 if (compare_len != 0 || len == 0)
283 {
284 return compare_len;
285 }
286 return memcmp(a.ptr, b.ptr, len);
287 };
288
289 /**
290 * Described in header.
291 */
292 bool chunk_equals(chunk_t a, chunk_t b)
293 {
294 return a.ptr != NULL && b.ptr != NULL &&
295 a.len == b.len && memeq(a.ptr, b.ptr, a.len);
296 }
297
298 /**
299 * Described in header.
300 */
301 bool chunk_equals_or_null(chunk_t a, chunk_t b)
302 {
303 if (a.ptr == NULL || b.ptr == NULL)
304 return TRUE;
305 return a.len == b.len && memeq(a.ptr, b.ptr, a.len);
306 }
307
308 /**
309 * Number of bytes per line to dump raw data
310 */
311 #define BYTES_PER_LINE 16
312
313 /**
314 * output handler in printf() for byte ranges
315 */
316 static int print_bytes(FILE *stream, const struct printf_info *info,
317 const void *const *args)
318 {
319 char *bytes = *((void**)(args[0]));
320 int len = *((size_t*)(args[1]));
321
322 char buffer[BYTES_PER_LINE * 3];
323 char ascii_buffer[BYTES_PER_LINE + 1];
324 char *buffer_pos = buffer;
325 char *bytes_pos = bytes;
326 char *bytes_roof = bytes + len;
327 int line_start = 0;
328 int i = 0;
329 int written = 0;
330
331 written += fprintf(stream, "=> %d bytes @ %p", len, bytes);
332
333 while (bytes_pos < bytes_roof)
334 {
335 static char hexdig[] = "0123456789ABCDEF";
336
337 *buffer_pos++ = hexdig[(*bytes_pos >> 4) & 0xF];
338 *buffer_pos++ = hexdig[ *bytes_pos & 0xF];
339
340 ascii_buffer[i++] =
341 (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.';
342
343 if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE)
344 {
345 int padding = 3 * (BYTES_PER_LINE - i);
346 int written;
347
348 while (padding--)
349 {
350 *buffer_pos++ = ' ';
351 }
352 *buffer_pos++ = '\0';
353 ascii_buffer[i] = '\0';
354
355 written += fprintf(stream, "\n%4d: %s %s",
356 line_start, buffer, ascii_buffer);
357
358
359 buffer_pos = buffer;
360 line_start += BYTES_PER_LINE;
361 i = 0;
362 }
363 else
364 {
365 *buffer_pos++ = ' ';
366 }
367 }
368 return written;
369 }
370
371 /**
372 * output handler in printf() for chunks
373 */
374 static int print_chunk(FILE *stream, const struct printf_info *info,
375 const void *const *args)
376 {
377 chunk_t *chunk = *((chunk_t**)(args[0]));
378 bool first = TRUE;
379 chunk_t copy = *chunk;
380 int written = 0;
381
382 if (!info->alt)
383 {
384 const void *new_args[] = {&chunk->ptr, &chunk->len};
385 return print_bytes(stream, info, new_args);
386 }
387
388 while (copy.len > 0)
389 {
390 if (first)
391 {
392 first = FALSE;
393 }
394 else
395 {
396 written += fprintf(stream, ":");
397 }
398 written += fprintf(stream, "%02x", *copy.ptr++);
399 copy.len--;
400 }
401 return written;
402 }
403
404 /**
405 * register printf() handlers
406 */
407 static void __attribute__ ((constructor))print_register()
408 {
409 register_printf_function(PRINTF_CHUNK, print_chunk, arginfo_ptr);
410 register_printf_function(PRINTF_BYTES, print_bytes, arginfo_ptr_int);
411 }