/*************************************************************************** * Copyright (c) 2009-2010 Open Information Security Foundation * Copyright (c) 2010-2013 Qualys, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - Neither the name of the Qualys, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ /** * @file * @author Ivan Ristic */ #include #include "bstr.h" bstr *bstr_alloc(size_t len) { bstr *b = malloc(sizeof (bstr) + len); if (b == NULL) return NULL; b->len = 0; b->size = len; b->realptr = NULL; return b; } bstr *bstr_add(bstr *destination, const bstr *source) { return bstr_add_mem(destination, bstr_ptr(source), bstr_len(source)); } bstr *bstr_add_c(bstr *bdestination, const char *csource) { return bstr_add_mem(bdestination, csource, strlen(csource)); } bstr *bstr_add_c_noex(bstr *destination, const char *source) { return bstr_add_mem_noex(destination, source, strlen(source)); } bstr *bstr_add_mem(bstr *destination, const void *data, size_t len) { // Expand the destination if necessary if (bstr_size(destination) < bstr_len(destination) + len) { destination = bstr_expand(destination, bstr_len(destination) + len); if (destination == NULL) return NULL; } // Add source to destination bstr *b = (bstr *) destination; memcpy(bstr_ptr(destination) + bstr_len(b), data, len); bstr_adjust_len(b, bstr_len(b) + len); return destination; } bstr *bstr_add_mem_noex(bstr *destination, const void *data, size_t len) { size_t copylen = len; // Is there enough room in the destination? if (bstr_size(destination) < bstr_len(destination) + copylen) { copylen = bstr_size(destination) - bstr_len(destination); if (copylen <= 0) return destination; } // Copy over the bytes bstr *b = (bstr *) destination; memcpy(bstr_ptr(destination) + bstr_len(b), data, copylen); bstr_adjust_len(b, bstr_len(b) + copylen); return destination; } bstr *bstr_add_noex(bstr *destination, const bstr *source) { return bstr_add_mem_noex(destination, bstr_ptr(source), bstr_len(source)); } void bstr_adjust_len(bstr *b, size_t newlen) { b->len = newlen; } void bstr_adjust_realptr(bstr *b, void *newrealptr) { b->realptr = newrealptr; } void bstr_adjust_size(bstr *b, size_t newsize) { b->size = newsize; } int bstr_begins_with(const bstr *haystack, const bstr *needle) { return bstr_begins_with_mem(haystack, bstr_ptr(needle), bstr_len(needle)); } int bstr_begins_with_c(const bstr *haystack, const char *needle) { return bstr_begins_with_mem(haystack, needle, strlen(needle)); } int bstr_begins_with_c_nocase(const bstr *haystack, const char *needle) { return bstr_begins_with_mem_nocase(haystack, needle, strlen(needle)); } int bstr_begins_with_nocase(const bstr *haystack, const bstr *needle) { return bstr_begins_with_mem_nocase(haystack, bstr_ptr(needle), bstr_len(needle)); } int bstr_begins_with_mem(const bstr *haystack, const void *_data, size_t len) { const unsigned char *data = (unsigned char *) _data; const unsigned char *hdata = bstr_ptr(haystack); size_t hlen = bstr_len(haystack); size_t pos = 0; while ((pos < len) && (pos < hlen)) { if (hdata[pos] != data[pos]) { return 0; } pos++; } if (pos == len) { return 1; } else { return 0; } } int bstr_begins_with_mem_nocase(const bstr *haystack, const void *_data, size_t len) { const unsigned char *data = (const unsigned char *) _data; const unsigned char *hdata = bstr_ptr(haystack); size_t hlen = bstr_len(haystack); size_t pos = 0; while ((pos < len) && (pos < hlen)) { if (tolower((int) hdata[pos]) != tolower((int) data[pos])) { return 0; } pos++; } if (pos == len) { return 1; } else { return 0; } } int bstr_char_at(const bstr *b, size_t pos) { unsigned char *data = bstr_ptr(b); size_t len = bstr_len(b); if (pos >= len) return -1; return data[pos]; } int bstr_char_at_end(const bstr *b, size_t pos) { unsigned char *data = bstr_ptr(b); size_t len = bstr_len(b); if (pos >= len) return -1; return data[len - 1 - pos]; } void bstr_chop(bstr *b) { if (bstr_len(b) > 0) { bstr_adjust_len(b, bstr_len(b) - 1); } } int bstr_chr(const bstr *b, int c) { unsigned char *data = bstr_ptr(b); size_t len = bstr_len(b); size_t i = 0; while (i < len) { if (data[i] == c) { return (int) i; } i++; } return -1; } int bstr_cmp(const bstr *b1, const bstr *b2) { return bstr_util_cmp_mem(bstr_ptr(b1), bstr_len(b1), bstr_ptr(b2), bstr_len(b2)); } int bstr_cmp_c(const bstr *b, const char *c) { return bstr_util_cmp_mem(bstr_ptr(b), bstr_len(b), c, strlen(c)); } int bstr_cmp_c_nocase(const bstr *b, const char *c) { return bstr_util_cmp_mem_nocase(bstr_ptr(b), bstr_len(b), c, strlen(c)); } int bstr_cmp_c_nocasenorzero(const bstr *b, const char *c) { return bstr_util_cmp_mem_nocasenorzero(bstr_ptr(b), bstr_len(b), c, strlen(c)); } int bstr_cmp_mem(const bstr *b, const void *data, size_t len) { return bstr_util_cmp_mem(bstr_ptr(b), bstr_len(b), data, len); } int bstr_cmp_mem_nocase(const bstr *b, const void *data, size_t len) { return bstr_util_cmp_mem_nocase(bstr_ptr(b), bstr_len(b), data, len); } int bstr_cmp_nocase(const bstr *b1, const bstr *b2) { return bstr_util_cmp_mem_nocase(bstr_ptr(b1), bstr_len(b1), bstr_ptr(b2), bstr_len(b2)); } bstr *bstr_dup(const bstr *b) { return bstr_dup_ex(b, 0, bstr_len(b)); } bstr *bstr_dup_c(const char *cstr) { return bstr_dup_mem(cstr, strlen(cstr)); } bstr *bstr_dup_ex(const bstr *b, size_t offset, size_t len) { bstr *bnew = bstr_alloc(len); if (bnew == NULL) return NULL; memcpy(bstr_ptr(bnew), bstr_ptr(b) + offset, len); bstr_adjust_len(bnew, len); return bnew; } bstr *bstr_dup_lower(const bstr *b) { return bstr_to_lowercase(bstr_dup(b)); } bstr *bstr_dup_mem(const void *data, size_t len) { bstr *bnew = bstr_alloc(len); if (bnew == NULL) return NULL; memcpy(bstr_ptr(bnew), data, len); bstr_adjust_len(bnew, len); return bnew; } bstr *bstr_expand(bstr *b, size_t newsize) { if (bstr_realptr(b) != NULL) { // Refuse to expand a wrapped bstring. In the future, // we can change this to make a copy of the data, thus // leaving the original memory area intact. return NULL; } // Catch attempts to "expand" to a smaller size if (bstr_size(b) > newsize) return NULL; bstr *bnew = realloc(b, sizeof (bstr) + newsize); if (bnew == NULL) return NULL; bstr_adjust_size(bnew, newsize); return bnew; } void bstr_free(bstr *b) { if (b == NULL) return; free(b); } int bstr_index_of(const bstr *haystack, const bstr *needle) { return bstr_index_of_mem(haystack, bstr_ptr(needle), bstr_len(needle)); } int bstr_index_of_c(const bstr *haystack, const char *needle) { return bstr_index_of_mem(haystack, needle, strlen(needle)); } int bstr_index_of_c_nocase(const bstr *haystack, const char *needle) { return bstr_index_of_mem_nocase(haystack, needle, strlen(needle)); } int bstr_index_of_c_nocasenorzero(const bstr *haystack, const char *needle) { return bstr_util_mem_index_of_mem_nocasenorzero(bstr_ptr(haystack), bstr_len(haystack), needle, strlen(needle)); } int bstr_index_of_mem(const bstr *haystack, const void *_data2, size_t len2) { return bstr_util_mem_index_of_mem(bstr_ptr(haystack), bstr_len(haystack), _data2, len2); } int bstr_index_of_mem_nocase(const bstr *haystack, const void *_data2, size_t len2) { return bstr_util_mem_index_of_mem_nocase(bstr_ptr(haystack), bstr_len(haystack), _data2, len2); } int bstr_index_of_nocase(const bstr *haystack, const bstr *needle) { return bstr_index_of_mem_nocase(haystack, bstr_ptr(needle), bstr_len(needle)); } int bstr_rchr(const bstr *b, int c) { const unsigned char *data = bstr_ptr(b); size_t len = bstr_len(b); size_t i = len; while (i > 0) { if (data[i - 1] == c) { return (int) (i - 1); } i--; } return -1; } bstr *bstr_to_lowercase(bstr *b) { if (b == NULL) return NULL; unsigned char *data = bstr_ptr(b); size_t len = bstr_len(b); size_t i = 0; while (i < len) { data[i] = (uint8_t)tolower(data[i]); i++; } return b; } int bstr_util_cmp_mem(const void *_data1, size_t len1, const void *_data2, size_t len2) { const unsigned char *data1 = (const unsigned char *) _data1; const unsigned char *data2 = (const unsigned char *) _data2; size_t p1 = 0, p2 = 0; while ((p1 < len1) && (p2 < len2)) { if (data1[p1] != data2[p2]) { // Difference. return (data1[p1] < data2[p2]) ? -1 : 1; } p1++; p2++; } if ((p1 == len2) && (p2 == len1)) { // They're identical. return 0; } else { // One string is shorter. if (p1 == len1) return -1; else return 1; } } int bstr_util_cmp_mem_nocase(const void *_data1, size_t len1, const void *_data2, size_t len2) { const unsigned char *data1 = (const unsigned char *) _data1; const unsigned char *data2 = (const unsigned char *) _data2; size_t p1 = 0, p2 = 0; while ((p1 < len1) && (p2 < len2)) { if (tolower(data1[p1]) != tolower(data2[p2])) { // Difference. return (tolower(data1[p1]) < tolower(data2[p2])) ? -1 : 1; } p1++; p2++; } if ((p1 == len2) && (p2 == len1)) { // They're identical. return 0; } else { // One string is shorter. if (p1 == len1) return -1; else return 1; } } int bstr_util_cmp_mem_nocasenorzero(const void *_data1, size_t len1, const void *_data2, size_t len2) { const unsigned char *data1 = (const unsigned char *) _data1; const unsigned char *data2 = (const unsigned char *) _data2; size_t p1 = 0, p2 = 0; while ((p1 < len1) && (p2 < len2)) { if (data1[p1] == 0) { p1++; continue; } if (tolower(data1[p1]) != tolower(data2[p2])) { // Difference. return (tolower(data1[p1]) < tolower(data2[p2])) ? -1 : 1; } p1++; p2++; } while((p1 < len1) && (data1[p1] == 0)) { p1++; } if ((p1 == len1) && (p2 == len2)) { // They're identical. return 0; } else { // One string is shorter. if (p1 == len1) return -1; else return 1; } } int64_t bstr_util_mem_to_pint(const void *_data, size_t len, int base, size_t *lastlen) { const unsigned char *data = (unsigned char *) _data; int64_t rval = 0, tflag = 0; size_t i = 0; *lastlen = i; for (i = 0; i < len; i++) { int d = data[i]; *lastlen = i; // Convert character to digit. if ((d >= '0') && (d <= '9')) { d -= '0'; } else if ((d >= 'a') && (d <= 'z')) { d -= 'a' - 10; } else if ((d >= 'A') && (d <= 'Z')) { d -= 'A' - 10; } else { d = -1; } // Check that the digit makes sense with the base we are using. if ((d == -1) || (d >= base)) { if (tflag) { // Return what we have so far; lastlen points // to the first non-digit position. return rval; } else { // We didn't see a single digit. return -1; } } if (tflag) { if (((INT64_MAX - d) / base) < rval) { // Overflow return -2; } rval *= base; rval += d; } else { rval = d; tflag = 1; } } *lastlen = i + 1; return rval; } int bstr_util_mem_index_of_c(const void *_data1, size_t len1, const char *cstr) { return bstr_util_mem_index_of_mem(_data1, len1, cstr, strlen(cstr)); } int bstr_util_mem_index_of_c_nocase(const void *_data1, size_t len1, const char *cstr) { return bstr_util_mem_index_of_mem_nocase(_data1, len1, cstr, strlen(cstr)); } int bstr_util_mem_index_of_mem(const void *_data1, size_t len1, const void *_data2, size_t len2) { const unsigned char *data1 = (unsigned char *) _data1; const unsigned char *data2 = (unsigned char *) _data2; size_t i, j; // If we ever want to optimize this function, the following link // might be useful: http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm for (i = 0; i < len1; i++) { size_t k = i; for (j = 0; ((j < len2) && (k < len1)); j++, k++) { if (data1[k] != data2[j]) break; } if (j == len2) { return (int) i; } } return -1; } int bstr_util_mem_index_of_mem_nocase(const void *_data1, size_t len1, const void *_data2, size_t len2) { const unsigned char *data1 = (unsigned char *) _data1; const unsigned char *data2 = (unsigned char *) _data2; size_t i, j; // If we ever want to optimize this function, the following link // might be useful: http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm for (i = 0; i < len1; i++) { size_t k = i; for (j = 0; ((j < len2) && (k < len1)); j++, k++) { if (toupper(data1[k]) != toupper(data2[j])) break; } if (j == len2) { return (int) i; } } return -1; } int bstr_util_mem_index_of_mem_nocasenorzero(const void *_data1, size_t len1, const void *_data2, size_t len2) { const unsigned char *data1 = (unsigned char *) _data1; const unsigned char *data2 = (unsigned char *) _data2; size_t i, j; // If we ever want to optimize this function, the following link // might be useful: http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm for (i = 0; i < len1; i++) { size_t k = i; if (data1[i] == 0) { // skip leading zeroes to avoid quadratic complexity continue; } for (j = 0; ((j < len2) && (k < len1)); j++, k++) { if (data1[k] == 0) { j--; continue; } if (toupper(data1[k]) != toupper(data2[j])) break; } if (j == len2) { return (int) i; } } return -1; } void bstr_util_mem_trim(unsigned char **data, size_t *len) { if ((data == NULL)||(len == NULL)) return; unsigned char *d = *data; size_t l = *len; // Ignore whitespace at the beginning. size_t pos = 0; while ((pos < l) && isspace(d[pos])) pos++; d += pos; l -= pos; // Ignore whitespace at the end. while ((l > 0)&&(isspace(d[l - 1]))) l--; *data = d; *len = l; } char *bstr_util_memdup_to_c(const void *_data, size_t len) { const unsigned char *data = (unsigned char *) _data; // Count how many NUL bytes we have in the string. size_t i, nulls = 0; for (i = 0; i < len; i++) { if (data[i] == '\0') { nulls++; } } // Now copy the string into a NUL-terminated buffer. char *r, *d; r = d = malloc(len + nulls + 1); if (d == NULL) return NULL; while (len--) { if (*data == '\0') { data++; *d++ = '\\'; *d++ = '0'; } else { *d++ = *data++; } } *d = '\0'; return r; } char *bstr_util_strdup_to_c(const bstr *b) { if (b == NULL) return NULL; return bstr_util_memdup_to_c(bstr_ptr(b), bstr_len(b)); } bstr *bstr_wrap_c(const char *cstr) { return bstr_wrap_mem((unsigned char *) cstr, strlen(cstr)); } bstr *bstr_wrap_mem(const void *data, size_t len) { bstr *b = (bstr *) malloc(sizeof (bstr)); if (b == NULL) return NULL; b->size = b->len = len; b->realptr = (unsigned char *) data; return b; }