1 #include "buffer.h"
2 
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include <stdio.h>
7 #include <assert.h>
8 #include <ctype.h>
9 
10 
11 static const char hex_chars[] = "0123456789abcdef";
12 
13 
14 /**
15  * init the buffer
16  *
17  */
18 
19 buffer* buffer_init(void) {
20 	buffer *b;
21 
22 	b = malloc(sizeof(*b));
23 	assert(b);
24 
25 	b->ptr = NULL;
26 	b->size = 0;
27 	b->used = 0;
28 
29 	return b;
30 }
31 
32 buffer *buffer_init_buffer(buffer *src) {
33 	buffer *b = buffer_init();
34 	buffer_copy_string_buffer(b, src);
35 	return b;
36 }
37 
38 /**
39  * free the buffer
40  *
41  */
42 
43 void buffer_free(buffer *b) {
44 	if (!b) return;
45 
46 	free(b->ptr);
47 	free(b);
48 }
49 
50 void buffer_reset(buffer *b) {
51 	if (!b) return;
52 
53 	/* limit don't reuse buffer larger than ... bytes */
54 	if (b->size > BUFFER_MAX_REUSE_SIZE) {
55 		free(b->ptr);
56 		b->ptr = NULL;
57 		b->size = 0;
58 	} else if (b->size) {
59 		b->ptr[0] = '\0';
60 	}
61 
62 	b->used = 0;
63 }
64 
65 
66 /**
67  *
68  * allocate (if neccessary) enough space for 'size' bytes and
69  * set the 'used' counter to 0
70  *
71  */
72 
73 #define BUFFER_PIECE_SIZE 64
74 
75 int buffer_prepare_copy(buffer *b, size_t size) {
76 	if (!b) return -1;
77 
78 	if ((0 == b->size) ||
79 	    (size > b->size)) {
80 		if (b->size) free(b->ptr);
81 
82 		b->size = size;
83 
84 		/* always allocate a multiply of BUFFER_PIECE_SIZE */
85 		b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
86 
87 		b->ptr = malloc(b->size);
88 		assert(b->ptr);
89 	}
90 	b->used = 0;
91 	return 0;
92 }
93 
94 /**
95  *
96  * increase the internal buffer (if neccessary) to append another 'size' byte
97  * ->used isn't changed
98  *
99  */
100 
101 int buffer_prepare_append(buffer *b, size_t size) {
102 	if (!b) return -1;
103 
104 	if (0 == b->size) {
105 		b->size = size;
106 
107 		/* always allocate a multiply of BUFFER_PIECE_SIZE */
108 		b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
109 
110 		b->ptr = malloc(b->size);
111 		b->used = 0;
112 		assert(b->ptr);
113 	} else if (b->used + size > b->size) {
114 		b->size += size;
115 
116 		/* always allocate a multiply of BUFFER_PIECE_SIZE */
117 		b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
118 
119 		b->ptr = realloc(b->ptr, b->size);
120 		assert(b->ptr);
121 	}
122 	return 0;
123 }
124 
125 int buffer_copy_string(buffer *b, const char *s) {
126 	size_t s_len;
127 
128 	if (!s || !b) return -1;
129 
130 	s_len = strlen(s) + 1;
131 	buffer_prepare_copy(b, s_len);
132 
133 	memcpy(b->ptr, s, s_len);
134 	b->used = s_len;
135 
136 	return 0;
137 }
138 
139 int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
140 	if (!s || !b) return -1;
141 #if 0
142 	/* removed optimization as we have to keep the empty string
143 	 * in some cases for the config handling
144 	 *
145 	 * url.access-deny = ( "" )
146 	 */
147 	if (s_len == 0) return 0;
148 #endif
149 	buffer_prepare_copy(b, s_len + 1);
150 
151 	memcpy(b->ptr, s, s_len);
152 	b->ptr[s_len] = '\0';
153 	b->used = s_len + 1;
154 
155 	return 0;
156 }
157 
158 int buffer_copy_string_buffer(buffer *b, const buffer *src) {
159 	if (!src) return -1;
160 
161 	if (src->used == 0) {
162 		buffer_reset(b);
163 		return 0;
164 	}
165 	return buffer_copy_string_len(b, src->ptr, src->used - 1);
166 }
167 
168 int buffer_append_string(buffer *b, const char *s) {
169 	size_t s_len;
170 
171 	if (!s || !b) return -1;
172 
173 	s_len = strlen(s);
174 	buffer_prepare_append(b, s_len + 1);
175 	if (b->used == 0)
176 		b->used++;
177 
178 	memcpy(b->ptr + b->used - 1, s, s_len + 1);
179 	b->used += s_len;
180 
181 	return 0;
182 }
183 
184 int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {
185 	size_t s_len;
186 
187 	if (!s || !b) return -1;
188 
189 	s_len = strlen(s);
190 	if (s_len > maxlen)  s_len = maxlen;
191 	buffer_prepare_append(b, maxlen + 1);
192 	if (b->used == 0)
193 		b->used++;
194 
195 	memcpy(b->ptr + b->used - 1, s, s_len);
196 	if (maxlen > s_len) {
197 		memset(b->ptr + b->used - 1 + s_len, ' ', maxlen - s_len);
198 	}
199 
200 	b->used += maxlen;
201 	b->ptr[b->used - 1] = '\0';
202 	return 0;
203 }
204 
205 /**
206  * append a string to the end of the buffer
207  *
208  * the resulting buffer is terminated with a '\0'
209  * s is treated as a un-terminated string (a \0 is handled a normal character)
210  *
211  * @param b a buffer
212  * @param s the string
213  * @param s_len size of the string (without the terminating \0)
214  */
215 
216 int buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
217 	if (!s || !b) return -1;
218 	if (s_len == 0) return 0;
219 
220 	buffer_prepare_append(b, s_len + 1);
221 	if (b->used == 0)
222 		b->used++;
223 
224 	memcpy(b->ptr + b->used - 1, s, s_len);
225 	b->used += s_len;
226 	b->ptr[b->used - 1] = '\0';
227 
228 	return 0;
229 }
230 
231 int buffer_append_string_buffer(buffer *b, const buffer *src) {
232 	if (!src) return -1;
233 	if (src->used == 0) return 0;
234 
235 	return buffer_append_string_len(b, src->ptr, src->used - 1);
236 }
237 
238 int buffer_append_memory(buffer *b, const char *s, size_t s_len) {
239 	if (!s || !b) return -1;
240 	if (s_len == 0) return 0;
241 
242 	buffer_prepare_append(b, s_len);
243 	memcpy(b->ptr + b->used, s, s_len);
244 	b->used += s_len;
245 
246 	return 0;
247 }
248 
249 int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
250 	if (!s || !b) return -1;
251 
252 	b->used = 0;
253 
254 	return buffer_append_memory(b, s, s_len);
255 }
256 
257 int buffer_append_long_hex(buffer *b, unsigned long value) {
258 	char *buf;
259 	int shift = 0;
260 	unsigned long copy = value;
261 
262 	while (copy) {
263 		copy >>= 4;
264 		shift++;
265 	}
266 	if (shift == 0)
267 		shift++;
268 	if (shift & 0x01)
269 		shift++;
270 
271 	buffer_prepare_append(b, shift + 1);
272 	if (b->used == 0)
273 		b->used++;
274 	buf = b->ptr + (b->used - 1);
275 	b->used += shift;
276 
277 	shift <<= 2;
278 	while (shift > 0) {
279 		shift -= 4;
280 		*(buf++) = hex_chars[(value >> shift) & 0x0F];
281 	}
282 	*buf = '\0';
283 
284 	return 0;
285 }
286 
287 int LI_ltostr(char *buf, long val) {
288 	char swap;
289 	char *end;
290 	int len = 1;
291 
292 	if (val < 0) {
293 		len++;
294 		*(buf++) = '-';
295 		val = -val;
296 	}
297 
298 	end = buf;
299 	while (val > 9) {
300 		*(end++) = '0' + (val % 10);
301 		val = val / 10;
302 	}
303 	*(end) = '0' + val;
304 	*(end + 1) = '\0';
305 	len += end - buf;
306 
307 	while (buf < end) {
308 		swap = *end;
309 		*end = *buf;
310 		*buf = swap;
311 
312 		buf++;
313 		end--;
314 	}
315 
316 	return len;
317 }
318 
319 int buffer_append_long(buffer *b, long val) {
320 	if (!b) return -1;
321 
322 	buffer_prepare_append(b, 32);
323 	if (b->used == 0)
324 		b->used++;
325 
326 	b->used += LI_ltostr(b->ptr + (b->used - 1), val);
327 	return 0;
328 }
329 
330 int buffer_copy_long(buffer *b, long val) {
331 	if (!b) return -1;
332 
333 	b->used = 0;
334 	return buffer_append_long(b, val);
335 }
336 
337 #if !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T)
338 int buffer_append_off_t(buffer *b, off_t val) {
339 	char swap;
340 	char *end;
341 	char *start;
342 	int len = 1;
343 
344 	if (!b) return -1;
345 
346 	buffer_prepare_append(b, 32);
347 	if (b->used == 0)
348 		b->used++;
349 
350 	start = b->ptr + (b->used - 1);
351 	if (val < 0) {
352 		len++;
353 		*(start++) = '-';
354 		val = -val;
355 	}
356 
357 	end = start;
358 	while (val > 9) {
359 		*(end++) = '0' + (val % 10);
360 		val = val / 10;
361 	}
362 	*(end) = '0' + val;
363 	*(end + 1) = '\0';
364 	len += end - start;
365 
366 	while (start < end) {
367 		swap   = *end;
368 		*end   = *start;
369 		*start = swap;
370 
371 		start++;
372 		end--;
373 	}
374 
375 	b->used += len;
376 	return 0;
377 }
378 
379 int buffer_copy_off_t(buffer *b, off_t val) {
380 	if (!b) return -1;
381 
382 	b->used = 0;
383 	return buffer_append_off_t(b, val);
384 }
385 #endif /* !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T) */
386 
387 char int2hex(char c) {
388 	return hex_chars[(c & 0x0F)];
389 }
390 
391 /* converts hex char (0-9, A-Z, a-z) to decimal.
392  * returns 0xFF on invalid input.
393  */
394 char hex2int(unsigned char hex) {
395 	hex = hex - '0';
396 	if (hex > 9) {
397 		hex = (hex + '0' - 1) | 0x20;
398 		hex = hex - 'a' + 11;
399 	}
400 	if (hex > 15)
401 		hex = 0xFF;
402 
403 	return hex;
404 }
405 
406 
407 /**
408  * init the buffer
409  *
410  */
411 
412 buffer_array* buffer_array_init(void) {
413 	buffer_array *b;
414 
415 	b = malloc(sizeof(*b));
416 
417 	assert(b);
418 	b->ptr = NULL;
419 	b->size = 0;
420 	b->used = 0;
421 
422 	return b;
423 }
424 
425 void buffer_array_reset(buffer_array *b) {
426 	size_t i;
427 
428 	if (!b) return;
429 
430 	/* if they are too large, reduce them */
431 	for (i = 0; i < b->used; i++) {
432 		buffer_reset(b->ptr[i]);
433 	}
434 
435 	b->used = 0;
436 }
437 
438 
439 /**
440  * free the buffer_array
441  *
442  */
443 
444 void buffer_array_free(buffer_array *b) {
445 	size_t i;
446 	if (!b) return;
447 
448 	for (i = 0; i < b->size; i++) {
449 		if (b->ptr[i]) buffer_free(b->ptr[i]);
450 	}
451 	free(b->ptr);
452 	free(b);
453 }
454 
455 buffer *buffer_array_append_get_buffer(buffer_array *b) {
456 	size_t i;
457 
458 	if (b->size == 0) {
459 		b->size = 16;
460 		b->ptr = malloc(sizeof(*b->ptr) * b->size);
461 		assert(b->ptr);
462 		for (i = 0; i < b->size; i++) {
463 			b->ptr[i] = NULL;
464 		}
465 	} else if (b->size == b->used) {
466 		b->size += 16;
467 		b->ptr = realloc(b->ptr, sizeof(*b->ptr) * b->size);
468 		assert(b->ptr);
469 		for (i = b->used; i < b->size; i++) {
470 			b->ptr[i] = NULL;
471 		}
472 	}
473 
474 	if (b->ptr[b->used] == NULL) {
475 		b->ptr[b->used] = buffer_init();
476 	}
477 
478 	b->ptr[b->used]->used = 0;
479 
480 	return b->ptr[b->used++];
481 }
482 
483 
484 char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
485 	size_t i;
486 	if (len == 0) return NULL;
487 	if (needle == NULL) return NULL;
488 
489 	if (b->used < len) return NULL;
490 
491 	for(i = 0; i < b->used - len; i++) {
492 		if (0 == memcmp(b->ptr + i, needle, len)) {
493 			return b->ptr + i;
494 		}
495 	}
496 
497 	return NULL;
498 }
499 
500 buffer *buffer_init_string(const char *str) {
501 	buffer *b = buffer_init();
502 
503 	buffer_copy_string(b, str);
504 
505 	return b;
506 }
507 
508 int buffer_is_empty(buffer *b) {
509 	if (!b) return 1;
510 	return (b->used == 0);
511 }
512 
513 /**
514  * check if two buffer contain the same data
515  *
516  * HISTORY: this function was pretty much optimized, but didn't handled
517  * alignment properly.
518  */
519 
520 int buffer_is_equal(buffer *a, buffer *b) {
521 	if (a->used != b->used) return 0;
522 	if (a->used == 0) return 1;
523 
524 	return (0 == strcmp(a->ptr, b->ptr));
525 }
526 
527 int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
528 	buffer b;
529 
530 	b.ptr = (char *)s;
531 	b.used = b_len + 1;
532 
533 	return buffer_is_equal(a, &b);
534 }
535 
536 /* simple-assumption:
537  *
538  * most parts are equal and doing a case conversion needs time
539  *
540  */
541 int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
542 	size_t ndx = 0, max_ndx;
543 	size_t *al, *bl;
544 	size_t mask = sizeof(*al) - 1;
545 
546 	al = (size_t *)a;
547 	bl = (size_t *)b;
548 
549 	/* is the alignment correct ? */
550 	if ( ((size_t)al & mask) == 0 &&
551 	     ((size_t)bl & mask) == 0 ) {
552 
553 		max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
554 
555 		for (; ndx < max_ndx; ndx += sizeof(*al)) {
556 			if (*al != *bl) break;
557 			al++; bl++;
558 
559 		}
560 
561 	}
562 
563 	a = (char *)al;
564 	b = (char *)bl;
565 
566 	max_ndx = ((a_len < b_len) ? a_len : b_len);
567 
568 	for (; ndx < max_ndx; ndx++) {
569 		int a1 = *a++, b1 = *b++;
570 
571 		if (a1 != b1) {
572 			/* always lowercase for transitive results */
573 			if (a1 >= 'A' && a1 <= 'Z') a1 |= 32;
574 			if (b1 >= 'A' && b1 <= 'Z') b1 |= 32;
575 
576 			if ((a1 - b1) != 0) return (a1 - b1);
577 		}
578 	}
579 
580 	/* all chars are the same, and the length match too
581 	 *
582 	 * they are the same */
583 	if (a_len == b_len) return 0;
584 
585 	/* if a is shorter then b, then b is larger */
586 	return (a_len - b_len);
587 }
588 
589 
590 /**
591  * check if the rightmost bytes of the string are equal.
592  *
593  *
594  */
595 
596 int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
597 	/* no, len -> equal */
598 	if (len == 0) return 1;
599 
600 	/* len > 0, but empty buffers -> not equal */
601 	if (b1->used == 0 || b2->used == 0) return 0;
602 
603 	/* buffers too small -> not equal */
604 	if (b1->used - 1 < len || b1->used - 1 < len) return 0;
605 
606 	if (0 == strncmp(b1->ptr + b1->used - 1 - len,
607 			 b2->ptr + b2->used - 1 - len, len)) {
608 		return 1;
609 	}
610 
611 	return 0;
612 }
613 
614 int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
615 	size_t i;
616 
617 	/* BO protection */
618 	if (in_len * 2 < in_len) return -1;
619 
620 	buffer_prepare_copy(b, in_len * 2 + 1);
621 
622 	for (i = 0; i < in_len; i++) {
623 		b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
624 		b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
625 	}
626 	b->ptr[b->used++] = '\0';
627 
628 	return 0;
629 }
630 
631 /* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
632 static const char encoded_chars_rel_uri_part[] = {
633 	/*
634 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
635 	*/
636 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
637 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
638 	1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
639 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; < = > ? */
640 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
641 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
642 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
643 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */
644 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
645 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
646 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
647 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
648 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
649 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
650 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
651 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
652 };
653 
654 /* everything except: ! ( ) * - . / 0-9 A-Z _ a-z */
655 static const char encoded_chars_rel_uri[] = {
656 	/*
657 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
658 	*/
659 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
660 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
661 	1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,  /*  20 -  2F space " # $ % & ' + , */
662 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; < = > ? */
663 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
664 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
665 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
666 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */
667 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
668 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
669 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
670 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
671 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
672 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
673 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
674 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
675 };
676 
677 static const char encoded_chars_html[] = {
678 	/*
679 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
680 	*/
681 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
682 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
683 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
684 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
685 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
686 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
687 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
688 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */
689 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
690 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
691 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
692 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
693 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
694 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
695 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
696 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
697 };
698 
699 static const char encoded_chars_minimal_xml[] = {
700 	/*
701 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
702 	*/
703 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
704 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
705 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
706 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
707 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
708 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
709 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
710 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */
711 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  80 -  8F */
712 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  90 -  9F */
713 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  A0 -  AF */
714 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  B0 -  BF */
715 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  C0 -  CF */
716 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  D0 -  DF */
717 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  E0 -  EF */
718 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  F0 -  FF */
719 };
720 
721 static const char encoded_chars_hex[] = {
722 	/*
723 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
724 	*/
725 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
726 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
727 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */
728 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */
729 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */
730 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */
731 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */
732 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  70 -  7F */
733 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
734 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
735 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
736 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
737 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
738 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
739 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
740 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
741 };
742 
743 static const char encoded_chars_http_header[] = {
744 	/*
745 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
746 	*/
747 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  /*  00 -  0F */
748 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  10 -  1F */
749 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F */
750 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  30 -  3F */
751 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
752 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
753 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
754 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  70 -  7F */
755 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  80 -  8F */
756 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  90 -  9F */
757 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  A0 -  AF */
758 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  B0 -  BF */
759 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  C0 -  CF */
760 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  D0 -  DF */
761 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  E0 -  EF */
762 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  F0 -  FF */
763 };
764 
765 
766 
767 int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
768 	unsigned char *ds, *d;
769 	size_t d_len, ndx;
770 	const char *map = NULL;
771 
772 	if (!s || !b) return -1;
773 
774 	if (b->ptr[b->used - 1] != '\0') {
775 		SEGFAULT();
776 	}
777 
778 	if (s_len == 0) return 0;
779 
780 	switch(encoding) {
781 	case ENCODING_REL_URI:
782 		map = encoded_chars_rel_uri;
783 		break;
784 	case ENCODING_REL_URI_PART:
785 		map = encoded_chars_rel_uri_part;
786 		break;
787 	case ENCODING_HTML:
788 		map = encoded_chars_html;
789 		break;
790 	case ENCODING_MINIMAL_XML:
791 		map = encoded_chars_minimal_xml;
792 		break;
793 	case ENCODING_HEX:
794 		map = encoded_chars_hex;
795 		break;
796 	case ENCODING_HTTP_HEADER:
797 		map = encoded_chars_http_header;
798 		break;
799 	case ENCODING_UNSET:
800 		break;
801 	}
802 
803 	assert(map != NULL);
804 
805 	/* count to-be-encoded-characters */
806 	for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
807 		if (map[*ds]) {
808 			switch(encoding) {
809 			case ENCODING_REL_URI:
810 			case ENCODING_REL_URI_PART:
811 				d_len += 3;
812 				break;
813 			case ENCODING_HTML:
814 			case ENCODING_MINIMAL_XML:
815 				d_len += 6;
816 				break;
817 			case ENCODING_HTTP_HEADER:
818 			case ENCODING_HEX:
819 				d_len += 2;
820 				break;
821 			case ENCODING_UNSET:
822 				break;
823 			}
824 		} else {
825 			d_len ++;
826 		}
827 	}
828 
829 	buffer_prepare_append(b, d_len);
830 
831 	for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
832 		if (map[*ds]) {
833 			switch(encoding) {
834 			case ENCODING_REL_URI:
835 			case ENCODING_REL_URI_PART:
836 				d[d_len++] = '%';
837 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
838 				d[d_len++] = hex_chars[(*ds) & 0x0F];
839 				break;
840 			case ENCODING_HTML:
841 			case ENCODING_MINIMAL_XML:
842 				d[d_len++] = '&';
843 				d[d_len++] = '#';
844 				d[d_len++] = 'x';
845 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
846 				d[d_len++] = hex_chars[(*ds) & 0x0F];
847 				d[d_len++] = ';';
848 				break;
849 			case ENCODING_HEX:
850 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
851 				d[d_len++] = hex_chars[(*ds) & 0x0F];
852 				break;
853 			case ENCODING_HTTP_HEADER:
854 				d[d_len++] = *ds;
855 				d[d_len++] = '\t';
856 				break;
857 			case ENCODING_UNSET:
858 				break;
859 			}
860 		} else {
861 			d[d_len++] = *ds;
862 		}
863 	}
864 
865 	/* terminate buffer and calculate new length */
866 	b->ptr[b->used + d_len - 1] = '\0';
867 
868 	b->used += d_len;
869 
870 	return 0;
871 }
872 
873 
874 /* decodes url-special-chars inplace.
875  * replaces non-printable characters with '_'
876  */
877 
878 static int buffer_urldecode_internal(buffer *url, int is_query) {
879 	unsigned char high, low;
880 	const char *src;
881 	char *dst;
882 
883 	if (!url || !url->ptr) return -1;
884 
885 	src = (const char*) url->ptr;
886 	dst = (char*) url->ptr;
887 
888 	while ((*src) != '\0') {
889 		if (is_query && *src == '+') {
890 			*dst = ' ';
891 		} else if (*src == '%') {
892 			*dst = '%';
893 
894 			high = hex2int(*(src + 1));
895 			if (high != 0xFF) {
896 				low = hex2int(*(src + 2));
897 				if (low != 0xFF) {
898 					high = (high << 4) | low;
899 
900 					/* map control-characters out */
901 					if (high < 32 || high == 127) high = '_';
902 
903 					*dst = high;
904 					src += 2;
905 				}
906 			}
907 		} else {
908 			*dst = *src;
909 		}
910 
911 		dst++;
912 		src++;
913 	}
914 
915 	*dst = '\0';
916 	url->used = (dst - url->ptr) + 1;
917 
918 	return 0;
919 }
920 
921 int buffer_urldecode_path(buffer *url) {
922 	return buffer_urldecode_internal(url, 0);
923 }
924 
925 int buffer_urldecode_query(buffer *url) {
926 	return buffer_urldecode_internal(url, 1);
927 }
928 
929 /* Remove "/../", "//", "/./" parts from path.
930  *
931  * /blah/..         gets  /
932  * /blah/../foo     gets  /foo
933  * /abc/./xyz       gets  /abc/xyz
934  * /abc//xyz        gets  /abc/xyz
935  *
936  * NOTE: src and dest can point to the same buffer, in which case,
937  *       the operation is performed in-place.
938  */
939 
940 int buffer_path_simplify(buffer *dest, buffer *src)
941 {
942 	int toklen;
943 	char c, pre1;
944 	char *start, *slash, *walk, *out;
945 	unsigned short pre;
946 
947 	if (src == NULL || src->ptr == NULL || dest == NULL)
948 		return -1;
949 
950 	if (src == dest)
951 		buffer_prepare_append(dest, 1);
952 	else
953 		buffer_prepare_copy(dest, src->used + 1);
954 
955 	walk  = src->ptr;
956 	start = dest->ptr;
957 	out   = dest->ptr;
958 	slash = dest->ptr;
959 
960 
961 #if defined(__WIN32) || defined(__CYGWIN__)
962 	/* cygwin is treating \ and / the same, so we have to that too
963 	 */
964 
965 	for (walk = src->ptr; *walk; walk++) {
966 		if (*walk == '\\') *walk = '/';
967 	}
968 	walk = src->ptr;
969 #endif
970 
971 	while (*walk == ' ') {
972 		walk++;
973 	}
974 
975 	pre1 = *(walk++);
976 	c    = *(walk++);
977 	pre  = pre1;
978 	if (pre1 != '/') {
979 		pre = ('/' << 8) | pre1;
980 		*(out++) = '/';
981 	}
982 	*(out++) = pre1;
983 
984 	if (pre1 == '\0') {
985 		dest->used = (out - start) + 1;
986 		return 0;
987 	}
988 
989 	while (1) {
990 		if (c == '/' || c == '\0') {
991 			toklen = out - slash;
992 			if (toklen == 3 && pre == (('.' << 8) | '.')) {
993 				out = slash;
994 				if (out > start) {
995 					out--;
996 					while (out > start && *out != '/') {
997 						out--;
998 					}
999 				}
1000 
1001 				if (c == '\0')
1002 					out++;
1003 			} else if (toklen == 1 || pre == (('/' << 8) | '.')) {
1004 				out = slash;
1005 				if (c == '\0')
1006 					out++;
1007 			}
1008 
1009 			slash = out;
1010 		}
1011 
1012 		if (c == '\0')
1013 			break;
1014 
1015 		pre1 = c;
1016 		pre  = (pre << 8) | pre1;
1017 		c    = *walk;
1018 		*out = pre1;
1019 
1020 		out++;
1021 		walk++;
1022 	}
1023 
1024 	*out = '\0';
1025 	dest->used = (out - start) + 1;
1026 
1027 	return 0;
1028 }
1029 
1030 int light_isdigit(int c) {
1031 	return (c >= '0' && c <= '9');
1032 }
1033 
1034 int light_isxdigit(int c) {
1035 	if (light_isdigit(c)) return 1;
1036 
1037 	c |= 32;
1038 	return (c >= 'a' && c <= 'f');
1039 }
1040 
1041 int light_isalpha(int c) {
1042 	c |= 32;
1043 	return (c >= 'a' && c <= 'z');
1044 }
1045 
1046 int light_isalnum(int c) {
1047 	return light_isdigit(c) || light_isalpha(c);
1048 }
1049 
1050 int buffer_to_lower(buffer *b) {
1051 	char *c;
1052 
1053 	if (b->used == 0) return 0;
1054 
1055 	for (c = b->ptr; *c; c++) {
1056 		if (*c >= 'A' && *c <= 'Z') {
1057 			*c |= 32;
1058 		}
1059 	}
1060 
1061 	return 0;
1062 }
1063 
1064 
1065 int buffer_to_upper(buffer *b) {
1066 	char *c;
1067 
1068 	if (b->used == 0) return 0;
1069 
1070 	for (c = b->ptr; *c; c++) {
1071 		if (*c >= 'a' && *c <= 'z') {
1072 			*c &= ~32;
1073 		}
1074 	}
1075 
1076 	return 0;
1077 }
1078