diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2008-12-09 14:43:11 +0000 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2008-12-09 14:43:11 +0000 |
| commit | 1b54e64d34f87dca00a9d93bf110207a1098a2a5 (patch) | |
| tree | 59f1041c47a38945b0cb57a2ca4bcc2e8386847d /src | |
| parent | bd8645262ddbff5df280da40953da1fe2bb06cdb (diff) | |
2008-12-09 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added bencode helper functions and BDE class.
They will replace MetaFileUtil and Dictionary/List/Data classes.
* src/Makefile.am
* src/bencode.cc
* src/bencode.h
* test/BencodeTest.cc
* test/Makefile.am
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 3 | ||||
| -rw-r--r-- | src/Makefile.in | 39 | ||||
| -rw-r--r-- | src/bencode.cc | 469 | ||||
| -rw-r--r-- | src/bencode.h | 214 |
4 files changed, 706 insertions, 19 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 80b6f751..270da0fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -193,7 +193,8 @@ SRCS = Socket.h\ NsCookieParser.cc NsCookieParser.h\ CookieStorage.cc CookieStorage.h\ SocketBuffer.cc SocketBuffer.h\ - OptionHandlerException.cc OptionHandlerException.h + OptionHandlerException.cc OptionHandlerException.h\ + bencode.cc bencode.h if ENABLE_SSL SRCS += TLSContext.h diff --git a/src/Makefile.in b/src/Makefile.in index 09f73dca..a8373ec6 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -417,9 +417,10 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ ServerStatURISelector.h NsCookieParser.cc NsCookieParser.h \ CookieStorage.cc CookieStorage.h SocketBuffer.cc \ SocketBuffer.h OptionHandlerException.cc \ - OptionHandlerException.h TLSContext.h LibgnutlsTLSContext.cc \ - LibgnutlsTLSContext.h LibsslTLSContext.cc LibsslTLSContext.h \ - GZipDecoder.cc GZipDecoder.h Sqlite3MozCookieParser.cc \ + OptionHandlerException.h bencode.cc bencode.h TLSContext.h \ + LibgnutlsTLSContext.cc LibgnutlsTLSContext.h \ + LibsslTLSContext.cc LibsslTLSContext.h GZipDecoder.cc \ + GZipDecoder.h Sqlite3MozCookieParser.cc \ Sqlite3MozCookieParser.h AsyncNameResolver.cc \ AsyncNameResolver.h IteratableChunkChecksumValidator.cc \ IteratableChunkChecksumValidator.h \ @@ -813,14 +814,14 @@ am__objects_21 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \ ServerStatMan.$(OBJEXT) InOrderURISelector.$(OBJEXT) \ ServerStatURISelector.$(OBJEXT) NsCookieParser.$(OBJEXT) \ CookieStorage.$(OBJEXT) SocketBuffer.$(OBJEXT) \ - OptionHandlerException.$(OBJEXT) $(am__objects_1) \ - $(am__objects_2) $(am__objects_3) $(am__objects_4) \ - $(am__objects_5) $(am__objects_6) $(am__objects_7) \ - $(am__objects_8) $(am__objects_9) $(am__objects_10) \ - $(am__objects_11) $(am__objects_12) $(am__objects_13) \ - $(am__objects_14) $(am__objects_15) $(am__objects_16) \ - $(am__objects_17) $(am__objects_18) $(am__objects_19) \ - $(am__objects_20) + OptionHandlerException.$(OBJEXT) bencode.$(OBJEXT) \ + $(am__objects_1) $(am__objects_2) $(am__objects_3) \ + $(am__objects_4) $(am__objects_5) $(am__objects_6) \ + $(am__objects_7) $(am__objects_8) $(am__objects_9) \ + $(am__objects_10) $(am__objects_11) $(am__objects_12) \ + $(am__objects_13) $(am__objects_14) $(am__objects_15) \ + $(am__objects_16) $(am__objects_17) $(am__objects_18) \ + $(am__objects_19) $(am__objects_20) am_libaria2c_a_OBJECTS = $(am__objects_21) libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" @@ -1144,13 +1145,14 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \ ServerStatURISelector.h NsCookieParser.cc NsCookieParser.h \ CookieStorage.cc CookieStorage.h SocketBuffer.cc \ SocketBuffer.h OptionHandlerException.cc \ - OptionHandlerException.h $(am__append_1) $(am__append_2) \ - $(am__append_3) $(am__append_4) $(am__append_5) \ - $(am__append_6) $(am__append_7) $(am__append_8) \ - $(am__append_9) $(am__append_10) $(am__append_11) \ - $(am__append_12) $(am__append_13) $(am__append_14) \ - $(am__append_15) $(am__append_16) $(am__append_17) \ - $(am__append_18) $(am__append_19) $(am__append_20) + OptionHandlerException.h bencode.cc bencode.h $(am__append_1) \ + $(am__append_2) $(am__append_3) $(am__append_4) \ + $(am__append_5) $(am__append_6) $(am__append_7) \ + $(am__append_8) $(am__append_9) $(am__append_10) \ + $(am__append_11) $(am__append_12) $(am__append_13) \ + $(am__append_14) $(am__append_15) $(am__append_16) \ + $(am__append_17) $(am__append_18) $(am__append_19) \ + $(am__append_20) noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\ @@ -1522,6 +1524,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VersionMetalinkParserState.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XML2SAXMetalinkProcessor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asctime_r.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/download_helper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gai_strerror.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getaddrinfo.Po@am__quote@ diff --git a/src/bencode.cc b/src/bencode.cc new file mode 100644 index 00000000..60a790a2 --- /dev/null +++ b/src/bencode.cc @@ -0,0 +1,469 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2006 Tatsuhiro Tsujikawa + * + * 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 + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#include "bencode.h" + +#include <fstream> +#include <sstream> + +#include "StringFormat.h" +#include "Util.h" + +namespace aria2 { + +namespace bencode { + +const BDE BDE::none; + +BDE::BDE() throw():_type(TYPE_NONE) {} + +BDE::BDE(Integer integer) throw():_type(TYPE_INTEGER), + _integer(new Integer(integer)) {} + + +BDE::BDE(const std::string& string) throw():_type(TYPE_STRING), + _string(new std::string(string)) {} + +BDE::BDE(const char* cstring) throw():_type(TYPE_STRING), + _string(new std::string(cstring)) {} + +BDE::BDE(const char* data, size_t length) throw(): + _type(TYPE_STRING), + _string(new std::string(&data[0], &data[length])) {} + +BDE::BDE(const unsigned char* data, size_t length) throw(): + _type(TYPE_STRING), + _string(new std::string(&data[0], &data[length])) {} + +BDE BDE::dict() throw() +{ + BDE bde; + bde._type = TYPE_DICT; + bde._dict.reset(new Dict()); + return bde; +} + +BDE BDE::list() throw() +{ + BDE bde; + bde._type = TYPE_LIST; + bde._list.reset(new List()); + return bde; +} + +// Test for Null data +bool BDE::isNone() const throw() +{ + return _type == TYPE_NONE; +} + +// Integer Interface + +bool BDE::isInteger() const throw() +{ + return _type == TYPE_INTEGER; +} + +BDE::Integer BDE::i() const throw(RecoverableException) +{ + if(isInteger()) { + return *_integer.get(); + } else { + throw RecoverableException("Not Integer"); + } +} + +// String Interface + +bool BDE::isString() const throw() +{ + return _type == TYPE_STRING; +} + +const std::string& BDE::s() const throw(RecoverableException) +{ + if(isString()) { + return *_string.get(); + } else { + throw RecoverableException("Not String"); + } +} + +// Dictionary Interface + +bool BDE::isDict() const throw() +{ + return _type == TYPE_DICT; +} + +BDE& BDE::operator[](const std::string& key) throw(RecoverableException) +{ + if(isDict()) { + return (*_dict.get())[key]; + } else { + throw RecoverableException("Not Dict"); + } +} + +const BDE& BDE::operator[](const std::string& key) const + throw(RecoverableException) +{ + if(isDict()) { + BDE::Dict::const_iterator i = _dict->find(key); + if(i == _dict->end()) { + return none; + } else { + return (*i).second; + } + } else { + throw RecoverableException("Not Dict"); + } +} + +bool BDE::containsKey(const std::string& key) const throw(RecoverableException) +{ + if(isDict()) { + return _dict->find(key) != _dict->end(); + } else { + throw RecoverableException("Not Dict"); + } +} + + +BDE::Dict::iterator BDE::dictBegin() throw(RecoverableException) +{ + if(isDict()) { + return _dict->begin(); + } else { + throw RecoverableException("Not Dict"); + } +} + +BDE::Dict::const_iterator BDE::dictBegin() const throw(RecoverableException) +{ + if(isDict()) { + return _dict->begin(); + } else { + throw RecoverableException("Not Dict"); + } +} + +BDE::Dict::iterator BDE::dictEnd() throw(RecoverableException) +{ + if(isDict()) { + return _dict->end(); + } else { + throw RecoverableException("Not Dict"); + } +} + +BDE::Dict::const_iterator BDE::dictEnd() const throw(RecoverableException) +{ + if(isDict()) { + return _dict->end(); + } else { + throw RecoverableException("Not Dict"); + } +} + +// List Interface + +bool BDE::isList() const throw() +{ + return _type == TYPE_LIST; +} + +void BDE::append(const BDE& bde) throw(RecoverableException) +{ + if(isList()) { + _list->push_back(bde); + } else { + throw RecoverableException("Not List"); + } +} + +void BDE::operator<<(const BDE& bde) throw(RecoverableException) +{ + if(isList()) { + _list->push_back(bde); + } else { + throw RecoverableException("Not List"); + } +} + +BDE& BDE::operator[](size_t index) throw(RecoverableException) +{ + if(isList()) { + return (*_list.get())[index]; + } else { + throw RecoverableException("Not List"); + } +} + +const BDE& BDE::operator[](size_t index) const throw(RecoverableException) +{ + if(isList()) { + return (*_list.get())[index]; + } else { + throw RecoverableException("Not List"); + } +} + +BDE::List::iterator BDE::listBegin() throw(RecoverableException) +{ + if(isList()) { + return _list->begin(); + } else { + throw RecoverableException("Not List"); + } +} + +BDE::List::const_iterator BDE::listBegin() const throw(RecoverableException) +{ + if(isList()) { + return _list->begin(); + } else { + throw RecoverableException("Not List"); + } +} + +BDE::List::iterator BDE::listEnd() throw(RecoverableException) +{ + if(isList()) { + return _list->end(); + } else { + throw RecoverableException("Not List"); + } +} + +BDE::List::const_iterator BDE::listEnd() const throw(RecoverableException) +{ + if(isList()) { + return _list->end(); + } else { + throw RecoverableException("Not List"); + } +} + +// Callable from List and Dict +size_t BDE::size() const throw(RecoverableException) +{ + if(isDict()) { + return _dict->size(); + } else if(isList()) { + return _list->size(); + } else { + throw RecoverableException("Not Dict nor List"); + } +} + +// Callable from List and Dict +bool BDE::empty() const throw(RecoverableException) +{ + if(isDict()) { + return _dict->empty(); + } else if(isList()) { + return _list->empty(); + } else { + throw RecoverableException("Not Dict nor List"); + } +} + +static BDE decodeiter(std::istream& ss) throw(RecoverableException); + +static void checkdelim(std::istream& ss, const char delim = ':') + throw(RecoverableException) +{ + char d; + if(!(ss.get(d) && d == delim)) { + throw RecoverableException + (StringFormat("Delimiter '%c' not found.", delim).str()); + } +} + +static std::string decoderawstring(std::istream& ss) + throw(RecoverableException) +{ + size_t length; + ss >> length; + if(!ss) { + throw RecoverableException("Integer expected but none found."); + } + // TODO check length, it must be less than or equal to INT_MAX + checkdelim(ss); + char* buf = new char[length]; + ss.read(buf, length); + if(ss.gcount() != static_cast<int>(length)) { + throw RecoverableException + (StringFormat("Expected %lu bytes of data, but only %d read.", + static_cast<unsigned long>(length), ss.gcount()).str()); + } + std::string str(&buf[0], &buf[length]); + delete [] buf; + return str; +} + +static BDE decodestring(std::istream& ss) throw(RecoverableException) +{ + return BDE(decoderawstring(ss)); +} + +static BDE decodeinteger(std::istream& ss) throw(RecoverableException) +{ + BDE::Integer integer; + ss >> integer; + if(!ss) { + throw RecoverableException("Integer expected but none found"); + } + checkdelim(ss, 'e'); + return BDE(integer); +} + +static BDE decodedict(std::istream& ss) throw(RecoverableException) +{ + BDE dict = BDE::dict(); + char c; + while(ss.get(c)) { + if(c == 'e') { + return dict; + } else { + ss.unget(); + std::string key = decoderawstring(ss); + dict[key] = decodeiter(ss); + } + } + throw RecoverableException("Unexpected EOF in dict context. 'e' expected."); +} + +static BDE decodelist(std::istream& ss) throw(RecoverableException) +{ + BDE list = BDE::list(); + char c; + while(ss.get(c)) { + if(c == 'e') { + return list; + } else { + ss.unget(); + list << decodeiter(ss); + } + } + throw RecoverableException("Unexpected EOF in list context. 'e' expected."); +} + +static BDE decodeiter(std::istream& ss) throw(RecoverableException) +{ + char c; + if(!ss.get(c)) { + throw RecoverableException("Unexpected EOF in term context." + " 'd', 'l', 'i' or digit is expected."); + } + if(c == 'd') { + return decodedict(ss); + } else if(c == 'l') { + return decodelist(ss); + } else if(c == 'i') { + return decodeinteger(ss); + } else { + ss.unget(); + return decodestring(ss); + } +} + +BDE decode(std::istream& in) throw(RecoverableException) +{ + return decodeiter(in); +} + +BDE decode(const std::string& s) throw(RecoverableException) +{ + if(s.empty()) { + return BDE::none; + } + std::istringstream ss(s); + + return decodeiter(ss); +} + +BDE decode(const unsigned char* data, size_t length) throw(RecoverableException) +{ + return decode(std::string(&data[0], &data[length])); +} + +BDE decodeFromFile(const std::string& filename) throw(RecoverableException) +{ + std::ifstream f(filename.c_str()); + if(f) { + return decode(f); + } else { + throw RecoverableException + (StringFormat("Cannot open file '%s'.", filename.c_str()).str()); + } +} + +static void encodeIter(std::ostream& o, const BDE& bde) throw() +{ + if(bde.isInteger()) { + o << "i" << bde.i() << "e"; + } else if(bde.isString()) { + const std::string& s = bde.s(); + o << s.size() << ":"; + o.write(s.data(), s.size()); + } else if(bde.isDict()) { + o << "d"; + for(BDE::Dict::const_iterator i = bde.dictBegin(); i != bde.dictEnd(); ++i){ + const std::string& key = (*i).first; + o << key.size() << ":"; + o.write(key.data(), key.size()); + encodeIter(o, (*i).second); + } + o << "e"; + } else if(bde.isList()) { + o << "l"; + for(BDE::List::const_iterator i = bde.listBegin(); i != bde.listEnd(); ++i){ + encodeIter(o, *i); + } + o << "e"; + } +} + +std::string encode(const BDE& bde) throw() +{ + std::ostringstream ss; + encodeIter(ss, bde); + return ss.str(); +} + +} // namespace bencode + +} // namespace aria2 diff --git a/src/bencode.h b/src/bencode.h new file mode 100644 index 00000000..2a7fcea3 --- /dev/null +++ b/src/bencode.h @@ -0,0 +1,214 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2006 Tatsuhiro Tsujikawa + * + * 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 + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#include "common.h" + +#include <string> +#include <map> +#include <deque> +#include <iosfwd> + +#include "SharedHandle.h" +#include "RecoverableException.h" + +namespace aria2 { + +namespace bencode { + +class BDE; + +class BDE { +public: + typedef std::map<std::string, BDE> Dict; + typedef std::deque<BDE> List; + typedef int64_t Integer; +private: + enum TYPE{ + TYPE_NONE, + TYPE_INTEGER, + TYPE_STRING, + TYPE_DICT, + TYPE_LIST, + }; + + TYPE _type; + SharedHandle<Dict> _dict; + SharedHandle<List> _list; + SharedHandle<std::string> _string; + SharedHandle<Integer> _integer; + +public: + BDE() throw(); + + static BDE dict() throw(); + + static BDE list() throw(); + + static const BDE none; + + // Test for Null data + // Return true if the type of this object is None. + bool isNone() const throw(); + + ////////////////////////////////////////////////////////////////////////////// + // Integer Interface + + BDE(Integer integer) throw(); + + // Returns true if the type of this object is Integer. + bool isInteger() const throw(); + + // Returns Integer. Requires this object to be Integer. + Integer i() const throw(RecoverableException); + + ////////////////////////////////////////////////////////////////////////////// + // String Interface + + BDE(const std::string& string) throw(); + + // Made explicit to avoid ambiguity with BDE(Integer). + explicit BDE(const char* cstring) throw(); + + BDE(const char* data, size_t length) throw(); + + BDE(const unsigned char* data, size_t length) throw(); + + // Returns true if the type of this object is String. + bool isString() const throw(); + + // Returns std::string. Requires this object to be String + const std::string& s() const throw(RecoverableException); + + ////////////////////////////////////////////////////////////////////////////// + // Dictionary Interface + + // Returns true if the type of this object is Dict. + bool isDict() const throw(); + + // Returns the reference to BDE object associated with given key. + // If the key is not found, new pair with that key is created using default + // values, which is then returned. In other words, this is the same behavior + // of std::map's operator[]. + // Requires this object to be Dict. + BDE& operator[](const std::string& key) throw(RecoverableException); + + // Returns the const reference to BDE ojbect associated with given key. + // If the key is not found, BDE::none is returned. + // Requires this object to be Dict. + const BDE& operator[](const std::string& key) const + throw(RecoverableException); + + // Returns true if the given key is found in dict. + // Requires this object to be Dict. + bool containsKey(const std::string& key) const throw(RecoverableException); + + // Returns a read/write iterator that points to the first pair in the dict. + // Requires this object to be Dict. + Dict::iterator dictBegin() throw(RecoverableException); + + // Returns a read/write read-only iterator that points to the first pair in + // the dict. + // Requires this object to be Dict. + Dict::const_iterator dictBegin() const throw(RecoverableException); + + // Returns a read/write read-only iterator that points to one past the last + // pair in the dict. + // Requires this object to be Dict. + Dict::iterator dictEnd() throw(RecoverableException); + + // Returns a read/write read-only iterator that points to one past the last + // pair in the dict. + // Requires this object to be Dict. + Dict::const_iterator dictEnd() const throw(RecoverableException); + + ////////////////////////////////////////////////////////////////////////////// + // List Interface + + // Returns true if the type of this object is List. + bool isList() const throw(); + + // Appends given bde to list. Required the type of this object to be List. + void append(const BDE& bde) throw(RecoverableException); + + // Alias for append() + void operator<<(const BDE& bde) throw(RecoverableException); + + // Returns the reference of the object at the given index. Required this + // object to be List. + BDE& operator[](size_t index) throw(RecoverableException); + + // Returns the const reference of the object at the given index. + // Required this object to be List. + const BDE& operator[](size_t index) const throw(RecoverableException); + + // Returns a read/write iterator that points to the first object in list. + // Required this object to be List. + List::iterator listBegin() throw(RecoverableException); + + // Returns a read/write read-only iterator that points to the first object + // in list. Required this object to be List. + List::const_iterator listBegin() const throw(RecoverableException); + + // Returns a read/write iterator that points to the one past the last object + // in list. Required this object to be List. + List::iterator listEnd() throw(RecoverableException); + + // Returns a read/write read-only iterator that points to the one past the + // last object in list. Required this object to be List. + List::const_iterator listEnd() const throw(RecoverableException); + + // For List type: Returns size of list. + // For Dict type: Returns size of dict. + size_t size() const throw(RecoverableException); + + // For List type: Returns true if size of list is 0. + // For Dict type: Returns true if size of dict is 0. + bool empty() const throw(RecoverableException); +}; + +BDE decode(std::istream& in) throw(RecoverableException); + +// Decode the data in s. +BDE decode(const std::string& s) throw(RecoverableException); + +BDE decode(const unsigned char* data, size_t length) + throw(RecoverableException); + +BDE decodeFromFile(const std::string& filename) throw(RecoverableException); + +std::string encode(const BDE& bde) throw(); + +} // namespace bencode + +} // namespace aria2 |
