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