|
|
|
@ -7,7 +7,6 @@
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <json-glib/json-glib.h>
|
|
|
|
|
|
|
|
|
|
#include "helpers.h"
|
|
|
|
|
|
|
|
|
@ -809,171 +808,3 @@ static ssize_t __bencode_next(const char *s, ssize_t offset, size_t len) {
|
|
|
|
|
ssize_t bencode_valid(const char *s, size_t len) {
|
|
|
|
|
return __bencode_next(s, 0, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bencode_item_t *bencode_convert_json_node(bencode_buffer_t *buf, JsonNode *node);
|
|
|
|
|
|
|
|
|
|
static bencode_item_t *bencode_convert_json_dict(bencode_buffer_t *buf, JsonNode *node) {
|
|
|
|
|
JsonObject *obj = json_node_get_object(node);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return NULL;
|
|
|
|
|
bencode_item_t *dict = bencode_dictionary(buf);
|
|
|
|
|
if (!dict)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
JsonObjectIter iter;
|
|
|
|
|
json_object_iter_init(&iter, obj);
|
|
|
|
|
const char *key;
|
|
|
|
|
JsonNode *value;
|
|
|
|
|
while (json_object_iter_next(&iter, &key, &value)) {
|
|
|
|
|
if (!key || !value)
|
|
|
|
|
return NULL;
|
|
|
|
|
bencode_item_t *b_val = bencode_convert_json_node(buf, value);
|
|
|
|
|
if (!b_val)
|
|
|
|
|
return NULL;
|
|
|
|
|
bencode_dictionary_add(dict, key, b_val);
|
|
|
|
|
}
|
|
|
|
|
return dict;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bencode_item_t *bencode_convert_json_array(bencode_buffer_t *buf, JsonNode *node) {
|
|
|
|
|
JsonArray *arr = json_node_get_array(node);
|
|
|
|
|
if (!arr)
|
|
|
|
|
return NULL;
|
|
|
|
|
bencode_item_t *list = bencode_list(buf);
|
|
|
|
|
if (!list)
|
|
|
|
|
return NULL;
|
|
|
|
|
guint len = json_array_get_length(arr);
|
|
|
|
|
for (guint i = 0; i < len; i++) {
|
|
|
|
|
JsonNode *el = json_array_get_element(arr, i);
|
|
|
|
|
if (!el)
|
|
|
|
|
return NULL;
|
|
|
|
|
bencode_item_t *it = bencode_convert_json_node(buf, el);
|
|
|
|
|
if (!it)
|
|
|
|
|
return NULL;
|
|
|
|
|
bencode_list_add(list, it);
|
|
|
|
|
}
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bencode_item_t *bencode_convert_json_value(bencode_buffer_t *buf, JsonNode *node) {
|
|
|
|
|
GType type = json_node_get_value_type(node);
|
|
|
|
|
switch (type) {
|
|
|
|
|
case G_TYPE_STRING:;
|
|
|
|
|
const char *s = json_node_get_string(node);
|
|
|
|
|
if (!s)
|
|
|
|
|
return NULL;
|
|
|
|
|
return bencode_string(buf, s);
|
|
|
|
|
case G_TYPE_INT:
|
|
|
|
|
case G_TYPE_UINT:
|
|
|
|
|
case G_TYPE_LONG:
|
|
|
|
|
case G_TYPE_ULONG:
|
|
|
|
|
case G_TYPE_INT64:
|
|
|
|
|
case G_TYPE_UINT64:
|
|
|
|
|
case G_TYPE_BOOLEAN:;
|
|
|
|
|
gint64 i = json_node_get_int(node);
|
|
|
|
|
return bencode_integer(buf, i);
|
|
|
|
|
// everything else is unsupported
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bencode_item_t *bencode_convert_json_node(bencode_buffer_t *buf, JsonNode *node) {
|
|
|
|
|
JsonNodeType type = json_node_get_node_type(node);
|
|
|
|
|
switch (type) {
|
|
|
|
|
case JSON_NODE_OBJECT:
|
|
|
|
|
return bencode_convert_json_dict(buf, node);
|
|
|
|
|
case JSON_NODE_ARRAY:
|
|
|
|
|
return bencode_convert_json_array(buf, node);
|
|
|
|
|
case JSON_NODE_VALUE:
|
|
|
|
|
return bencode_convert_json_value(buf, node);
|
|
|
|
|
default:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bencode_item_t *bencode_convert_json(bencode_buffer_t *buf, JsonParser *json) {
|
|
|
|
|
JsonNode *root = json_parser_get_root(json);
|
|
|
|
|
if (!root)
|
|
|
|
|
return NULL;
|
|
|
|
|
return bencode_convert_json_node(buf, root);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gboolean bencode_collapse_json_item(bencode_item_t *item, JsonBuilder *builder);
|
|
|
|
|
|
|
|
|
|
gboolean bencode_collapse_json_list(bencode_item_t *item, JsonBuilder *builder) {
|
|
|
|
|
json_builder_begin_array(builder);
|
|
|
|
|
for (bencode_item_t *el = item->child; el; el = el->sibling) {
|
|
|
|
|
if (!bencode_collapse_json_item(el, builder))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
json_builder_end_array(builder);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean bencode_collapse_json_string(bencode_item_t *item, JsonBuilder *builder) {
|
|
|
|
|
char buf[item->iov[1].iov_len + 1];
|
|
|
|
|
memcpy(buf, item->iov[1].iov_base, item->iov[1].iov_len);
|
|
|
|
|
buf[item->iov[1].iov_len] = '\0';
|
|
|
|
|
json_builder_add_string_value(builder, buf);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean bencode_collapse_json_dict(bencode_item_t *item, JsonBuilder *builder) {
|
|
|
|
|
json_builder_begin_object(builder);
|
|
|
|
|
bencode_item_t *val;
|
|
|
|
|
for (bencode_item_t *key = item->child; key; key = val->sibling) {
|
|
|
|
|
val = key->sibling;
|
|
|
|
|
if (key->type != BENCODE_STRING)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
char buf[key->iov[1].iov_len + 1];
|
|
|
|
|
memcpy(buf, key->iov[1].iov_base, key->iov[1].iov_len);
|
|
|
|
|
buf[key->iov[1].iov_len] = '\0';
|
|
|
|
|
|
|
|
|
|
json_builder_set_member_name(builder, buf);
|
|
|
|
|
|
|
|
|
|
if (!bencode_collapse_json_item(val, builder))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
json_builder_end_object(builder);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean bencode_collapse_json_int(bencode_item_t *item, JsonBuilder *builder) {
|
|
|
|
|
json_builder_add_int_value(builder, item->value);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean bencode_collapse_json_item(bencode_item_t *item, JsonBuilder *builder) {
|
|
|
|
|
switch (item->type) {
|
|
|
|
|
case BENCODE_LIST:
|
|
|
|
|
return bencode_collapse_json_list(item, builder);
|
|
|
|
|
case BENCODE_STRING:
|
|
|
|
|
return bencode_collapse_json_string(item, builder);
|
|
|
|
|
case BENCODE_DICTIONARY:
|
|
|
|
|
return bencode_collapse_json_dict(item, builder);
|
|
|
|
|
case BENCODE_INTEGER:
|
|
|
|
|
return bencode_collapse_json_int(item, builder);
|
|
|
|
|
default:
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str *bencode_collapse_str_json(bencode_item_t *root, str *out) {
|
|
|
|
|
JsonBuilder *builder = json_builder_new();
|
|
|
|
|
if (!bencode_collapse_json_item(root, builder))
|
|
|
|
|
goto err;
|
|
|
|
|
char *result = glib_json_print(builder);
|
|
|
|
|
out->s = result;
|
|
|
|
|
out->len = strlen(result);
|
|
|
|
|
bencode_buffer_destroy_add(root->buffer, free, result);
|
|
|
|
|
return out;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
g_object_unref(builder);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|