Annotation of embedaddon/lighttpd/src/buffer.c, revision 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>