real->str,
real->len + 1);
- real->align_offset = 0;
real->str = real->str - real->align_offset;
+ real->align_offset = 0;
}
}
/**
- * Initializes a string. The maximum length may be _DBUS_INT_MAX for
- * no maximum. The string starts life with zero length.
- * The string must eventually be freed with _dbus_string_free().
- *
- * @todo the max length feature is useless, because it looks to the
- * app like out of memory, and the app might try to "recover" - but
- * recovery in this case is impossible, as we can't ever "get more
- * memory" - so should delete the max length feature I think. Well, at
- * least there's a strong caveat that it can only be used when
- * out-of-memory is a permanent fatal error.
- *
- * @todo we could make this init routine not alloc any memory and
- * return void, would simplify a lot of code, however it might
- * complexify things elsewhere because _dbus_string_get_data()
- * etc. could suddenly fail as they'd need to alloc new memory.
+ * Initializes a string. The string starts life with zero length. The
+ * string must eventually be freed with _dbus_string_free().
*
* @param str memory to hold the string
- * @param max_length the maximum size of the string
- * @returns #TRUE on success */
+ * @returns #TRUE on success, #FALSE if no memory
+ */
dbus_bool_t
-_dbus_string_init (DBusString *str,
- int max_length)
+_dbus_string_init (DBusString *str)
{
DBusRealString *real;
_dbus_assert (str != NULL);
- _dbus_assert (max_length >= 0);
_dbus_assert (sizeof (DBusString) == sizeof (DBusRealString));
real->len = 0;
real->str[real->len] = '\0';
- real->max_length = max_length;
- if (real->max_length > MAX_MAX_LENGTH)
- real->max_length = MAX_MAX_LENGTH;
+ real->max_length = MAX_MAX_LENGTH;
real->constant = FALSE;
real->locked = FALSE;
real->invalid = FALSE;
return TRUE;
}
+/* The max length thing is sort of a historical artifact
+ * from a feature that turned out to be dumb; perhaps
+ * we should purge it entirely. The problem with
+ * the feature is that it looks like memory allocation
+ * failure, but is not a transient or resolvable failure.
+ */
+static void
+set_max_length (DBusString *str,
+ int max_length)
+{
+ DBusRealString *real;
+
+ real = (DBusRealString*) str;
+
+ real->max_length = max_length;
+}
+
/**
* Initializes a constant string. The value parameter is not copied
* (should be static), and the string may never be modified.
* function on a const string.
*
* @param str the string
- * @param data_return place to store the returned data
+ * @returns the data
*/
-void
-_dbus_string_get_data (DBusString *str,
- char **data_return)
+char*
+_dbus_string_get_data (DBusString *str)
{
DBUS_STRING_PREAMBLE (str);
- _dbus_assert (data_return != NULL);
- *data_return = real->str;
+ return real->str;
}
/**
* Gets the raw character buffer from a const string.
*
- * @todo should return the const char* instead of using an out param;
- * the temporary variable encourages a bug where you use const data
- * after modifying the string and possibly causing a realloc.
- *
* @param str the string
- * @param data_return location to store returned data
+ * @returns the string data
*/
-void
-_dbus_string_get_const_data (const DBusString *str,
- const char **data_return)
+const char*
+_dbus_string_get_const_data (const DBusString *str)
{
DBUS_CONST_STRING_PREAMBLE (str);
- _dbus_assert (data_return != NULL);
- *data_return = real->str;
+ return real->str;
}
/**
* string, not at start + len.
*
* @param str the string
- * @param data_return location to return the buffer
* @param start byte offset to return
* @param len length of segment to return
+ * @returns the string data
*/
-void
+char*
_dbus_string_get_data_len (DBusString *str,
- char **data_return,
int start,
int len)
{
DBUS_STRING_PREAMBLE (str);
- _dbus_assert (data_return != NULL);
_dbus_assert (start >= 0);
_dbus_assert (len >= 0);
_dbus_assert (start <= real->len);
_dbus_assert (len <= real->len - start);
- *data_return = real->str + start;
+ return real->str + start;
}
/**
* after modifying the string and possibly causing a realloc.
*
* @param str the string
- * @param data_return location to return the buffer
* @param start byte offset to return
* @param len length of segment to return
+ * @returns the string data
*/
-void
+const char*
_dbus_string_get_const_data_len (const DBusString *str,
- const char **data_return,
int start,
int len)
{
DBUS_CONST_STRING_PREAMBLE (str);
- _dbus_assert (data_return != NULL);
_dbus_assert (start >= 0);
_dbus_assert (len >= 0);
_dbus_assert (start <= real->len);
_dbus_assert (len <= real->len - start);
- *data_return = real->str + start;
+ return real->str + start;
}
/**
_dbus_string_steal_data (DBusString *str,
char **data_return)
{
+ int old_max_length;
DBUS_STRING_PREAMBLE (str);
_dbus_assert (data_return != NULL);
*data_return = real->str;
+ old_max_length = real->max_length;
+
/* reset the string */
- if (!_dbus_string_init (str, real->max_length))
+ if (!_dbus_string_init (str))
{
/* hrm, put it back then */
real->str = *data_return;
return FALSE;
}
+ real->max_length = old_max_length;
+
return TRUE;
}
int len)
{
DBusString dest;
-
DBUS_STRING_PREAMBLE (str);
_dbus_assert (data_return != NULL);
_dbus_assert (start >= 0);
_dbus_assert (start <= real->len);
_dbus_assert (len <= real->len - start);
- if (!_dbus_string_init (&dest, real->max_length))
+ if (!_dbus_string_init (&dest))
return FALSE;
+ set_max_length (&dest, real->max_length);
+
if (!_dbus_string_move_len (str, start, len, &dest, 0))
{
_dbus_string_free (&dest);
return FALSE;
}
- _dbus_warn ("Broken code in _dbus_string_steal_data_len(), FIXME\n");
+ _dbus_warn ("Broken code in _dbus_string_steal_data_len(), see @todo, FIXME\n");
+ if (!_dbus_string_steal_data (&dest, data_return))
+ {
+ _dbus_string_free (&dest);
+ return FALSE;
+ }
+
+ _dbus_string_free (&dest);
+ return TRUE;
+}
+
+
+/**
+ * Copies the data from the string into a char*
+ *
+ * @param str the string
+ * @param data_return place to return the data
+ * @returns #TRUE on success, #FALSE on no memory
+ */
+dbus_bool_t
+_dbus_string_copy_data (const DBusString *str,
+ char **data_return)
+{
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (data_return != NULL);
+
+ *data_return = dbus_malloc (real->len + 1);
+ if (*data_return == NULL)
+ return FALSE;
+
+ memcpy (*data_return, real->str, real->len + 1);
+
+ return TRUE;
+}
+
+/**
+ * Copies a segment of the string into a char*
+ *
+ * @param str the string
+ * @param data_return place to return the data
+ * @param start start index
+ * @param len length to copy
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_string_copy_data_len (const DBusString *str,
+ char **data_return,
+ int start,
+ int len)
+{
+ DBusString dest;
+
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (data_return != NULL);
+ _dbus_assert (start >= 0);
+ _dbus_assert (len >= 0);
+ _dbus_assert (start <= real->len);
+ _dbus_assert (len <= real->len - start);
+
+ if (!_dbus_string_init (&dest))
+ return FALSE;
+
+ set_max_length (&dest, real->max_length);
+
+ if (!_dbus_string_copy_len (str, start, len, &dest, 0))
+ {
+ _dbus_string_free (&dest);
+ return FALSE;
+ }
+
if (!_dbus_string_steal_data (&dest, data_return))
{
_dbus_string_free (&dest);
return TRUE;
}
-/* Unicode macros from GLib */
+/* Unicode macros and utf8_validate() from GLib Owen Taylor, Havoc
+ * Pennington, and Tom Tromey are the authors and authorized relicense.
+ */
/** computes length and mask of a unicode character
* @param Char the char
*/
#define UNICODE_VALID(Char) \
((Char) < 0x110000 && \
- ((Char) < 0xD800 || (Char) >= 0xE000) && \
- (Char) != 0xFFFE && (Char) != 0xFFFF)
+ (((Char) & 0xFFFFF800) != 0xD800) && \
+ ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
+ ((Char) & 0xFFFF) != 0xFFFF)
/**
* Gets a unicode character from a UTF-8 string. Does no validation;
/**
* Skips blanks from start, storing the first non-blank in *end
+ * (blank is space or tab).
*
* @param str the string
* @param start where to start
}
/**
+ * Skips whitespace from start, storing the first non-whitespace in *end.
+ * (whitespace is space, tab, newline, CR).
+ *
+ * @param str the string
+ * @param start where to start
+ * @param end where to store the first non-whitespace byte index
+ */
+void
+_dbus_string_skip_white (const DBusString *str,
+ int start,
+ int *end)
+{
+ int i;
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (start <= real->len);
+ _dbus_assert (start >= 0);
+
+ i = start;
+ while (i < real->len)
+ {
+ if (!(real->str[i] == ' ' ||
+ real->str[i] == '\n' ||
+ real->str[i] == '\r' ||
+ real->str[i] == '\t'))
+ break;
+
+ ++i;
+ }
+
+ _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
+ real->str[i] == '\t'));
+
+ if (end)
+ *end = i;
+}
+
+/**
* Assigns a newline-terminated or \r\n-terminated line from the front
* of the string to the given dest string. The dest string's previous
* contents are deleted. If the source string contains no newline,
if (source_len == 0)
return TRUE;
- if (!_dbus_string_init (&result, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&result))
return FALSE;
pad_count = 0;
*/
if (pad_count < 1)
- _dbus_string_append_byte (&result,
- triplet >> 16);
+ {
+ if (!_dbus_string_append_byte (&result,
+ triplet >> 16))
+ goto failed;
+ }
if (pad_count < 2)
- _dbus_string_append_byte (&result,
- (triplet >> 8) & 0xff);
+ {
+ if (!_dbus_string_append_byte (&result,
+ (triplet >> 8) & 0xff))
+ goto failed;
+ }
- _dbus_string_append_byte (&result,
- triplet & 0xff);
+ if (!_dbus_string_append_byte (&result,
+ triplet & 0xff))
+ goto failed;
sextet_count = 0;
pad_count = 0;
_dbus_string_free (&result);
return TRUE;
+
+ failed:
+ _dbus_string_free (&result);
+
+ return FALSE;
}
/**
_dbus_assert (start <= _dbus_string_get_length (source));
- if (!_dbus_string_init (&result, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&result))
return FALSE;
retval = FALSE;
- _dbus_string_get_const_data (source, (const char**) &p);
+ p = (const unsigned char*) _dbus_string_get_const_data (source);
end = p + _dbus_string_get_length (source);
p += start;
_dbus_assert (start <= _dbus_string_get_length (source));
- if (!_dbus_string_init (&result, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&result))
return FALSE;
retval = FALSE;
high_bits = TRUE;
- _dbus_string_get_const_data (source, (const char**) &p);
+ p = (const unsigned char*) _dbus_string_get_const_data (source);
end = p + _dbus_string_get_length (source);
p += start;
* Checks that the given range of the string is valid UTF-8. If the
* given range is not entirely contained in the string, returns
* #FALSE. If the string contains any nul bytes in the given range,
- * returns #FALSE.
- *
- * @todo right now just calls _dbus_string_validate_ascii()
+ * returns #FALSE. If the start and start+len are not on character
+ * boundaries, returns #FALSE.
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
int start,
int len)
{
- /* FIXME actually validate UTF-8 */
- return _dbus_string_validate_ascii (str, start, len);
+ const unsigned char *p;
+ const unsigned char *end;
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (start >= 0);
+ _dbus_assert (start <= real->len);
+ _dbus_assert (len >= 0);
+
+ if (len > real->len - start)
+ return FALSE;
+
+ p = real->str + start;
+ end = p + len;
+
+ while (p < end)
+ {
+ int i, mask = 0, char_len;
+ dbus_unichar_t result;
+ unsigned char c = (unsigned char) *p;
+
+ UTF8_COMPUTE (c, mask, char_len);
+
+ if (char_len == -1)
+ break;
+
+ /* check that the expected number of bytes exists in the remaining length */
+ if ((end - p) < char_len)
+ break;
+
+ UTF8_GET (result, p, i, mask, char_len);
+
+ if (UTF8_LENGTH (result) != char_len) /* Check for overlong UTF-8 */
+ break;
+
+ if (result == (dbus_unichar_t)-1)
+ break;
+
+ if (!UNICODE_VALID (result))
+ break;
+
+ p += char_len;
+ }
+
+ /* See that we covered the entire length if a length was
+ * passed in
+ */
+ if (p != end)
+ return FALSE;
+ else
+ return TRUE;
}
/**
if (len < 0)
len = strlen (data);
- if (!_dbus_string_init (&orig, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&orig))
_dbus_assert_not_reached ("could not init string");
- if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&encoded))
_dbus_assert_not_reached ("could not init string");
- if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&decoded))
_dbus_assert_not_reached ("could not init string");
if (!_dbus_string_append_len (&orig, data, len))
_dbus_string_get_length (&encoded),
_dbus_string_get_length (&decoded));
printf ("Original: %s\n", data);
- _dbus_string_get_const_data (&decoded, &s);
+ s = _dbus_string_get_const_data (&decoded);
printf ("Decoded: %s\n", s);
_dbus_assert_not_reached ("original string not the same as string decoded from base64");
}
if (len < 0)
len = strlen (data);
- if (!_dbus_string_init (&orig, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&orig))
_dbus_assert_not_reached ("could not init string");
- if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&encoded))
_dbus_assert_not_reached ("could not init string");
- if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&decoded))
_dbus_assert_not_reached ("could not init string");
if (!_dbus_string_append_len (&orig, data, len))
_dbus_string_get_length (&encoded),
_dbus_string_get_length (&decoded));
printf ("Original: %s\n", data);
- _dbus_string_get_const_data (&decoded, &s);
+ s = _dbus_string_get_const_data (&decoded);
printf ("Decoded: %s\n", s);
_dbus_assert_not_reached ("original string not the same as string decoded from base64");
}
i = 0;
while (i < _DBUS_N_ELEMENTS (lens))
{
- if (!_dbus_string_init (&str, lens[i]))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
+
+ set_max_length (&str, lens[i]);
test_max_len (&str, lens[i]);
_dbus_string_free (&str);
{
int j;
- if (!_dbus_string_init (&str, lens[i]))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
+
+ set_max_length (&str, lens[i]);
if (!_dbus_string_set_length (&str, lens[i]))
_dbus_assert_not_reached ("failed to set string length");
}
/* Test appending data */
- if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
i = 0;
/* Check steal_data */
- if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
if (!_dbus_string_append (&str, "Hello World"))
i = _dbus_string_get_length (&str);
- if (!_dbus_string_init (&other, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&other))
_dbus_assert_not_reached ("could not init string");
if (!_dbus_string_move (&str, 0, &other, 0))
i = _dbus_string_get_length (&str);
- if (!_dbus_string_init (&other, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&other))
_dbus_assert_not_reached ("could not init string");
if (!_dbus_string_copy (&str, 0, &other, 0))
/* Check replace */
- if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
if (!_dbus_string_append (&str, "Hello World"))
i = _dbus_string_get_length (&str);
- if (!_dbus_string_init (&other, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&other))
_dbus_assert_not_reached ("could not init string");
if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
/* Check append/get unichar */
- if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
ch = 0;
/* Check insert/set/get byte */
- if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
if (!_dbus_string_append (&str, "Hello"))
/* Check append/parse int/double */
- if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
if (!_dbus_string_append_int (&str, 27))
_dbus_string_free (&str);
- if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
if (!_dbus_string_append_double (&str, 50.3))
_dbus_string_free (&str);
/* Test find */
- if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("failed to init string");
if (!_dbus_string_append (&str, "Hello"))