/*************************************************************************** * 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 */ #ifndef _BSTR_H #define _BSTR_H #ifdef __cplusplus extern "C" { #endif typedef struct bstr_t bstr; #include #include #include #include #include "bstr_builder.h" // Data structures struct bstr_t { /** The length of the string stored in the buffer. */ size_t len; /** The current size of the buffer. If there is extra room in the * buffer the string will be able to expand without reallocation. */ size_t size; /** Optional buffer pointer. If this pointer is NULL the string buffer * will immediately follow this structure. If the pointer is not NUL, * it points to the actual buffer used, and there's no data following * this structure. */ unsigned char *realptr; }; // Defines #define bstr_len(X) ((*(X)).len) #define bstr_size(X) ((*(X)).size) #define bstr_ptr(X) ( ((*(X)).realptr == NULL) ? ((unsigned char *)(X) + sizeof(bstr)) : (unsigned char *)(*(X)).realptr ) #define bstr_realptr(X) ((*(X)).realptr) // Functions /** * Append source bstring to destination bstring, growing destination if * necessary. If the destination bstring is expanded, the pointer will change. * You must replace the original destination pointer with the returned one. * Destination is not changed on memory allocation failure. * * @param[in] bdestination * @param[in] bsource * @return Updated bstring, or NULL on memory allocation failure. */ bstr *bstr_add(bstr *bdestination, const bstr *bsource); /** * Append a NUL-terminated source to destination, growing destination if * necessary. If the string is expanded, the pointer will change. You must * replace the original destination pointer with the returned one. Destination * is not changed on memory allocation failure. * * @param[in] b * @param[in] cstr * @return Updated bstring, or NULL on memory allocation failure. */ bstr *bstr_add_c(bstr *b, const char *cstr); /** * Append as many bytes from the source to destination bstring. The * destination storage will not be expanded if there is not enough space in it * already to accommodate all of the data. * * @param[in] b * @param[in] cstr * @return The destination bstring. */ bstr *bstr_add_c_noex(bstr *b, const char *cstr); /** * Append a memory region to destination, growing destination if necessary. If * the string is expanded, the pointer will change. You must replace the * original destination pointer with the returned one. Destination is not * changed on memory allocation failure. * * @param[in] b * @param[in] data * @param[in] len * @return Updated bstring, or NULL on memory allocation failure. */ bstr *bstr_add_mem(bstr *b, const void *data, size_t len); /** * Append as many bytes from the source to destination bstring. The * destination storage will not be expanded if there is not enough space in it * already to accommodate all of the data. * * @param[in] b * @param[in] data * @param[in] len * @return The destination bstring. */ bstr *bstr_add_mem_noex(bstr *b, const void *data, size_t len); /** * Append as many bytes from the source bstring to destination bstring. The * destination storage will not be expanded if there is not enough space in it * already to accommodate all of the data. * * @param[in] bdestination * @param[in] bsource * @return The destination bstring. */ bstr *bstr_add_noex(bstr *bdestination, const bstr *bsource); /** * Adjust bstring length. You will need to use this method whenever * you work directly with the string contents, and end up changing * its length by direct structure manipulation. * * @param[in] b * @param[in] newlen */ void bstr_adjust_len(bstr *b, size_t newlen); /** * Change the external pointer used by bstring. You will need to use this * function only if you're messing with bstr internals. Use with caution. * * @param[in] b * @param[in] newrealptr */ void bstr_adjust_realptr(bstr *b, void *newrealptr); /** * Adjust bstring size. This does not change the size of the storage behind * the bstring, just changes the field that keeps track of how many bytes * there are in the storage. You will need to use this function only if * you're messing with bstr internals. Use with caution. * * @param[in] b * @param[in] newsize */ void bstr_adjust_size(bstr *b, size_t newsize); /** * Allocate a zero-length bstring, reserving space for at least size bytes. * * @param[in] size * @return New string instance */ bstr *bstr_alloc(size_t size); /** * Checks whether bstring begins with another bstring. Case sensitive. * * @param[in] bhaystack * @param[in] bneedle * @return 1 if true, otherwise 0. */ int bstr_begins_with(const bstr *bhaystack, const bstr *bneedle); /** * Checks whether bstring begins with NUL-terminated string. Case sensitive. * * @param[in] bhaystack * @param[in] cneedle * @return 1 if true, otherwise 0. */ int bstr_begins_with_c(const bstr *bhaystack, const char *cneedle); /** * Checks whether bstring begins with NUL-terminated string. Case insensitive. * * @param[in] bhaystack * @param[in] cneedle * @return 1 if true, otherwise 0. */ int bstr_begins_with_c_nocase(const bstr *bhaystack, const char *cneedle); /** * Checks whether the bstring begins with the given memory block. Case sensitive. * * @param[in] bhaystack * @param[in] data * @param[in] len * @return 1 if true, otherwise 0. */ int bstr_begins_with_mem(const bstr *bhaystack, const void *data, size_t len); /** * Checks whether bstring begins with memory block. Case insensitive. * * @param[in] bhaystack * @param[in] data * @param[in] len * @return 1 if true, otherwise 0. */ int bstr_begins_with_mem_nocase(const bstr *bhaystack, const void *data, size_t len); /** * Checks whether bstring begins with another bstring. Case insensitive. * * @param[in] bhaystack * @param[in] cneedle * @return 1 if true, otherwise 0. */ int bstr_begins_with_nocase(const bstr *bhaystack, const bstr *cneedle); /** * Return the byte at the given position. * * @param[in] b * @param[in] pos * @return The byte at the given location, or -1 if the position is out of range. */ int bstr_char_at(const bstr *b, size_t pos); /** * Return the byte at the given position, counting from the end of the string (e.g., * byte at position 0 is the last byte in the string.) * * @param[in] b * @param[in] pos * @return The byte at the given location, or -1 if the position is out of range. */ int bstr_char_at_end(const bstr *b, size_t pos); /** * Remove the last byte from bstring, assuming it contains at least one byte. This * function will not reduce the storage that backs the string, only the amount * of data used. * * @param[in] b */ void bstr_chop(bstr *b); /** * Return the first position of the provided byte. * * @param[in] b * @param[in] c * @return The first position of the byte, or -1 if it could not be found */ int bstr_chr(const bstr *b, int c); /** * Case-sensitive comparison of two bstrings. * * @param[in] b1 * @param[in] b2 * @return Zero on string match, 1 if b1 is greater than b2, and -1 if b2 is * greater than b1. */ int bstr_cmp(const bstr *b1, const bstr *b2); /** * Case-sensitive comparison of a bstring and a NUL-terminated string. * * @param[in] b * @param[in] cstr * @return Zero on string match, 1 if b is greater than cstr, and -1 if cstr is * greater than b. */ int bstr_cmp_c(const bstr *b, const char *cstr); /** * Case-insensitive comparison of a bstring with a NUL-terminated string. * * @param[in] b * @param[in] cstr * @return Zero on string match, 1 if b is greater than cstr, and -1 if cstr is greater than b. */ int bstr_cmp_c_nocase(const bstr *b, const char *cstr); /** * Case-insensitive zero-skipping comparison of a bstring with a NUL-terminated string. * * @param[in] b * @param[in] cstr * @return Zero on string match, 1 if b is greater than cstr, and -1 if cstr is greater than b. */ int bstr_cmp_c_nocasenorzero(const bstr *b, const char *cstr); /** * Performs a case-sensitive comparison of a bstring with a memory region. * * @param[in] b * @param[in] data * @param[in] len * @return Zero ona match, 1 if b is greater than data, and -1 if data is greater than b. */ int bstr_cmp_mem(const bstr *b, const void *data, size_t len); /** * Performs a case-insensitive comparison of a bstring with a memory region. * * @param[in] b * @param[in] data * @param[in] len * @return Zero ona match, 1 if b is greater than data, and -1 if data is greater than b. */ int bstr_cmp_mem_nocase(const bstr *b, const void *data, size_t len); /** * Case-insensitive comparison two bstrings. * * @param[in] b1 * @param[in] b2 * @return Zero on string match, 1 if b1 is greater than b2, and -1 if b2 is * greater than b1. */ int bstr_cmp_nocase(const bstr *b1, const bstr *b2); /** * Case-insensitive and zero skipping comparison two bstrings. * * @param[in] b1 * @param[in] b2 * @return Zero on string match, 1 if b1 is greater than b2, and -1 if b2 is * greater than b1. */ int bstr_cmp_nocasenorzero(const bstr *b1, const bstr *b2); /** * Create a new bstring by copying the provided bstring. * * @param[in] b * @return New bstring, or NULL if memory allocation failed. */ bstr *bstr_dup(const bstr *b); /** * Create a new bstring by copying the provided NUL-terminated string. * * @param[in] cstr * @return New bstring, or NULL if memory allocation failed. */ bstr *bstr_dup_c(const char *cstr); /** * Create a new bstring by copying a part of the provided bstring. * * @param[in] b * @param[in] offset * @param[in] len * @return New bstring, or NULL if memory allocation failed. */ bstr *bstr_dup_ex(const bstr *b, size_t offset, size_t len); /** * Create a copy of the provided bstring, then convert it to lowercase. * * @param[in] b * @return New bstring, or NULL if memory allocation failed */ bstr *bstr_dup_lower(const bstr *b); /** * Create a new bstring by copying the provided memory region. * * @param[in] data * @param[in] len * @return New bstring, or NULL if memory allocation failed */ bstr *bstr_dup_mem(const void *data, size_t len); /** * Expand internal bstring storage to support at least newsize bytes. The storage * is not expanded if the current size is equal or greater to newsize. Because * realloc is used underneath, the old pointer to bstring may no longer be valid * after this function completes successfully. * * @param[in] b * @param[in] newsize * @return Updated string instance, or NULL if memory allocation failed or if * attempt was made to "expand" the bstring to a smaller size. */ bstr *bstr_expand(bstr *b, size_t newsize); /** * Deallocate the supplied bstring instance and set it to NULL. Allows NULL on * input. * * @param[in] b */ void bstr_free(bstr *b); /** * Find the needle in the haystack. * * @param[in] bhaystack * @param[in] bneedle * @return Position of the match, or -1 if the needle could not be found. */ int bstr_index_of(const bstr *bhaystack, const bstr *bneedle); /** * Find the needle in the haystack, ignoring case differences. * * @param[in] bhaystack * @param[in] bneedle * @return Position of the match, or -1 if the needle could not be found. */ int bstr_index_of_nocase(const bstr *bhaystack, const bstr *bneedle); /** * Find the needle in the haystack, with the needle being a NUL-terminated * string. * * @param[in] bhaystack * @param[in] cneedle * @return Position of the match, or -1 if the needle could not be found. */ int bstr_index_of_c(const bstr *bhaystack, const char *cneedle); /** * Find the needle in the haystack, with the needle being a NUL-terminated * string. Ignore case differences. * * @param[in] bhaystack * @param[in] cneedle * @return Position of the match, or -1 if the needle could not be found. */ int bstr_index_of_c_nocase(const bstr *bhaystack, const char *cneedle); /** * Find the needle in the haystack, with the needle being a NUL-terminated * string. Ignore case differences. Skip zeroes in haystack * * @param[in] bhaystack * @param[in] cneedle * @return Position of the match, or -1 if the needle could not be found. */ int bstr_index_of_c_nocasenorzero(const bstr *bhaystack, const char *cneedle); /** * Find the needle in the haystack, with the needle being a memory region. * * @param[in] bhaystack * @param[in] data * @param[in] len * @return Position of the match, or -1 if the needle could not be found. */ int bstr_index_of_mem(const bstr *bhaystack, const void *data, size_t len); /** * Find the needle in the haystack, with the needle being a memory region. * Ignore case differences. * * @param[in] bhaystack * @param[in] data * @param[in] len * @return Position of the match, or -1 if the needle could not be found. */ int bstr_index_of_mem_nocase(const bstr *bhaystack, const void *data, size_t len); /** * Return the last position of a character (byte). * * @param[in] b * @param[in] c * @return The last position of the character, or -1 if it could not be found. */ int bstr_rchr(const bstr *b, int c); /** * Convert bstring to lowercase. This function converts the supplied string, * it does not create a new string. * * @param[in] b * @return The same bstring received on input */ bstr *bstr_to_lowercase(bstr *b); /** * Case-sensitive comparison of two memory regions. * * @param[in] data1 * @param[in] len1 * @param[in] data2 * @param[in] len2 * @return Zero if the memory regions are identical, 1 if data1 is greater than * data2, and -1 if data2 is greater than data1. */ int bstr_util_cmp_mem(const void *data1, size_t len1, const void *data2, size_t len2); /** * Case-insensitive comparison of two memory regions. * * @param[in] data1 * @param[in] len1 * @param[in] data2 * @param[in] len2 * @return Zero if the memory regions are identical, 1 if data1 is greater than * data2, and -1 if data2 is greater than data1. */ int bstr_util_cmp_mem_nocase(const void *data1, size_t len1, const void *data2, size_t len2); /** * Case-insensitive zero-skipping comparison of two memory regions. * * @param[in] data1 * @param[in] len1 * @param[in] data2 * @param[in] len2 * @return Zero if the memory regions are identical, 1 if data1 is greater than * data2, and -1 if data2 is greater than data1. */ int bstr_util_cmp_mem_nocasenorzero(const void *data1, size_t len1, const void *data2, size_t len2); /** * Convert contents of a memory region to a positive integer. * * @param[in] data * @param[in] len * @param[in] base The desired number base. * @param[in] lastlen Points to the first unused byte in the region * @return If the conversion was successful, this function returns the * number. When the conversion fails, -1 will be returned when not * one valid digit was found, and -2 will be returned if an overflow * occurred. */ int64_t bstr_util_mem_to_pint(const void *data, size_t len, int base, size_t *lastlen); /** * Searches a memory block for the given NUL-terminated string. Case sensitive. * * @param[in] data * @param[in] len * @param[in] cstr * @return Index of the first location of the needle on success, or -1 if the needle was not found. */ int bstr_util_mem_index_of_c(const void *data, size_t len, const char *cstr); /** * Searches a memory block for the given NUL-terminated string. Case insensitive. * * @param[in] data * @param[in] len * @param[in] cstr * @return Index of the first location of the needle on success, or -1 if the needle was not found. */ int bstr_util_mem_index_of_c_nocase(const void *data, size_t len, const char *cstr); /** * Searches the haystack memory block for the needle memory block. Case sensitive. * * @param data1 * @param len1 * @param data2 * @param len2 * @return Index of the first location of the needle on success, or -1 if the needle was not found. */ int bstr_util_mem_index_of_mem(const void *data1, size_t len1, const void *data2, size_t len2); /** * Searches the haystack memory block for the needle memory block. Case sensitive. * * @param data1 * @param len1 * @param data2 * @param len2 * @return Index of the first location of the needle on success, or -1 if the needle was not found. */ int bstr_util_mem_index_of_mem_nocase(const void *data1, size_t len1, const void *data2, size_t len2); /** * Searches the haystack memory block for the needle memory block. Case sensitive. Skips zeroes in data1 * * @param data1 * @param len1 * @param data2 * @param len2 * @return Index of the first location of the needle on success, or -1 if the needle was not found. */ int bstr_util_mem_index_of_mem_nocasenorzero(const void *data1, size_t len1, const void *data2, size_t len2); /** * Removes whitespace from the beginning and the end of a memory region. The data * itself is not modified; this function only adjusts the provided pointers. * * @param[in,out] data * @param[in,out] len */ void bstr_util_mem_trim(unsigned char **data, size_t *len); /** * Take the provided memory region, allocate a new memory buffer, and construct * a NUL-terminated string, replacing each NUL byte with "\0" (two bytes). The * caller is responsible to keep track of the allocated memory area and free * it once it is no longer needed. * * @param[in] data * @param[in] len * @return The newly created NUL-terminated string, or NULL in case of memory * allocation failure. */ char *bstr_util_memdup_to_c(const void *data, size_t len); /** * Create a new NUL-terminated string out of the provided bstring. If NUL bytes * are contained in the bstring, each will be replaced with "\0" (two characters). * The caller is responsible to keep track of the allocated memory area and free * it once it is no longer needed. * * @param[in] b * @return The newly created NUL-terminated string, or NULL in case of memory * allocation failure. */ char *bstr_util_strdup_to_c(const bstr *b); /** * Create a new bstring from the provided NUL-terminated string and without * copying the data. The caller must ensure that the input string continues * to point to a valid memory location for as long as the bstring is used. * * @param[in] cstr * @return New bstring, or NULL on memory allocation failure. */ bstr *bstr_wrap_c(const char *cstr); /** * Create a new bstring from the provided memory buffer without * copying the data. The caller must ensure that the buffer remains * valid for as long as the bstring is used. * * @param[in] data * @param[in] len * @return New bstring, or NULL on memory allocation failure. */ bstr *bstr_wrap_mem(const void *data, size_t len); #ifdef __cplusplus } #endif #endif /* _BSTR_H */