static int test1(void) { char const* in = "{\n" " \"headers\": {\n" " \"type\": \"request\",\n" " \"tag\": 666\n" " },\n" " \"body\": {\n" " \"name\": \"torrent-info\",\n" " \"arguments\": {\n" " \"ids\": [ 7, 10 ]\n" " }\n" " }\n" "}\n"; tr_variant top; tr_variant* headers; tr_variant* body; tr_variant* args; tr_variant* ids; char const* str; int64_t i; int const err = tr_variantFromJson(&top, in, strlen(in)); check_int(err, ==, 0); check(tr_variantIsDict(&top)); check_ptr((headers = tr_variantDictFind(&top, tr_quark_new("headers", 7))), !=, NULL); check(tr_variantIsDict(headers)); check(tr_variantDictFindStr(headers, tr_quark_new("type", 4), &str, NULL)); check_str(str, ==, "request"); check(tr_variantDictFindInt(headers, TR_KEY_tag, &i)); check_int(i, ==, 666); check_ptr((body = tr_variantDictFind(&top, tr_quark_new("body", 4))), !=, NULL); check(tr_variantDictFindStr(body, TR_KEY_name, &str, NULL)); check_str(str, ==, "torrent-info"); check_ptr((args = tr_variantDictFind(body, tr_quark_new("arguments", 9))), !=, NULL); check(tr_variantIsDict(args)); check_ptr((ids = tr_variantDictFind(args, TR_KEY_ids)), !=, NULL); check(tr_variantIsList(ids)); check_uint(tr_variantListSize(ids), ==, 2); check(tr_variantGetInt(tr_variantListChild(ids, 0), &i)); check_int(i, ==, 7); check(tr_variantGetInt(tr_variantListChild(ids, 1), &i)); check_int(i, ==, 10); tr_variantFree(&top); return 0; }
static tr_variant* get_node (struct jsonsl_st * jsn) { tr_variant * parent; tr_variant * node = NULL; struct json_wrapper_data * data = jsn->data; parent = tr_ptrArrayEmpty (&data->stack) ? NULL : tr_ptrArrayBack (&data->stack); if (!parent) { node = data->top; } else if (tr_variantIsList (parent)) { node = tr_variantListAdd (parent); } else if (tr_variantIsDict (parent) && (data->key!=NULL)) { node = tr_variantDictAdd (parent, tr_quark_new (data->key, data->keylen)); data->key = NULL; data->keylen = 0; } return node; }
static void save_recent_destination (TrCore * core, const char * dir) { int i; GSList * l; GSList * list = get_recent_destinations (); if (dir == NULL) return; /* if it was already in the list, remove it */ if ((l = g_slist_find_custom (list, dir, (GCompareFunc)g_strcmp0))) list = g_slist_delete_link (list, l); /* add it to the front of the list */ list = g_slist_prepend (list, (void*)dir); /* make local copies of the strings that aren't * invalidated by gtr_pref_string_set () */ for (l=list; l; l=l->next) l->data = g_strdup (l->data); /* save the first N_RECENT directories */ for (l=list, i=0; l && (i<N_RECENT); ++i, l=l->next) { char key[64]; g_snprintf (key, sizeof (key), "recent-download-dir-%d", i + 1); gtr_pref_string_set (tr_quark_new(key,-1), l->data); } gtr_pref_save (gtr_core_session (core)); /* cleanup */ g_slist_foreach (list, (GFunc)g_free, NULL); g_slist_free (list); }
static int test_static_quarks (void) { int i; for (i=0; i<TR_N_KEYS; i++) { tr_quark q; size_t len; const char * str; str = tr_quark_get_string ((tr_quark)i, &len); check_uint_eq (strlen(str), len); check (tr_quark_lookup (str, len, &q)); check_int_eq (i, (int)q); } for (i=0; i+1<TR_N_KEYS; i++) { size_t len1, len2; const char *str1, *str2; str1 = tr_quark_get_string ((tr_quark)i, &len1); str2 = tr_quark_get_string ((tr_quark)(i+1), &len2); check (strcmp (str1, str2) < 0); } const tr_quark q = tr_quark_new (NULL, TR_BAD_SIZE); check_int_eq (TR_KEY_NONE, (int)q); check_streq ("", tr_quark_get_string (q, NULL)); return 0; }
static int test_utf8 (void) { const char * in = "{ \"key\": \"Letöltések\" }"; tr_variant top; const char * str; char * json; int err; const tr_quark key = tr_quark_new ("key", 3); err = tr_variantFromJson (&top, in, strlen(in)); check (!err); check (tr_variantIsDict (&top)); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("Letöltések", str); if (!err) tr_variantFree (&top); in = "{ \"key\": \"\\u005C\" }"; err = tr_variantFromJson (&top, in, strlen(in)); check (!err); check (tr_variantIsDict (&top)); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("\\", str); if (!err) tr_variantFree (&top); /** * 1. Feed it JSON-escaped nonascii to the JSON decoder. * 2. Confirm that the result is UTF-8. * 3. Feed the same UTF-8 back into the JSON encoder. * 4. Confirm that the result is JSON-escaped. * 5. Dogfood that result back into the parser. * 6. Confirm that the result is UTF-8. */ in = "{ \"key\": \"Let\\u00f6lt\\u00e9sek\" }"; err = tr_variantFromJson (&top, in, strlen(in)); check (!err); check (tr_variantIsDict (&top)); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("Letöltések", str); json = tr_variantToStr (&top, TR_VARIANT_FMT_JSON, NULL); if (!err) tr_variantFree (&top); check (json); check (strstr (json, "\\u00f6") != NULL); check (strstr (json, "\\u00e9") != NULL); err = tr_variantFromJson (&top, json, strlen(json)); check (!err); check (tr_variantIsDict (&top)); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("Letöltések", str); if (!err) tr_variantFree (&top); tr_free (json); return 0; }
static int test1 (void) { const char * in = "{\n" " \"headers\": {\n" " \"type\": \"request\",\n" " \"tag\": 666\n" " },\n" " \"body\": {\n" " \"name\": \"torrent-info\",\n" " \"arguments\": {\n" " \"ids\": [ 7, 10 ]\n" " }\n" " }\n" "}\n"; tr_variant top, *headers, *body, *args, *ids; const char * str; int64_t i; const int err = tr_variantFromJson (&top, in, strlen(in)); check (!err); check (tr_variantIsDict (&top)); check ((headers = tr_variantDictFind (&top, tr_quark_new("headers",7)))); check (tr_variantIsDict (headers)); check (tr_variantDictFindStr (headers, tr_quark_new("type",4), &str, NULL)); check_streq ("request", str); check (tr_variantDictFindInt (headers, TR_KEY_tag, &i)); check_int_eq (666, i); check ((body = tr_variantDictFind (&top, tr_quark_new("body",4)))); check (tr_variantDictFindStr (body, TR_KEY_name, &str, NULL)); check_streq ("torrent-info", str); check ((args = tr_variantDictFind (body, tr_quark_new("arguments",9)))); check (tr_variantIsDict (args)); check ((ids = tr_variantDictFind (args, TR_KEY_ids))); check (tr_variantIsList (ids)); check_int_eq (2, tr_variantListSize (ids)); check (tr_variantGetInt (tr_variantListChild (ids, 0), &i)); check_int_eq (7, i); check (tr_variantGetInt (tr_variantListChild (ids, 1), &i)); check_int_eq (10, i); tr_variantFree (&top); return 0; }
static int test_unescape(void) { char const* in = "{ \"string-1\": \"\\/usr\\/lib\" }"; tr_variant top; char const* str; int const err = tr_variantFromJson(&top, in, strlen(in)); check_int(err, ==, 0); check(tr_variantDictFindStr(&top, tr_quark_new("string-1", 8), &str, NULL)); check_str(str, ==, "/usr/lib"); tr_variantFree(&top); return 0; }
static int test_unescape (void) { const char * in = "{ \"string-1\": \"\\/usr\\/lib\" }"; tr_variant top; const char * str; const int err = tr_variantFromJson (&top, in, strlen(in)); check_int_eq (0, err); check (tr_variantDictFindStr (&top, tr_quark_new("string-1",8), &str, NULL)); check_streq ("/usr/lib", str); tr_variantFree (&top); return 0; }
static int test_elements(void) { char const* in; tr_variant top; char const* str; bool f; double d; int64_t i; int err = 0; tr_quark key; in = "{ \"string\": \"hello world\"," " \"escaped\": \"bell \\b formfeed \\f linefeed \\n carriage return \\r tab \\t\"," " \"int\": 5, " " \"float\": 6.5, " " \"true\": true, " " \"false\": false, " " \"null\": null }"; err = tr_variantFromJson(&top, in, strlen(in)); check_int(err, ==, 0); check(tr_variantIsDict(&top)); str = NULL; key = tr_quark_new("string", 6); check(tr_variantDictFindStr(&top, key, &str, NULL)); check_str(str, ==, "hello world"); check(tr_variantDictFindStr(&top, tr_quark_new("escaped", 7), &str, NULL)); check_str(str, ==, "bell \b formfeed \f linefeed \n carriage return \r tab \t"); i = 0; check(tr_variantDictFindInt(&top, tr_quark_new("int", 3), &i)); check_int(i, ==, 5); d = 0; check(tr_variantDictFindReal(&top, tr_quark_new("float", 5), &d)); check_int(((int)(d * 10)), ==, 65); f = false; check(tr_variantDictFindBool(&top, tr_quark_new("true", 4), &f)); check_int(f, ==, true); check(tr_variantDictFindBool(&top, tr_quark_new("false", 5), &f)); check_int(f, ==, false); check(tr_variantDictFindStr(&top, tr_quark_new("null", 4), &str, NULL)); check_str(str, ==, ""); if (err == 0) { tr_variantFree(&top); } return 0; }
static GSList* get_recent_destinations (void) { int i; GSList * list = NULL; for (i=0; i<N_RECENT; ++i) { char key[64]; const char * val; g_snprintf (key, sizeof (key), "recent-download-dir-%d", i+1); if ((val = gtr_pref_string_get (tr_quark_new(key,-1)))) list = g_slist_append (list, (void*)val); } return list; }
static int test_elements (void) { const char * in; tr_variant top; const char * str; bool f; double d; int64_t i; int err = 0; tr_quark key; in = "{ \"string\": \"hello world\"," " \"escaped\": \"bell \\b formfeed \\f linefeed \\n carriage return \\r tab \\t\"," " \"int\": 5, " " \"float\": 6.5, " " \"true\": true, " " \"false\": false, " " \"null\": null }"; err = tr_variantFromJson (&top, in, strlen(in)); check_int_eq (0, err); check (tr_variantIsDict (&top)); str = NULL; key = tr_quark_new ("string", 6); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("hello world", str); check (tr_variantDictFindStr (&top, tr_quark_new("escaped",7), &str, NULL)); check_streq ("bell \b formfeed \f linefeed \n carriage return \r tab \t", str); i = 0; check (tr_variantDictFindInt (&top, tr_quark_new("int",3), &i)); check_int_eq (5, i); d = 0; check (tr_variantDictFindReal (&top, tr_quark_new("float",5), &d)); check_int_eq (65, ((int)(d*10))); f = false; check (tr_variantDictFindBool (&top, tr_quark_new("true",4), &f)); check_int_eq (true, f); check (tr_variantDictFindBool (&top, tr_quark_new("false",5), &f)); check_int_eq (false, f); check (tr_variantDictFindStr (&top, tr_quark_new("null",4), &str, NULL)); check_streq ("", str); if (!err) tr_variantFree (&top); return 0; }
/** * This function's previous recursive implementation was * easier to read, but was vulnerable to a smash-stacking * attack via maliciously-crafted bencoded data. (#667) */ int tr_variantParseBenc (const void * buf_in, const void * bufend_in, tr_variant * top, const char ** setme_end) { 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... */ err = EILSEQ; if (err) break; if (*buf == 'i') /* int */ { int64_t val; const uint8_t * end; tr_variant * v; if ((err = tr_bencParseInt (buf, bufend, &end, &val))) break; buf = end; if ((v = get_node (&stack, &key, top, &err))) tr_variantInitInt (v, val); } else if (*buf == 'l') /* list */ { tr_variant * v; ++buf; if ((v = get_node (&stack, &key, top, &err))) { tr_variantInitList (v, 0); tr_ptrArrayAppend (&stack, v); } } else if (*buf == 'd') /* dict */ { tr_variant * v; ++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 */ { ++buf; if (tr_ptrArrayEmpty (&stack) || (key != 0)) { err = EILSEQ; break; } else { tr_ptrArrayPop (&stack); if (tr_ptrArrayEmpty (&stack)) break; } } else if (isdigit (*buf)) /* string? */ { tr_variant * v; const uint8_t * end; const uint8_t * str; size_t str_len; if ((err = tr_bencParseStr (buf, bufend, &end, &str, &str_len))) break; buf = end; 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; } if (!err && (!top->type || !tr_ptrArrayEmpty(&stack))) err = EILSEQ; if (!err && setme_end) *setme_end = (const char*) buf; tr_ptrArrayDestruct (&stack, NULL); return err; }
static inline tr_quark toQuark (const char * str) { return tr_quark_new (str, strlen(str)); }