/** * Parse an unknown data type. * This is not exposed to the world because it is expected that one would * know what type they are parsing to begin with. This is used by parseDictionary * and parseList to grab pieces of data which are of unknown type and parse them. * * @param reader the reader to get the stream of data from. * @param allocator the means of storing the parsed data. * @param output a pointer which will be pointed to the output. */ static int32_t parseGeneric(const struct Reader* reader, const struct Allocator* allocator, Object** output) { #define OUT_OF_CONTENT_TO_READ -2 #define UNPARSABLE -3 int ret; char firstChar; ret = reader->read(&firstChar, 0, reader); if (ret != 0) { return OUT_OF_CONTENT_TO_READ; } Object* out = Allocator_malloc(allocator, sizeof(Object)); if (firstChar <= '9' && firstChar >= '0') { /* It's a string! */ String* string = NULL; ret = parseString(reader, allocator, &string); out->type = Object_STRING; out->as.string = string; } else { switch (firstChar) { case 'i':; /* int64_t. Int is special because it is not a pointer but a int64_t. */ int64_t bint = 0; ret = parseint64_t(reader, &bint); out->type = Object_INTEGER; out->as.number = bint; break; case 'l':; /* List. */ List* list = Allocator_calloc(allocator, sizeof(List), 1); ret = parseList(reader, allocator, list); out->type = Object_LIST; out->as.list = list; break; case 'd':; /* Dictionary. */ Dict* dict = Allocator_calloc(allocator, sizeof(Dict), 1); ret = parseDictionary(reader, allocator, dict); out->type = Object_DICT; out->as.dictionary = dict; break; default: return UNPARSABLE; } } if (ret != 0) { /* Something went wrong while parsing. */ return ret; } *output = out; return 0; #undef OUT_OF_CONTENT_TO_READ #undef UNPARSABLE }
static int32_t parseGeneric(const struct Reader* reader, const struct Allocator* allocator, Object** output) { int ret = 0; char firstChar; for (;;) { ret = reader->read(&firstChar, 0, reader); switch (firstChar) { case ' ': case '\r': case '\n': case '\t': reader->skip(1, reader); continue; case '/':; if ((ret = parseComment(reader)) != 0) { return ret; } continue; default: break; } if (ret) { printf("Unexpected end of input\n"); return OUT_OF_CONTENT_TO_READ; } break; } Object* out = allocator->malloc(sizeof(Object), allocator); switch (firstChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':; // int64_t. Int is special because it is not a pointer but a int64_t. int64_t bint; ret = parseint64_t(reader, &bint); out->type = Object_INTEGER; out->as.number = bint; break; case '[':; // List. List* list = allocator->calloc(sizeof(List), 1, allocator); ret = parseList(reader, allocator, list); out->type = Object_LIST; out->as.list = list; break; case '{':; // Dictionary Dict* dict = allocator->calloc(sizeof(Dict), 1, allocator); ret = parseDictionary(reader, allocator, dict); out->type = Object_DICT; out->as.dictionary = dict; break; case '"':; // String String* string = NULL; ret = parseString(reader, allocator, &string); out->type = Object_STRING; out->as.string = string; break; default: printf("While looking for something to parse: " "expected one of 0 1 2 3 4 5 6 7 8 9 [ { \", found '%c'\n", firstChar); return UNPARSABLE; } if (ret != 0) { // Something went wrong while parsing. return ret; } *output = out; return 0; }
BitTorrent::BitTorrent(std::string filename) { std::fstream in(filename.c_str(),std::ios::in | std::ios::binary | std::ios::ate); char * contents = 0; if (in.is_open()){ size_t size = in.tellg(); contents = new char[size + 1]; in.seekg(0, std::ios::beg); in.read(contents, size); contents[size] = 0; in.close(); } ListType lst; DictionaryType dic; if (contents != 0){ char * to_delete = contents; parseDictionary(contents, lst, dic); delete [] to_delete; } for (size_t i = 0; i < dic.getItems().size(); ++i){ const auto & item = dic.getItems().at(i); auto key = item.first; const auto & value = item.second; std::transform(key.begin(), key.end(), key.begin(), ::tolower); if (key == "announce"){ assert(value->getType() == BType::STRING); this->announce_ = static_cast<StringType*>(value)->getValue(); } else if (key == "announce-list"){ assert(value->getType() == BType::LIST); auto & items = static_cast<ListType*>(value)->getItems(); for (size_t j = 0; j < items.size(); ++j){ auto & item = items[j]; if (item->getType() == BType::STRING){ const std::string & name = static_cast<StringType*>(item)->getValue(); this->announce_list_.push_back(name); } } } else if (key == "comment"){ assert(value->getType() == BType::STRING); this->comment_ = this->comment_utf_8_ = static_cast<StringType*>(value)->getValue(); } else if (key == "creation date"){ assert(value->getType() == BType::INTEGER); this->creation_date_ = static_cast<IntegerType*>(value)->getValue(); } else if (key == "length"){ assert(value->getType() == BType::INTEGER); this->info_.length = static_cast<IntegerType*>(value)->getValue(); } else if (key == "name"){ assert(value->getType() == BType::STRING); this->info_.name = this->info_.name_utf_8 = static_cast<StringType*>(value)->getValue(); } else if (key == "piece length"){ assert(value->getType() == BType::INTEGER); this->piece_length_ = static_cast<IntegerType*>(value)->getValue(); } else if (key == "pieces"){ assert(value->getType() == BType::STRING); this->pieces_ = static_cast<StringType*>(value)->getValue(); } else if (key == "info"){ // do nothing } else if (key == "httpseeds"){ // do nothing } else if (key == "files"){ THROW_BT_EXCEPTION("currrent don't support multi files"); } else{ THROW_BT_EXCEPTION("unexpected token"); } } this->encoding_ = "utf-8"; }