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