(trunk, libT) more tr_variant revision: faster serialization, dictionaries use less space
This commit is contained in:
parent
e19fd611c7
commit
94b5e88d36
|
@ -11,12 +11,10 @@
|
|||
*/
|
||||
|
||||
#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>
|
||||
|
||||
|
@ -25,13 +23,13 @@
|
|||
#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;
|
||||
node = top;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_variant * parent = tr_ptrArrayBack (stack);
|
||||
|
||||
/* 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;
|
||||
if (tr_variantIsList (parent))
|
||||
{
|
||||
node = tr_variantListAdd (parent);
|
||||
}
|
||||
else if (*key && tr_variantIsDict (parent))
|
||||
{
|
||||
node = tr_variantDictAdd (parent, *key);
|
||||
*key = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*err = EILSEQ;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -12,27 +12,27 @@
|
|||
|
||||
#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"
|
||||
|
||||
|
@ -40,13 +40,13 @@
|
|||
***
|
||||
**/
|
||||
|
||||
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;
|
||||
node->isVisited = false;
|
||||
node->childIndex = 0;
|
||||
|
||||
assert (tr_variantIsDict (val));
|
||||
|
||||
node->val = val;
|
||||
node->children = tr_new0 (int, n);
|
||||
|
||||
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);
|
||||
|
||||
for (i=0; i<j; ++i)
|
||||
{
|
||||
const int index = indices[i].index;
|
||||
node->children[node->childCount++] = index;
|
||||
node->children[node->childCount++] = index + 1;
|
||||
}
|
||||
|
||||
tr_free (indices);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
qsort (tmp, n, sizeof (struct KeyIndex), compareKeyIndex);
|
||||
|
||||
tr_variantInitDict (&node->sorted, n);
|
||||
for (i=0; i<n; ++i)
|
||||
node->children[node->childCount++] = i;
|
||||
node->sorted.val.l.vals[i] = *tmp[i].val;
|
||||
node->sorted.val.l.count = n;
|
||||
|
||||
tr_free (tmp);
|
||||
|
||||
node->v = &node->sorted;
|
||||
}
|
||||
|
||||
assert (node->childCount == n);
|
||||
}
|
||||
|
||||
static void
|
||||
nodeInitList (struct SaveNode * node,
|
||||
const tr_variant * val)
|
||||
{
|
||||
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);
|
||||
{
|
||||
node->v = v;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nodeDestruct (struct SaveNode * node)
|
||||
{
|
||||
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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue