]> granicus.if.org Git - transmission/commitdiff
(trunk, libT) more tr_variant revision: faster serialization, dictionaries use less...
authorJordan Lee <jordan@transmissionbt.com>
Mon, 24 Dec 2012 22:38:41 +0000 (22:38 +0000)
committerJordan Lee <jordan@transmissionbt.com>
Mon, 24 Dec 2012 22:38:41 +0000 (22:38 +0000)
libtransmission/variant-benc.c
libtransmission/variant-common.h
libtransmission/variant-json.c
libtransmission/variant.c
libtransmission/variant.h
qt/my-valgrind.sh

index f18b1ecfcd8c544f12cee502ae790c9bdc275bc1..e31af2a0d49bbfccef0191b277daad79d99d6357 100644 (file)
  */
 
 #include <assert.h>
-#include <ctype.h> /* isdigit () */
+#include <ctype.h> /* isdigit() */
 #include <errno.h>
-#include <stdlib.h> /* strtoul (), strtod (), realloc (), qsort (), mkstemp () */
-#include <string.h> /* strlen (), memchr () */
-
-#include <locale.h> /* setlocale () */
+#include <stdlib.h> /* strtoul(), strtod(), realloc(), qsort(), mkstemp() */
+#include <string.h> /* strlen(), memchr() */
 
 #include <event2/buffer.h>
 
 #define __LIBTRANSMISSION_VARIANT_MODULE___
 #include "transmission.h"
 #include "ptrarray.h"
-#include "utils.h" /* tr_strlcpy () */
+#include "utils.h" /* tr_snprintf() */
 #include "variant.h"
 #include "variant-common.h"
 
 /***
-****  tr_variantParse ()
-****  tr_variantLoad ()
+****  tr_variantParse()
+****  tr_variantLoad()
 ***/
 
 /**
@@ -117,68 +115,35 @@ tr_bencParseStr (const uint8_t  * buf,
   return 0;
 }
 
-static int
-makeroom (tr_variant * container, size_t count)
+static tr_variant*
+get_node (tr_ptrArray * stack, tr_quark * key, tr_variant * top, int * err)
 {
-  const size_t needed = container->val.l.count + count;
+  tr_variant * node = NULL;
 
-  assert (tr_variantIsContainer (container));
-
-  if (needed > container->val.l.alloc)
+  if (tr_ptrArrayEmpty (stack))
     {
-      size_t n;
-      void * tmp;
-
-      /* scale the alloc size in powers-of-2 */
-      n = container->val.l.alloc ? container->val.l.alloc : 8;
-      while (n < needed)
-        n *= 2u;
-
-      tmp = realloc (container->val.l.vals, n * sizeof (tr_variant));
-      if (tmp == NULL)
-        return 1;
-
-      container->val.l.alloc = n;
-      container->val.l.vals = tmp;
+      node = top;
     }
+  else
+    {
+      tr_variant * parent = tr_ptrArrayBack (stack);
 
-  return 0;
-}
-
-static inline bool
-isReadyForDictKey (tr_ptrArray * parentStack)
-{
-  tr_variant * parent = tr_ptrArrayBack (parentStack);
-
-  return (parent != NULL)
-      && (tr_variantIsDict(parent))
-      && ((parent->val.l.count%2)==0);
-}
-
-static tr_variant*
-getNode (tr_variant  * top,
-         tr_ptrArray * parentStack,
-         int           type)
-{
-  tr_variant * parent;
-
-  assert (top);
-  assert (parentStack);
-
-  if (tr_ptrArrayEmpty (parentStack))
-    return top;
-
-  parent = tr_ptrArrayBack (parentStack);
-  assert (parent);
-
-  /* dictionary keys must be strings */
-  if ((parent->type == TR_VARIANT_TYPE_DICT)
-      && (type != TR_VARIANT_TYPE_STR)
-      && (! (parent->val.l.count % 2)))
-    return NULL;
+      if (tr_variantIsList (parent))
+        {
+          node = tr_variantListAdd (parent);
+        }
+      else if (*key && tr_variantIsDict (parent))
+        {
+          node = tr_variantDictAdd (parent, *key);
+          *key = 0;
+        }
+      else
+        {
+          *err = EILSEQ;
+        }
+    }
 
-  makeroom (parent, 1);
-  return parent->val.l.vals + parent->val.l.count++;
+  return node;
 }
 
 /**
@@ -186,137 +151,113 @@ getNode (tr_variant  * top,
  * easier to read, but was vulnerable to a smash-stacking
  * attack via maliciously-crafted bencoded data. (#667)
  */
