xref: /lighttpd1.4/src/buffer.c (revision 960d34c7)
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 		char a1 = *a++, b1 = *b++;
570 
571 		if (a1 != b1) {
572 			if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
573 				a1 |= 32;
574 			else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
575 				b1 |= 32;
576 			if ((a1 - b1) != 0) return (a1 - b1);
577 
578 		}
579 	}
580 
581 	/* all chars are the same, and the length match too
582 	 *
583 	 * they are the same */
584 	if (a_len == b_len) return 0;
585 
586 	/* if a is shorter then b, then b is larger */
587 	return (a_len - b_len);
588 }
589 
590 
591 /**
592  * check if the rightmost bytes of the string are equal.
593  *
594  *
595  */
596 
597 int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
598 	/* no, len -> equal */
599 	if (len == 0) return 1;
600 
601 	/* len > 0, but empty buffers -> not equal */
602 	if (b1->used == 0 || b2->used == 0) return 0;
603 
604 	/* buffers too small -> not equal */
605 	if (b1->used - 1 < len || b1->used - 1 < len) return 0;
606 
607 	if (0 == strncmp(b1->ptr + b1->used - 1 - len,
608 			 b2->ptr + b2->used - 1 - len, len)) {
609 		return 1;
610 	}
611 
612 	return 0;
613 }
614 
615 int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
616 	size_t i;
617 
618 	/* BO protection */
619 	if (in_len * 2 < in_len) return -1;
620 
621 	buffer_prepare_copy(b, in_len * 2 + 1);
622 
623 	for (i = 0; i < in_len; i++) {
624 		b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
625 		b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
626 	}
627 	b->ptr[b->used++] = '\0';
628 
629 	return 0;
630 }
631 
632 /* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
633 const char encoded_chars_rel_uri_part[] = {
634 	/*
635 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
636 	*/
637 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
638 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
639 	1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
640 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; < = > ? */
641 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
642 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
643 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
644 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */
645 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
646 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
647 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
648 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
649 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
650 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
651 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
652 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
653 };
654 
655 /* everything except: ! ( ) * - . / 0-9 A-Z _ a-z */
656 const char encoded_chars_rel_uri[] = {
657 	/*
658 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
659 	*/
660 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
661 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
662 	1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,  /*  20 -  2F space " # $ % & ' + , */
663 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; < = > ? */
664 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
665 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
666 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
667 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */
668 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
669 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
670 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
671 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
672 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
673 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
674 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
675 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
676 };
677 
678 const char encoded_chars_html[] = {
679 	/*
680 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
681 	*/
682 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
683 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
684 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
685 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
686 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
687 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
688 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
689 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */
690 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
691 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
692 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
693 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
694 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
695 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
696 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
697 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
698 };
699 
700 const char encoded_chars_minimal_xml[] = {
701 	/*
702 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
703 	*/
704 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
705 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
706 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
707 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
708 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
709 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
710 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
711 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */
712 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  80 -  8F */
713 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  90 -  9F */
714 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  A0 -  AF */
715 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  B0 -  BF */
716 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  C0 -  CF */
717 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  D0 -  DF */
718 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  E0 -  EF */
719 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  F0 -  FF */
720 };
721 
722 const char encoded_chars_hex[] = {
723 	/*
724 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
725 	*/
726 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
727 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
728 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */
729 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */
730 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */
731 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */
732 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */
733 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  70 -  7F */
734 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
735 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
736 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
737 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
738 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
739 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
740 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
741 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
742 };
743 
744 const char encoded_chars_http_header[] = {
745 	/*
746 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
747 	*/
748 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  /*  00 -  0F */
749 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  10 -  1F */
750 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F */
751 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  30 -  3F */
752 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
753 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
754 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
755 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  70 -  7F */
756 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  80 -  8F */
757 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  90 -  9F */
758 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  A0 -  AF */
759 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  B0 -  BF */
760 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  C0 -  CF */
761 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  D0 -  DF */
762 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  E0 -  EF */
763 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  F0 -  FF */
764 };
765 
766 
767 
768 int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
769 	unsigned char *ds, *d;
770 	size_t d_len, ndx;
771 	const char *map = NULL;
772 
773 	if (!s || !b) return -1;
774 
775 	if (b->ptr[b->used - 1] != '\0') {
776 		SEGFAULT();
777 	}
778 
779 	if (s_len == 0) return 0;
780 
781 	switch(encoding) {
782 	case ENCODING_REL_URI:
783 		map = encoded_chars_rel_uri;
784 		break;
785 	case ENCODING_REL_URI_PART:
786 		map = encoded_chars_rel_uri_part;
787 		break;
788 	case ENCODING_HTML:
789 		map = encoded_chars_html;
790 		break;
791 	case ENCODING_MINIMAL_XML:
792 		map = encoded_chars_minimal_xml;
793 		break;
794 	case ENCODING_HEX:
795 		map = encoded_chars_hex;
796 		break;
797 	case ENCODING_HTTP_HEADER:
798 		map = encoded_chars_http_header;
799 		break;
800 	case ENCODING_UNSET:
801 		break;
802 	}
803 
804 	assert(map != NULL);
805 
806 	/* count to-be-encoded-characters */
807 	for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
808 		if (map[*ds]) {
809 			switch(encoding) {
810 			case ENCODING_REL_URI:
811 			case ENCODING_REL_URI_PART:
812 				d_len += 3;
813 				break;
814 			case ENCODING_HTML:
815 			case ENCODING_MINIMAL_XML:
816 				d_len += 6;
817 				break;
818 			case ENCODING_HTTP_HEADER:
819 			case ENCODING_HEX:
820 				d_len += 2;
821 				break;
822 			case ENCODING_UNSET:
823 				break;
824 			}
825 		} else {
826 			d_len ++;
827 		}
828 	}
829 
830 	buffer_prepare_append(b, d_len);
831 
832 	for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
833 		if (map[*ds]) {
834 			switch(encoding) {
835 			case ENCODING_REL_URI:
836 			case ENCODING_REL_URI_PART:
837 				d[d_len++] = '%';
838 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
839 				d[d_len++] = hex_chars[(*ds) & 0x0F];
840 				break;
841 			case ENCODING_HTML:
842 			case ENCODING_MINIMAL_XML:
843 				d[d_len++] = '&';
844 				d[d_len++] = '#';
845 				d[d_len++] = 'x';
846 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
847 				d[d_len++] = hex_chars[(*ds) & 0x0F];
848 				d[d_len++] = ';';
849 				break;
850 			case ENCODING_HEX:
851 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
852 				d[d_len++] = hex_chars[(*ds) & 0x0F];
853 				break;
854 			case ENCODING_HTTP_HEADER:
855 				d[d_len++] = *ds;
856 				d[d_len++] = '\t';
857 				break;
858 			case ENCODING_UNSET:
859 				break;
860 			}
861 		} else {
862 			d[d_len++] = *ds;
863 		}
864 	}
865 
866 	/* terminate buffer and calculate new length */
867 	b->ptr[b->used + d_len - 1] = '\0';
868 
869 	b->used += d_len;
870 
871 	return 0;
872 }
873 
874 
875 /* decodes url-special-chars inplace.
876  * replaces non-printable characters with '_'
877  */
878 
879 static int buffer_urldecode_internal(buffer *url, int is_query) {
880 	unsigned char high, low;
881 	const char *src;
882 	char *dst;
883 
884 	if (!url || !url->ptr) return -1;
885 
886 	src = (const char*) url->ptr;
887 	dst = (char*) url->ptr;
888 
889 	while ((*src) != '\0') {
890 		if (is_query && *src == '+') {
891 			*dst = ' ';
892 		} else if (*src == '%') {
893 			*dst = '%';
894 
895 			high = hex2int(*(src + 1));
896 			if (high != 0xFF) {
897 				low = hex2int(*(src + 2));
898 				if (low != 0xFF) {
899 					high = (high << 4) | low;
900 
901 					/* map control-characters out */
902 					if (high < 32 || high == 127) high = '_';
903 
904 					*dst = high;
905 					src += 2;
906 				}
907 			}
908 		} else {
909 			*dst = *src;
910 		}
911 
912 		dst++;
913 		src++;
914 	}
915 
916 	*dst = '\0';
917 	url->used = (dst - url->ptr) + 1;
918 
919 	return 0;
920 }
921 
922 int buffer_urldecode_path(buffer *url) {
923 	return buffer_urldecode_internal(url, 0);
924 }
925 
926 int buffer_urldecode_query(buffer *url) {
927 	return buffer_urldecode_internal(url, 1);
928 }
929 
930 /* Remove "/../", "//", "/./" parts from path.
931  *
932  * /blah/..         gets  /
933  * /blah/../foo     gets  /foo
934  * /abc/./xyz       gets  /abc/xyz
935  * /abc//xyz        gets  /abc/xyz
936  *
937  * NOTE: src and dest can point to the same buffer, in which case,
938  *       the operation is performed in-place.
939  */
940 
941 int buffer_path_simplify(buffer *dest, buffer *src)
942 {
943 	int toklen;
944 	char c, pre1;
945 	char *start, *slash, *walk, *out;
946 	unsigned short pre;
947 
948 	if (src == NULL || src->ptr == NULL || dest == NULL)
949 		return -1;
950 
951 	if (src == dest)
952 		buffer_prepare_append(dest, 1);
953 	else
954 		buffer_prepare_copy(dest, src->used + 1);
955 
956 	walk  = src->ptr;
957 	start = dest->ptr;
958 	out   = dest->ptr;
959 	slash = dest->ptr;
960 
961 
962 #if defined(__WIN32) || defined(__CYGWIN__)
963 	/* cygwin is treating \ and / the same, so we have to that too
964 	 */
965 
966 	for (walk = src->ptr; *walk; walk++) {
967 		if (*walk == '\\') *walk = '/';
968 	}
969 	walk = src->ptr;
970 #endif
971 
972 	while (*walk == ' ') {
973 		walk++;
974 	}
975 
976 	pre1 = *(walk++);
977 	c    = *(walk++);
978 	pre  = pre1;
979 	if (pre1 != '/') {
980 		pre = ('/' << 8) | pre1;
981 		*(out++) = '/';
982 	}
983 	*(out++) = pre1;
984 
985 	if (pre1 == '\0') {
986 		dest->used = (out - start) + 1;
987 		return 0;
988 	}
989 
990 	while (1) {
991 		if (c == '/' || c == '\0') {
992 			toklen = out - slash;
993 			if (toklen == 3 && pre == (('.' << 8) | '.')) {
994 				out = slash;
995 				if (out > start) {
996 					out--;
997 					while (out > start && *out != '/') {
998 						out--;
999 					}
1000 				}
1001 
1002 				if (c == '\0')
1003 					out++;
1004 			} else if (toklen == 1 || pre == (('/' << 8) | '.')) {
1005 				out = slash;
1006 				if (c == '\0')
1007 					out++;
1008 			}
1009 
1010 			slash = out;
1011 		}
1012 
1013 		if (c == '\0')
1014 			break;
1015 
1016 		pre1 = c;
1017 		pre  = (pre << 8) | pre1;
1018 		c    = *walk;
1019 		*out = pre1;
1020 
1021 		out++;
1022 		walk++;
1023 	}
1024 
1025 	*out = '\0';
1026 	dest->used = (out - start) + 1;
1027 
1028 	return 0;
1029 }
1030 
1031 int light_isdigit(int c) {
1032 	return (c >= '0' && c <= '9');
1033 }
1034 
1035 int light_isxdigit(int c) {
1036 	if (light_isdigit(c)) return 1;
1037 
1038 	c |= 32;
1039 	return (c >= 'a' && c <= 'f');
1040 }
1041 
1042 int light_isalpha(int c) {
1043 	c |= 32;
1044 	return (c >= 'a' && c <= 'z');
1045 }
1046 
1047 int light_isalnum(int c) {
1048 	return light_isdigit(c) || light_isalpha(c);
1049 }
1050 
1051 int buffer_to_lower(buffer *b) {
1052 	char *c;
1053 
1054 	if (b->used == 0) return 0;
1055 
1056 	for (c = b->ptr; *c; c++) {
1057 		if (*c >= 'A' && *c <= 'Z') {
1058 			*c |= 32;
1059 		}
1060 	}
1061 
1062 	return 0;
1063 }
1064 
1065 
1066 int buffer_to_upper(buffer *b) {
1067 	char *c;
1068 
1069 	if (b->used == 0) return 0;
1070 
1071 	for (c = b->ptr; *c; c++) {
1072 		if (*c >= 'a' && *c <= 'z') {
1073 			*c &= ~32;
1074 		}
1075 	}
1076 
1077 	return 0;
1078 }
1079