2000-09-11 16:16:13 +00:00
|
|
|
/* strutil.c
|
|
|
|
* String utility routines
|
|
|
|
*
|
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
|
|
|
|
*
|
2018-02-08 16:59:17 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2000-09-11 16:16:13 +00:00
|
|
|
*/
|
|
|
|
|
2012-09-20 01:48:30 +00:00
|
|
|
#include "config.h"
|
2000-09-11 16:16:13 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <glib.h>
|
2000-09-11 20:05:13 +00:00
|
|
|
#include "strutil.h"
|
2010-08-30 15:33:32 +00:00
|
|
|
|
2014-01-08 00:28:13 +00:00
|
|
|
#include <wsutil/str_util.h>
|
2022-10-16 10:35:33 +00:00
|
|
|
#include <wsutil/unicode-utils.h>
|
2014-04-13 03:20:15 +00:00
|
|
|
#include <epan/proto.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
|
|
|
|
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
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
const guchar *lineend;
|
2000-09-11 16:16:13 +00:00
|
|
|
|
2013-03-18 21:16:23 +00:00
|
|
|
lineend = (guchar *)memchr(data, '\n', dataend - data);
|
2012-12-22 23:27:40 +00:00
|
|
|
if (lineend == NULL) {
|
2000-09-11 16:16:13 +00:00
|
|
|
/*
|
2012-12-22 23:27:40 +00:00
|
|
|
* No LF - line is probably continued in next TCP segment.
|
|
|
|
*/
|
|
|
|
lineend = dataend;
|
|
|
|
*eol = dataend;
|
|
|
|
} else {
|
2000-09-11 16:16:13 +00:00
|
|
|
/*
|
2012-12-22 23:27:40 +00:00
|
|
|
* Is the LF at the beginning of the line?
|
2000-09-11 16:16:13 +00:00
|
|
|
*/
|
2012-12-22 23:27:40 +00:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Yes - the EOL starts with the LF.
|
|
|
|
*/
|
|
|
|
*eol = lineend;
|
|
|
|
}
|
2000-09-11 16:16:13 +00:00
|
|
|
|
|
|
|
/*
|
2012-12-22 23:27:40 +00:00
|
|
|
* Point to the character after the last character.
|
2000-09-11 16:16:13 +00:00
|
|
|
*/
|
2012-12-22 23:27:40 +00:00
|
|
|
lineend++;
|
2000-09-11 16:16:13 +00:00
|
|
|
}
|
2012-12-22 23:27:40 +00:00
|
|
|
return lineend;
|
2000-09-11 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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,
|
2012-12-22 23:27:40 +00:00
|
|
|
const guchar **next_token)
|
2000-09-11 16:16:13 +00:00
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
const guchar *tokenp;
|
|
|
|
int token_len;
|
2000-09-11 16:16:13 +00:00
|
|
|
|
2012-12-22 23:27:40 +00:00
|
|
|
tokenp = linep;
|
2002-08-28 20:41:00 +00:00
|
|
|
|
2012-12-22 23:27:40 +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++;
|
|
|
|
token_len = (int) (linep - tokenp);
|
2000-09-11 16:16:13 +00:00
|
|
|
|
2012-12-22 23:27:40 +00:00
|
|
|
/*
|
|
|
|
* Skip trailing blanks.
|
|
|
|
*/
|
|
|
|
while (linep < lineend && *linep == ' ')
|
|
|
|
linep++;
|
2000-09-11 16:16:13 +00:00
|
|
|
|
2012-12-22 23:27:40 +00:00
|
|
|
*next_token = linep;
|
2000-09-11 16:16:13 +00:00
|
|
|
|
2012-12-22 23:27:40 +00:00
|
|
|
return token_len;
|
2000-09-11 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
2003-12-29 04:07:06 +00:00
|
|
|
static gboolean
|
|
|
|
is_byte_sep(guint8 c)
|
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
return (c == '-' || c == ':' || c == '.');
|
2003-12-29 04:07:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Turn a string of hex digits with optional separators (defined by
|
|
|
|
* is_byte_sep() into a byte array.
|
|
|
|
*/
|
|
|
|
gboolean
|
2014-09-04 01:39:04 +00:00
|
|
|
hex_str_to_bytes(const char *hex_str, GByteArray *bytes, gboolean force_separators)
|
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
guint8 val;
|
2014-10-17 23:10:53 +00:00
|
|
|
const gchar *p, *q, *r, *s, *punct;
|
2012-12-22 23:27:40 +00:00
|
|
|
char four_digits_first_half[3];
|
|
|
|
char four_digits_second_half[3];
|
|
|
|
char two_digits[3];
|
|
|
|
char one_digit[2];
|
|
|
|
|
|
|
|
if (! hex_str || ! bytes) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
g_byte_array_set_size(bytes, 0);
|
2014-10-17 23:10:53 +00:00
|
|
|
p = hex_str;
|
2012-12-22 23:27:40 +00:00
|
|
|
while (*p) {
|
|
|
|
q = p+1;
|
|
|
|
r = p+2;
|
|
|
|
s = p+3;
|
|
|
|
|
|
|
|
if (*q && *r && *s
|
2014-10-17 23:10:53 +00:00
|
|
|
&& g_ascii_isxdigit(*p) && g_ascii_isxdigit(*q) &&
|
|
|
|
g_ascii_isxdigit(*r) && g_ascii_isxdigit(*s)) {
|
2012-12-22 23:27:40 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p = punct;
|
|
|
|
continue;
|
|
|
|
}
|
2014-10-17 23:10:53 +00:00
|
|
|
else if (*q && g_ascii_isxdigit(*p) && g_ascii_isxdigit(*q)) {
|
2012-12-22 23:27:40 +00:00
|
|
|
two_digits[0] = *p;
|
|
|
|
two_digits[1] = *q;
|
|
|
|
two_digits[2] = '\0';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Two hex digits in a row.
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
else if (force_separators) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p = punct;
|
|
|
|
continue;
|
|
|
|
}
|
2014-10-17 23:10:53 +00:00
|
|
|
else if (*q && g_ascii_isxdigit(*p) && is_byte_sep(*q)) {
|
2012-12-22 23:27:40 +00:00
|
|
|
one_digit[0] = *p;
|
|
|
|
one_digit[1] = '\0';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only one hex digit (not at the end of the string)
|
|
|
|
*/
|
|
|
|
val = (guint8) strtoul(one_digit, NULL, 16);
|
|
|
|
g_byte_array_append(bytes, &val, 1);
|
|
|
|
p = q + 1;
|
|
|
|
continue;
|
|
|
|
}
|
2014-10-17 23:10:53 +00:00
|
|
|
else if (!*q && g_ascii_isxdigit(*p)) {
|
2012-12-22 23:27:40 +00:00
|
|
|
one_digit[0] = *p;
|
|
|
|
one_digit[1] = '\0';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only one hex digit (at the end of the string)
|
|
|
|
*/
|
|
|
|
val = (guint8) strtoul(one_digit, NULL, 16);
|
|
|
|
g_byte_array_append(bytes, &val, 1);
|
|
|
|
p = q;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
2003-12-29 04:07:06 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 03:20:15 +00:00
|
|
|
static inline gchar
|
|
|
|
get_valid_byte_sep(gchar c, const guint encoding)
|
|
|
|
{
|
|
|
|
gchar retval = -1; /* -1 means failure */
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case ':':
|
|
|
|
if (encoding & ENC_SEP_COLON)
|
|
|
|
retval = c;
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
if (encoding & ENC_SEP_DASH)
|
|
|
|
retval = c;
|
|
|
|
break;
|
|
|
|
case '.':
|
|
|
|
if (encoding & ENC_SEP_DOT)
|
|
|
|
retval = c;
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
if (encoding & ENC_SEP_SPACE)
|
|
|
|
retval = c;
|
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
/* we were given the end of the string, so it's fine */
|
|
|
|
retval = 0;
|
|
|
|
break;
|
|
|
|
default:
|
2014-10-17 23:10:53 +00:00
|
|
|
if (g_ascii_isxdigit(c) && (encoding & ENC_SEP_NONE))
|
2014-04-13 03:20:15 +00:00
|
|
|
retval = 0;
|
|
|
|
/* anything else means we've got a failure */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Turn a string of hex digits with optional separators (defined by is_byte_sep())
|
|
|
|
* into a byte array. Unlike hex_str_to_bytes(), this will read as many hex-char
|
|
|
|
* pairs as possible and not error if it hits a non-hex-char; instead it just ends
|
|
|
|
* there. (i.e., like strtol()/atoi()/etc.) Unless fail_if_partial is TRUE.
|
|
|
|
*
|
|
|
|
* The **endptr, if not NULL, is set to the char after the last hex character.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
hex_str_to_bytes_encoding(const gchar *hex_str, GByteArray *bytes, const gchar **endptr,
|
|
|
|
const guint encoding, const gboolean fail_if_partial)
|
|
|
|
{
|
2014-10-16 18:16:11 +00:00
|
|
|
gint8 c, d;
|
2014-04-13 03:20:15 +00:00
|
|
|
guint8 val;
|
|
|
|
const gchar *end = hex_str;
|
|
|
|
gboolean retval = FALSE;
|
|
|
|
gchar sep = -1;
|
|
|
|
|
|
|
|
/* a map from ASCII hex chars to their value */
|
2014-10-16 18:16:11 +00:00
|
|
|
static const gint8 str_to_nibble[256] = {
|
2014-04-13 03:20:15 +00:00
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
|
|
|
};
|
|
|
|
|
|
|
|
/* we must see two hex chars at the beginning, or fail */
|
2014-10-17 23:10:53 +00:00
|
|
|
if (bytes && *end && g_ascii_isxdigit(*end) && g_ascii_isxdigit(*(end+1))) {
|
2014-04-13 03:20:15 +00:00
|
|
|
retval = TRUE;
|
|
|
|
|
|
|
|
/* set the separator character we'll allow; if this returns a -1, it means something's
|
|
|
|
* invalid after the hex, but we'll let the while-loop grab the first hex-pair anyway
|
|
|
|
*/
|
|
|
|
sep = get_valid_byte_sep(*(end+2), encoding);
|
|
|
|
|
|
|
|
while (*end) {
|
2014-10-16 18:16:11 +00:00
|
|
|
c = str_to_nibble[(guchar)*end];
|
2014-04-13 03:20:15 +00:00
|
|
|
if (c < 0) {
|
|
|
|
if (fail_if_partial) retval = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-10-20 23:39:52 +00:00
|
|
|
d = str_to_nibble[(guchar)*(end+1)];
|
2014-04-13 03:20:15 +00:00
|
|
|
if (d < 0) {
|
|
|
|
if (fail_if_partial) retval = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
val = ((guint8)c * 16) + d;
|
|
|
|
g_byte_array_append(bytes, &val, 1);
|
2022-10-20 23:39:52 +00:00
|
|
|
end += 2;
|
2014-04-13 03:20:15 +00:00
|
|
|
|
|
|
|
/* check for separator and peek at next char to make sure we should keep going */
|
2014-10-16 20:03:52 +00:00
|
|
|
if (sep > 0 && *end == sep && str_to_nibble[(guchar)*(end+1)] > -1) {
|
2014-04-13 03:20:15 +00:00
|
|
|
/* yes, it's the right sep and followed by more hex, so skip the sep */
|
|
|
|
++end;
|
|
|
|
} else if (sep != 0 && *end) {
|
|
|
|
/* we either need a separator, but we don't see one; or the get_valid_byte_sep()
|
|
|
|
earlier didn't find a valid one to begin with */
|
|
|
|
if (fail_if_partial) retval = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* otherwise, either no separator allowed, or *end is null, or *end is an invalid
|
|
|
|
* sep, or *end is a valid sep but after it is not a hex char - in all those
|
|
|
|
* cases, just loop back up and let it fail later naturally.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!retval) {
|
|
|
|
if (bytes) g_byte_array_set_size(bytes, 0);
|
|
|
|
end = hex_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (endptr) *endptr = end;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2007-01-11 02:42:34 +00:00
|
|
|
/*
|
2022-08-30 01:25:35 +00:00
|
|
|
* Turn an RFC 3986 percent-encoded array of characters, not
|
|
|
|
* necessarily null-terminated, into a byte array.
|
2007-01-11 02:42:34 +00:00
|
|
|
* XXX - We don't check for reserved characters.
|
2022-08-30 01:25:35 +00:00
|
|
|
* XXX - g_uri_unescape_bytes is superior, but limited to
|
|
|
|
* glib >= 2.66
|
2007-01-11 02:42:34 +00:00
|
|
|
*/
|
|
|
|
#define HEX_DIGIT_BUF_LEN 3
|
|
|
|
gboolean
|
2022-08-30 01:25:35 +00:00
|
|
|
uri_to_bytes(const char *uri_str, GByteArray *bytes, size_t len)
|
2014-09-04 01:39:04 +00:00
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
guint8 val;
|
2022-08-30 01:25:35 +00:00
|
|
|
const gchar *p;
|
|
|
|
const gchar *uri_end = uri_str + len;
|
2014-10-17 23:10:53 +00:00
|
|
|
gchar hex_digit[HEX_DIGIT_BUF_LEN];
|
2012-12-22 23:27:40 +00:00
|
|
|
|
|
|
|
g_byte_array_set_size(bytes, 0);
|
|
|
|
if (! uri_str) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2014-10-17 23:10:53 +00:00
|
|
|
p = uri_str;
|
2012-12-22 23:27:40 +00:00
|
|
|
|
2022-08-30 01:25:35 +00:00
|
|
|
while (p < uri_end) {
|
2013-12-21 15:12:11 +00:00
|
|
|
if (!g_ascii_isprint(*p))
|
2012-12-22 23:27:40 +00:00
|
|
|
return FALSE;
|
|
|
|
if (*p == '%') {
|
|
|
|
p++;
|
|
|
|
if (*p == '\0') return FALSE;
|
|
|
|
hex_digit[0] = *p;
|
|
|
|
p++;
|
|
|
|
if (*p == '\0') return FALSE;
|
|
|
|
hex_digit[1] = *p;
|
|
|
|
hex_digit[2] = '\0';
|
2014-10-17 23:10:53 +00:00
|
|
|
if (! g_ascii_isxdigit(hex_digit[0]) || ! g_ascii_isxdigit(hex_digit[1]))
|
2012-12-22 23:27:40 +00:00
|
|
|
return FALSE;
|
2014-10-17 23:10:53 +00:00
|
|
|
val = (guint8) strtoul(hex_digit, NULL, 16);
|
2012-12-22 23:27:40 +00:00
|
|
|
g_byte_array_append(bytes, &val, 1);
|
|
|
|
} else {
|
|
|
|
g_byte_array_append(bytes, (const guint8 *) p, 1);
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
|
|
|
|
}
|
|
|
|
return TRUE;
|
2007-01-11 02:42:34 +00:00
|
|
|
}
|
|
|
|
|
2022-08-30 01:25:35 +00:00
|
|
|
/*
|
|
|
|
* Turn an RFC 3986 percent-encoded string into a byte array.
|
|
|
|
* XXX - We don't check for reserved characters.
|
|
|
|
* XXX - Just use g_uri_unescape_string instead?
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
uri_str_to_bytes(const char *uri_str, GByteArray *bytes)
|
|
|
|
{
|
|
|
|
return uri_to_bytes(uri_str, bytes, strlen(uri_str));
|
|
|
|
}
|
|
|
|
|
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 *
|
2014-09-04 01:39:04 +00:00
|
|
|
byte_array_dup(const GByteArray *ba)
|
|
|
|
{
|
2007-01-11 02:42:34 +00:00
|
|
|
GByteArray *new_ba;
|
|
|
|
|
|
|
|
if (!ba)
|
2012-12-22 23:27:40 +00:00
|
|
|
return NULL;
|
2007-01-11 02:42:34 +00:00
|
|
|
|
|
|
|
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
|
2014-09-04 01:39:04 +00:00
|
|
|
oid_str_to_bytes(const char *oid_str, GByteArray *bytes)
|
|
|
|
{
|
2013-10-06 02:31:10 +00:00
|
|
|
return rel_oid_str_to_bytes(oid_str, bytes, TRUE);
|
|
|
|
}
|
|
|
|
gboolean
|
2014-09-04 01:39:04 +00:00
|
|
|
rel_oid_str_to_bytes(const char *oid_str, GByteArray *bytes, gboolean is_absolute)
|
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
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) {
|
2014-10-17 23:10:53 +00:00
|
|
|
if (!g_ascii_isdigit(*p) && (*p != '.')) return FALSE;
|
2012-12-22 23:27:40 +00:00
|
|
|
if (*p == '.') {
|
2013-10-06 02:31:10 +00:00
|
|
|
if (p == oid_str && is_absolute) return FALSE;
|
2012-12-22 23:27:40 +00:00
|
|
|
if (!*(p+1)) return FALSE;
|
|
|
|
if ((p-1) == dot) return FALSE;
|
|
|
|
dot = p;
|
|
|
|
}
|
|
|
|
p++;
|
2005-12-02 13:16:58 +00:00
|
|
|
}
|
2012-12-22 23:27:40 +00:00
|
|
|
if (!dot) return FALSE;
|
|
|
|
|
|
|
|
p = oid_str;
|
2013-10-06 02:31:10 +00:00
|
|
|
sicnt = is_absolute ? 0 : 2;
|
|
|
|
if (!is_absolute) p++;
|
2012-12-22 23:27:40 +00:00
|
|
|
subid0 = 0; /* squelch GCC complaints */
|
|
|
|
while (*p) {
|
|
|
|
subid = 0;
|
2014-10-17 23:10:53 +00:00
|
|
|
while (g_ascii_isdigit(*p)) {
|
2012-12-22 23:27:40 +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++;
|
2005-12-02 13:16:58 +00:00
|
|
|
}
|
|
|
|
|
2012-12-22 23:27:40 +00:00
|
|
|
return TRUE;
|
2005-12-02 13:16:58 +00:00
|
|
|
}
|
|
|
|
|
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
|
2014-09-04 01:39:04 +00:00
|
|
|
byte_array_equal(GByteArray *ba1, GByteArray *ba2)
|
|
|
|
{
|
2007-01-11 02:42:34 +00:00
|
|
|
if (!ba1 || !ba2)
|
2012-12-22 23:27:40 +00:00
|
|
|
return FALSE;
|
2007-01-11 02:42:34 +00:00
|
|
|
|
|
|
|
if (ba1->len != ba2->len)
|
2012-12-22 23:27:40 +00:00
|
|
|
return FALSE;
|
2007-01-11 02:42:34 +00:00
|
|
|
|
|
|
|
if (memcmp(ba1->data, ba2->data, ba1->len) != 0)
|
2012-12-22 23:27:40 +00:00
|
|
|
return FALSE;
|
2007-01-11 02:42:34 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
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 '\'':
|
2014-10-06 23:02:16 +00:00
|
|
|
g_string_append(buffer, "'");
|
2012-12-22 23:27:40 +00:00
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
g_string_append(buffer, """);
|
|
|
|
break;
|
2022-09-21 12:26:35 +00:00
|
|
|
case '\t':
|
|
|
|
case '\n':
|
|
|
|
case '\r':
|
2012-12-22 23:27:40 +00:00
|
|
|
g_string_append_c(buffer, c);
|
|
|
|
break;
|
2022-09-21 12:26:35 +00:00
|
|
|
default:
|
|
|
|
/* XML 1.0 doesn't allow ASCII control characters, except
|
|
|
|
* for the three whitespace ones above (which do *not*
|
|
|
|
* include '\v' and '\f', so not the same group as isspace),
|
|
|
|
* even as character references.
|
|
|
|
* There's no official way to escape them, so we'll do this. */
|
|
|
|
if (g_ascii_iscntrl(c)) {
|
|
|
|
g_string_append_printf(buffer, "\\x%x", c);
|
|
|
|
} else {
|
|
|
|
g_string_append_c(buffer, c);
|
|
|
|
}
|
|
|
|
break;
|
2012-12-22 23:27:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* 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);
|
2004-05-01 20:46:24 +00:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
size_t n_bytes;
|
|
|
|
const char *p;
|
2014-10-17 23:10:53 +00:00
|
|
|
gchar c;
|
2012-12-22 23:27:40 +00:00
|
|
|
guint8 *bytes, *q, byte_val;
|
|
|
|
|
|
|
|
n_bytes = 0;
|
|
|
|
p = &string[0];
|
|
|
|
for (;;) {
|
|
|
|
c = *p++;
|
|
|
|
if (c == '\0')
|
|
|
|
break;
|
2014-10-17 23:10:53 +00:00
|
|
|
if (g_ascii_isspace(c))
|
2012-12-22 23:27:40 +00:00
|
|
|
continue; /* allow white space */
|
|
|
|
if (c==':' || c=='.' || c=='-')
|
|
|
|
continue; /* skip any ':', '.', or '-' between bytes */
|
2014-10-17 23:10:53 +00:00
|
|
|
if (!g_ascii_isxdigit(c)) {
|
2012-12-22 23:27:40 +00:00
|
|
|
/* 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++;
|
2014-10-17 23:10:53 +00:00
|
|
|
if (!g_ascii_isxdigit(c))
|
2012-12-22 23:27:40 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* 2 hex digits = 1 byte */
|
|
|
|
n_bytes++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Were we given any hex digits?
|
|
|
|
*/
|
|
|
|
if (n_bytes == 0) {
|
|
|
|
/* No. */
|
|
|
|
return NULL;
|
2004-08-13 02:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-12-22 23:27:40 +00:00
|
|
|
* OK, it's valid, and it generates "n_bytes" bytes; generate the
|
|
|
|
* raw byte array.
|
2004-08-13 02:39:49 +00:00
|
|
|
*/
|
2013-03-18 21:16:23 +00:00
|
|
|
bytes = (guint8 *)g_malloc(n_bytes);
|
2012-12-22 23:27:40 +00:00
|
|
|
p = &string[0];
|
|
|
|
q = &bytes[0];
|
|
|
|
for (;;) {
|
|
|
|
c = *p++;
|
|
|
|
if (c == '\0')
|
|
|
|
break;
|
2014-10-17 23:10:53 +00:00
|
|
|
if (g_ascii_isspace(c))
|
2012-12-22 23:27:40 +00:00
|
|
|
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 */
|
2014-01-08 00:28:13 +00:00
|
|
|
byte_val = ws_xton(c);
|
2012-12-22 23:27:40 +00:00
|
|
|
byte_val <<= 4;
|
|
|
|
|
|
|
|
/* We also know this is a hex digit */
|
|
|
|
c = *p++;
|
2014-01-08 00:28:13 +00:00
|
|
|
byte_val |= ws_xton(c);
|
2012-12-22 23:27:40 +00:00
|
|
|
|
|
|
|
*q++ = byte_val;
|
|
|
|
}
|
|
|
|
*nbytes = n_bytes;
|
|
|
|
return bytes;
|
2004-08-13 02:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2021-12-20 02:40:23 +00:00
|
|
|
* Copy if it's a case-sensitive search; uppercase it if it's
|
2004-08-13 02:39:49 +00:00
|
|
|
* a case-insensitive search.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
convert_string_case(const char *string, gboolean case_insensitive)
|
|
|
|
{
|
|
|
|
|
2012-12-22 23:27:40 +00:00
|
|
|
if (case_insensitive) {
|
|
|
|
return g_utf8_strup(string, -1);
|
|
|
|
} else {
|
|
|
|
return g_strdup(string);
|
|
|
|
}
|
2004-08-13 02:39:49 +00:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2012-12-22 23:27:40 +00:00
|
|
|
if (value < GN_CHAR_ALPHABET_SIZE) {
|
|
|
|
return IA5_default_alphabet[value];
|
2009-10-23 01:56:09 +00:00
|
|
|
}
|
2012-12-22 23:27:40 +00:00
|
|
|
else {
|
|
|
|
return '?';
|
2009-10-23 01:56:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IA5_7BIT_decode(unsigned char * dest, const unsigned char* src, int len)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
gunichar buf;
|
|
|
|
|
2012-12-22 23:27:40 +00:00
|
|
|
for (i = 0, j = 0; j < len; j++) {
|
|
|
|
buf = char_def_ia5_alphabet_decode(src[j]);
|
|
|
|
i += g_unichar_to_utf8(buf,&(dest[i]));
|
2009-10-23 01:56:09 +00:00
|
|
|
}
|
|
|
|
dest[i]=0;
|
|
|
|
}
|
|
|
|
|
2021-11-04 14:16:49 +00:00
|
|
|
/* chars allowed: lower case letters, digits, '-', "_", and ".". */
|
|
|
|
static
|
|
|
|
const guint8 module_valid_chars_lower_case[128] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x0F */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1F */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, /* 0x20-0x2F '-', '.' */
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F '0'-'9' */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x4F */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0x50-0x5F '_' */
|
|
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F 'a'-'o' */
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x70-0x7F 'p'-'z' */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* chars allowed: alphanumerics, '-', "_", and ".". */
|
|
|
|
static
|
|
|
|
const guint8 module_valid_chars[128] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x0F */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1F */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, /* 0x20-0x2F '-', '.' */
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F '0'-'9' */
|
|
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40-0x4F 'A'-'O' */
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50-0x5F 'P'-'Z', '_' */
|
|
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F 'a'-'o' */
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x70-0x7F 'p'-'z' */
|
|
|
|
};
|
|
|
|
|
|
|
|
guchar
|
|
|
|
module_check_valid_name(const char *name, gboolean lower_only)
|
|
|
|
{
|
|
|
|
const char *p = name;
|
|
|
|
guchar c = '.', lastc;
|
|
|
|
const guint8 *chars;
|
|
|
|
|
|
|
|
/* First character cannot be '-'. */
|
|
|
|
if (name[0] == '-')
|
|
|
|
return '-';
|
|
|
|
|
|
|
|
if (lower_only)
|
|
|
|
chars = module_valid_chars_lower_case;
|
|
|
|
else
|
|
|
|
chars = module_valid_chars;
|
|
|
|
|
|
|
|
do {
|
|
|
|
lastc = c;
|
|
|
|
c = *(p++);
|
|
|
|
/* Leading '.' or substring ".." are disallowed. */
|
|
|
|
if (c == '.' && lastc == '.') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (c < 128 && chars[c]);
|
|
|
|
|
|
|
|
/* Trailing '.' is disallowed. */
|
|
|
|
if (lastc == '.') {
|
|
|
|
return '.';
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2022-10-16 10:35:33 +00:00
|
|
|
static const char _hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
|
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy byte by byte without UTF-8 truncation (assume valid UTF-8 input).
|
|
|
|
* Return byte size written, or that would have been
|
|
|
|
* written with enough space.
|
|
|
|
*/
|
|
|
|
size_t
|
2022-10-21 12:33:29 +00:00
|
|
|
ws_label_strcpy(char *label_str, size_t buf_size, size_t pos,
|
2022-10-16 10:35:33 +00:00
|
|
|
const uint8_t *str, int flags)
|
|
|
|
{
|
|
|
|
if (pos >= buf_size)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
uint8_t r = 0;
|
|
|
|
ssize_t chlen;
|
|
|
|
ssize_t idx, src_len;
|
|
|
|
ssize_t free_len;
|
|
|
|
|
2022-10-27 22:37:17 +00:00
|
|
|
label_str[pos] = '\0';
|
|
|
|
|
2022-10-16 10:35:33 +00:00
|
|
|
idx = 0;
|
|
|
|
src_len = strlen(str);
|
|
|
|
free_len = buf_size - pos - 1;
|
|
|
|
|
|
|
|
while (idx < src_len) {
|
|
|
|
chlen = ws_utf8_char_len(str[idx]);
|
|
|
|
if (chlen <= 0) {
|
|
|
|
/* We were passed invalid UTF-8. This is an error. Complain and do... something. */
|
|
|
|
ws_log_utf8(str, -1, NULL);
|
|
|
|
/*
|
|
|
|
* XXX If we are going to return here instead of trying to recover maybe the log level should
|
|
|
|
* be higher than DEBUG.
|
|
|
|
*/
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ASCII */
|
|
|
|
if (chlen == 1) {
|
|
|
|
if (flags & FORMAT_LABEL_REPLACE_SPACE && g_ascii_isspace(str[idx])) {
|
|
|
|
if (free_len >= 1) {
|
|
|
|
label_str[pos] = ' ';
|
2022-10-21 08:49:20 +00:00
|
|
|
label_str[pos+1] = '\0';
|
2022-10-16 10:35:33 +00:00
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
idx++;
|
|
|
|
free_len--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
switch (str[idx]) {
|
|
|
|
case '\a': r = 'a'; break;
|
|
|
|
case '\b': r = 'b'; break;
|
|
|
|
case '\f': r = 'f'; break;
|
|
|
|
case '\n': r = 'n'; break;
|
|
|
|
case '\r': r = 'r'; break;
|
|
|
|
case '\t': r = 't'; break;
|
|
|
|
case '\v': r = 'v'; break;
|
|
|
|
}
|
|
|
|
if (r != 0) {
|
|
|
|
if (free_len >= 2) {
|
|
|
|
label_str[pos] = '\\';
|
|
|
|
label_str[pos+1] = r;
|
2022-10-21 08:49:20 +00:00
|
|
|
label_str[pos+2] = '\0';
|
2022-10-16 10:35:33 +00:00
|
|
|
}
|
|
|
|
pos += 2;
|
|
|
|
idx += 1;
|
|
|
|
free_len -= 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_ascii_isprint(str[idx])) {
|
|
|
|
if (free_len >= 1) {
|
|
|
|
label_str[pos] = str[idx];
|
2022-10-21 08:49:20 +00:00
|
|
|
label_str[pos+1] = '\0';
|
2022-10-16 10:35:33 +00:00
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
idx++;
|
|
|
|
free_len--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (free_len >= 4) {
|
|
|
|
label_str[pos+0] = '\\';
|
|
|
|
label_str[pos+1] = 'x';
|
|
|
|
|
|
|
|
uint8_t ch = str[idx];
|
|
|
|
label_str[pos+2] = _hex[ch >> 4];
|
|
|
|
label_str[pos+3] = _hex[ch & 0x0F];
|
2022-10-21 08:49:20 +00:00
|
|
|
label_str[pos+4] = '\0';
|
2022-10-16 10:35:33 +00:00
|
|
|
}
|
|
|
|
pos += 4;
|
|
|
|
idx += chlen;
|
|
|
|
free_len -= 4;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* UTF-8 multibyte */
|
|
|
|
if (chlen == 2 && str[idx] == 0xC2 &&
|
|
|
|
str[idx+1] >= 0x80 && str[idx+1] <= 0x9F) {
|
|
|
|
/*
|
|
|
|
* Escape the C1 control codes. C0 (covered above) and C1 are
|
|
|
|
* inband signalling and transparent to Unicode.
|
|
|
|
* Anything else probably has text semantics should not be removed.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Special case: The second UTF-8 byte is the same as the Unicode
|
|
|
|
* code point for range U+0080 - U+009F.
|
|
|
|
*/
|
|
|
|
if (free_len >= 6) {
|
|
|
|
label_str[pos+0] = '\\';
|
|
|
|
label_str[pos+1] = 'u';
|
|
|
|
label_str[pos+2] = '0';
|
|
|
|
label_str[pos+3] = '0';
|
|
|
|
|
|
|
|
uint8_t ch = str[idx+1];
|
|
|
|
label_str[pos+4] = _hex[ch >> 4];
|
|
|
|
label_str[pos+5] = _hex[ch & 0x0F];
|
2022-10-21 08:49:20 +00:00
|
|
|
label_str[pos+6] = '\0';
|
2022-10-16 10:35:33 +00:00
|
|
|
}
|
|
|
|
pos += 6;
|
|
|
|
idx += chlen;
|
|
|
|
free_len -= 6;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Just copy */
|
|
|
|
if (free_len >= chlen) {
|
|
|
|
for (ssize_t j = 0; j < chlen; j++) {
|
|
|
|
label_str[pos+j] = str[idx+j];
|
|
|
|
}
|
2022-10-21 08:49:20 +00:00
|
|
|
label_str[pos+chlen] = '\0';
|
2022-10-16 10:35:33 +00:00
|
|
|
}
|
|
|
|
pos += chlen;
|
|
|
|
idx += chlen;
|
|
|
|
free_len -= chlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
2022-10-21 12:37:42 +00:00
|
|
|
size_t
|
|
|
|
ws_label_strcat(char *label_str, size_t bufsize, const uint8_t *str, int flags)
|
|
|
|
{
|
|
|
|
return ws_label_strcpy(label_str, bufsize, strlen(label_str), str, flags);
|
|
|
|
}
|
|
|
|
|
2012-12-22 23:27:40 +00:00
|
|
|
/*
|
2019-07-26 18:43:17 +00:00
|
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
2012-12-22 23:27:40 +00:00
|
|
|
*
|
|
|
|
* Local variables:
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
|
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
|
|
*/
|