From 834a3f2151dd8738a1f878489f6207664c4af5aa Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Sun, 14 Jul 2013 17:14:53 -0700 Subject: Imported Upstream version 1.1.1 --- src/trg-file-parser.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 src/trg-file-parser.c (limited to 'src/trg-file-parser.c') diff --git a/src/trg-file-parser.c b/src/trg-file-parser.c new file mode 100644 index 0000000..fbfb6aa --- /dev/null +++ b/src/trg-file-parser.c @@ -0,0 +1,201 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011-2013 Alan Fitton + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include + +#include "bencode.h" +#include "trg-file-parser.h" + +static trg_files_tree_node *trg_file_parser_node_insert(trg_files_tree_node + * top, + trg_files_tree_node + * last, + be_node * + file_node, + gint index) +{ + be_node *file_length_node = be_dict_find(file_node, "length", BE_INT); + be_node *file_path_list = be_dict_find(file_node, "path", BE_LIST); + trg_files_tree_node *lastIter = last; + GList *parentList = NULL; + be_node *path_el_node; + GList *li; + int i; + + if (!file_path_list || !file_length_node) + return NULL; + + if (lastIter) + while ((lastIter = lastIter->parent)) + parentList = g_list_prepend(parentList, lastIter); + + li = parentList; + lastIter = top; + + /* Iterate over the path list which contains each file/directory + * component of the path in order. + */ + for (i = 0; (path_el_node = file_path_list->val.l[i]); i++) { + gboolean isFile = !file_path_list->val.l[i + 1]; + trg_files_tree_node *target_node = NULL; + + if (li && !isFile) { + trg_files_tree_node *lastPathNode = (trg_files_tree_node *) li->data; + + if (!g_strcmp0(lastPathNode->name, path_el_node->val.s)) { + target_node = lastPathNode; + li = g_list_next(li); + } else { + li = NULL; + } + } + + if (!target_node && lastIter && lastIter->childrenHash && !isFile) + target_node = g_hash_table_lookup(lastIter->childrenHash, path_el_node->val.s); + + if (!target_node) { + target_node = g_new0(trg_files_tree_node, 1); + target_node->name = g_strdup(path_el_node->val.s); + target_node->parent = lastIter; + trg_files_tree_node_add_child(lastIter, target_node); + } + + if (isFile) { + target_node->length = (gint64) file_length_node->val.i; + + while (lastIter) { + lastIter->length = target_node->length; + lastIter = lastIter->parent; + } + } + + target_node->index = isFile ? index : -1; + lastIter = target_node; + } + + g_list_free(parentList); + + return lastIter; +} + +void trg_torrent_file_free(trg_torrent_file * t) +{ + trg_files_tree_node_free(t->top_node); + g_free(t->name); + g_free(t); +} + +static trg_files_tree_node *trg_parse_torrent_file_nodes(be_node * + info_node) +{ + be_node *files_node = be_dict_find(info_node, "files", BE_LIST); + trg_files_tree_node *top_node = g_new0(trg_files_tree_node, 1); + trg_files_tree_node *lastNode = NULL; + int i; + + /* Probably means single file mode. */ + if (!files_node) + return NULL; + + for (i = 0; files_node->val.l[i]; ++i) { + be_node *file_node = files_node->val.l[i]; + + if (!be_validate_node(file_node, BE_DICT) + || !(lastNode = + trg_file_parser_node_insert(top_node, lastNode, + file_node, i))) { + /* Unexpected format. Throw away everything, file indexes need to + * be correct. */ + trg_files_tree_node_free(top_node); + return NULL; + } + } + + return top_node; +} + +trg_torrent_file *trg_parse_torrent_file(const gchar * filename) +{ + GError *error = NULL; + GMappedFile *mf; + be_node *top_node, *info_node, *name_node; + trg_torrent_file *ret = NULL; + + if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { + g_message("%s does not exist", filename); + return NULL; + } + + mf = g_mapped_file_new(filename, FALSE, &error); + + if (error) { + g_error("%s", error->message); + g_error_free(error); + g_mapped_file_unref(mf); + return NULL; + } else { + top_node = + be_decoden(g_mapped_file_get_contents(mf), + g_mapped_file_get_length(mf)); + } + + g_mapped_file_unref(mf); + + if (!top_node) { + return NULL; + } else if (!be_validate_node(top_node, BE_DICT)) { + goto out; + } + + info_node = be_dict_find(top_node, "info", BE_DICT); + if (!info_node) + goto out; + + name_node = be_dict_find(info_node, "name", BE_STR); + if (!name_node) + goto out; + + ret = g_new0(trg_torrent_file, 1); + ret->name = g_strdup(name_node->val.s); + + ret->top_node = trg_parse_torrent_file_nodes(info_node); + if (!ret->top_node) { + trg_files_tree_node *file_node; + be_node *length_node = be_dict_find(info_node, "length", BE_INT); + + if (!length_node) { + g_free(ret); + ret = NULL; + goto out; + } + + file_node = g_new0(trg_files_tree_node, 1); + file_node->length = (gint64) (length_node->val.i); + file_node->name = g_strdup(ret->name); + ret->top_node = file_node; + } + + out: + be_free(top_node); + return ret; +} -- cgit v1.2.3