File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / buffer.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:20:06 2014 UTC (10 years ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, HEAD
lighttpd 1.4.35

    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: 	force_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: 		force_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: 		force_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: 		force_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: 	force_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: 		force_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: 		force_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 || b2->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: 	force_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: }
 1061: 
 1062: void log_failed_assert(const char *filename, unsigned int line, const char *msg) {
 1063: 	/* can't use buffer here; could lead to recursive assertions */
 1064: 	fprintf(stderr, "%s.%d: %s\n", filename, line, msg);
 1065: 	fflush(stderr);
 1066: 	abort();
 1067: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>