1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-string-util.c Would be in dbus-string.c, but not used in libdbus
4 * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "dbus-internals.h"
25 #include "dbus-string.h"
26 #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
27 #include "dbus-string-private.h"
30 * @addtogroup DBusString
35 * Returns whether a string ends with the given suffix
37 * @todo memcmp might make this faster.
40 * @param c_str the C-style string
41 * @returns #TRUE if the string ends with the suffix
44 _dbus_string_ends_with_c_str (const DBusString *a,
47 const unsigned char *ap;
48 const unsigned char *bp;
49 const unsigned char *a_end;
50 unsigned long c_str_len;
51 const DBusRealString *real_a = (const DBusRealString*) a;
52 DBUS_GENERIC_STRING_PREAMBLE (real_a);
53 _dbus_assert (c_str != NULL);
55 c_str_len = strlen (c_str);
56 if (((unsigned long)real_a->len) < c_str_len)
59 ap = real_a->str + (real_a->len - c_str_len);
60 bp = (const unsigned char*) c_str;
61 a_end = real_a->str + real_a->len;
71 _dbus_assert (*ap == '\0');
72 _dbus_assert (*bp == '\0');
78 * Find the given byte scanning backward from the given start.
79 * Sets *found to -1 if the byte is not found.
81 * @param str the string
82 * @param start the place to start scanning (will not find the byte at this point)
83 * @param byte the byte to find
84 * @param found return location for where it was found
85 * @returns #TRUE if found
88 _dbus_string_find_byte_backward (const DBusString *str,
94 DBUS_CONST_STRING_PREAMBLE (str);
95 _dbus_assert (start <= real->len);
96 _dbus_assert (start >= 0);
97 _dbus_assert (found != NULL);
102 if (real->str[i] == byte)
115 * Skips whitespace from start, storing the first non-whitespace in *end.
116 * (whitespace is space, tab, newline, CR).
118 * @param str the string
119 * @param start where to start
120 * @param end where to store the first non-whitespace byte index
123 _dbus_string_skip_white (const DBusString *str,
128 DBUS_CONST_STRING_PREAMBLE (str);
129 _dbus_assert (start <= real->len);
130 _dbus_assert (start >= 0);
133 while (i < real->len)
135 if (!(real->str[i] == ' ' ||
136 real->str[i] == '\n' ||
137 real->str[i] == '\r' ||
138 real->str[i] == '\t'))
144 _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
145 real->str[i] == '\t'));
153 #ifdef DBUS_BUILD_TESTS
154 #include "dbus-test.h"
158 test_max_len (DBusString *str,
163 if (!_dbus_string_set_length (str, max_len - 1))
164 _dbus_assert_not_reached ("setting len to one less than max should have worked");
167 if (!_dbus_string_set_length (str, max_len))
168 _dbus_assert_not_reached ("setting len to max len should have worked");
170 if (_dbus_string_set_length (str, max_len + 1))
171 _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
173 if (!_dbus_string_set_length (str, 0))
174 _dbus_assert_not_reached ("setting len to zero should have worked");
178 test_hex_roundtrip (const unsigned char *data,
189 if (!_dbus_string_init (&orig))
190 _dbus_assert_not_reached ("could not init string");
192 if (!_dbus_string_init (&encoded))
193 _dbus_assert_not_reached ("could not init string");
195 if (!_dbus_string_init (&decoded))
196 _dbus_assert_not_reached ("could not init string");
198 if (!_dbus_string_append_len (&orig, data, len))
199 _dbus_assert_not_reached ("couldn't append orig data");
201 if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0))
202 _dbus_assert_not_reached ("could not encode");
204 if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0))
205 _dbus_assert_not_reached ("could not decode");
207 _dbus_assert (_dbus_string_get_length (&encoded) == end);
209 if (!_dbus_string_equal (&orig, &decoded))
213 printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
214 _dbus_string_get_length (&orig),
215 _dbus_string_get_length (&encoded),
216 _dbus_string_get_length (&decoded));
217 printf ("Original: %s\n", data);
218 s = _dbus_string_get_const_data (&decoded);
219 printf ("Decoded: %s\n", s);
220 _dbus_assert_not_reached ("original string not the same as string decoded from hex");
223 _dbus_string_free (&orig);
224 _dbus_string_free (&encoded);
225 _dbus_string_free (&decoded);
228 typedef void (* TestRoundtripFunc) (const unsigned char *data,
231 test_roundtrips (TestRoundtripFunc func)
233 (* func) ("Hello this is a string\n", -1);
234 (* func) ("Hello this is a string\n1", -1);
235 (* func) ("Hello this is a string\n12", -1);
236 (* func) ("Hello this is a string\n123", -1);
237 (* func) ("Hello this is a string\n1234", -1);
238 (* func) ("Hello this is a string\n12345", -1);
243 (* func) ("1234", 4);
244 (* func) ("12345", 5);
249 (* func) ("1234", 5);
250 (* func) ("12345", 6);
252 unsigned char buf[512];
256 while (i < _DBUS_N_ELEMENTS (buf))
262 while (i < _DBUS_N_ELEMENTS (buf))
270 #ifdef DBUS_BUILD_TESTS
271 /* The max length thing is sort of a historical artifact
272 * from a feature that turned out to be dumb; perhaps
273 * we should purge it entirely. The problem with
274 * the feature is that it looks like memory allocation
275 * failure, but is not a transient or resolvable failure.
278 set_max_length (DBusString *str,
281 DBusRealString *real;
283 real = (DBusRealString*) str;
285 real->max_length = max_length;
287 #endif /* DBUS_BUILD_TESTS */
290 * @ingroup DBusStringInternals
291 * Unit test for DBusString.
293 * @todo Need to write tests for _dbus_string_copy() and
294 * _dbus_string_move() moving to/from each of start/middle/end of a
295 * string. Also need tests for _dbus_string_move_len ()
297 * @returns #TRUE on success.
300 _dbus_string_test (void)
307 int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 };
312 while (i < _DBUS_N_ELEMENTS (lens))
314 if (!_dbus_string_init (&str))
315 _dbus_assert_not_reached ("failed to init string");
317 set_max_length (&str, lens[i]);
319 test_max_len (&str, lens[i]);
320 _dbus_string_free (&str);
325 /* Test shortening and setting length */
327 while (i < _DBUS_N_ELEMENTS (lens))
331 if (!_dbus_string_init (&str))
332 _dbus_assert_not_reached ("failed to init string");
334 set_max_length (&str, lens[i]);
336 if (!_dbus_string_set_length (&str, lens[i]))
337 _dbus_assert_not_reached ("failed to set string length");
342 _dbus_assert (_dbus_string_get_length (&str) == j);
345 _dbus_string_shorten (&str, 1);
346 _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
351 _dbus_string_free (&str);
357 if (!_dbus_string_init (&str))
358 _dbus_assert_not_reached ("oom");
360 if (!_dbus_string_append (&str, "Hello World"))
361 _dbus_assert_not_reached ("oom");
363 _dbus_string_init_const (&other, "H");
364 _dbus_assert (_dbus_string_equal_substring (&str, 0, 1, &other, 0));
365 _dbus_assert (_dbus_string_equal_substring (&str, 1, 0, &other, 1));
366 _dbus_string_init_const (&other, "Hello");
367 _dbus_assert (_dbus_string_equal_substring (&str, 0, 5, &other, 0));
368 _dbus_assert (_dbus_string_equal_substring (&str, 1, 4, &other, 1));
369 _dbus_assert (_dbus_string_equal_substring (&str, 2, 3, &other, 2));
370 _dbus_assert (_dbus_string_equal_substring (&str, 3, 2, &other, 3));
371 _dbus_assert (_dbus_string_equal_substring (&str, 4, 1, &other, 4));
372 _dbus_assert (_dbus_string_equal_substring (&str, 5, 0, &other, 5));
374 _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 0));
375 _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 1));
376 _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 2));
377 _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 3));
378 _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 4));
379 _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 5));
382 _dbus_string_init_const (&other, "World");
383 _dbus_assert (_dbus_string_equal_substring (&str, 6, 5, &other, 0));
384 _dbus_assert (_dbus_string_equal_substring (&str, 7, 4, &other, 1));
385 _dbus_assert (_dbus_string_equal_substring (&str, 8, 3, &other, 2));
386 _dbus_assert (_dbus_string_equal_substring (&str, 9, 2, &other, 3));
387 _dbus_assert (_dbus_string_equal_substring (&str, 10, 1, &other, 4));
388 _dbus_assert (_dbus_string_equal_substring (&str, 11, 0, &other, 5));
390 _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 6));
391 _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 7));
392 _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 8));
393 _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 9));
394 _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 10));
395 _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 11));
397 _dbus_string_free (&str);
399 /* Test appending data */
400 if (!_dbus_string_init (&str))
401 _dbus_assert_not_reached ("failed to init string");
406 if (!_dbus_string_append (&str, "a"))
407 _dbus_assert_not_reached ("failed to append string to string\n");
409 _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);
411 if (!_dbus_string_append_byte (&str, 'b'))
412 _dbus_assert_not_reached ("failed to append byte to string\n");
414 _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
419 _dbus_string_free (&str);
421 /* Check steal_data */
423 if (!_dbus_string_init (&str))
424 _dbus_assert_not_reached ("failed to init string");
426 if (!_dbus_string_append (&str, "Hello World"))
427 _dbus_assert_not_reached ("could not append to string");
429 i = _dbus_string_get_length (&str);
431 if (!_dbus_string_steal_data (&str, &s))
432 _dbus_assert_not_reached ("failed to steal data");
434 _dbus_assert (_dbus_string_get_length (&str) == 0);
435 _dbus_assert (((int)strlen (s)) == i);
441 if (!_dbus_string_append (&str, "Hello World"))
442 _dbus_assert_not_reached ("could not append to string");
444 i = _dbus_string_get_length (&str);
446 if (!_dbus_string_init (&other))
447 _dbus_assert_not_reached ("could not init string");
449 if (!_dbus_string_move (&str, 0, &other, 0))
450 _dbus_assert_not_reached ("could not move");
452 _dbus_assert (_dbus_string_get_length (&str) == 0);
453 _dbus_assert (_dbus_string_get_length (&other) == i);
455 if (!_dbus_string_append (&str, "Hello World"))
456 _dbus_assert_not_reached ("could not append to string");
458 if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other)))
459 _dbus_assert_not_reached ("could not move");
461 _dbus_assert (_dbus_string_get_length (&str) == 0);
462 _dbus_assert (_dbus_string_get_length (&other) == i * 2);
464 if (!_dbus_string_append (&str, "Hello World"))
465 _dbus_assert_not_reached ("could not append to string");
467 if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2))
468 _dbus_assert_not_reached ("could not move");
470 _dbus_assert (_dbus_string_get_length (&str) == 0);
471 _dbus_assert (_dbus_string_get_length (&other) == i * 3);
473 _dbus_string_free (&other);
477 if (!_dbus_string_append (&str, "Hello World"))
478 _dbus_assert_not_reached ("could not append to string");
480 i = _dbus_string_get_length (&str);
482 if (!_dbus_string_init (&other))
483 _dbus_assert_not_reached ("could not init string");
485 if (!_dbus_string_copy (&str, 0, &other, 0))
486 _dbus_assert_not_reached ("could not copy");
488 _dbus_assert (_dbus_string_get_length (&str) == i);
489 _dbus_assert (_dbus_string_get_length (&other) == i);
491 if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other)))
492 _dbus_assert_not_reached ("could not copy");
494 _dbus_assert (_dbus_string_get_length (&str) == i);
495 _dbus_assert (_dbus_string_get_length (&other) == i * 2);
496 _dbus_assert (_dbus_string_equal_c_str (&other,
497 "Hello WorldHello World"));
499 if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2))
500 _dbus_assert_not_reached ("could not copy");
502 _dbus_assert (_dbus_string_get_length (&str) == i);
503 _dbus_assert (_dbus_string_get_length (&other) == i * 3);
504 _dbus_assert (_dbus_string_equal_c_str (&other,
505 "Hello WorldHello WorldHello World"));
507 _dbus_string_free (&str);
508 _dbus_string_free (&other);
512 if (!_dbus_string_init (&str))
513 _dbus_assert_not_reached ("failed to init string");
515 if (!_dbus_string_append (&str, "Hello World"))
516 _dbus_assert_not_reached ("could not append to string");
518 i = _dbus_string_get_length (&str);
520 if (!_dbus_string_init (&other))
521 _dbus_assert_not_reached ("could not init string");
523 if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
524 &other, 0, _dbus_string_get_length (&other)))
525 _dbus_assert_not_reached ("could not replace");
527 _dbus_assert (_dbus_string_get_length (&str) == i);
528 _dbus_assert (_dbus_string_get_length (&other) == i);
529 _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World"));
531 if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
533 _dbus_assert_not_reached ("could not replace center space");
535 _dbus_assert (_dbus_string_get_length (&str) == i);
536 _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
537 _dbus_assert (_dbus_string_equal_c_str (&other,
538 "HelloHello WorldWorld"));
541 if (!_dbus_string_replace_len (&str, 1, 1,
543 _dbus_string_get_length (&other) - 1,
545 _dbus_assert_not_reached ("could not replace end character");
547 _dbus_assert (_dbus_string_get_length (&str) == i);
548 _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
549 _dbus_assert (_dbus_string_equal_c_str (&other,
550 "HelloHello WorldWorle"));
552 _dbus_string_free (&str);
553 _dbus_string_free (&other);
555 /* Check append/get unichar */
557 if (!_dbus_string_init (&str))
558 _dbus_assert_not_reached ("failed to init string");
561 if (!_dbus_string_append_unichar (&str, 0xfffc))
562 _dbus_assert_not_reached ("failed to append unichar");
564 _dbus_string_get_unichar (&str, 0, &ch, &i);
566 _dbus_assert (ch == 0xfffc);
567 _dbus_assert (i == _dbus_string_get_length (&str));
569 _dbus_string_free (&str);
571 /* Check insert/set/get byte */
573 if (!_dbus_string_init (&str))
574 _dbus_assert_not_reached ("failed to init string");
576 if (!_dbus_string_append (&str, "Hello"))
577 _dbus_assert_not_reached ("failed to append Hello");
579 _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H');
580 _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e');
581 _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l');
582 _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l');
583 _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o');
585 _dbus_string_set_byte (&str, 1, 'q');
586 _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
588 if (!_dbus_string_insert_bytes (&str, 0, 1, 255))
589 _dbus_assert_not_reached ("can't insert byte");
591 if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z'))
592 _dbus_assert_not_reached ("can't insert byte");
594 if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W'))
595 _dbus_assert_not_reached ("can't insert byte");
597 _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
598 _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
599 _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
600 _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z');
601 _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z');
602 _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z');
603 _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q');
604 _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l');
605 _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l');
606 _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o');
607 _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W');
609 _dbus_string_free (&str);
611 /* Check append/parse int/double */
613 if (!_dbus_string_init (&str))
614 _dbus_assert_not_reached ("failed to init string");
616 if (!_dbus_string_append_int (&str, 27))
617 _dbus_assert_not_reached ("failed to append int");
619 i = _dbus_string_get_length (&str);
621 if (!_dbus_string_parse_int (&str, 0, &v, &end))
622 _dbus_assert_not_reached ("failed to parse int");
624 _dbus_assert (v == 27);
625 _dbus_assert (end == i);
627 _dbus_string_free (&str);
629 if (!_dbus_string_init (&str))
630 _dbus_assert_not_reached ("failed to init string");
632 if (!_dbus_string_append_double (&str, 50.3))
633 _dbus_assert_not_reached ("failed to append float");
635 i = _dbus_string_get_length (&str);
637 if (!_dbus_string_parse_double (&str, 0, &d, &end))
638 _dbus_assert_not_reached ("failed to parse float");
640 _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
641 _dbus_assert (end == i);
643 _dbus_string_free (&str);
646 if (!_dbus_string_init (&str))
647 _dbus_assert_not_reached ("failed to init string");
649 if (!_dbus_string_append (&str, "Hello"))
650 _dbus_assert_not_reached ("couldn't append to string");
652 if (!_dbus_string_find (&str, 0, "He", &i))
653 _dbus_assert_not_reached ("didn't find 'He'");
654 _dbus_assert (i == 0);
656 if (!_dbus_string_find (&str, 0, "Hello", &i))
657 _dbus_assert_not_reached ("didn't find 'Hello'");
658 _dbus_assert (i == 0);
660 if (!_dbus_string_find (&str, 0, "ello", &i))
661 _dbus_assert_not_reached ("didn't find 'ello'");
662 _dbus_assert (i == 1);
664 if (!_dbus_string_find (&str, 0, "lo", &i))
665 _dbus_assert_not_reached ("didn't find 'lo'");
666 _dbus_assert (i == 3);
668 if (!_dbus_string_find (&str, 2, "lo", &i))
669 _dbus_assert_not_reached ("didn't find 'lo'");
670 _dbus_assert (i == 3);
672 if (_dbus_string_find (&str, 4, "lo", &i))
673 _dbus_assert_not_reached ("did find 'lo'");
675 if (!_dbus_string_find (&str, 0, "l", &i))
676 _dbus_assert_not_reached ("didn't find 'l'");
677 _dbus_assert (i == 2);
679 if (!_dbus_string_find (&str, 0, "H", &i))
680 _dbus_assert_not_reached ("didn't find 'H'");
681 _dbus_assert (i == 0);
683 if (!_dbus_string_find (&str, 0, "", &i))
684 _dbus_assert_not_reached ("didn't find ''");
685 _dbus_assert (i == 0);
687 if (_dbus_string_find (&str, 0, "Hello!", NULL))
688 _dbus_assert_not_reached ("Did find 'Hello!'");
690 if (_dbus_string_find (&str, 0, "Oh, Hello", NULL))
691 _dbus_assert_not_reached ("Did find 'Oh, Hello'");
693 if (_dbus_string_find (&str, 0, "ill", NULL))
694 _dbus_assert_not_reached ("Did find 'ill'");
696 if (_dbus_string_find (&str, 0, "q", NULL))
697 _dbus_assert_not_reached ("Did find 'q'");
699 if (!_dbus_string_find_to (&str, 0, 2, "He", NULL))
700 _dbus_assert_not_reached ("Didn't find 'He'");
702 if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL))
703 _dbus_assert_not_reached ("Did find 'Hello'");
705 if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i))
706 _dbus_assert_not_reached ("Did not find 'H'");
707 _dbus_assert (i == 0);
709 if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i))
710 _dbus_assert_not_reached ("Did not find 'o'");
711 _dbus_assert (i == _dbus_string_get_length (&str) - 1);
713 if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i))
714 _dbus_assert_not_reached ("Did find 'o'");
715 _dbus_assert (i == -1);
717 if (_dbus_string_find_byte_backward (&str, 1, 'e', &i))
718 _dbus_assert_not_reached ("Did find 'e'");
719 _dbus_assert (i == -1);
721 if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i))
722 _dbus_assert_not_reached ("Didn't find 'e'");
723 _dbus_assert (i == 1);
725 _dbus_string_free (&str);
728 _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string");
729 if (!_dbus_string_init (&other))
730 _dbus_assert_not_reached ("could not init string");
732 if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0))
733 _dbus_assert_not_reached ("deccoded bogus hex string with no error");
735 _dbus_assert (end == 8);
737 _dbus_string_free (&other);
739 test_roundtrips (test_hex_roundtrip);
741 _dbus_string_free (&str);
746 #endif /* DBUS_BUILD_TESTS */