-static int
-tr_variantParseImpl (const void    * buf_in,
+int
+tr_variantParseBenc (const void    * buf_in,
                      const void    * bufend_in,
                      tr_variant    * top,
-                     tr_ptrArray   * parentStack,
                      const char   ** setme_end)
 {
-  int err;
+  int err = 0;
   const uint8_t * buf = buf_in;
   const uint8_t * bufend = bufend_in;
+  tr_ptrArray stack = TR_PTR_ARRAY_INIT;
+  tr_quark key = 0;
 
   tr_variantInit (top, 0);
 
   while (buf != bufend)
     {
       if (buf > bufend) /* no more text to parse... */
-        return 1;
+        err = EILSEQ;
+
+      if (err)
+        break;
 
       if (*buf == 'i') /* int */
         {
           int64_t val;
           const uint8_t * end;
-          tr_variant * node;
+          tr_variant * v;
 
           if ((err = tr_bencParseInt (buf, bufend, &end, &val)))
-            return err;
-
-          node = getNode (top, parentStack, TR_VARIANT_TYPE_INT);
-          if (!node)
-            return EILSEQ;
-
-          tr_variantInitInt (node, val);
+            break;
           buf = end;
 
-          if (tr_ptrArrayEmpty (parentStack))
-            break;
+          if ((v = get_node (&stack, &key, top, &err)))
+            tr_variantInitInt (v, val);
         }
       else if (*buf == 'l') /* list */
         {
-          tr_variant * node = getNode (top, parentStack, TR_VARIANT_TYPE_LIST);
-          if (!node)
-            return EILSEQ;
+          tr_variant * v;
 
-          tr_variantInit (node, TR_VARIANT_TYPE_LIST);
-          tr_ptrArrayAppend (parentStack, node);
           ++buf;
+
+          if ((v = get_node (&stack, &key, top, &err)))
+            {
+              tr_variantInitList (v, 0);
+              tr_ptrArrayAppend (&stack, v);
+            }
         }
       else if (*buf == 'd') /* dict */
         {
-          tr_variant * node = getNode (top, parentStack, TR_VARIANT_TYPE_DICT);
-          if (!node)
-            return EILSEQ;
+          tr_variant * v;
 
-          tr_variantInit (node, TR_VARIANT_TYPE_DICT);
-          tr_ptrArrayAppend (parentStack, node);
           ++buf;
+
+          if ((v = get_node (&stack, &key, top, &err)))
+            {
+              tr_variantInitDict (v, 0);
+              tr_ptrArrayAppend (&stack, v);
+            }
         }
       else if (*buf == 'e') /* end of list or dict */
         {
-          tr_variant * node;
           ++buf;
-          if (tr_ptrArrayEmpty (parentStack))
-              return EILSEQ;
 
-          node = tr_ptrArrayBack (parentStack);
-          if (tr_variantIsDict (node) && (node->val.l.count % 2))
+          if (tr_ptrArrayEmpty (&stack) || (key != 0))
             {
-              /* odd # of children in dict */
-              tr_variantFree (&node->val.l.vals[--node->val.l.count]);
-              return EILSEQ;
+              err = EILSEQ;
+              break;
+            }
+          else
+            {
+              tr_ptrArrayPop (&stack);
+              if (tr_ptrArrayEmpty (&stack))
+                break;
             }
-
-          tr_ptrArrayPop (parentStack);
-          if (tr_ptrArrayEmpty (parentStack))
-            break;
         }
       else if (isdigit (*buf)) /* string? */
         {
+          tr_variant * v;
           const uint8_t * end;
           const uint8_t * str;
           size_t str_len;
-          tr_variant * node;
-          const bool is_key = isReadyForDictKey (parentStack);
 
           if ((err = tr_bencParseStr (buf, bufend, &end, &str, &str_len)))
-            return err;
-
-          node = getNode (top, parentStack, TR_VARIANT_TYPE_STR);
-          if (!node)
-            return EILSEQ;
-
-          if (is_key)
-            tr_variantInitQuark (node, tr_quark_new (str, str_len));
-          else
-            tr_variantInitStr (node, str, str_len);
-
+            break;
           buf = end;
 
-          if (tr_ptrArrayEmpty (parentStack))
-            break;
+          if (!key && !tr_ptrArrayEmpty(&stack) && tr_variantIsDict(tr_ptrArrayBack(&stack)))
+            key = tr_quark_new (str, str_len);
+          else if ((v = get_node (&stack, &key, top, &err)))
+            tr_variantInitStr (v, str, str_len);
         }
       else /* invalid bencoded text... march past it */
         {
           ++buf;
         }
+
+      if (tr_ptrArrayEmpty (&stack))
+        break;
     }
 
-  err = !tr_variantIsSomething (top) || !tr_ptrArrayEmpty (parentStack);
+  if (!err)
+    err = !top->type || !tr_ptrArrayEmpty(&stack);
 
   if (!err && setme_end)
     *setme_end = (const char*) buf;
 
-  return err;
-}
-
-
-int
-tr_variantParseBenc (const void     * buf,
-                     const void     * end,
-                     tr_variant     * top,
-                     const char    ** setme_end)
-{
-  int err;
-  tr_ptrArray parentStack = TR_PTR_ARRAY_INIT;
-
-  top->type = 0; /* set to `uninitialized' */
-  err = tr_variantParseImpl (buf, end, top, &parentStack, setme_end);
-  if (err)
-    tr_variantFree (top);
-
-  tr_ptrArrayDestruct (&parentStack, NULL);
+  tr_ptrArrayDestruct (&stack, NULL);
   return err;
 }
 
@@ -342,18 +283,11 @@ saveBoolFunc (const tr_variant * val, void * evbuf)
 static void
 saveRealFunc (const tr_variant * val, void * evbuf)
 {
+  int len;
   char buf[128];
-  char locale[128];
-  size_t len;
-
-  /* always use a '.' decimal point s.t. locale-hopping doesn't bite us */
-  tr_strlcpy (locale, setlocale (LC_NUMERIC, NULL), sizeof (locale));
-  setlocale (LC_NUMERIC, "POSIX");
-  tr_snprintf (buf, sizeof (buf), "%f", val->val.d);
-  setlocale (LC_NUMERIC, locale);
 
-  len = strlen (buf);
-  evbuffer_add_printf (evbuf, "%lu:", (unsigned long)len);
+  len = tr_snprintf (buf, sizeof (buf), "%f", val->val.d);
+  evbuffer_add_printf (evbuf, "%d:", len);
   evbuffer_add (evbuf, buf, len);
 }
 
index 7d91ccd9d4514fcce8932f5a734a7c0e68e5db52..9adc3583ca0ea1db47dcb8fb2699f67789a96c34 100644 (file)
@@ -40,10 +40,6 @@ void tr_variantToBufJson (const tr_variant * top, struct evbuffer * buf, bool le
 
 void tr_variantToBufBenc (const tr_variant * top, struct evbuffer * buf);
 
-bool tr_variantIsSomething (const tr_variant * v);
-
-bool tr_variantIsContainer (const tr_variant * v);
-
 void tr_variantInit (tr_variant * v, char type);
 
 int tr_jsonParse (const char    * source, /* Such as a filename. Only when logging an error */
index d6b715a04569aaf0251b9ed9d9742703b0c343d7..c841f8702698faf5a58d60b7d0748e0a72e4ba3c 100644 (file)
@@ -17,8 +17,6 @@
 #include <string.h>
 #include <errno.h> /* EILSEQ, EINVAL */
 
-#include <locale.h> /* setlocale() */
-
 #include <event2/buffer.h> /* evbuffer_add() */
 #include <event2/util.h> /* evutil_strtoll () */
 
@@ -389,15 +387,15 @@ struct jsonWalk
 static void
 jsonIndent (struct jsonWalk * data)
 {
-  if (data->doIndent)
+  static char buf[1024] = { '\0' };
+  if (!*buf)
     {
-      char buf[1024];
-      const int width = tr_list_size (data->parents) * 4;
-
+      memset (buf, ' ', sizeof(buf));
       buf[0] = '\n';
-      memset (buf+1, ' ', width);
-      evbuffer_add (data->out, buf, 1+width);
     }
+
+  if (data->doIndent)
+    evbuffer_add (data->out, buf, tr_list_size(data->parents)*4 + 1);
 }
 
 static void
@@ -455,6 +453,9 @@ jsonPushParent (struct jsonWalk  * data,
   pstate->variantType = v->type;
   pstate->childIndex = 0;
   pstate->childCount = v->val.l.count;
+  if (tr_variantIsDict (v))
+    pstate->childCount *= 2;
+
   tr_list_prepend (&data->parents, pstate);
 }
 
@@ -620,18 +621,13 @@ static const struct VariantWalkFuncs walk_funcs = { jsonIntFunc,
 void
 tr_variantToBufJson (const tr_variant * top, struct evbuffer * buf, bool lean)
 {
-  char lc_numeric[128];
   struct jsonWalk data;
 
   data.doIndent = !lean;
   data.out = buf;
   data.parents = NULL;
 
-  /* json requires a '.' decimal point regardless of locale */
-  tr_strlcpy (lc_numeric, setlocale (LC_NUMERIC, NULL), sizeof (lc_numeric));
-  setlocale (LC_NUMERIC, "POSIX");
   tr_variantWalk (top, &walk_funcs, &data, true);
-  setlocale (LC_NUMERIC, lc_numeric);
 
   if (evbuffer_get_length (buf))
     evbuffer_add_printf (buf, "\n");
index 75554539486440e3005b8817df8610d973c98b40..3b7d340390c7e407fcfd46580c765e0725f3d7b7 100644 (file)
 
 #include <assert.h>
 #include <errno.h>
-#include <stdio.h> /* rename () */
-#include <stdlib.h> /* strtoul (), strtod (), realloc (), qsort (), mkstemp () */
+#include <stdio.h> /* rename() */
+#include <stdlib.h> /* strtoul(), strtod(), realloc(), qsort(), mkstemp() */
 #include <string.h>
 
-#ifdef WIN32 /* tr_mkstemp () */
+#ifdef WIN32 /* tr_mkstemp() */
  #include <fcntl.h>
  #define _S_IREAD 256
  #define _S_IWRITE 128
 #endif
 
-#include <locale.h> /* setlocale () */
-#include <unistd.h> /* write (), unlink () */
+#include <locale.h> /* setlocale() */
+#include <unistd.h> /* write(), unlink() */
 
 #include <event2/buffer.h>
 
 #define __LIBTRANSMISSION_VARIANT_MODULE___
 #include "transmission.h"
 #include "ConvertUTF.h"  
-#include "fdlimit.h" /* tr_close_file () */
+#include "fdlimit.h" /* tr_close_file() */
 #include "platform.h" /* TR_PATH_MAX */
-#include "utils.h" /* tr_new (), tr_free () */
+#include "utils.h" /* tr_new(), tr_free() */
 #include "variant.h"
 #include "variant-common.h"
 
 ***
 **/
 
-bool
+static bool
 tr_variantIsContainer (const tr_variant * v)
 {
   return tr_variantIsList (v) || tr_variantIsDict (v);
 }
 
-bool
+static bool
 tr_variantIsSomething (const tr_variant * v)
 {
   return tr_variantIsContainer (v)
@@ -59,34 +59,14 @@ tr_variantIsSomething (const tr_variant * v)
 void
 tr_variantInit (tr_variant * v, char type)
 {
-  memset (v, 0, sizeof (*v));
   v->type = type;
+  memset (&v->val, 0, sizeof(v->val));
 }
 
 /***
 ****
 ***/
 
-/*
-zzz
-
-typedef enum
-{
-  TR_STRING_TYPE_KEY,
-  TR_STRING_TYPE_HEAP,
-  TR_STRING_TYPE_BUF
-}
-tr_string_type;
-
-struct tr_variant_string
-{
-  tr_key key;
-  tr_string_type type;
-  size_t len;
-  union { char buf[8]; char * ptr; } str;
-};
-*/
-
 static const struct tr_variant_string STRING_INIT =
 {
   .type = TR_STRING_TYPE_QUARK,
@@ -122,7 +102,8 @@ tr_variant_string_get_string (const struct tr_variant_string * str)
 }
 
 static void
-tr_variant_string_set_quark (struct tr_variant_string * str, const tr_quark quark)
+tr_variant_string_set_quark (struct tr_variant_string  * str,
+                             const tr_quark              quark)
 {
   tr_variant_string_clear (str);
 
@@ -132,7 +113,9 @@ tr_variant_string_set_quark (struct tr_variant_string * str, const tr_quark quar
 }
 
 static void
-tr_variant_string_set_string (struct tr_variant_string * str, const char * bytes, int len)
+tr_variant_string_set_string (struct tr_variant_string  * str,
+                              const char                * bytes,
+                              int                         len)
 {
   tr_quark quark;
   tr_variant_string_clear (str);
@@ -188,14 +171,9 @@ dictIndexOf (const tr_variant * dict, const tr_quark key)
       const tr_variant * const begin = dict->val.l.vals;
       const tr_variant * const end = begin + dict->val.l.count;
 
-      for (walk=begin; walk!=end; walk+=2)
-      {
-        assert (walk->type == TR_VARIANT_TYPE_STR);
-        assert (walk->val.s.type == TR_STRING_TYPE_QUARK);
-
-        if (walk->val.s.quark == key)
+      for (walk=begin; walk!=end; ++walk)
+        if (walk->key == key)
           return walk - begin;
-      }
     }
 
   return -1;
@@ -206,7 +184,7 @@ tr_variantDictFind (tr_variant * dict, const tr_quark key)
 {
   const int i = dictIndexOf (dict, key);
 
-  return i < 0 ? NULL : &dict->val.l.vals[i + 1];
+  return i < 0 ? NULL : dict->val.l.vals+i;
 }
 
 static bool
@@ -225,104 +203,97 @@ tr_variantListSize (const tr_variant * list)
 }
 
 tr_variant*
-tr_variantListChild (tr_variant * val,
-                  size_t    i)
+tr_variantListChild (tr_variant * v,
+                     size_t    i)
 {
   tr_variant * ret = NULL;
 
-  if (tr_variantIsList (val) && (i < val->val.l.count))
-    ret = val->val.l.vals + i;
+  if (tr_variantIsList (v) && (i < v->val.l.count))
+    ret = v->val.l.vals + i;
 
   return ret;
 }
 
-int
+bool
 tr_variantListRemove (tr_variant * list, size_t i)
 {
+  bool removed = false;
+
   if (tr_variantIsList (list) && (i < list->val.l.count))
     {
+      removed = true;
       tr_variantFree (&list->val.l.vals[i]);
       tr_removeElementFromArray (list->val.l.vals, i,
                                  sizeof (tr_variant),
                                  list->val.l.count--);
-      return 1;
     }
 
-  return 0;
-}
-
-static void
-tr_variant_warning (const char * err)
-{
-  fprintf (stderr, "warning: %s\n", err);
+  return removed;
 }
 
 bool
-tr_variantGetInt (const tr_variant  * val,
+tr_variantGetInt (const tr_variant  * v,
                   int64_t           * setme)
 {
   bool success = false;
 
-  if (!success && ((success = tr_variantIsInt (val))))
+  if (!success && ((success = tr_variantIsInt (v))))
     if (setme)
-      *setme = val->val.i;
+      *setme = v->val.i;
 
-  if (!success && ((success = tr_variantIsBool (val))))
-    {
-      tr_variant_warning ("reading bool as an int");
-      if (setme)
-        *setme = val->val.b ? 1 : 0;
-    }
+  if (!success && ((success = tr_variantIsBool (v))))
+    if (setme)
+      *setme = v->val.b ? 1 : 0;
 
   return success;
 }
 
 bool
-tr_variantGetStr (const tr_variant   * val,
+tr_variantGetStr (const tr_variant   * v,
                   const char        ** setme,
                   size_t             * len)
 {
-  const bool success = tr_variantIsString (val);
+  const bool success = tr_variantIsString (v);
 
   if (success)
-    *setme = getStr (val);
+    *setme = getStr (v);
 
   if (len != NULL)
-    *len = success ? val->val.s.len : 0;
+    *len = success ? v->val.s.len : 0;
 
   return success;
 }
 
 bool
-tr_variantGetRaw (const tr_variant   * val,
+tr_variantGetRaw (const tr_variant   * v,
                   const uint8_t     ** setme_raw,
                   size_t             * setme_len)
 {
-  const bool success = tr_variantIsString (val);
+  const bool success = tr_variantIsString (v);
 
   if (success)
     {
-      *setme_raw = (uint8_t*) getStr (val);
-      *setme_len = val->val.s.len;
+      *setme_raw = (uint8_t*) getStr (v);
+      *setme_len = v->val.s.len;
     }
 
   return success;
 }
 
 bool
-tr_variantGetBool (const tr_variant * val, bool * setme)
+tr_variantGetBool (const tr_variant * v, bool * setme)
 {
   const char * str;
   bool success = false;
 
-  if ((success = tr_variantIsBool (val)))
-    *setme = val->val.b;
+  if ((success = tr_variantIsBool (v)))
+    *setme = v->val.b;
 
-  if (!success && tr_variantIsInt (val))
-    if ((success = (val->val.i==0 || val->val.i==1)))
-      *setme = val->val.i!=0;
+  if (!success && tr_variantIsInt (v))
+    if ((success = (v->val.i==0 || v->val.i==1)))
+      *setme = v->val.i!=0;
 
-  if (!success && tr_variantGetStr (val, &str, NULL))
+  if (!success && tr_variantGetStr (v, &str, NULL))
     if ((success = (!strcmp (str,"true") || !strcmp (str,"false"))))
       *setme = !strcmp (str,"true");
 
@@ -330,17 +301,17 @@ tr_variantGetBool (const tr_variant * val, bool * setme)
 }
 
 bool
-tr_variantGetReal (const tr_variant * val, double * setme)
+tr_variantGetReal (const tr_variant * v, double * setme)
 {
   bool success = false;
 
-  if (!success && ((success = tr_variantIsReal (val))))
-    *setme = val->val.d;
+  if (!success && ((success = tr_variantIsReal (v))))
+    *setme = v->val.d;
 
-  if (!success && ((success = tr_variantIsInt (val))))
-    *setme = val->val.i;
+  if (!success && ((success = tr_variantIsInt (v))))
+    *setme = v->val.i;
 
-  if (!success && tr_variantIsString (val))
+  if (!success && tr_variantIsString (v))
     {
       char * endptr;
       char locale[128];
@@ -349,10 +320,10 @@ tr_variantGetReal (const tr_variant * val, double * setme)
       /* the json spec requires a '.' decimal point regardless of locale */
       tr_strlcpy (locale, setlocale (LC_NUMERIC, NULL), sizeof (locale));
       setlocale (LC_NUMERIC, "POSIX");
-      d  = strtod (getStr (val), &endptr);
+      d  = strtod (getStr (v), &endptr);
       setlocale (LC_NUMERIC, locale);
 
-      if ((success = (getStr (val) != endptr) && !*endptr))
+      if ((success = (getStr (v) != endptr) && !*endptr))
         *setme = d;
     }
 
@@ -401,10 +372,7 @@ tr_variantDictFindList (tr_variant       * dict,
                         const tr_quark     key,
                         tr_variant      ** setme)
 {
-  return tr_variantDictFindType (dict,
-                                 key,
-                                 TR_VARIANT_TYPE_LIST,
-                                 setme);
+  return tr_variantDictFindType (dict, key, TR_VARIANT_TYPE_LIST, setme);
 }
 
 bool
@@ -412,10 +380,7 @@ tr_variantDictFindDict (tr_variant       * dict,
                         const tr_quark     key,
                         tr_variant      ** setme)
 {
-  return tr_variantDictFindType (dict,
-                                 key,
-                                 TR_VARIANT_TYPE_DICT,
-                                 setme);
+  return tr_variantDictFindType (dict, key, TR_VARIANT_TYPE_DICT, setme);
 }
 
 bool
@@ -454,81 +419,72 @@ tr_variantInitStr (tr_variant * v, const void * str, int len)
 }
 
 void
-tr_variantInitBool (tr_variant * variant, bool value)
+tr_variantInitBool (tr_variant * v, bool value)
 {
-  tr_variantInit (variant, TR_VARIANT_TYPE_BOOL);
-  variant->val.b = value != 0;
+  tr_variantInit (v, TR_VARIANT_TYPE_BOOL);
+  v->val.b = value != 0;
 }
 
 void
-tr_variantInitReal (tr_variant * b, double value)
+tr_variantInitReal (tr_variant * v, double value)
 {
-  tr_variantInit (b, TR_VARIANT_TYPE_REAL);
-  b->val.d = value;
+  tr_variantInit (v, TR_VARIANT_TYPE_REAL);
+  v->val.d = value;
 }
 
 void
-tr_variantInitInt (tr_variant * variant, int64_t value)
+tr_variantInitInt (tr_variant * v, int64_t value)
 {
-  tr_variantInit (variant, TR_VARIANT_TYPE_INT);
-  variant->val.i = value;
+  tr_variantInit (v, TR_VARIANT_TYPE_INT);
+  v->val.i = value;
 }
 
-int
-tr_variantInitList (tr_variant * variant, size_t reserve_count)
+void
+tr_variantInitList (tr_variant * v, size_t reserve_count)
 {
-  tr_variantInit (variant, TR_VARIANT_TYPE_LIST);
-  return tr_variantListReserve (variant, reserve_count);
+  tr_variantInit (v, TR_VARIANT_TYPE_LIST);
+  tr_variantListReserve (v, reserve_count);
 }
 
-static int
-containerReserve (tr_variant * container, size_t count)
+static void
+containerReserve (tr_variant * v, size_t count)
 {
-  const size_t needed = container->val.l.count + count;
+  const size_t needed = v->val.l.count + count;
 
-  assert (tr_variantIsContainer (container));
+  assert (tr_variantIsContainer (v));
 
-  if (needed > container->val.l.alloc)
+  if (needed > v->val.l.alloc)
     {
-      size_t n;
-      void * tmp;
-
       /* scale the alloc size in powers-of-2 */
-      n = container->val.l.alloc ? container->val.l.alloc : 8;
+      size_t n = v->val.l.alloc ? v->val.l.alloc : 8;
       while (n < needed)
         n *= 2u;
 
-      tmp = tr_renew (tr_variant, container->val.l.vals, n);
-      if (tmp == NULL)
-        return 1;
-
-      container->val.l.alloc = n;
-      container->val.l.vals = tmp;
+      v->val.l.vals = tr_renew (tr_variant, v->val.l.vals, n);
+      v->val.l.alloc = n;
     }
-
-  return 0;
 }
 
-int
+void
 tr_variantListReserve (tr_variant * list, size_t count)
 {
   assert (tr_variantIsList (list));
-  return containerReserve (list, count);
+  containerReserve (list, count);
 }
 
-int
-tr_variantInitDict (tr_variant * variant, size_t reserve_count)
+void
+tr_variantInitDict (tr_variant * v, size_t reserve_count)
 {
-  tr_variantInit (variant, TR_VARIANT_TYPE_DICT);
-  return tr_variantDictReserve (variant, reserve_count);
+  tr_variantInit (v, TR_VARIANT_TYPE_DICT);
+  tr_variantDictReserve (v, reserve_count);
 }
 
-int
+void
 tr_variantDictReserve (tr_variant  * dict,
                        size_t        reserve_count)
 {
   assert (tr_variantIsDict (dict));
-  return containerReserve (dict, reserve_count * 2);
+  containerReserve (dict, reserve_count);
 }
 
 tr_variant *
@@ -540,6 +496,7 @@ tr_variantListAdd (tr_variant * list)
 
   containerReserve (list, 1);
   child = &list->val.l.vals[list->val.l.count++];
+  child->key = 0;
   tr_variantInit (child, TR_VARIANT_TYPE_INT);
 
   return child;
@@ -622,19 +579,16 @@ tr_variant *
 tr_variantDictAdd (tr_variant      * dict,
                    const tr_quark    key)
 {
-  tr_variant * child_key;
-  tr_variant * child_val;
+  tr_variant * val;
 
   assert (tr_variantIsDict (dict));
 
-  containerReserve (dict, 2);
+  containerReserve (dict, 1);
 
-  child_key = dict->val.l.vals + dict->val.l.count++;
-  tr_variantInitQuark (child_key, key);
-
-  child_val = dict->val.l.vals + dict->val.l.count++;
-  tr_variantInit (child_val, TR_VARIANT_TYPE_INT);
-  return child_val;
+  val = dict->val.l.vals + dict->val.l.count++;
+  tr_variantInit (val, TR_VARIANT_TYPE_INT);
+  val->key = key;
+  return val;
 }
 
 static tr_variant*
@@ -674,7 +628,9 @@ tr_variantDictAddInt (tr_variant      * dict,
 }
 
 tr_variant*
-tr_variantDictAddBool (tr_variant * dict, const tr_quark key, bool val)
+tr_variantDictAddBool (tr_variant      * dict,
+                       const tr_quark    key,
+                       bool              val)
 {
   tr_variant * child = dictFindOrAdd (dict, key, TR_VARIANT_TYPE_BOOL);
   tr_variantInitBool (child, val);
@@ -682,7 +638,9 @@ tr_variantDictAddBool (tr_variant * dict, const tr_quark key, bool val)
 }
 
 tr_variant*
-tr_variantDictAddReal (tr_variant * dict, const tr_quark key, double val)
+tr_variantDictAddReal (tr_variant      * dict,
+                       const tr_quark    key,
+                       double            val)
 {
   tr_variant * child = dictFindOrAdd (dict, key, TR_VARIANT_TYPE_REAL);
   tr_variantInitReal (child, val);
@@ -690,7 +648,9 @@ tr_variantDictAddReal (tr_variant * dict, const tr_quark key, double val)
 }
 
 tr_variant*
-tr_variantDictAddQuark (tr_variant * dict, const tr_quark key, const tr_quark val)
+tr_variantDictAddQuark (tr_variant      * dict,
+                        const tr_quark    key,
+                        const tr_quark    val)
 {
   tr_variant * child = dictFindOrAdd (dict, key, TR_VARIANT_TYPE_STR);
   tr_variantInitQuark (child, val);
@@ -698,7 +658,9 @@ tr_variantDictAddQuark (tr_variant * dict, const tr_quark key, const tr_quark va
 }
 
 tr_variant*
-tr_variantDictAddStr (tr_variant * dict, const tr_quark key, const char * val)
+tr_variantDictAddStr (tr_variant      * dict,
+                      const tr_quark    key,
+                      const char      * val)
 {
   tr_variant * child = dictFindOrAdd (dict, key, TR_VARIANT_TYPE_STR);
   tr_variantInitStr (child, val, -1);
@@ -736,26 +698,28 @@ tr_variantDictAddDict (tr_variant     * dict,
   return child;
 }
 
-int
+bool
 tr_variantDictRemove (tr_variant     * dict,
                       const tr_quark   key)
 {
+  bool removed = false;
   const int i = dictIndexOf (dict, key);
 
   if (i >= 0)
     {
-      const int n = dict->val.l.count;
+      const int last = dict->val.l.count - 1;
+
       tr_variantFree (&dict->val.l.vals[i]);
-      tr_variantFree (&dict->val.l.vals[i + 1]);
-      if (i + 2 < n)
-        {
-          dict->val.l.vals[i]   = dict->val.l.vals[n - 2];
-          dict->val.l.vals[i + 1] = dict->val.l.vals[n - 1];
-        }
-      dict->val.l.count -= 2;
+
+      if (i != last)
+        dict->val.l.vals[i] = dict->val.l.vals[last];
+
+      --dict->val.l.count;
+
+       removed = true;
     }
 
-  return i >= 0; /* return true if found */
+  return removed;
 }
 
 /***
@@ -764,8 +728,8 @@ tr_variantDictRemove (tr_variant     * dict,
 
 struct KeyIndex
 {
-  const char *  key;
-  int           index;
+  const char * keystr;
+  tr_variant * val;
 };
 
 static int
@@ -774,105 +738,61 @@ compareKeyIndex (const void * va, const void * vb)
   const struct KeyIndex * a = va;
   const struct KeyIndex * b = vb;
 
-  return strcmp (a->key, b->key);
+  return strcmp (a->keystr, b->keystr);
 }
 
 struct SaveNode
 {
-  const tr_variant * val;
-  int valIsVisited;
-  int childCount;
-  int childIndex;
-  int * children;
+  const tr_variant * v;
+  tr_variant sorted;
+  size_t childIndex;
+  bool isVisited;
 };
 
 static void
-nodeInitDict (struct SaveNode   * node,
-              const tr_variant  * val,
-              bool                sort_dicts)
+nodeConstruct (struct SaveNode   * node,
+               const tr_variant  * v,
+               bool                sort_dicts)
 {
-  const int n = val->val.l.count;
-  const int nKeys = n / 2;
-
-  assert (tr_variantIsDict (val));
-
-  node->val = val;
-  node->children = tr_new0 (int, n);
+  node->isVisited = false;
+  node->childIndex = 0;
 
-  if (sort_dicts)
+  if (sort_dicts && tr_variantIsDict(v))
     {
-      int i, j;
-      struct KeyIndex * indices = tr_new (struct KeyIndex, nKeys);
+      /* make node->sorted a sorted version of this dictionary */
 
-      for (i=j=0; i<n; i+=2, ++j)
+      size_t i;
+      const size_t n = v->val.l.count;
+      struct KeyIndex * tmp = tr_new (struct KeyIndex, n);
+
+      for (i=0; i<n; i++)
         {
-          indices[j].key = getStr (&val->val.l.vals[i]);
-          indices[j].index = i;
+          tmp[i].val = v->val.l.vals+i;
+          tmp[i].keystr = tr_quark_get_string (tmp[i].val->key, NULL);
         }
 
-      qsort (indices, j, sizeof (struct KeyIndex), compareKeyIndex);
+      qsort (tmp, n, sizeof (struct KeyIndex), compareKeyIndex);
 
-      for (i=0; i<j; ++i)
-        {
-          const int index = indices[i].index;
-          node->children[node->childCount++] = index;
-          node->children[node->childCount++] = index + 1;
-        }
+      tr_variantInitDict (&node->sorted, n);
+      for (i=0; i<n; ++i)
+        node->sorted.val.l.vals[i] = *tmp[i].val;
+      node->sorted.val.l.count = n;
+
+      tr_free (tmp);
 
-      tr_free (indices);
+      node->v = &node->sorted;
     }
   else
     {
-      int i;
-
-      for (i=0; i<n; ++i)
-        node->children[node->childCount++] = i;
+      node->v = v;
     }
-
-  assert (node->childCount == n);
 }
 
 static void
-nodeInitList (struct SaveNode   * node,
-              const tr_variant  * val)
+nodeDestruct (struct SaveNode * node)
 {
-  int i;
-  int n;
-
-  assert (tr_variantIsList (val));
-
-  n = val->val.l.count;
-  node->val = val;
-  node->childCount = n;
-  node->children = tr_new0 (int, n);
-  for (i=0; i<n; ++i) /* a list's children don't need to be reordered */
-    node->children[i] = i;
-}
-
-static void
-nodeInitLeaf (struct SaveNode   * node,
-              const tr_variant  * variant)
-{
-  assert (!tr_variantIsContainer (variant));
-
-  node->val = variant;
-}
-
-static void
-nodeInit (struct SaveNode   * node,
-          const tr_variant  * variant,
-          bool                sort_dicts)
-{
-  static const struct SaveNode INIT_NODE = { NULL, 0, 0, 0, NULL };
-
-  *node = INIT_NODE;
-
-  if (tr_variantIsList (variant))
-    nodeInitList (node, variant);
-  else if (tr_variantIsDict (variant))
-    nodeInitDict (node, variant, sort_dicts);
-  else
-    nodeInitLeaf (node, variant);
+  if (node->v == &node->sorted)
+    tr_free (node->sorted.val.l.vals);
 }
 
 /**
@@ -881,63 +801,75 @@ nodeInit (struct SaveNode   * node,
  * attack via maliciously-crafted data. (#667)
  */
 void
-tr_variantWalk (const tr_variant               * top,
+tr_variantWalk (const tr_variant               * v,
                 const struct VariantWalkFuncs  * walkFuncs,
                 void                           * user_data,
                 bool                             sort_dicts)
 {
   int stackSize = 0;
   int stackAlloc = 64;
+  char lc_numeric[128];
   struct SaveNode * stack = tr_new (struct SaveNode, stackAlloc);
 
-  nodeInit (&stack[stackSize++], top, sort_dicts);
+  /* always use a '.' decimal point s.t. locale-hopping doesn't bite us */
+  tr_strlcpy (lc_numeric, setlocale (LC_NUMERIC, NULL), sizeof (lc_numeric));
+  setlocale (LC_NUMERIC, "POSIX");
+
+  nodeConstruct (&stack[stackSize++], v, sort_dicts);
 
   while (stackSize > 0)
     {
       struct SaveNode * node = &stack[stackSize-1];
-      const tr_variant * val;
+      const tr_variant * v;
 
-      if (!node->valIsVisited)
+      if (!node->isVisited)
         {
-            val = node->val;
-            node->valIsVisited = true;
+          v = node->v;
+          node->isVisited = true;
         }
-      else if (node->childIndex < node->childCount)
+      else if (tr_variantIsContainer(node->v) && (node->childIndex < node->v->val.l.count))
         {
-            const int index = node->children[node->childIndex++];
-            val = node->val->val.l.vals +  index;
+          const int index = node->childIndex++;
+          v = node->v->val.l.vals + index;
+
+          if (tr_variantIsDict (node->v))
+            {
+              tr_variant tmp;
+              tr_variantInitQuark (&tmp, v->key);
+              walkFuncs->stringFunc (&tmp, user_data);
+            }
         }
       else /* done with this node */
         {
-            if (tr_variantIsContainer (node->val))
-                walkFuncs->containerEndFunc (node->val, user_data);
-            --stackSize;
-            tr_free (node->children);
-            continue;
+          if (tr_variantIsContainer (node->v))
+            walkFuncs->containerEndFunc (node->v, user_data);
+          --stackSize;
+          nodeDestruct (node);
+          continue;
         }
 
-      if (val) switch (val->type)
+      if (v) switch (v->type)
         {
           case TR_VARIANT_TYPE_INT:
-            walkFuncs->intFunc (val, user_data);
+            walkFuncs->intFunc (v, user_data);
             break;
 
           case TR_VARIANT_TYPE_BOOL:
-            walkFuncs->boolFunc (val, user_data);
+            walkFuncs->boolFunc (v, user_data);
             break;
 
           case TR_VARIANT_TYPE_REAL:
-            walkFuncs->realFunc (val, user_data);
+            walkFuncs->realFunc (v, user_data);
             break;
 
           case TR_VARIANT_TYPE_STR:
-            walkFuncs->stringFunc (val, user_data);
+            walkFuncs->stringFunc (v, user_data);
             break;
 
           case TR_VARIANT_TYPE_LIST:
-            if (val == node->val)
+            if (v == node->v)
               {
-                walkFuncs->listBeginFunc (val, user_data);
+                walkFuncs->listBeginFunc (v, user_data);
               }
             else
               {
@@ -946,14 +878,14 @@ tr_variantWalk (const tr_variant               * top,
                     stackAlloc *= 2;
                     stack = tr_renew (struct SaveNode, stack, stackAlloc);
                   }
-                nodeInit (&stack[stackSize++], val, sort_dicts);
+                nodeConstruct (&stack[stackSize++], v, sort_dicts);
               }
             break;
 
           case TR_VARIANT_TYPE_DICT:
-            if (val == node->val)
+            if (v == node->v)
               {
-                walkFuncs->dictBeginFunc (val, user_data);
+                walkFuncs->dictBeginFunc (v, user_data);
               }
             else
               {
@@ -962,7 +894,7 @@ tr_variantWalk (const tr_variant               * top,
                     stackAlloc *= 2;
                     stack = tr_renew (struct SaveNode, stack, stackAlloc);
                   }
-                nodeInit (&stack[stackSize++], val, sort_dicts);
+                nodeConstruct (&stack[stackSize++], v, sort_dicts);
               }
             break;
 
@@ -973,6 +905,9 @@ tr_variantWalk (const tr_variant               * top,
         }
     }
 
+  /* restore the locale... */
+  setlocale (LC_NUMERIC, lc_numeric);
+
   tr_free (stack);
 }
 
@@ -1066,12 +1001,7 @@ tr_variantListCopy (tr_variant * target, const tr_variant * src)
 static size_t
 tr_variantDictSize (const tr_variant * dict)
 {
-  size_t count = 0;
-
-  if (tr_variantIsDict (dict))
-    count = dict->val.l.count / 2;
-
-  return count;
+  return tr_variantIsDict (dict) ? dict->val.l.count : 0;
 }
 
 bool
@@ -1084,16 +1014,11 @@ tr_variantDictChild (tr_variant   * dict,
 
   assert (tr_variantIsDict (dict));
 
-  if (tr_variantIsDict (dict) && (n*2)+1 <= dict->val.l.count)
+  if (tr_variantIsDict (dict) && (n<dict->val.l.count))
     {
-      tr_variant * k = dict->val.l.vals + (n*2);
-      tr_variant * v = dict->val.l.vals + (n*2) + 1;
-      if ((k->val.s.type == TR_STRING_TYPE_QUARK) && tr_variantIsSomething (v))
-        {
-          *key = k->val.s.quark;
-          *val = v;
-          success = true;
-        }
+      *key = dict->val.l.vals[n].key;
+      *val = dict->val.l.vals+n;
+      success = true;
     }
 
   return success;
@@ -1175,24 +1100,24 @@ tr_variantMergeDicts (tr_variant * target, const tr_variant * source)
 ***/
 
 struct evbuffer *
-tr_variantToBuf (const tr_variant * top, tr_variant_fmt fmt)
+tr_variantToBuf (const tr_variant * v, tr_variant_fmt fmt)
 {
-  struct evbuffer * buf = evbuffer_new ();
+  struct evbuffer * buf = evbuffer_new();
 
   evbuffer_expand (buf, 4096); /* alloc a little memory to start off with */
 
   switch (fmt)
     {
       case TR_VARIANT_FMT_BENC:
-        tr_variantToBufBenc (top, buf);
+        tr_variantToBufBenc (v, buf);
         break;
 
       case TR_VARIANT_FMT_JSON:
-        tr_variantToBufJson (top, buf, false);
+        tr_variantToBufJson (v, buf, false);
         break;
 
       case TR_VARIANT_FMT_JSON_LEAN:
-        tr_variantToBufJson (top, buf, true);
+        tr_variantToBufJson (v, buf, true);
         break;
     }
 
@@ -1200,9 +1125,9 @@ tr_variantToBuf (const tr_variant * top, tr_variant_fmt fmt)
 }
 
 char*
-tr_variantToStr (const tr_variant * top, tr_variant_fmt fmt, int * len)
+tr_variantToStr (const tr_variant * v, tr_variant_fmt fmt, int * len)
 {
-  struct evbuffer * buf = tr_variantToBuf (top, fmt);
+  struct evbuffer * buf = tr_variantToBuf (v, fmt);
   const size_t n = evbuffer_get_length (buf);
   char * ret = evbuffer_free_to_str (buf);
   if (len != NULL)
@@ -1210,7 +1135,7 @@ tr_variantToStr (const tr_variant * top, tr_variant_fmt fmt, int * len)
   return ret;
 }
 
-/* portability wrapper for mkstemp (). */
+/* portability wrapper for mkstemp(). */
 static int
 tr_mkstemp (char * template)
 {
@@ -1225,7 +1150,7 @@ tr_mkstemp (char * template)
 }
 
 int
-tr_variantToFile (const tr_variant  * top,
+tr_variantToFile (const tr_variant  * v,
                   tr_variant_fmt      fmt,
                   const char        * filename)
 {
@@ -1235,7 +1160,7 @@ tr_variantToFile (const tr_variant  * top,
   char buf[TR_PATH_MAX];
 
   /* follow symlinks to find the "real" file, to make sure the temporary
-   * we build with tr_mkstemp () is created on the right partition */
+   * we build with tr_mkstemp() is created on the right partition */
   if (tr_realpath (filename, buf) != NULL)
     filename = buf;
 
@@ -1249,7 +1174,7 @@ tr_variantToFile (const tr_variant  * top,
 
       /* save the variant to a temporary file */
       {
-        struct evbuffer * buf = tr_variantToBuf (top, fmt);
+        struct evbuffer * buf = tr_variantToBuf (v, fmt);
         const char * walk = (const char *) evbuffer_pullup (buf, -1);
         nleft = evbuffer_get_length (buf);
 
index e4047bb5321a56cb4daa38a7890a236c2dbf4ba9..6e3eb175ffbc8eaabfa456f90673de5fa16eb4eb 100644 (file)
@@ -74,6 +74,8 @@ typedef struct tr_variant
 {
   char type;
 
+  tr_quark key;
+
   union
     {
       bool b;
@@ -86,9 +88,9 @@ typedef struct tr_variant
 
       struct
         {
-          struct tr_variant * vals; /* nodes */
-          size_t alloc; /* nodes allocated */
-          size_t count; /* nodes used */
+          size_t alloc;
+          size_t count;
+          struct tr_variant * vals;
         } l;
     }
   val;
@@ -275,10 +277,10 @@ tr_variantIsList (const tr_variant * v)
   return (v != NULL) && (v->type == TR_VARIANT_TYPE_LIST);
 }
 
-int          tr_variantInitList        (tr_variant       * list,
+void         tr_variantInitList        (tr_variant       * list,
                                         size_t             reserve_count);
 
-int          tr_variantListReserve     (tr_variant       * list,
+void         tr_variantListReserve     (tr_variant       * list,
                                         size_t             reserve_count);
 
 tr_variant * tr_variantListAdd         (tr_variant       * list);
@@ -311,7 +313,7 @@ tr_variant * tr_variantListAddDict     (tr_variant       * list,
 tr_variant * tr_variantListChild       (tr_variant       * list,
                                         size_t             pos);
 
-int          tr_variantListRemove      (tr_variant       * list,
+bool         tr_variantListRemove      (tr_variant       * list,
                                         size_t             pos);
 
 size_t       tr_variantListSize        (const tr_variant * list);
@@ -327,13 +329,13 @@ tr_variantIsDict (const tr_variant * v)
   return (v != NULL) && (v->type == TR_VARIANT_TYPE_DICT);
 }
 
-int          tr_variantInitDict        (tr_variant       * initme,
+void         tr_variantInitDict        (tr_variant       * initme,
                                         size_t             reserve_count);
 
-int          tr_variantDictReserve     (tr_variant       * dict,
+void         tr_variantDictReserve     (tr_variant       * dict,
                                         size_t             reserve_count);
 
-int          tr_variantDictRemove      (tr_variant       * dict,
+bool         tr_variantDictRemove      (tr_variant       * dict,
                                         const tr_quark     key);
 
 tr_variant * tr_variantDictAdd         (tr_variant       * dict,
index 9a628e07dc9aad8fa60953268fd8ca1e6d84234d..916b59450a77061454ea6d28c56580172ebf6e15 100755 (executable)
@@ -1,2 +1,3 @@
 #/bin/sh
-valgrind --tool=cachegrind ./transmission-qt
+valgrind --tool=cachegrind ./transmission-qt 2>&1 | tee runlog
+#valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=48 --log-file=x-valgrind --show-reachable=no ./transmission-qt 2>&1 | tee runlog