2004-05-17 Kristian Høgsberg <krh@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-string.c
index 6a83398..8820273 100644 (file)
@@ -2125,400 +2125,6 @@ _dbus_string_ends_with_c_str (const DBusString *a,
   return TRUE;
 }
 
-static const signed char base64_table[] = {
-  /* 0 */ 'A',
-  /* 1 */ 'B',
-  /* 2 */ 'C',
-  /* 3 */ 'D',
-  /* 4 */ 'E',
-  /* 5 */ 'F',
-  /* 6 */ 'G',
-  /* 7 */ 'H',
-  /* 8 */ 'I',
-  /* 9 */ 'J',
-  /* 10 */ 'K',
-  /* 11 */ 'L',
-  /* 12 */ 'M',
-  /* 13 */ 'N',
-  /* 14 */ 'O',
-  /* 15 */ 'P',
-  /* 16 */ 'Q',
-  /* 17 */ 'R',
-  /* 18 */ 'S',
-  /* 19 */ 'T',
-  /* 20 */ 'U',
-  /* 21 */ 'V',
-  /* 22 */ 'W',
-  /* 23 */ 'X',
-  /* 24 */ 'Y',
-  /* 25 */ 'Z',
-  /* 26 */ 'a',
-  /* 27 */ 'b',
-  /* 28 */ 'c',
-  /* 29 */ 'd',
-  /* 30 */ 'e',
-  /* 31 */ 'f',
-  /* 32 */ 'g',
-  /* 33 */ 'h',
-  /* 34 */ 'i',
-  /* 35 */ 'j',
-  /* 36 */ 'k',
-  /* 37 */ 'l',
-  /* 38 */ 'm',
-  /* 39 */ 'n',
-  /* 40 */ 'o',
-  /* 41 */ 'p',
-  /* 42 */ 'q',
-  /* 43 */ 'r',
-  /* 44 */ 's',
-  /* 45 */ 't',
-  /* 46 */ 'u',
-  /* 47 */ 'v',
-  /* 48 */ 'w',
-  /* 49 */ 'x',
-  /* 50 */ 'y',
-  /* 51 */ 'z',
-  /* 52 */ '0',
-  /* 53 */ '1',
-  /* 54 */ '2',
-  /* 55 */ '3',
-  /* 56 */ '4',
-  /* 57 */ '5',
-  /* 58 */ '6',
-  /* 59 */ '7',
-  /* 60 */ '8',
-  /* 61 */ '9',
-  /* 62 */ '+',
-  /* 63 */ '/'
-};
-
-/** The minimum char that's a valid char in Base64-encoded text */
-#define UNBASE64_MIN_CHAR (43)
-/** The maximum char that's a valid char in Base64-encoded text */
-#define UNBASE64_MAX_CHAR (122)
-/** Must subtract this from a char's integer value before offsetting
- * into unbase64_table
- */
-#define UNBASE64_TABLE_OFFSET UNBASE64_MIN_CHAR
-static const signed char unbase64_table[] = {
-  /* 43 + */ 62,
-  /* 44 , */ -1,
-  /* 45 - */ -1,
-  /* 46 . */ -1,
-  /* 47 / */ 63,
-  /* 48 0 */ 52,
-  /* 49 1 */ 53,
-  /* 50 2 */ 54,
-  /* 51 3 */ 55,
-  /* 52 4 */ 56,
-  /* 53 5 */ 57,
-  /* 54 6 */ 58,
-  /* 55 7 */ 59,
-  /* 56 8 */ 60,
-  /* 57 9 */ 61,
-  /* 58 : */ -1,
-  /* 59 ; */ -1,
-  /* 60 < */ -1,
-  /* 61 = */ -1,
-  /* 62 > */ -1,
-  /* 63 ? */ -1,
-  /* 64 @ */ -1,
-  /* 65 A */ 0,
-  /* 66 B */ 1,
-  /* 67 C */ 2,
-  /* 68 D */ 3,
-  /* 69 E */ 4,
-  /* 70 F */ 5,
-  /* 71 G */ 6,
-  /* 72 H */ 7,
-  /* 73 I */ 8,
-  /* 74 J */ 9,
-  /* 75 K */ 10,
-  /* 76 L */ 11,
-  /* 77 M */ 12,
-  /* 78 N */ 13,
-  /* 79 O */ 14,
-  /* 80 P */ 15,
-  /* 81 Q */ 16,
-  /* 82 R */ 17,
-  /* 83 S */ 18,
-  /* 84 T */ 19,
-  /* 85 U */ 20,
-  /* 86 V */ 21,
-  /* 87 W */ 22,
-  /* 88 X */ 23,
-  /* 89 Y */ 24,
-  /* 90 Z */ 25,
-  /* 91 [ */ -1,
-  /* 92 \ */ -1,
-  /* 93 ] */ -1,
-  /* 94 ^ */ -1,
-  /* 95 _ */ -1,
-  /* 96 ` */ -1,
-  /* 97 a */ 26,
-  /* 98 b */ 27,
-  /* 99 c */ 28,
-  /* 100 d */ 29,
-  /* 101 e */ 30,
-  /* 102 f */ 31,
-  /* 103 g */ 32,
-  /* 104 h */ 33,
-  /* 105 i */ 34,
-  /* 106 j */ 35,
-  /* 107 k */ 36,
-  /* 108 l */ 37,
-  /* 109 m */ 38,
-  /* 110 n */ 39,
-  /* 111 o */ 40,
-  /* 112 p */ 41,
-  /* 113 q */ 42,
-  /* 114 r */ 43,
-  /* 115 s */ 44,
-  /* 116 t */ 45,
-  /* 117 u */ 46,
-  /* 118 v */ 47,
-  /* 119 w */ 48,
-  /* 120 x */ 49,
-  /* 121 y */ 50,
-  /* 122 z */ 51
-};
-
-/**
- * Encodes a string using Base64, as documented in RFC 2045.
- *
- * @param source the string to encode
- * @param start byte index to start encoding
- * @param dest string where encoded data should be placed
- * @param insert_at where to place encoded data
- * @returns #TRUE if encoding was successful, #FALSE if no memory etc.
- */
-dbus_bool_t
-_dbus_string_base64_encode (const DBusString *source,
-                            int               start,
-                            DBusString       *dest,
-                            int               insert_at)
-{
-  int source_len;
-  unsigned int dest_len; /* unsigned for overflow checks below */
-  const unsigned char *s;
-  unsigned char *d;
-  const unsigned char *triplet_end;
-  const unsigned char *final_end;
-  DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);  
-  _dbus_assert (source != dest);
-  
-  /* For each 24 bits (3 bytes) of input, we have 4 bytes of
-   * output.
-   */
-  source_len = real_source->len - start;
-  dest_len = (source_len / 3) * 4;
-  if (source_len % 3 != 0)
-    dest_len += 4;
-
-  if (dest_len > (unsigned int) real_dest->max_length)
-    return FALSE;
-  
-  if (source_len == 0)
-    return TRUE;
-  
-  if (!open_gap (dest_len, real_dest, insert_at))
-    return FALSE;
-
-  d = real_dest->str + insert_at;
-  s = real_source->str + start;
-  final_end = real_source->str + (start + source_len);
-  triplet_end = final_end - (source_len % 3);
-  _dbus_assert (triplet_end <= final_end);
-  _dbus_assert ((final_end - triplet_end) < 3);
-
-#define ENCODE_64(v) (base64_table[ (unsigned char) (v) ])
-#define SIX_BITS_MASK (0x3f)
-  _dbus_assert (SIX_BITS_MASK < _DBUS_N_ELEMENTS (base64_table));
-  
-  while (s != triplet_end)
-    {
-      unsigned int triplet;
-
-      triplet = s[2] | (s[1] << 8) | (s[0] << 16);
-
-      /* Encode each 6 bits. */
-
-      *d++ = ENCODE_64 (triplet >> 18);
-      *d++ = ENCODE_64 ((triplet >> 12) & SIX_BITS_MASK);
-      *d++ = ENCODE_64 ((triplet >> 6) & SIX_BITS_MASK);
-      *d++ = ENCODE_64 (triplet & SIX_BITS_MASK);
-      
-      s += 3;
-    }
-
-  switch (final_end - triplet_end)
-    {
-    case 2:
-      {
-        unsigned int doublet;
-        
-        doublet = s[1] | (s[0] << 8);        
-
-        *d++ = ENCODE_64 (doublet >> 12);
-        *d++ = ENCODE_64 ((doublet >> 6) & SIX_BITS_MASK);
-        *d++ = ENCODE_64 (doublet & SIX_BITS_MASK);
-        *d++ = '=';
-      }
-      break;
-    case 1:
-      {
-        unsigned int singlet;
-        
-        singlet = s[0];
-
-        *d++ = ENCODE_64 ((singlet >> 6) & SIX_BITS_MASK);
-        *d++ = ENCODE_64 (singlet & SIX_BITS_MASK);
-        *d++ = '=';
-        *d++ = '=';
-      }
-      break;
-    case 0:
-      break;
-    }
-
-  _dbus_assert (d == (real_dest->str + (insert_at + dest_len)));
-
-  return TRUE;
-}
-
-/**
- * Decodes a string from Base64, as documented in RFC 2045.
- *
- * @todo sort out the AUDIT comment in here. The case it mentions
- * ("====" or "x===") is not allowed in correct base64, so need to
- * decide what to do with that kind of input. Probably ignore it
- * since we ignore any other junk seen.
- *
- * @param source the string to decode
- * @param start byte index to start decode
- * @param dest string where decoded data should be placed
- * @param insert_at where to place decoded data
- * @returns #TRUE if decoding was successful, #FALSE if no memory etc.
- */
-dbus_bool_t
-_dbus_string_base64_decode (const DBusString *source,
-                            int               start,
-                            DBusString       *dest,
-                            int               insert_at)
-{
-  int source_len;
-  const char *s;
-  const char *end;
-  DBusString result;
-  unsigned int triplet = 0;
-  int sextet_count;
-  int pad_count;
-  DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
-  _dbus_assert (source != dest);
-  
-  source_len = real_source->len - start;
-  s = real_source->str + start;
-  end = real_source->str + source_len;
-
-  if (source_len == 0)
-    return TRUE;
-
-  if (!_dbus_string_init (&result))
-    return FALSE;
-
-  pad_count = 0;
-  sextet_count = 0;
-  while (s != end)
-    {
-      /* The idea is to just skip anything that isn't
-       * a base64 char - it's allowed to have whitespace,
-       * newlines, etc. in here. We also ignore trailing
-       * base64 chars, though that's suspicious.
-       */
-      
-      if (*s >= UNBASE64_MIN_CHAR &&
-          *s <= UNBASE64_MAX_CHAR)
-        {
-          if (*s == '=')
-            {
-              /* '=' is padding, doesn't represent additional data
-               * but does increment our count.
-               */
-              pad_count += 1;
-              sextet_count += 1;
-            }
-          else
-            {
-              int val;
-
-              val = unbase64_table[(*s) - UNBASE64_TABLE_OFFSET];
-
-              if (val >= 0)
-                {
-                  triplet <<= 6;
-                  triplet |= (unsigned int) val;
-                  sextet_count += 1;
-                }
-            }
-
-          if (sextet_count == 4)
-            {
-              /* no pad = 3 bytes, 1 pad = 2 bytes, 2 pad = 1 byte */
-
-
-             /* AUDIT: Comment doesn't mention 4 pad => 0,
-              *         3 pad => 1 byte, though the code should
-              *        work fine if those are the required outputs.
-              *
-              *        I assume that the spec requires dropping
-              *        the top two bits of, say, ///= which is > 2 
-              *        bytes worth of bits. (Or otherwise, you couldn't
-              *        actually represent 2 byte sequences.
-              */
-              
-              if (pad_count < 1)
-                {
-                  if (!_dbus_string_append_byte (&result,
-                                                 triplet >> 16))
-                    goto failed;
-                }
-              
-              if (pad_count < 2)
-                {
-                  if (!_dbus_string_append_byte (&result,
-                                                 (triplet >> 8) & 0xff))
-                    goto failed;
-                }
-              
-              if (!_dbus_string_append_byte (&result,
-                                             triplet & 0xff))
-                goto failed;
-              
-              sextet_count = 0;
-              pad_count = 0;
-              triplet = 0;
-            }
-        }
-      
-      ++s;
-    }
-
-  if (!_dbus_string_move (&result, 0, dest, insert_at))
-    {
-      _dbus_string_free (&result);
-      return FALSE;
-    }
-
-  _dbus_string_free (&result);
-
-  return TRUE;
-
- failed:
-  _dbus_string_free (&result);
-
-  return FALSE;
-}
-
 /**
  * Encodes a string in hex, the way MD5 and SHA-1 are usually
  * encoded. (Each byte is two hex digits.)
@@ -2583,13 +2189,15 @@ _dbus_string_hex_encode (const DBusString *source,
  *
  * @param source the string to decode
  * @param start byte index to start decode
+ * @param end_return return location of the end of the hex data, or #NULL
  * @param dest string where decoded data should be placed
  * @param insert_at where to place decoded data
- * @returns #TRUE if decoding was successful, #FALSE if no memory etc.
+ * @returns #TRUE if decoding was successful, #FALSE if no memory.
  */
 dbus_bool_t
 _dbus_string_hex_decode (const DBusString *source,
                          int               start,
+                        int              *end_return,
                          DBusString       *dest,
                          int               insert_at)
 {
@@ -2672,17 +2280,14 @@ _dbus_string_hex_decode (const DBusString *source,
           val = 15;
           break;
         default:
-          val = 0;
-          _dbus_verbose ("invalid character '%c' in hex encoded text\n",
-                         *p);
-          goto out;
+          goto done;
         }
 
       if (high_bits)
         {
           if (!_dbus_string_append_byte (&result,
                                          val << 4))
-            goto out;
+           goto out;
         }
       else
         {
@@ -2703,9 +2308,13 @@ _dbus_string_hex_decode (const DBusString *source,
       ++p;
     }
 
+ done:
   if (!_dbus_string_move (&result, 0, dest, insert_at))
     goto out;
 
+  if (end_return)
+    *end_return = p - (const unsigned char*) _dbus_string_get_const_data (source);
+
   retval = TRUE;
   
  out:
@@ -3228,60 +2837,13 @@ test_max_len (DBusString *str,
 }
 
 static void
-test_base64_roundtrip (const unsigned char *data,
-                       int                  len)
-{
-  DBusString orig;
-  DBusString encoded;
-  DBusString decoded;
-
-  if (len < 0)
-    len = strlen (data);
-  
-  if (!_dbus_string_init (&orig))
-    _dbus_assert_not_reached ("could not init string");
-
-  if (!_dbus_string_init (&encoded))
-    _dbus_assert_not_reached ("could not init string");
-  
-  if (!_dbus_string_init (&decoded))
-    _dbus_assert_not_reached ("could not init string");
-
-  if (!_dbus_string_append_len (&orig, data, len))
-    _dbus_assert_not_reached ("couldn't append orig data");
-
-  if (!_dbus_string_base64_encode (&orig, 0, &encoded, 0))
-    _dbus_assert_not_reached ("could not encode");
-
-  if (!_dbus_string_base64_decode (&encoded, 0, &decoded, 0))
-    _dbus_assert_not_reached ("could not decode");
-
-  if (!_dbus_string_equal (&orig, &decoded))
-    {
-      const char *s;
-      
-      printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
-              _dbus_string_get_length (&orig),
-              _dbus_string_get_length (&encoded),
-              _dbus_string_get_length (&decoded));
-      printf ("Original: %s\n", data);
-      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");
-    }
-  
-  _dbus_string_free (&orig);
-  _dbus_string_free (&encoded);
-  _dbus_string_free (&decoded);  
-}
-
-static void
 test_hex_roundtrip (const unsigned char *data,
                     int                  len)
 {
   DBusString orig;
   DBusString encoded;
   DBusString decoded;
+  int end;
 
   if (len < 0)
     len = strlen (data);
@@ -3301,9 +2863,11 @@ test_hex_roundtrip (const unsigned char *data,
   if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0))
     _dbus_assert_not_reached ("could not encode");
 
-  if (!_dbus_string_hex_decode (&encoded, 0, &decoded, 0))
+  if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0))
     _dbus_assert_not_reached ("could not decode");
     
+  _dbus_assert (_dbus_string_get_length (&encoded) == end);
+
   if (!_dbus_string_equal (&orig, &decoded))
     {
       const char *s;
@@ -3315,7 +2879,7 @@ test_hex_roundtrip (const unsigned char *data,
       printf ("Original: %s\n", data);
       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");
+      _dbus_assert_not_reached ("original string not the same as string decoded from hex");
     }
   
   _dbus_string_free (&orig);
@@ -3867,8 +3431,18 @@ _dbus_string_test (void)
   
   _dbus_string_free (&str);
 
-  /* Base 64 and Hex encoding */
-  test_roundtrips (test_base64_roundtrip);
+  /* Hex encoding */
+  _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string");
+  if (!_dbus_string_init (&other))
+    _dbus_assert_not_reached ("could not init string");
+
+  if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0))
+    _dbus_assert_not_reached ("deccoded bogus hex string with no error");
+
+  _dbus_assert (end == 8);
+
+  _dbus_string_free (&other);
+
   test_roundtrips (test_hex_roundtrip);
 
   /* Path validation */