src/strings.c
/*
MODULE -- string manipulation functions
Copyright (C) Alberto Ornaghi
$Id: strings.c 2854 2010-09-10 15:04:07Z alor $
*/
#include <main.h>
#include <ctype.h>
/* globals */
/* protos... */
#ifndef HAVE_CTYPE_H
int isprint(int c);
#endif
int match_pattern(const char *s, const char *pattern);
int base64_decode(char *bufplain, const char *bufcoded);
static int hextoint(int c);
int strescape(char *dst, char *src);
int str_replace(char **text, const char *s, const char *d);
size_t strlen_utf8(const char *s);
char * my_strtok(char *s, const char *delim, char **ptrptr);
void str_decode_url(u_char *src);
char * str_tohex(u_char *bin, size_t len, char *dst, size_t dst_len);
char * hex_format(const u_char *buf, size_t len, char *dst);
/*******************************************/
/* implement the function if it is not available */
#ifndef HAVE_CTYPE_H
int isprint(int c)
{
return ( (c > 31 && c < 127) ? 1 : 0 );
}
#endif
/* Pattern matching code from OpenSSH. */
int match_pattern(const char *s, const char *pattern)
{
for (;;) {
if (!*pattern) return (!*s);
if (*pattern == '*') {
pattern++;
if (!*pattern) return (1);
if (*pattern != '?' && *pattern != '*') {
for (; *s; s++) {
if (*s == *pattern && match_pattern(s + 1, pattern + 1))
return (1);
}
return (0);
}
for (; *s; s++) {
if (match_pattern(s, pattern))
return (1);
}
return (0);
}
if (!*s) return (0);
if (*pattern != '?' && *pattern != *s)
return (0);
s++;
pattern++;
}
/* NOTREACHED */
}
/* stolen from ap_base64.c (apache source code) */
static const unsigned char pr2six[256] =
{
/* ASCII table */
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
int base64_decode(char *bufplain, const char *bufcoded)
{
int nbytesdecoded;
register const unsigned char *bufin;
register unsigned char *bufout;
register int nprbytes;
bufin = (const unsigned char *) bufcoded;
while (pr2six[*(bufin++)] <= 63);
nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
bufout = (unsigned char *) bufplain;
bufin = (const unsigned char *) bufcoded;
while (nprbytes > 4)
{
*(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
*(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
*(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
bufin += 4;
nprbytes -= 4;
}
/* Note: (nprbytes == 1) would be an error, so just ingore that case */
if (nprbytes > 1)
*(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
if (nprbytes > 2)
*(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
if (nprbytes > 3)
*(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
nbytesdecoded -= (4 - nprbytes) & 3;
bufplain[nbytesdecoded] = '\0';
return nbytesdecoded;
}
/* adapted from magic.c part of dsniff <dugsong@monkey.org> source code... */
/*
* convert an HEX rapresentation into int
*/
static int hextoint(int c)
{
if (!isascii((int) c))
return (-1);
if (isdigit((int) c))
return (c - '0');
if ((c >= 'a') && (c <= 'f'))
return (c + 10 - 'a');
if ((c >= 'A') && (c <= 'F'))
return (c + 10 - 'A');
return (-1);
}
/*
* convert the escaped string into a binary one
*/
int strescape(char *dst, char *src)
{
char *olddst = dst;
int c;
int val;
while ((c = *src++) != '\0') {
if (c == '\\') {
switch ((c = *src++)) {
case '\0':
goto strend;
default:
*dst++ = (char) c;
break;
case 'n':
*dst++ = '\n';
break;
case 'r':
*dst++ = '\r';
break;
case 'b':
*dst++ = '\b';
break;
case 't':
*dst++ = '\t';
break;
case 'f':
*dst++ = '\f';
break;
case 'v':
*dst++ = '\v';
break;
/* \ and up to 3 octal digits */
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
val = c - '0';
c = *src++;
/* try for 2 */
if (c >= '0' && c <= '7') {
val = (val << 3) | (c - '0');
c = *src++;
/* try for 3 */
if (c >= '0' && c <= '7')
val = (val << 3) | (c - '0');
else
--src;
} else
--src;
*dst++ = (char) val;
break;
case 'x':
val = 'x'; /* Default if no digits */
c = hextoint(*src++); /* Get next char */
if (c >= 0) {
val = c;
c = hextoint(*src++);
if (c >= 0)
val = (val << 4) + c;
else
--src;
} else
--src;
*dst++ = (char) val;
break;
}
} else if (c == 8 || c == 263) /* the backspace */
dst--;
else
*dst++ = (char) c;
}
strend:
*dst = '\0';
return (dst - olddst);
}
/*
* replace 's' with 'd' in the string 'text'
* text will be realloc'ed, so a pointer is needed
* and stack based array can't be used
*/
int str_replace(char **text, const char *s, const char *d)
{
size_t slen = strlen(s);
size_t dlen = strlen(d);
int diff = dlen - slen;
char *p, *q = *text;
size_t size;
/* the search string does not exist */
if (strstr(*text, s) == NULL)
return -ENOTFOUND;
/* search all the occurrence of 's' */
while ( (p = strstr(q, s)) != NULL ) {
/* the new size */
if (diff > 0) {
size = strlen(*text) + diff + 1;
SAFE_REALLOC(*text, size);
} else {
size = strlen(*text);
/* if the substituted len is smaller, don't realloc */
}
q = *text;
/*
* make sure the pointer p is within the *text memory.
* realloc may have moved it...
*/
p = strstr(q, s);
/* do the actual replacement */
memmove(p + dlen, p + slen, strlen(p + slen) + 1);
memcpy(p, d, dlen);
/* avoid recursion on substituted string */
q = p + dlen;
}
return ESUCCESS;
}
/*
* Calculate the correct length of characters in an UTF-8 encoded string.
*/
size_t strlen_utf8(const char *s)
{
u_char c;
size_t len = 0;
while ((c = *s++)) {
if ((c & 0xC0) != 0x80)
++len;
}
return len;
}
/*
* a reentrant version of strtok
*/
char * my_strtok(char *s, const char *delim, char **ptrptr)
{
#ifdef HAVE_STRTOK_R
return strtok_r(s, delim, ptrptr);
#else
#warning unsafe strtok
/* to avoid the warning on this function (the wrapper macro) */
#undef strtok
return strtok(s, delim);
#endif
}
/* Unescape the string */
void str_decode_url(u_char *src)
{
u_char t[3];
u_int32 i, j, ch;
/* Paranoid test */
if (!src)
return;
/* NULL terminate for the strtoul */
t[2] = 0;
for (i=0, j=0; src[i] != 0; i++, j++) {
ch = (u_int32)src[i];
if (ch == '%' && isxdigit((u_int32)src[i + 1]) && isxdigit((u_int32)src[i + 2])) {
memcpy(t, src+i+1, 2);
ch = strtoul((char *)t, NULL, 16);
i += 2;
}
src[j] = (u_char)ch;
}
src[j] = 0;
}
/* convert a string of hex values into an array of bytes */
int str_hex_to_bytes(char *string, u_char *bytes)
{
char value[3]; /* two for the hex and the NULL terminator */
unsigned int value_bin;
u_int i;
for (i = 0; i < strlen(string); i++) {
strncpy(value, string + i*2, 2);
if (sscanf(value, "%02X", &value_bin) != 1)
return -EINVALID;
bytes[i] = value_bin & 0x000000FF;
}
return 0;
}
/* print a binary string in hex format */
char * str_tohex(u_char *bin, size_t len, char *dst, size_t dst_len)
{
size_t i;
memset(dst, 0, dst_len);
for (i = 0; i < len; i++)
sprintf(dst + i*2, "%02X", bin[i]);
return dst;
}
/*
* convert a buffer to a hex notation
*
* the string "HTTP/1.1 304 Not Modified" becomes:
*
* 0000: 4854 5450 2f31 2e31 2033 3034 204e 6f74 HTTP/1.1 304 Not
* 0010: 204d 6f64 6966 6965 64 Modified
*/
char * hex_format(const u_char *buf, size_t len, char *dst)
{
u_int i, j, jm, c;
int dim = 0;
/* some sanity checks */
if (len == 0 || buf == NULL) {
strcpy(dst, "");
return 0;
}
for (i = 0; i < len; i += HEX_CHAR_PER_LINE) {
sprintf(dst, "%s %04x: ", dst, i );
jm = len - i;
jm = jm > HEX_CHAR_PER_LINE ? HEX_CHAR_PER_LINE : jm;
for (j = 0; j < jm; j++) {
if ((j % 2) == 1) {
sprintf(dst, "%s%02x ", dst, (u_char) buf[i+j]);
} else {
sprintf(dst, "%s%02x", dst, (u_char) buf[i+j]);
}
}
for (; j < HEX_CHAR_PER_LINE; j++) {
if ((j % 2) == 1) {
strcat(dst, " ");
} else {
strcat(dst, " ");
}
}
strcat(dst, " ");
for (j = 0; j < jm; j++) {
c = (u_char) buf[i+j];
c = isprint(c) ? c : '.';
dim = sprintf(dst, "%s%c", dst, c);
}
strcat(dst, "\n");
}
//return dim + 1;
return dst;
}
/* EOF */
// vim:ts=3:expandtab