2000-09-11 16:16:13 +00:00
|
|
|
/* strutil.c
|
|
|
|
* String utility routines
|
|
|
|
*
|
2004-07-18 00:24:25 +00:00
|
|
|
* $Id$
|
2000-09-11 16:16:13 +00:00
|
|
|
*
|
2006-05-21 05:12:17 +00:00
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
2000-09-11 16:16:13 +00:00
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2002-08-28 20:41:00 +00:00
|
|
|
*
|
2000-09-11 16:16:13 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2002-08-28 20:41:00 +00:00
|
|
|
*
|
2000-09-11 16:16:13 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <glib.h>
|
2000-09-11 20:05:13 +00:00
|
|
|
#include "strutil.h"
|
2005-08-17 09:36:20 +00:00
|
|
|
#include "emem.h"
|
2010-08-30 15:33:32 +00:00
|
|
|
#include <../isprint.h>
|
|
|
|
|
2000-09-11 16:16:13 +00:00
|
|
|
|
2006-03-08 20:55:32 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#include <tchar.h>
|
|
|
|
#include <wchar.h>
|
|
|
|
#endif
|
2000-09-11 16:16:13 +00:00
|
|
|
|
2007-01-11 22:12:33 +00:00
|
|
|
static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
|
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
|
|
|
|
2000-09-11 16:16:13 +00:00
|
|
|
/*
|
|
|
|
* Given a pointer into a data buffer, and to the end of the buffer,
|
|
|
|
* find the end of the (putative) line at that position in the data
|
|
|
|
* buffer.
|
|
|
|
* Return a pointer to the EOL character(s) in "*eol".
|
|
|
|
*/
|
2002-08-02 21:29:45 +00:00
|
|
|
const guchar *
|
|
|
|
find_line_end(const guchar *data, const guchar *dataend, const guchar **eol)
|
2000-09-11 16:16:13 +00:00
|
|
|
{
|
2002-08-02 21:29:45 +00:00
|
|
|
const guchar *lineend;
|
2000-09-11 16:16:13 +00:00
|
|
|
|
|
|
|
lineend = memchr(data, '\n', dataend - data);
|
|
|
|
if (lineend == NULL) {
|
|
|
|
/*
|
|
|
|
* No LF - line is probably continued in next TCP segment.
|
|
|
|
*/
|
|
|
|
lineend = dataend;
|
|
|
|
*eol = dataend;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Is the LF at the beginning of the line?
|
|
|
|
*/
|
|
|
|
if (lineend > data) {
|
|
|
|
/*
|
|
|
|
* No - is it preceded by a carriage return?
|
|
|
|
* (Perhaps it's supposed to be, but that's not guaranteed....)
|
|
|
|
*/
|
|
|
|
if (*(lineend - 1) == '\r') {
|
|
|
|
/*
|
|
|
|
* Yes. The EOL starts with the CR.
|
|
|
|
*/
|
|
|
|
*eol = lineend - 1;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* No. The EOL starts with the LF.
|
|
|
|
*/
|
|
|
|
*eol = lineend;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* I seem to remember that we once saw lines ending with LF-CR
|
|
|
|
* in an HTTP request or response, so check if it's *followed*
|
|
|
|
* by a carriage return.
|
|
|
|
*/
|
|
|
|
if (lineend < (dataend - 1) && *(lineend + 1) == '\r') {
|
|
|
|
/*
|
|
|
|
* It's <non-LF><LF><CR>; say it ends with the CR.
|
|
|
|
*/
|
|
|
|
lineend++;
|
|
|
|
}
|
|
|
|
}
|
2000-09-30 05:44:48 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Yes - the EOL starts with the LF.
|
|
|
|
*/
|
|
|
|
*eol = lineend;
|
2000-09-11 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Point to the character after the last character.
|
|
|
|
*/
|
|
|
|
lineend++;
|
|
|
|
}
|
|
|
|
return lineend;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the length of the next token in a line, and the beginning of the
|
|
|
|
* next token after that (if any).
|
|
|
|
* Return 0 if there is no next token.
|
|
|
|
*/
|
|
|
|
int
|
2002-08-02 21:29:45 +00:00
|
|
|
get_token_len(const guchar *linep, const guchar *lineend,
|
|
|
|
const guchar **next_token)
|
2000-09-11 16:16:13 +00:00
|
|
|
{
|
2002-08-02 21:29:45 +00:00
|
|
|
const guchar *tokenp;
|
2000-09-11 16:16:13 +00:00
|
|
|
int token_len;
|
|
|
|
|
|
|
|
tokenp = linep;
|
2002-08-28 20:41:00 +00:00
|
|
|
|
2000-09-11 16:16:13 +00:00
|
|
|
/*
|
|
|
|
* Search for a blank, a CR or an LF, or the end of the buffer.
|
|
|
|
*/
|
|
|
|
while (linep < lineend && *linep != ' ' && *linep != '\r' && *linep != '\n')
|
|
|
|
linep++;
|
2009-04-08 16:50:20 +00:00
|
|
|
token_len = (int) (linep - tokenp);
|
2000-09-11 16:16:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip trailing blanks.
|
|
|
|
*/
|
|
|
|
while (linep < lineend && *linep == ' ')
|
|
|
|
linep++;
|
|
|
|
|
|
|
|
*next_token = linep;
|
|
|
|
|
|
|
|
return token_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-29 19:02:37 +00:00
|
|
|
#define INITIAL_FMTBUF_SIZE 128
|
2000-09-11 16:16:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Given a string, generate a string from it that shows non-printable
|
|
|
|
* characters as C-style escapes, and return a pointer to it.
|
|
|
|
*/
|
|
|
|
gchar *
|
2009-03-30 03:40:12 +00:00
|
|
|
format_text(const guchar *string, size_t len)
|
2000-09-11 16:16:13 +00:00
|
|
|
{
|
2004-10-29 00:39:56 +00:00
|
|
|
static gchar *fmtbuf[3];
|
|
|
|
static int fmtbuf_len[3];
|
|
|
|
static int idx;
|
2000-09-11 16:16:13 +00:00
|
|
|
int column;
|
2002-08-02 21:29:45 +00:00
|
|
|
const guchar *stringend = string + len;
|
|
|
|
guchar c;
|
2000-09-11 16:16:13 +00:00
|
|
|
int i;
|
|
|
|
|
2004-10-29 00:39:56 +00:00
|
|
|
idx = (idx + 1) % 3;
|
|
|
|
|
2000-09-29 19:02:37 +00:00
|
|
|
/*
|
|
|
|
* Allocate the buffer if it's not already allocated.
|
|
|
|
*/
|
2004-10-29 00:39:56 +00:00
|
|
|
if (fmtbuf[idx] == NULL) {
|
|
|
|
fmtbuf[idx] = g_malloc(INITIAL_FMTBUF_SIZE);
|
|
|
|
fmtbuf_len[idx] = INITIAL_FMTBUF_SIZE;
|
2000-09-29 19:02:37 +00:00
|
|
|
}
|
2000-09-11 16:16:13 +00:00
|
|
|
column = 0;
|
|
|
|
while (string < stringend) {
|
2000-09-29 19:02:37 +00:00
|
|
|
/*
|
|
|
|
* Is there enough room for this character, if it expands to
|
|
|
|
* a backslash plus 3 octal digits (which is the most it can
|
|
|
|
* expand to), and also enough room for a terminating '\0'?
|
|
|
|
*/
|
2004-10-29 00:39:56 +00:00
|
|
|
if (column+3+1 >= fmtbuf_len[idx]) {
|
2000-09-11 16:16:13 +00:00
|
|
|
/*
|
2000-09-29 19:02:37 +00:00
|
|
|
* Double the buffer's size if it's not big enough.
|
|
|
|
* The size of the buffer starts at 128, so doubling its size
|
|
|
|
* adds at least another 128 bytes, which is more than enough
|
|
|
|
* for one more character plus a terminating '\0'.
|
2000-09-11 16:16:13 +00:00
|
|
|
*/
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf_len[idx] = fmtbuf_len[idx] * 2;
|
|
|
|
fmtbuf[idx] = g_realloc(fmtbuf[idx], fmtbuf_len[idx]);
|
2000-09-11 16:16:13 +00:00
|
|
|
}
|
|
|
|
c = *string++;
|
2002-12-31 21:51:10 +00:00
|
|
|
|
2010-12-06 18:30:39 +00:00
|
|
|
if (g_unichar_isprint(c)) {
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf[idx][column] = c;
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
} else {
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf[idx][column] = '\\';
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
case '\a':
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf[idx][column] = 'a';
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\b':
|
2006-06-19 15:53:03 +00:00
|
|
|
fmtbuf[idx][column] = 'b'; /* BS */
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\f':
|
2006-06-19 15:53:03 +00:00
|
|
|
fmtbuf[idx][column] = 'f'; /* FF */
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\n':
|
2006-06-19 15:53:03 +00:00
|
|
|
fmtbuf[idx][column] = 'n'; /* NL */
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\r':
|
2006-06-19 15:53:03 +00:00
|
|
|
fmtbuf[idx][column] = 'r'; /* CR */
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\t':
|
2006-06-19 15:53:03 +00:00
|
|
|
fmtbuf[idx][column] = 't'; /* tab */
|
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\v':
|
|
|
|
fmtbuf[idx][column] = 'v';
|
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
i = (c>>6)&03;
|
|
|
|
fmtbuf[idx][column] = i + '0';
|
|
|
|
column++;
|
|
|
|
i = (c>>3)&07;
|
|
|
|
fmtbuf[idx][column] = i + '0';
|
|
|
|
column++;
|
|
|
|
i = (c>>0)&07;
|
|
|
|
fmtbuf[idx][column] = i + '0';
|
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmtbuf[idx][column] = '\0';
|
|
|
|
return fmtbuf[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Given a string, generate a string from it that shows non-printable
|
2006-09-22 21:14:54 +00:00
|
|
|
* characters as C-style escapes except a whitespace character
|
2006-06-19 15:53:03 +00:00
|
|
|
* (space, tab, carriage return, new line, vertical tab, or formfeed)
|
2008-05-05 00:39:47 +00:00
|
|
|
* which will be replaced by a space, and return a pointer to it.
|
2006-06-19 15:53:03 +00:00
|
|
|
*/
|
|
|
|
gchar *
|
2009-03-30 03:40:12 +00:00
|
|
|
format_text_wsp(const guchar *string, size_t len)
|
2006-06-19 15:53:03 +00:00
|
|
|
{
|
|
|
|
static gchar *fmtbuf[3];
|
|
|
|
static int fmtbuf_len[3];
|
|
|
|
static int idx;
|
|
|
|
int column;
|
|
|
|
const guchar *stringend = string + len;
|
|
|
|
guchar c;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
idx = (idx + 1) % 3;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate the buffer if it's not already allocated.
|
|
|
|
*/
|
|
|
|
if (fmtbuf[idx] == NULL) {
|
|
|
|
fmtbuf[idx] = g_malloc(INITIAL_FMTBUF_SIZE);
|
|
|
|
fmtbuf_len[idx] = INITIAL_FMTBUF_SIZE;
|
|
|
|
}
|
|
|
|
column = 0;
|
|
|
|
while (string < stringend) {
|
|
|
|
/*
|
|
|
|
* Is there enough room for this character, if it expands to
|
|
|
|
* a backslash plus 3 octal digits (which is the most it can
|
|
|
|
* expand to), and also enough room for a terminating '\0'?
|
|
|
|
*/
|
|
|
|
if (column+3+1 >= fmtbuf_len[idx]) {
|
|
|
|
/*
|
|
|
|
* Double the buffer's size if it's not big enough.
|
|
|
|
* The size of the buffer starts at 128, so doubling its size
|
|
|
|
* adds at least another 128 bytes, which is more than enough
|
|
|
|
* for one more character plus a terminating '\0'.
|
|
|
|
*/
|
|
|
|
fmtbuf_len[idx] = fmtbuf_len[idx] * 2;
|
|
|
|
fmtbuf[idx] = g_realloc(fmtbuf[idx], fmtbuf_len[idx]);
|
|
|
|
}
|
|
|
|
c = *string++;
|
|
|
|
|
2010-12-06 18:30:39 +00:00
|
|
|
if (g_unichar_isprint(c)) {
|
2006-06-19 15:53:03 +00:00
|
|
|
fmtbuf[idx][column] = c;
|
|
|
|
column++;
|
|
|
|
} else if (isspace(c)) {
|
|
|
|
fmtbuf[idx][column] = ' ';
|
|
|
|
column++;
|
2008-07-12 19:28:24 +00:00
|
|
|
} else {
|
2006-06-19 15:53:03 +00:00
|
|
|
fmtbuf[idx][column] = '\\';
|
|
|
|
column++;
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
case '\a':
|
|
|
|
fmtbuf[idx][column] = 'a';
|
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\b':
|
|
|
|
fmtbuf[idx][column] = 'b'; /* BS */
|
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\f':
|
|
|
|
fmtbuf[idx][column] = 'f'; /* FF */
|
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\n':
|
|
|
|
fmtbuf[idx][column] = 'n'; /* NL */
|
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\r':
|
|
|
|
fmtbuf[idx][column] = 'r'; /* CR */
|
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\t':
|
|
|
|
fmtbuf[idx][column] = 't'; /* tab */
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\v':
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf[idx][column] = 'v';
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
i = (c>>6)&03;
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf[idx][column] = i + '0';
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
i = (c>>3)&07;
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf[idx][column] = i + '0';
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
i = (c>>0)&07;
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf[idx][column] = i + '0';
|
2000-09-11 16:16:13 +00:00
|
|
|
column++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-10-29 00:39:56 +00:00
|
|
|
fmtbuf[idx][column] = '\0';
|
|
|
|
return fmtbuf[idx];
|
2000-09-11 16:16:13 +00:00
|
|
|
}
|
2000-11-13 07:19:37 +00:00
|
|
|
|
2003-12-29 04:07:06 +00:00
|
|
|
static gboolean
|
|
|
|
is_byte_sep(guint8 c)
|
|
|
|
{
|
|
|
|
return (c == '-' || c == ':' || c == '.');
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Turn a string of hex digits with optional separators (defined by
|
|
|
|
* is_byte_sep() into a byte array.
|
|
|
|
*/
|
|
|
|
gboolean
|
2004-06-06 14:29:07 +00:00
|
|
|
hex_str_to_bytes(const char *hex_str, GByteArray *bytes, gboolean force_separators) {
|
2003-12-29 04:07:06 +00:00
|
|
|
guint8 val;
|
2007-02-01 01:37:34 +00:00
|
|
|
const guchar *p, *q, *r, *s, *punct;
|
|
|
|
char four_digits_first_half[3];
|
|
|
|
char four_digits_second_half[3];
|
2003-12-29 04:07:06 +00:00
|
|
|
char two_digits[3];
|
|
|
|
char one_digit[2];
|
|
|
|
|
2007-06-21 17:49:03 +00:00
|
|
|
if (! hex_str || ! bytes) {
|
2006-10-18 17:55:29 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2007-06-21 17:49:03 +00:00
|
|
|
g_byte_array_set_size(bytes, 0);
|
2004-02-01 04:54:48 +00:00
|
|
|
p = (const guchar *)hex_str;
|
2003-12-29 04:07:06 +00:00
|
|
|
while (*p) {
|
|
|
|
q = p+1;
|
2007-02-01 01:37:34 +00:00
|
|
|
r = p+2;
|
|
|
|
s = p+3;
|
|
|
|
|
2007-06-21 17:49:03 +00:00
|
|
|
if (*q && *r && *s
|
2007-02-04 19:23:10 +00:00
|
|
|
&& isxdigit(*p) && isxdigit(*q) &&
|
2007-02-01 01:37:34 +00:00
|
|
|
isxdigit(*r) && isxdigit(*s)) {
|
|
|
|
four_digits_first_half[0] = *p;
|
|
|
|
four_digits_first_half[1] = *q;
|
|
|
|
four_digits_first_half[2] = '\0';
|
|
|
|
four_digits_second_half[0] = *r;
|
|
|
|
four_digits_second_half[1] = *s;
|
|
|
|
four_digits_second_half[2] = '\0';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Four or more hex digits in a row.
|
|
|
|
*/
|
|
|
|
val = (guint8) strtoul(four_digits_first_half, NULL, 16);
|
|
|
|
g_byte_array_append(bytes, &val, 1);
|
|
|
|
val = (guint8) strtoul(four_digits_second_half, NULL, 16);
|
|
|
|
g_byte_array_append(bytes, &val, 1);
|
2007-06-21 17:49:03 +00:00
|
|
|
|
2007-02-01 01:37:34 +00:00
|
|
|
punct = s + 1;
|
|
|
|
if (*punct) {
|
|
|
|
/*
|
|
|
|
* Make sure the character after
|
|
|
|
* the forth hex digit is a byte
|
|
|
|
* separator, i.e. that we don't have
|
|
|
|
* more than four hex digits, or a
|
|
|
|
* bogus character.
|
|
|
|
*/
|
|
|
|
if (is_byte_sep(*punct)) {
|
|
|
|
p = punct + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (force_separators) {
|
|
|
|
return FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p = punct;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (*q && isxdigit(*p) && isxdigit(*q)) {
|
2003-12-29 04:07:06 +00:00
|
|
|
two_digits[0] = *p;
|
|
|
|
two_digits[1] = *q;
|
|
|
|
two_digits[2] = '\0';
|
|
|
|
|
|
|
|
/*
|
2007-02-01 01:37:34 +00:00
|
|
|
* Two hex digits in a row.
|
2003-12-29 04:07:06 +00:00
|
|
|
*/
|
|
|
|
val = (guint8) strtoul(two_digits, NULL, 16);
|
|
|
|
g_byte_array_append(bytes, &val, 1);
|
|
|
|
punct = q + 1;
|
|
|
|
if (*punct) {
|
|
|
|
/*
|
|
|
|
* Make sure the character after
|
|
|
|
* the second hex digit is a byte
|
|
|
|
* separator, i.e. that we don't have
|
|
|
|
* more than two hex digits, or a
|
|
|
|
* bogus character.
|
|
|
|
*/
|
|
|
|
if (is_byte_sep(*punct)) {
|
|
|
|
p = punct + 1;
|
|
|
|
continue;
|
|
|
|
}
|
2004-06-06 14:29:07 +00:00
|
|
|
else if (force_separators) {
|
2003-12-29 04:07:06 +00:00
|
|
|
return FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-06-06 14:29:07 +00:00
|
|
|
p = punct;
|
|
|
|
continue;
|
2003-12-29 04:07:06 +00:00
|
|
|
}
|
|
|
|
else if (*q && isxdigit(*p) && is_byte_sep(*q)) {
|
|
|
|
one_digit[0] = *p;
|
|
|
|
one_digit[1] = '\0';
|
|
|
|
|
|
|
|
/*
|
2007-02-01 01:37:34 +00:00
|
|
|
* Only one hex digit (not at the end of the string)
|
2003-12-29 04:07:06 +00:00
|
|
|
*/
|
|
|
|
val = (guint8) strtoul(one_digit, NULL, 16);
|
|
|
|
g_byte_array_append(bytes, &val, 1);
|
|
|
|
p = q + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (!*q && isxdigit(*p)) {
|
|
|
|
one_digit[0] = *p;
|
|
|
|
one_digit[1] = '\0';
|
|
|
|
|
|
|
|
/*
|
2007-02-01 01:37:34 +00:00
|
|
|
* Only one hex digit (at the end of the string)
|
2003-12-29 04:07:06 +00:00
|
|
|
*/
|
|
|
|
val = (guint8) strtoul(one_digit, NULL, 16);
|
|
|
|
g_byte_array_append(bytes, &val, 1);
|
|
|
|
p = q;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-01-11 02:42:34 +00:00
|
|
|
/*
|
|
|
|
* Turn an RFC 3986 percent-encoded string into a byte array.
|
|
|
|
* XXX - We don't check for reserved characters.
|
|
|
|
*/
|
|
|
|
#define HEX_DIGIT_BUF_LEN 3
|
|
|
|
gboolean
|
|
|
|
uri_str_to_bytes(const char *uri_str, GByteArray *bytes) {
|
|
|
|
guint8 val;
|
2007-07-14 00:37:01 +00:00
|
|
|
const guchar *p;
|
|
|
|
guchar hex_digit[HEX_DIGIT_BUF_LEN];
|
2007-01-11 02:42:34 +00:00
|
|
|
|
|
|
|
g_byte_array_set_size(bytes, 0);
|
|
|
|
if (! uri_str) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-07-14 00:37:01 +00:00
|
|
|
p = (const guchar *)uri_str;
|
2007-01-11 02:42:34 +00:00
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (! isascii(*p) || ! isprint(*p))
|
|
|
|
return FALSE;
|
|
|
|
if (*p == '%') {
|
|
|
|
p++;
|
2007-01-15 07:29:13 +00:00
|
|
|
if (*p == '\0') return FALSE;
|
|
|
|
hex_digit[0] = *p;
|
|
|
|
p++;
|
|
|
|
if (*p == '\0') return FALSE;
|
|
|
|
hex_digit[1] = *p;
|
|
|
|
hex_digit[2] = '\0';
|
2007-07-14 00:37:01 +00:00
|
|
|
if (! isxdigit(hex_digit[0]) || ! isxdigit(hex_digit[1]))
|
2007-01-11 02:42:34 +00:00
|
|
|
return FALSE;
|
2007-07-14 00:37:01 +00:00
|
|
|
val = (guint8) strtoul((char *)hex_digit, NULL, 16);
|
2007-01-11 02:42:34 +00:00
|
|
|
g_byte_array_append(bytes, &val, 1);
|
|
|
|
} else {
|
|
|
|
g_byte_array_append(bytes, (guint8 *) p, 1);
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-01-11 22:12:33 +00:00
|
|
|
/*
|
|
|
|
* Given a GByteArray, generate a string from it that shows non-printable
|
|
|
|
* characters as percent-style escapes, and return a pointer to it.
|
|
|
|
*/
|
|
|
|
gchar *
|
|
|
|
format_uri(const GByteArray *bytes, const gchar *reserved_chars)
|
|
|
|
{
|
|
|
|
static gchar *fmtbuf[3];
|
|
|
|
static guint fmtbuf_len[3];
|
|
|
|
static guint idx;
|
2010-11-04 11:26:20 +00:00
|
|
|
const guchar *reserved_def = ":/?#[]@!$&'()*+,;= ";
|
|
|
|
const guchar *reserved = reserved_def;
|
2007-01-11 22:12:33 +00:00
|
|
|
guint8 c;
|
|
|
|
guint column, i;
|
|
|
|
gboolean is_reserved = FALSE;
|
|
|
|
|
|
|
|
if (! bytes)
|
|
|
|
return "";
|
|
|
|
|
|
|
|
idx = (idx + 1) % 3;
|
|
|
|
if (reserved_chars)
|
|
|
|
reserved = reserved_chars;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate the buffer if it's not already allocated.
|
|
|
|
*/
|
|
|
|
if (fmtbuf[idx] == NULL) {
|
|
|
|
fmtbuf[idx] = g_malloc(INITIAL_FMTBUF_SIZE);
|
|
|
|
fmtbuf_len[idx] = INITIAL_FMTBUF_SIZE;
|
|
|
|
}
|
|
|
|
for (column = 0; column < bytes->len; column++) {
|
|
|
|
/*
|
|
|
|
* Is there enough room for this character, if it expands to
|
|
|
|
* a percent plus 2 hex digits (which is the most it can
|
|
|
|
* expand to), and also enough room for a terminating '\0'?
|
|
|
|
*/
|
|
|
|
if (column+2+1 >= fmtbuf_len[idx]) {
|
|
|
|
/*
|
|
|
|
* Double the buffer's size if it's not big enough.
|
|
|
|
* The size of the buffer starts at 128, so doubling its size
|
|
|
|
* adds at least another 128 bytes, which is more than enough
|
|
|
|
* for one more character plus a terminating '\0'.
|
|
|
|
*/
|
|
|
|
fmtbuf_len[idx] = fmtbuf_len[idx] * 2;
|
|
|
|
fmtbuf[idx] = g_realloc(fmtbuf[idx], fmtbuf_len[idx]);
|
|
|
|
}
|
|
|
|
c = bytes->data[column];
|
|
|
|
|
|
|
|
if (!isascii(c) || !isprint(c) || c == '%') {
|
|
|
|
is_reserved = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < strlen(reserved); i++) {
|
|
|
|
if (c == reserved[i])
|
|
|
|
is_reserved = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_reserved) {
|
|
|
|
fmtbuf[idx][column] = c;
|
|
|
|
} else {
|
|
|
|
fmtbuf[idx][column] = '%';
|
|
|
|
column++;
|
|
|
|
fmtbuf[idx][column] = hex[c >> 4];
|
|
|
|
column++;
|
|
|
|
fmtbuf[idx][column] = hex[c & 0xF];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmtbuf[idx][column] = '\0';
|
|
|
|
return fmtbuf[idx];
|
|
|
|
}
|
|
|
|
|
2007-01-11 02:42:34 +00:00
|
|
|
/**
|
|
|
|
* Create a copy of a GByteArray
|
|
|
|
*
|
|
|
|
* @param ba The byte array to be copied.
|
|
|
|
* @return If ba exists, a freshly allocated copy. NULL otherwise.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
GByteArray *
|
|
|
|
byte_array_dup(GByteArray *ba) {
|
|
|
|
GByteArray *new_ba;
|
|
|
|
|
|
|
|
if (!ba)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
new_ba = g_byte_array_new();
|
|
|
|
g_byte_array_append(new_ba, ba->data, ba->len);
|
|
|
|
return new_ba;
|
|
|
|
}
|
|
|
|
|
2005-12-02 13:16:58 +00:00
|
|
|
#define SUBID_BUF_LEN 5
|
|
|
|
gboolean
|
|
|
|
oid_str_to_bytes(const char *oid_str, GByteArray *bytes) {
|
|
|
|
guint32 subid0, subid, sicnt, i;
|
|
|
|
const char *p, *dot;
|
|
|
|
guint8 buf[SUBID_BUF_LEN];
|
|
|
|
|
|
|
|
g_byte_array_set_size(bytes, 0);
|
|
|
|
|
|
|
|
/* check syntax */
|
|
|
|
p = oid_str;
|
|
|
|
dot = NULL;
|
|
|
|
while (*p) {
|
2007-07-14 00:37:01 +00:00
|
|
|
if (!isdigit((guchar)*p) && (*p != '.')) return FALSE;
|
2005-12-02 13:16:58 +00:00
|
|
|
if (*p == '.') {
|
|
|
|
if (p == oid_str) return FALSE;
|
|
|
|
if (!*(p+1)) return FALSE;
|
|
|
|
if ((p-1) == dot) return FALSE;
|
|
|
|
dot = p;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (!dot) return FALSE;
|
|
|
|
|
|
|
|
p = oid_str;
|
|
|
|
sicnt = 0;
|
2005-12-04 04:13:07 +00:00
|
|
|
subid0 = 0; /* squelch GCC complaints */
|
2005-12-02 13:16:58 +00:00
|
|
|
while (*p) {
|
|
|
|
subid = 0;
|
2007-07-14 00:37:01 +00:00
|
|
|
while (isdigit((guchar)*p)) {
|
2005-12-02 13:16:58 +00:00
|
|
|
subid *= 10;
|
|
|
|
subid += *p - '0';
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (sicnt == 0) {
|
|
|
|
subid0 = subid;
|
|
|
|
if (subid0 > 2) return FALSE;
|
|
|
|
} else if (sicnt == 1) {
|
|
|
|
if ((subid0 < 2) && (subid > 39)) return FALSE;
|
|
|
|
subid += 40 * subid0;
|
|
|
|
}
|
|
|
|
if (sicnt) {
|
|
|
|
i = SUBID_BUF_LEN;
|
|
|
|
do {
|
|
|
|
i--;
|
|
|
|
buf[i] = 0x80 | (subid % 0x80);
|
|
|
|
subid >>= 7;
|
|
|
|
} while (subid && i);
|
|
|
|
buf[SUBID_BUF_LEN-1] &= 0x7F;
|
|
|
|
g_byte_array_append(bytes, buf + i, SUBID_BUF_LEN - i);
|
|
|
|
}
|
|
|
|
sicnt++;
|
|
|
|
if (*p) p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-01-11 02:42:34 +00:00
|
|
|
/**
|
|
|
|
* Compare the contents of two GByteArrays
|
|
|
|
*
|
|
|
|
* @param ba1 A byte array
|
|
|
|
* @param ba2 A byte array
|
|
|
|
* @return If both arrays are non-NULL and their lengths are equal and
|
|
|
|
* their contents are equal, returns TRUE. Otherwise, returns
|
|
|
|
* FALSE.
|
|
|
|
*
|
|
|
|
* XXX - Should this be in strutil.c?
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
byte_array_equal(GByteArray *ba1, GByteArray *ba2) {
|
|
|
|
if (!ba1 || !ba2)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (ba1->len != ba2->len)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (memcmp(ba1->data, ba2->data, ba1->len) != 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2003-12-29 04:07:06 +00:00
|
|
|
|
2004-05-01 20:46:24 +00:00
|
|
|
/* Return a XML escaped representation of the unescaped string.
|
|
|
|
* The returned string must be freed when no longer in use. */
|
|
|
|
gchar *
|
|
|
|
xml_escape(const gchar *unescaped)
|
|
|
|
{
|
|
|
|
GString *buffer = g_string_sized_new(128);
|
|
|
|
const gchar *p;
|
|
|
|
gchar c;
|
|
|
|
|
|
|
|
p = unescaped;
|
|
|
|
while ( (c = *p++) ) {
|
|
|
|
switch (c) {
|
|
|
|
case '<':
|
|
|
|
g_string_append(buffer, "<");
|
|
|
|
break;
|
|
|
|
case '>':
|
|
|
|
g_string_append(buffer, ">");
|
|
|
|
break;
|
|
|
|
case '&':
|
|
|
|
g_string_append(buffer, "&");
|
|
|
|
break;
|
|
|
|
case '\'':
|
|
|
|
g_string_append(buffer, "'");
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
g_string_append(buffer, """);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_string_append_c(buffer, c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Return the string value contained within the GString
|
|
|
|
* after getting rid of the GString structure.
|
|
|
|
* This is the way to do this, see the GLib reference. */
|
|
|
|
return g_string_free(buffer, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-27 15:23:11 +00:00
|
|
|
/* Return the first occurrence of needle in haystack.
|
|
|
|
* If not found, return NULL.
|
|
|
|
* If either haystack or needle has 0 length, return NULL.
|
|
|
|
* Algorithm copied from GNU's glibc 2.3.2 memcmp() */
|
|
|
|
const guint8 *
|
|
|
|
epan_memmem(const guint8 *haystack, guint haystack_len,
|
|
|
|
const guint8 *needle, guint needle_len)
|
|
|
|
{
|
|
|
|
const guint8 *begin;
|
|
|
|
const guint8 *const last_possible
|
|
|
|
= haystack + haystack_len - needle_len;
|
|
|
|
|
|
|
|
if (needle_len == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needle_len > haystack_len) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (begin = haystack ; begin <= last_possible; ++begin) {
|
|
|
|
if (begin[0] == needle[0] &&
|
|
|
|
!memcmp(&begin[1], needle + 1,
|
|
|
|
needle_len - 1)) {
|
|
|
|
return begin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-08-13 02:39:49 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan the search string to make sure it's valid hex. Return the
|
|
|
|
* number of bytes in nbytes.
|
|
|
|
*/
|
|
|
|
guint8 *
|
|
|
|
convert_string_to_hex(const char *string, size_t *nbytes)
|
|
|
|
{
|
|
|
|
size_t n_bytes;
|
|
|
|
const char *p;
|
|
|
|
guchar c;
|
|
|
|
guint8 *bytes, *q, byte_val;
|
|
|
|
|
|
|
|
n_bytes = 0;
|
|
|
|
p = &string[0];
|
|
|
|
for (;;) {
|
|
|
|
c = *p++;
|
|
|
|
if (c == '\0')
|
|
|
|
break;
|
|
|
|
if (isspace(c))
|
|
|
|
continue; /* allow white space */
|
|
|
|
if (c==':' || c=='.' || c=='-')
|
|
|
|
continue; /* skip any ':', '.', or '-' between bytes */
|
|
|
|
if (!isxdigit(c)) {
|
|
|
|
/* Not a valid hex digit - fail */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can only match bytes, not nibbles; we must have a valid
|
|
|
|
* hex digit immediately after that hex digit.
|
|
|
|
*/
|
|
|
|
c = *p++;
|
|
|
|
if (!isxdigit(c))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* 2 hex digits = 1 byte */
|
|
|
|
n_bytes++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Were we given any hex digits?
|
|
|
|
*/
|
|
|
|
if (n_bytes == 0) {
|
|
|
|
/* No. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* OK, it's valid, and it generates "n_bytes" bytes; generate the
|
|
|
|
* raw byte array.
|
|
|
|
*/
|
|
|
|
bytes = g_malloc(n_bytes);
|
|
|
|
p = &string[0];
|
|
|
|
q = &bytes[0];
|
|
|
|
for (;;) {
|
|
|
|
c = *p++;
|
|
|
|
if (c == '\0')
|
|
|
|
break;
|
|
|
|
if (isspace(c))
|
|
|
|
continue; /* allow white space */
|
|
|
|
if (c==':' || c=='.' || c=='-')
|
|
|
|
continue; /* skip any ':', '.', or '-' between bytes */
|
|
|
|
/* From the loop above, we know this is a hex digit */
|
|
|
|
if (isdigit(c))
|
|
|
|
byte_val = c - '0';
|
|
|
|
else if (c >= 'a')
|
|
|
|
byte_val = (c - 'a') + 10;
|
|
|
|
else
|
|
|
|
byte_val = (c - 'A') + 10;
|
|
|
|
byte_val <<= 4;
|
|
|
|
|
|
|
|
/* We also know this is a hex digit */
|
|
|
|
c = *p++;
|
|
|
|
if (isdigit(c))
|
|
|
|
byte_val |= c - '0';
|
|
|
|
else if (c >= 'a')
|
|
|
|
byte_val |= (c - 'a') + 10;
|
|
|
|
else if (c >= 'A')
|
|
|
|
byte_val |= (c - 'A') + 10;
|
|
|
|
|
|
|
|
*q++ = byte_val;
|
|
|
|
}
|
|
|
|
*nbytes = n_bytes;
|
|
|
|
return bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy if if it's a case-sensitive search; uppercase it if it's
|
|
|
|
* a case-insensitive search.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
convert_string_case(const char *string, gboolean case_insensitive)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (case_insensitive) {
|
2011-02-18 22:43:48 +00:00
|
|
|
return g_utf8_strup(string, -1);
|
|
|
|
} else {
|
|
|
|
return g_strdup(string);
|
|
|
|
}
|
2004-08-13 02:39:49 +00:00
|
|
|
}
|
|
|
|
|
2007-02-07 13:45:28 +00:00
|
|
|
char *
|
|
|
|
epan_strcasestr(const char *haystack, const char *needle)
|
|
|
|
{
|
|
|
|
gsize hlen = strlen(haystack);
|
|
|
|
gsize nlen = strlen(needle);
|
|
|
|
|
|
|
|
while (hlen-- >= nlen) {
|
strcasecmp(), strncasecmp(), g_strcasecmp(), and g_strncasecmp() delenda
est. Use g_ascii_strcasecmp() and g_ascii_strncasecmp(), and supply our
own versions if they're missing from GLib (as is the case with GLib
1.x).
In the code to build the list of named fields for Diameter, don't use
g_strdown(); do our own g_ascii_-style upper-case to lower-case mapping
in the hash function and use g_ascii_strcasecmp() in the compare
function.
We do this because there is no guarantee that toupper(), tolower(), and
functions that use them will, for example, map between "I" and "i" in
all locales; in Turkish locales, for example, there are, in both
upper case and lower case, versions of "i" with and without a dot, and
the upper-case version of "i" is "I"-with-a-dot and the lower-case
version of "I" is "i"-without-a-dot. This causes strings that should
match not to match.
This finishes fixing bug 2010 - an earlier checkin prevented the crash
(as there are other ways to produce the same crash, e.g. a bogus
dictionary.xml file), but didn't fix the case-insensitive string matching.
svn path=/trunk/; revision=23623
2007-11-27 18:52:51 +00:00
|
|
|
if (!g_ascii_strncasecmp(haystack, needle, nlen))
|
2007-02-07 13:45:28 +00:00
|
|
|
return (char*) haystack;
|
|
|
|
haystack++;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-02-17 23:15:35 +00:00
|
|
|
|
|
|
|
const char *
|
|
|
|
string_or_null(const char *string)
|
|
|
|
{
|
|
|
|
if (string)
|
|
|
|
return string;
|
|
|
|
return "[NULL]";
|
|
|
|
}
|
2009-08-19 18:37:13 +00:00
|
|
|
|
2010-08-30 15:33:32 +00:00
|
|
|
int
|
2009-08-19 18:37:13 +00:00
|
|
|
escape_string_len(const char *string)
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
gchar c;
|
|
|
|
int repr_len;
|
|
|
|
|
|
|
|
repr_len = 0;
|
|
|
|
for (p = string; (c = *p) != '\0'; p++) {
|
|
|
|
/* Backslashes and double-quotes must
|
|
|
|
* be escaped */
|
|
|
|
if (c == '\\' || c == '"') {
|
|
|
|
repr_len += 2;
|
|
|
|
}
|
|
|
|
/* Values that can't nicely be represented
|
|
|
|
* in ASCII need to be escaped. */
|
|
|
|
else if (!isprint((unsigned char)c)) {
|
|
|
|
/* c --> \xNN */
|
|
|
|
repr_len += 4;
|
|
|
|
}
|
|
|
|
/* Other characters are just passed through. */
|
|
|
|
else {
|
|
|
|
repr_len++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return repr_len + 2; /* string plus leading and trailing quotes */
|
|
|
|
}
|
|
|
|
|
2010-08-30 15:33:32 +00:00
|
|
|
char *
|
2009-08-19 18:37:13 +00:00
|
|
|
escape_string(char *buf, const char *string)
|
|
|
|
{
|
|
|
|
const gchar *p;
|
|
|
|
gchar c;
|
|
|
|
char *bufp;
|
2010-01-28 18:45:46 +00:00
|
|
|
char hexbuf[3];
|
2009-08-19 18:37:13 +00:00
|
|
|
|
|
|
|
bufp = buf;
|
|
|
|
*bufp++ = '"';
|
|
|
|
for (p = string; (c = *p) != '\0'; p++) {
|
|
|
|
/* Backslashes and double-quotes must
|
|
|
|
* be escaped. */
|
|
|
|
if (c == '\\' || c == '"') {
|
|
|
|
*bufp++ = '\\';
|
|
|
|
*bufp++ = c;
|
|
|
|
}
|
|
|
|
/* Values that can't nicely be represented
|
|
|
|
* in ASCII need to be escaped. */
|
|
|
|
else if (!isprint((unsigned char)c)) {
|
|
|
|
/* c --> \xNN */
|
2010-01-28 18:45:46 +00:00
|
|
|
g_snprintf(hexbuf,sizeof(hexbuf), "%02x", (unsigned char) c);
|
2009-08-19 18:37:13 +00:00
|
|
|
*bufp++ = '\\';
|
|
|
|
*bufp++ = 'x';
|
2010-01-28 18:45:46 +00:00
|
|
|
*bufp++ = hexbuf[0];
|
|
|
|
*bufp++ = hexbuf[1];
|
2009-08-19 18:37:13 +00:00
|
|
|
}
|
|
|
|
/* Other characters are just passed through. */
|
|
|
|
else {
|
|
|
|
*bufp++ = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*bufp++ = '"';
|
|
|
|
*bufp = '\0';
|
|
|
|
return buf;
|
|
|
|
}
|
2009-10-23 01:56:09 +00:00
|
|
|
|
|
|
|
#define GN_CHAR_ALPHABET_SIZE 128
|
|
|
|
|
|
|
|
static gunichar IA5_default_alphabet[GN_CHAR_ALPHABET_SIZE] = {
|
|
|
|
|
|
|
|
/*ITU-T recommendation T.50 specifies International Reference Alphabet 5 (IA5) */
|
|
|
|
|
|
|
|
'?', '?', '?', '?', '?', '?', '?', '?',
|
|
|
|
'?', '?', '?', '?', '?', '?', '?', '?',
|
|
|
|
'?', '?', '?', '?', '?', '?', '?', '?',
|
|
|
|
'?', '?', '?', '?', '?', '?', '?', '?',
|
|
|
|
' ', '!', '\"','#', '$', '%', '&', '\'',
|
|
|
|
'(', ')', '*', '+', ',', '-', '.', '/',
|
|
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
|
|
'8', '9', ':', ';', '<', '=', '>', '?',
|
|
|
|
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
|
|
|
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|
|
|
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
|
|
|
'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
|
|
|
|
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
|
|
|
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
|
|
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
|
|
|
|
'x', 'y', 'z', '{', '|', '}', '~', '?'
|
|
|
|
};
|
|
|
|
|
2010-08-30 15:33:32 +00:00
|
|
|
static gunichar
|
2009-10-23 01:56:09 +00:00
|
|
|
char_def_ia5_alphabet_decode(unsigned char value)
|
|
|
|
{
|
|
|
|
if (value < GN_CHAR_ALPHABET_SIZE)
|
|
|
|
{
|
|
|
|
return IA5_default_alphabet[value];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return '?';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IA5_7BIT_decode(unsigned char * dest, const unsigned char* src, int len)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
gunichar buf;
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0, j = 0; j < len; j++)
|
|
|
|
{
|
|
|
|
buf = char_def_ia5_alphabet_decode(src[j]);
|
|
|
|
i += g_unichar_to_utf8(buf,&(dest[i]));
|
|
|
|
}
|
|
|
|
dest[i]=0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-01-26 18:21:17 +00:00
|
|
|
/*
|
|
|
|
* This function takes a string and copies it, inserting an underscore before
|
|
|
|
* every underscore in it.
|
|
|
|
*/
|
|
|
|
gchar*
|
|
|
|
ws_strdup_escape_underscore (const gchar *str)
|
|
|
|
{
|
|
|
|
gchar *p, *q, *new_str;
|
|
|
|
|
|
|
|
if(!str)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
p = (gchar *)str;
|
|
|
|
/* Worst case: A string that is full of underscores */
|
|
|
|
q = new_str = g_malloc (strlen(str) * 2 + 1);
|
|
|
|
|
|
|
|
while(*p != 0)
|
|
|
|
{
|
|
|
|
if(*p == '_')
|
|
|
|
*q++ = '_';
|
|
|
|
|
|
|
|
*q++ = *p++;
|
|
|
|
}
|
2011-02-18 22:43:48 +00:00
|
|
|
*q = '\0';
|
2010-01-26 18:21:17 +00:00
|
|
|
|
|
|
|
return new_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function takes a string and copies it, removing any occurences of double
|
|
|
|
* underscores with a single underscore.
|
|
|
|
*/
|
|
|
|
gchar*
|
|
|
|
ws_strdup_unescape_underscore (const gchar *str)
|
|
|
|
{
|
|
|
|
gchar *p, *q, *new_str;
|
|
|
|
|
|
|
|
if(!str)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
p = (gchar *)str;
|
|
|
|
/* Worst case: A string that contains no underscores */
|
|
|
|
q = new_str = g_malloc (strlen(str) + 1);
|
|
|
|
|
|
|
|
while(*p != 0)
|
|
|
|
{
|
|
|
|
*q++ = *p;
|
|
|
|
if ((*p == '_') && (*(p+1) == '_'))
|
|
|
|
p += 2;
|
|
|
|
else
|
|
|
|
p++;
|
|
|
|
}
|
2011-02-18 22:43:48 +00:00
|
|
|
*q = '\0';
|
2010-01-26 18:21:17 +00:00
|
|
|
|
|
|
|
return new_str;
|
|
|
|
}
|
2010-05-27 15:51:25 +00:00
|
|
|
|
|
|
|
/* Create a newly-allocated string with replacement values. */
|
|
|
|
gchar *string_replace(const gchar* str, const gchar *old_val, const gchar *new_val) {
|
|
|
|
gchar **str_parts;
|
|
|
|
gchar *new_str;
|
|
|
|
|
|
|
|
if (!str || !old_val) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-08-30 15:33:32 +00:00
|
|
|
|
2010-05-27 15:51:25 +00:00
|
|
|
str_parts = g_strsplit(str, old_val, 0);
|
|
|
|
new_str = g_strjoinv(new_val, str_parts);
|
|
|
|
g_strfreev(str_parts);
|
2010-08-30 15:33:32 +00:00
|
|
|
|
2010-05-27 15:51:25 +00:00
|
|
|
return new_str;
|
|
|
|
}
|