root/trunk/src/buffer.c

Revision 2273, 23.9 kB (checked in by stbuehler, 5 weeks ago)

Fixed url encoding to encode more characters (#266)

  • Property svn:eol-style set to native
Line 
1#include <stdlib.h>
2#include <string.h>
3
4#include <stdio.h>
5#include <assert.h>
6#include <ctype.h>
7
8#include "buffer.h"
9
10
11static const char hex_chars[] = "0123456789abcdef";
12
13
14/**
15 * init the buffer
16 *
17 */
18
19buffer* 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
32buffer *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
43void buffer_free(buffer *b) {
44        if (!b) return;
45
46        free(b->ptr);
47        free(b);
48}
49
50void 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 necessary) enough space for 'size' (+1, if 'size' > 0) bytes and
69 * set the 'used' counter to 0
70 *
71 */
72
73#define BUFFER_PIECE_SIZE 64
74
75int 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 multiple of BUFFER_PIECE_SIZE */
85                /* adds a least 1 byte */
86                b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
87
88                b->ptr = malloc(b->size);
89                assert(b->ptr);
90        }
91        b->used = 0;
92        return 0;
93}
94
95/**
96 *
97 * increase the internal buffer (if necessary) to append another 'size' byte
98 * ->used isn't changed
99 *
100 */
101
102int buffer_prepare_append(buffer *b, size_t size) {
103        if (!b) return -1;
104
105        if (0 == b->size) {
106                b->size = size;
107
108                /* always allocate a multiple of BUFFER_PIECE_SIZE */
109                b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
110
111                b->ptr = malloc(b->size);
112                b->used = 0;
113                assert(b->ptr);
114        } else if (b->used + size >= b->size) {
115                b->size += size;
116
117                /* always allocate a multiple of BUFFER_PIECE_SIZE */
118                b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
119
120                b->ptr = realloc(b->ptr, b->size);
121                assert(b->ptr);
122        }
123        return 0;
124}
125
126int buffer_copy_string(buffer *b, const char *s) {
127        size_t s_len;
128
129        if (!s || !b) return -1;
130
131        s_len = strlen(s) + 1;
132        buffer_prepare_copy(b, s_len);
133
134        memcpy(b->ptr, s, s_len);
135        b->used = s_len;
136
137        return 0;
138}
139
140int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
141        if (!s || !b) return -1;
142#if 0
143        /* removed optimization as we have to keep the empty string
144         * in some cases for the config handling
145         *
146         * url.access-deny = ( "" )
147         */
148        if (s_len == 0) return 0;
149#endif
150        buffer_prepare_copy(b, s_len + 1);
151
152        memcpy(b->ptr, s, s_len);
153        b->ptr[s_len] = '\0';
154        b->used = s_len + 1;
155
156        return 0;
157}
158
159int buffer_copy_string_buffer(buffer *b, const buffer *src) {
160        if (!src) return -1;
161
162        if (src->used == 0) {
163                b->used = 0;
164                return 0;
165        }
166        return buffer_copy_string_len(b, src->ptr, src->used - 1);
167}
168
169int buffer_append_string(buffer *b, const char *s) {
170        size_t s_len;
171
172        if (!s || !b) return -1;
173
174        s_len = strlen(s);
175        buffer_prepare_append(b, s_len + 1);
176        if (b->used == 0)
177                b->used++;
178
179        memcpy(b->ptr + b->used - 1, s, s_len + 1);
180        b->used += s_len;
181
182        return 0;
183}
184
185int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {
186        size_t s_len;
187
188        if (!s || !b) return -1;
189
190        s_len = strlen(s);
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 an un-terminated string (a \0 is handled as 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
216int 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
231int 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
238int 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
249int 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
257int 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
287int 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
319int 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
330int 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)
338int 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
379int 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
387char 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 */
394char 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 ptr buffer
409 *
410 */
411buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
412{
413        buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
414        l->free = freer;
415
416        return l;
417}
418
419/**
420 * free the buffer_array
421 *
422 */
423void buffer_ptr_free(buffer_ptr *l)
424{
425        if (NULL != l) {
426                buffer_ptr_clear(l);
427                free(l);
428        }
429}
430
431void buffer_ptr_clear(buffer_ptr *l)
432{
433        assert(NULL != l);
434
435        if (l->free && l->used) {
436                size_t i;
437                for (i = 0; i < l->used; i ++) {
438                        l->free(l->ptr[i]);
439                }
440        }
441
442        if (l->ptr) {
443                free(l->ptr);
444                l->ptr = NULL;
445        }
446        l->used = 0;
447        l->size = 0;
448}
449
450void buffer_ptr_append(buffer_ptr* l, void *item)
451{
452        assert(NULL != l);
453        if (l->ptr == NULL) {
454                l->size = 16;
455                l->ptr = (void **)malloc(sizeof(void *) * l->size);
456        }
457        else if (l->used == l->size) {
458                l->size += 16;
459                l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
460        }
461        l->ptr[l->used++] = item;
462}
463
464void *buffer_ptr_pop(buffer_ptr* l)
465{
466        assert(NULL != l && l->used > 0);
467        return l->ptr[--l->used];
468}
469
470void *buffer_ptr_top(buffer_ptr* l)
471{
472        assert(NULL != l && l->used > 0);
473        return l->ptr[l->used-1];
474}
475
476/**
477 * init the buffer
478 *
479 */
480
481buffer_array* buffer_array_init(void) {
482        buffer_array *b;
483
484        b = malloc(sizeof(*b));
485
486        assert(b);
487        b->ptr = NULL;
488        b->size = 0;
489        b->used = 0;
490
491        return b;
492}
493
494void buffer_array_reset(buffer_array *b) {
495        size_t i;
496
497        if (!b) return;
498
499        /* if they are too large, reduce them */
500        for (i = 0; i < b->used; i++) {
501                buffer_reset(b->ptr[i]);
502        }
503
504        b->used = 0;
505}
506
507
508/**
509 * free the buffer_array
510 *
511 */
512
513void buffer_array_free(buffer_array *b) {
514        size_t i;
515        if (!b) return;
516
517        for (i = 0; i < b->size; i++) {
518                if (b->ptr[i]) buffer_free(b->ptr[i]);
519        }
520        free(b->ptr);
521        free(b);
522}
523
524buffer *buffer_array_append_get_buffer(buffer_array *b) {
525        size_t i;
526
527        if (b->size == 0) {
528                b->size = 16;
529                b->ptr = malloc(sizeof(*b->ptr) * b->size);
530                assert(b->ptr);
531                for (i = 0; i < b->size; i++) {
532                        b->ptr[i] = NULL;
533                }
534        } else if (b->size == b->used) {
535                b->size += 16;
536                b->ptr = realloc(b->ptr, sizeof(*b->ptr) * b->size);
537                assert(b->ptr);
538                for (i = b->used; i < b->size; i++) {
539                        b->ptr[i] = NULL;
540                }
541        }
542
543        if (b->ptr[b->used] == NULL) {
544                b->ptr[b->used] = buffer_init();
545        }
546
547        b->ptr[b->used]->used = 0;
548
549        return b->ptr[b->used++];
550}
551
552
553char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
554        size_t i;
555        if (len == 0) return NULL;
556        if (needle == NULL) return NULL;
557
558        if (b->used < len) return NULL;
559
560        for(i = 0; i < b->used - len; i++) {
561                if (0 == memcmp(b->ptr + i, needle, len)) {
562                        return b->ptr + i;
563                }
564        }
565
566        return NULL;
567}
568
569buffer *buffer_init_string(const char *str) {
570        buffer *b = buffer_init();
571
572        buffer_copy_string(b, str);
573
574        return b;
575}
576
577int buffer_is_empty(buffer *b) {
578        if (!b) return 1;
579
580        return (b->used == 0);
581}
582
583/**
584 * check if two buffers contain the same data
585 *
586 * HISTORY: this function was pretty much optimized, but didn't handled
587 * alignment properly.
588 */
589
590int buffer_is_equal(buffer *a, buffer *b) {
591        if (a->used != b->used) return 0;
592        if (a->used == 0) return 1;
593
594        return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
595}
596
597int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
598        buffer b;
599
600        b.ptr = (char *)s;
601        b.used = b_len + 1;
602
603        return buffer_is_equal(a, &b);
604}
605
606/* simple-assumption:
607 *
608 * most parts are equal and doing a case conversion takes time
609 *
610 */
611int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
612        size_t ndx = 0, max_ndx;
613        size_t *al, *bl;
614        size_t mask = sizeof(*al) - 1;
615
616        al = (size_t *)a;
617        bl = (size_t *)b;
618
619        /* is the alignment correct? */
620        if ( ((size_t)al & mask) == 0 &&
621             ((size_t)bl & mask) == 0 ) {
622
623                max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
624
625                for (; ndx < max_ndx; ndx += sizeof(*al)) {
626                        if (*al != *bl) break;
627                        al++; bl++;
628
629                }
630
631        }
632
633        a = (char *)al;
634        b = (char *)bl;
635
636        max_ndx = ((a_len < b_len) ? a_len : b_len);
637
638        for (; ndx < max_ndx; ndx++) {
639                char a1 = *a++, b1 = *b++;
640
641                if (a1 != b1) {
642                        if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
643                                a1 |= 32;
644                        else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
645                                b1 |= 32;
646                        if ((a1 - b1) != 0) return (a1 - b1);
647
648                }
649        }
650
651        return 0;
652}
653
654
655/**
656 * check if the rightmost bytes of the string are equal.
657 *
658 *
659 */
660
661int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
662        /* no, len -> equal */
663        if (len == 0) return 1;
664
665        /* len > 0, but empty buffers -> not equal */
666        if (b1->used == 0 || b2->used == 0) return 0;
667
668        /* buffers too small -> not equal */
669        if (b1->used - 1 < len || b2->used - 1 < len) return 0;
670
671        if (0 == strncmp(b1->ptr + b1->used - 1 - len,
672                         b2->ptr + b2->used - 1 - len, len)) {
673                return 1;
674        }
675
676        return 0;
677}
678
679int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
680        size_t i;
681
682        /* BO protection */
683        if (in_len * 2 < in_len) return -1;
684
685        buffer_prepare_copy(b, in_len * 2 + 1);
686
687        for (i = 0; i < in_len; i++) {
688                b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
689                b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
690        }
691        b->ptr[b->used++] = '\0';
692
693        return 0;
694}
695
696/* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
697const char encoded_chars_rel_uri_part[] = {
698        /*
699        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
700        */
701        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
702        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
703        1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
704        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; < = > ? */
705        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
706        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
707        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
708        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */
709        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
710        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,