//////////////////////////////////////// // Define ////////////////////////////// //////////////////////////////////////// /** Maximum ASCII ordinal in search strings. */ #define SEARCH_MAX_ORD 128 //////////////////////////////////////// // Include ///////////////////////////// //////////////////////////////////////// #include "str_utils.h" #include #include //////////////////////////////////////// // Local variable ////////////////////// //////////////////////////////////////// /** Search space to use. */ static const char *search_space = NULL; /** Search space size. */ static int search_space_size = 0; /** Lookup table for transformations. */ static int *search_lookup = NULL; /** htmlspecialchars replace table. */ static const char_replace_t htmlspecialchars_replaces[] = { { '&', "&", 5 }, { '<', "<", 4 }, { '>', ">", 4 }, { '"', """, 6 } //{ '\'', "&39;", 5 } // This replace is not used, }; /** htmlspecialchars replace table size. */ static const size_t htmlspecialchars_replace_count = 4; //////////////////////////////////////// // Local function ////////////////////// //////////////////////////////////////// /** \brief Get character at a given index in the search space. * * @param idx Index to fetch from. * @return Character found. */ static inline char search_lookup_forward(int idx); static inline char search_lookup_forward(int idx) { #ifdef TRIPCRUNCH_DEBUG if((idx < 0) || (idx >= search_space_size)) { printf("ERROR, search space index out of range"); exit(1); } #endif return search_space[idx]; } /** \brief Get the index of a character in the search space. * * @param cc Character. * @return Index of that character in the search space. */ static inline int search_lookup_backward(char cc); static inline int search_lookup_backward(char cc) { int idx = (int)cc; #ifdef TRIPCRUNCH_DEBUG if((idx < 0) || ((unsigned)idx >= SEARCH_MAX_ORD)) { printf("ERROR, search space char out of range"); exit(1); } #endif int ret = search_lookup[idx]; #ifdef TRIPCRUNCH_DEBUG if(ret < 0) { printf("ERROR, invalid search space char: %c", cc); exit(1); } #endif return ret; } /** \brief Append to string. * * Generates a new string with the given character at the beginning. * * Deletes previous string. * * Do not call with an old string that is not initialized. * * @param old Old string. * @param oldlen Old string length. * @param chr Character to append. * @return New string. */ static char* str_prepend(char *old, size_t oldlen, char chr); static char* str_prepend(char *old, size_t oldlen, char chr) { char *ret = (char*)malloc(sizeof(char) * (oldlen + 2)); memcpy(ret + 1, old, oldlen + 1); free(old); ret[0] = chr; return ret; } //////////////////////////////////////// // Extern ////////////////////////////// //////////////////////////////////////// char* create_safe_cstr_buffer(size_t len) { return (char*)malloc(sizeof(char) * ((len + 2) * 5)); } int get_search_space_size(void) { return search_space_size; } void* memdup(const void *src, size_t len) { void *ret = malloc(len); memcpy(ret, src, len); return ret; } int str_enumcmp(const char *lhs, size_t lhslen, const char *rhs, size_t rhslen) { if(lhslen > rhslen) { return 1; } else if(lhslen < rhslen) { return -1; } char *li = (char*)lhs, *ri = (char*)rhs; do { int cl = search_lookup_backward(*li), cr = search_lookup_backward(*ri); if(cl < cr) { return -1; } else if(cl > cr) { return 1; } ++li; ++ri; } while(--lhslen); return 0; } int str_enumerate_init(const char *sspace) { if(!sspace) { return -1; } search_space = sspace; search_space_size = (int)strlen(sspace); if(search_space_size <= 0) { return -1; } search_lookup = (int*)malloc(sizeof(int) * SEARCH_MAX_ORD); for(unsigned ii = 0; (ii < SEARCH_MAX_ORD); ++ii) { if(ii <= 0x20) { search_lookup[ii] = -1; } else { char *ptr = strchr(sspace, (int)ii); search_lookup[ii] = ptr ? ((int)(ptr - sspace)) : -1; } #ifdef TRIPCRUNCH_DEBUG printf("Search_lookup[%3i] : %c = %i\n", ii, ii, (int)search_lookup[ii]); #endif } return 0; } void str_enumerate_free(void) { if(search_lookup) { free(search_lookup); search_lookup = NULL; } } char* str_enumerate_1(char *old, size_t *len) { // Special case, first jump. if(!old) { char *ret = (char*)malloc(sizeof(char) * 2); ret[0] = search_lookup_forward(0); ret[1] = 0; *len = 1; return ret; } size_t oldlen = *len; char *iter = old + oldlen - 1; while(1) { int idx = search_lookup_backward(*iter) + 1; if(idx < search_space_size) { *iter = search_lookup_forward(idx); return old; } *iter = search_lookup_forward(0); if(iter == old) { *len = oldlen + 1; return str_prepend(old, oldlen, search_lookup_forward(0)); } --iter; } } char *str_enumerate_fn(char *old, int jump, size_t *len) { size_t oldlen = *len; char *iter = old + oldlen - 1; while(1) { int idx = search_lookup_backward(*iter) + jump; if(idx < search_space_size) { *iter = search_lookup_forward(idx); return old; } *iter = search_lookup_forward(idx - search_space_size); jump = 1; if(iter == old) { *len = oldlen + 1; return str_prepend(old, oldlen, search_lookup_forward(0)); } --iter; } } char* str_enumerate_n(char *old, int jump, size_t *len) { size_t oldlen = *len; // Special case, first jump. if(!old) { old = (char*)malloc(sizeof(char) * 2); old[0] = search_lookup_forward(jump % search_space_size); old[1] = 0; oldlen = 1; for(jump /= search_space_size; (jump); jump /= search_space_size) { char cc = search_lookup_forward(jump % search_space_size); old = str_prepend(old, oldlen, cc); ++oldlen; } *len = oldlen; return old; } char *iter = old + oldlen - 1; do { jump += search_lookup_backward(*iter); int rem = jump % search_space_size; *iter = search_lookup_forward(rem); jump /= search_space_size; if(iter == old) { for(; (jump); jump /= search_space_size) { char cc = search_lookup_forward(jump % search_space_size); old = str_prepend(old, oldlen, cc); ++oldlen; } *len = oldlen; return old; } --iter; } while(jump); /* // No need to update len since it isn't changed. */ return old; } char* str_multireplace(char *src, size_t *slen, const char_replace_t *replacements, size_t rnum) { size_t orig_len = *slen, new_len = *slen; int replace_needed = 0; for(size_t ii = 0; (ii < orig_len); ++ii) { char cc = src[ii]; for(size_t jj = 0; (jj < rnum); ++jj) { const char_replace_t *rep = replacements + jj; if(rep->src == cc) { new_len += rep->dstlen - 1; replace_needed = 1; break; } } } // Potentially just bail out. if(!replace_needed) { return src; } char *ret = (char*)malloc(sizeof(char) * (new_len + 1)); ret[new_len] = 0; *slen = new_len; size_t kk = 0; for(size_t ii = 0; (ii < orig_len); ++ii) { char cc = src[ii]; int replace_done = 0; for(size_t jj = 0; (jj < rnum); ++jj) { const char_replace_t *rep = replacements + jj; if(rep->src == cc) { size_t dstlen = rep->dstlen; memcpy(ret + kk, rep->dst, dstlen); kk += dstlen; replace_done = 1; break; } } if(!replace_done) { ret[kk++] = cc; } } free(src); return ret; } size_t str_multireplace_fast(char *dst, const char *src, size_t slen, const char_replace_t *replacements, size_t rnum) { size_t ret = slen, kk = 0; for(size_t ii = 0; (ii < slen); ++ii) { char cc = src[ii]; int replace_done = 0; for(size_t jj = 0; (jj < rnum); ++jj) { const char_replace_t *rep = replacements + jj; if(rep->src == cc) { size_t dstlen = rep->dstlen; memcpy(dst + kk, rep->dst, dstlen); ret += dstlen - 1; kk += dstlen; replace_done = 1; break; } } if(!replace_done) { dst[kk++] = cc; } } dst[ret] = 0; return ret; } char* str_replace(char *src, const char *needle, const char *replacement) { #ifdef TRIPCRUNCH_DEBUG printf("Performing replace: %s, %s, %s\n", src, needle, replacement); #endif size_t len = 0, jj = 0, nlen = strlen(needle), rlen = strlen(replacement), nnum = 0; for(size_t ii = 0; (src[ii]); ++ii) { ++len; if(needle[jj] == src[ii]) { ++jj; if(jj == nlen) { jj = 0; ++nnum; } } else { jj = 0; } } if(!nnum) { return src; } char *ret = (char*)malloc(sizeof(char) * (len - nlen * nnum + rlen * nnum + 1)); jj = 0; size_t kk = 0; for(size_t ii = 0; (ii < len); ++ii) { char cc = src[ii]; #ifdef TRIPCRUNCH_DEBUG printf("cc: %c kk ) %i\n", cc, (int)kk); #endif ret[kk] = cc; if(needle[jj] == cc) { ++jj; if(jj == nlen) { for(unsigned ll = 0; (ll < rlen); ++ll) { ret[kk + 1 - nlen + ll] = replacement[ll]; } jj = 0; kk += rlen; } else { ++kk; } } else { jj = 0; ++kk; } } ret[kk] = 0; free(src); #ifdef TRIPCRUNCH_DEBUG printf("Result: %s\n", ret); #endif return ret; } char* htmlspecialchars(char *src, size_t *slen) { return str_multireplace(src, slen, htmlspecialchars_replaces, htmlspecialchars_replace_count); } size_t htmlspecialchars_fast(char *dst, const char *src, size_t slen) { return str_multireplace_fast(dst, src, slen, htmlspecialchars_replaces, htmlspecialchars_replace_count); } //////////////////////////////////////// // End ///////////////////////////////// ////////////////////////////////////////