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>