Rewritten Metalink XML parser.

Now we don't strip white spaces while parsing Metalink V3 document.
Expat implementation does not included in this change.
pull/2/head
Tatsuhiro Tsujikawa 2011-11-10 22:38:01 +09:00
parent f114a6fba4
commit 440f29aca3
22 changed files with 1096 additions and 988 deletions

View File

@ -231,10 +231,8 @@ else
AM_CONDITIONAL([ENABLE_METALINK], false) AM_CONDITIONAL([ENABLE_METALINK], false)
fi fi
AM_CONDITIONAL([ENABLE_METALINK_LIBXML2], AM_CONDITIONAL([HAVE_SOME_XMLLIB],
[test "x$enable_metalink" = "xyes" && test "x$have_libxml2" = "xyes"]) [test "x$have_libxml2" = "xyes" || test "x$have_libexpat" = "xyes"])
AM_CONDITIONAL([ENABLE_METALINK_LIBEXPAT],
[test "x$enable_metalink" = "xyes" && test "x$have_libexpat" = "xyes"])
if test "x$have_libxml2" = "xyes" || test "x$have_libexpat" = "xyes"; then if test "x$have_libxml2" = "xyes" || test "x$have_libexpat" = "xyes"; then
enable_xml_rpc=yes enable_xml_rpc=yes

View File

@ -228,6 +228,12 @@ if MINGW_BUILD
SRCS += WinConsoleFile.cc WinConsoleFile.h SRCS += WinConsoleFile.cc WinConsoleFile.h
endif # MINGW_BUILD endif # MINGW_BUILD
if HAVE_SOME_XMLLIB
SRCS += XmlAttr.cc XmlAttr.h\
XmlParser.h\
ParserStateMachine.h
endif # HAVE_SOME_XMLLIB
if ENABLE_XML_RPC if ENABLE_XML_RPC
SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\ SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\
XmlRpcRequestParserStateMachine.cc XmlRpcRequestParserStateMachine.h\ XmlRpcRequestParserStateMachine.cc XmlRpcRequestParserStateMachine.h\
@ -487,7 +493,6 @@ SRCS += Metalinker.cc Metalinker.h\
MetalinkEntry.cc MetalinkEntry.h\ MetalinkEntry.cc MetalinkEntry.h\
MetalinkResource.cc MetalinkResource.h\ MetalinkResource.cc MetalinkResource.h\
MetalinkMetaurl.cc MetalinkMetaurl.h\ MetalinkMetaurl.cc MetalinkMetaurl.h\
MetalinkProcessor.h\
MetalinkParserController.cc MetalinkParserController.h\ MetalinkParserController.cc MetalinkParserController.h\
MetalinkParserStateMachine.cc MetalinkParserStateMachine.h\ MetalinkParserStateMachine.cc MetalinkParserStateMachine.h\
MetalinkParserState.cc MetalinkParserState.h\ MetalinkParserState.cc MetalinkParserState.h\
@ -497,16 +502,17 @@ SRCS += Metalinker.cc Metalinker.h\
Metalink2RequestGroup.cc Metalink2RequestGroup.h\ Metalink2RequestGroup.cc Metalink2RequestGroup.h\
MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h\ MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h\
metalink_helper.cc metalink_helper.h metalink_helper.cc metalink_helper.h
if HAVE_LIBXML2
SRCS += Xml2XmlParser.cc Xml2XmlParser.h
endif # HAVE_LIBXML2
if HAVE_LIBEXPAT
SRCS += ExpatXmlParser.cc ExpatXmlParser.h
endif # HAVE_LIBEXPAT
endif # ENABLE_METALINK endif # ENABLE_METALINK
if ENABLE_METALINK_LIBXML2
SRCS += XML2SAXMetalinkProcessor.cc XML2SAXMetalinkProcessor.h
endif # ENABLE_METALINK_LIBXML2
if ENABLE_METALINK_LIBEXPAT
SRCS += ExpatMetalinkProcessor.cc ExpatMetalinkProcessor.h
endif # ENABLE_METALINK_LIBEXPAT
if !HAVE_ASCTIME_R if !HAVE_ASCTIME_R
SRCS += asctime_r.c asctime_r.h SRCS += asctime_r.c asctime_r.h
endif # !HAVE_ASCTIME_R endif # !HAVE_ASCTIME_R

View File

@ -136,7 +136,7 @@ Metalink2RequestGroup::generate
const std::string& baseUri) const std::string& baseUri)
{ {
std::vector<SharedHandle<MetalinkEntry> > entries; std::vector<SharedHandle<MetalinkEntry> > entries;
metalink::parseAndQuery(entries, binaryStream, option.get(), baseUri); metalink::parseAndQuery(entries, binaryStream.get(), option.get(), baseUri);
std::vector<SharedHandle<RequestGroup> > tempgroups; std::vector<SharedHandle<RequestGroup> > tempgroups;
createRequestGroup(tempgroups, entries, option); createRequestGroup(tempgroups, entries, option);
SharedHandle<MetadataInfo> mi(new MetadataInfo()); SharedHandle<MetadataInfo> mi(new MetadataInfo());

View File

@ -36,23 +36,4 @@
namespace aria2 { namespace aria2 {
XmlAttr::XmlAttr() {}
XmlAttr::XmlAttr(const XmlAttr& c)
: localname(c.localname), prefix(c.prefix), nsUri(c.nsUri), value(c.value)
{}
XmlAttr::~XmlAttr() {}
XmlAttr& XmlAttr::operator=(const XmlAttr& c)
{
if(this != &c) {
localname = c.localname;
prefix = c.prefix;
nsUri = c.nsUri;
value = c.value;
}
return *this;
}
} // namespace aria2 } // namespace aria2

View File

@ -43,18 +43,7 @@
namespace aria2 { namespace aria2 {
class MetalinkParserStateMachine; class MetalinkParserStateMachine;
class XmlAttr;
struct XmlAttr {
std::string localname;
std::string prefix;
std::string nsUri;
std::string value;
XmlAttr();
XmlAttr(const XmlAttr& attr);
~XmlAttr();
XmlAttr& operator=(const XmlAttr&);
};
class MetalinkParserState class MetalinkParserState
{ {
@ -63,16 +52,16 @@ public:
virtual void beginElement virtual void beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* stm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) {} const std::vector<XmlAttr>& attrs) {}
virtual void endElement virtual void endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* stm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) {} const std::string& characters) {}
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const

View File

@ -33,36 +33,69 @@
*/ */
/* copyright --> */ /* copyright --> */
#include "MetalinkParserStateImpl.h" #include "MetalinkParserStateImpl.h"
#include <cstring>
#include "MetalinkParserStateV3Impl.h" #include "MetalinkParserStateV3Impl.h"
#include "MetalinkParserStateV4Impl.h" #include "MetalinkParserStateV4Impl.h"
#include "MetalinkParserStateMachine.h" #include "MetalinkParserStateMachine.h"
#include "XmlAttr.h"
namespace aria2 { namespace aria2 {
namespace {
class FindAttr {
private:
const char* localname_;
const char* nsUri_;
public:
FindAttr(const char* localname, const char* nsUri)
: localname_(localname),
nsUri_(nsUri)
{}
bool operator()(const XmlAttr& attr) const
{
return strcmp(attr.localname, localname_) == 0 &&
(attr.nsUri == 0 || strcmp(attr.nsUri, nsUri_) == 0);
}
};
} // namespace
std::vector<XmlAttr>::const_iterator findAttr
(const std::vector<XmlAttr>& attrs,
const char* localname,
const char* nsUri)
{
return std::find_if(attrs.begin(), attrs.end(), FindAttr(localname, nsUri));
}
void InitialMetalinkParserState::beginElement void InitialMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri == METALINK4_NAMESPACE_URI && localname == "metalink") { if(!nsUri || strcmp(localname, "metalink") != 0) {
stm->setMetalinkStateV4(); psm->setSkipTagState();
} else if(nsUri == METALINK3_NAMESPACE_URI && localname == "metalink") { } else if(strcmp(nsUri, METALINK4_NAMESPACE_URI) == 0) {
stm->setMetalinkState(); psm->setMetalinkStateV4();
} else if(strcmp(nsUri, METALINK3_NAMESPACE_URI) == 0) {
psm->setMetalinkState();
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void SkipTagMetalinkParserState::beginElement void SkipTagMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} // namespace aria2 } // namespace aria2

View File

@ -39,23 +39,28 @@
namespace aria2 { namespace aria2 {
std::vector<XmlAttr>::const_iterator findAttr
(const std::vector<XmlAttr>& attrs,
const char* localname,
const char* nsUri);
class SkipTagMetalinkParserState:public MetalinkParserState class SkipTagMetalinkParserState:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
}; };
class InitialMetalinkParserState:public MetalinkParserState class InitialMetalinkParserState:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
}; };

View File

@ -502,18 +502,18 @@ void MetalinkParserStateMachine::cancelMetaurlTransaction()
} }
void MetalinkParserStateMachine::beginElement void MetalinkParserStateMachine::beginElement
(const std::string& localname, (const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
stateStack_.top()->beginElement(this, localname, prefix, nsUri, attrs); stateStack_.top()->beginElement(this, localname, prefix, nsUri, attrs);
} }
void MetalinkParserStateMachine::endElement void MetalinkParserStateMachine::endElement
(const std::string& localname, (const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stateStack_.top()->endElement(this, localname, prefix, nsUri, characters); stateStack_.top()->endElement(this, localname, prefix, nsUri, characters);

View File

@ -35,7 +35,8 @@
#ifndef D_METALINK_PARSER_STATE_MACHINE_H #ifndef D_METALINK_PARSER_STATE_MACHINE_H
#define D_METALINK_PARSER_STATE_MACHINE_H #define D_METALINK_PARSER_STATE_MACHINE_H
#include "common.h" #include "ParserStateMachine.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <stack> #include <stack>
@ -48,7 +49,7 @@ namespace aria2 {
class Metalinker; class Metalinker;
class MetalinkParserStateMachine { class MetalinkParserStateMachine : public ParserStateMachine {
private: private:
SharedHandle<MetalinkParserController> ctrl_; SharedHandle<MetalinkParserController> ctrl_;
@ -92,7 +93,23 @@ private:
public: public:
MetalinkParserStateMachine(); MetalinkParserStateMachine();
~MetalinkParserStateMachine(); virtual ~MetalinkParserStateMachine();
virtual bool needsCharactersBuffering() const;
virtual bool finished() const;
virtual void beginElement
(const char* localname,
const char* prefix,
const char* nsUri,
const std::vector<XmlAttr>& attrs);
virtual void endElement
(const char* localname,
const char* prefix,
const char* nsUri,
const std::string& characters);
void setSkipTagState(); void setSkipTagState();
@ -138,20 +155,6 @@ public:
void setURLStateV4(); void setURLStateV4();
void setMetaurlStateV4(); void setMetaurlStateV4();
bool finished() const;
void beginElement
(const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
void endElement
(const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
void newEntryTransaction(); void newEntryTransaction();
void setFileNameOfEntry(const std::string& filename); void setFileNameOfEntry(const std::string& filename);
@ -250,8 +253,6 @@ public:
void cancelMetaurlTransaction(); void cancelMetaurlTransaction();
bool needsCharactersBuffering() const;
// Only stores first 10 errors. // Only stores first 10 errors.
void logError(const std::string& log); void logError(const std::string& log);

View File

@ -33,412 +33,385 @@
*/ */
/* copyright --> */ /* copyright --> */
#include "MetalinkParserStateV3Impl.h" #include "MetalinkParserStateV3Impl.h"
#include <cstring>
#include "MetalinkParserStateMachine.h" #include "MetalinkParserStateMachine.h"
#include "RecoverableException.h" #include "RecoverableException.h"
#include "MetalinkResource.h" #include "MetalinkResource.h"
#include "util.h" #include "util.h"
#include "XmlAttr.h"
namespace aria2 { namespace aria2 {
namespace { const char METALINK3_NAMESPACE_URI[] = "http://www.metalinker.org/";
const std::string FILE("file");
const std::string FILES("files");
const std::string HASH("hash");
const std::string LANGUAGE("language");
const std::string LENGTH("length");
const std::string LOCATION("location");
const std::string MAXCONNECTIONS("maxconnections");
// Can't use name VERSION because it is used as a macro.
const std::string METALINK_VERSION("version");
const std::string NAME("name");
const std::string OS("os");
const std::string PIECE("piece");
const std::string PIECES("pieces");
const std::string PREFERENCE("preference");
const std::string RESOURCES("resources");
const std::string SIGNATURE("signature");
const std::string SIZE("size");
const std::string TYPE("type");
const std::string URL("url");
const std::string VERIFICATION("verification");
} // namespace
const std::string METALINK3_NAMESPACE_URI("http://www.metalinker.org/");
namespace { namespace {
class FindAttr { bool checkNsUri(const char* nsUri)
private:
const std::string& localname_;
public:
FindAttr(const std::string& localname):localname_(localname) {}
bool operator()(const XmlAttr& attr) const
{
return attr.localname == localname_ &&
(attr.nsUri.empty() || attr.nsUri == METALINK3_NAMESPACE_URI);
}
};
} // namespace
namespace {
template<typename Container>
typename Container::const_iterator findAttr
(const Container& attrs, const std::string& localname)
{ {
return std::find_if(attrs.begin(), attrs.end(), FindAttr(localname)); return nsUri && strcmp(nsUri, METALINK3_NAMESPACE_URI) == 0;
} }
} // namespace } // namespace
void MetalinkMetalinkParserState::beginElement void MetalinkMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri == METALINK3_NAMESPACE_URI && localname == FILES) { if(checkNsUri(nsUri) && strcmp(localname, "files") == 0) {
stm->setFilesState(); psm->setFilesState();
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void FilesMetalinkParserState::beginElement void FilesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri == METALINK3_NAMESPACE_URI && localname == FILE) { if(checkNsUri(nsUri) && strcmp(localname, "file") == 0) {
stm->setFileState(); psm->setFileState();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "name", METALINK3_NAMESPACE_URI);
if(itr != attrs.end()) { if(itr != attrs.end()) {
std::string name = util::strip((*itr).value); std::string name((*itr).value, (*itr).valueLength);
if(name.empty() || util::detectDirTraversal(name)) { if(name.empty() || util::detectDirTraversal(name)) {
return; return;
} }
stm->newEntryTransaction(); psm->newEntryTransaction();
stm->setFileNameOfEntry(name); psm->setFileNameOfEntry(name);
} }
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void FileMetalinkParserState::beginElement void FileMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri != METALINK3_NAMESPACE_URI) { if(!checkNsUri(nsUri)) {
stm->setSkipTagState(); psm->setSkipTagState();
} else if(localname == SIZE) { } else if(strcmp(localname, "size") == 0) {
stm->setSizeState(); psm->setSizeState();
} else if(localname == METALINK_VERSION) { } else if(strcmp(localname, "version") == 0) {
stm->setVersionState(); psm->setVersionState();
} else if(localname == LANGUAGE) { } else if(strcmp(localname, "language") == 0) {
stm->setLanguageState(); psm->setLanguageState();
} else if(localname == OS) { } else if(strcmp(localname, "os") == 0) {
stm->setOSState(); psm->setOSState();
} else if(localname == VERIFICATION) { } else if(strcmp(localname, "verification") == 0) {
stm->setVerificationState(); psm->setVerificationState();
} else if(localname == RESOURCES) { } else if(strcmp(localname, "resources") == 0) {
stm->setResourcesState(); psm->setResourcesState();
int maxConnections; int maxConnections;
{ std::vector<XmlAttr>::const_iterator itr =
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs,MAXCONNECTIONS); findAttr(attrs, "maxconnections", METALINK3_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
maxConnections = -1;
} else {
if(!util::parseIntNoThrow
(maxConnections,(*itr).value, (*itr).value+(*itr).valueLength) ||
maxConnections <= 0) {
maxConnections = -1; maxConnections = -1;
} else {
try {
maxConnections =
util::parseInt((*itr).value.begin(), (*itr).value.end());
} catch(RecoverableException& e) {
maxConnections = -1;
}
} }
} }
stm->setMaxConnectionsOfEntry(maxConnections); psm->setMaxConnectionsOfEntry(maxConnections);
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void FileMetalinkParserState::endElement void FileMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->commitEntryTransaction(); psm->commitEntryTransaction();
} }
void SizeMetalinkParserState::endElement void SizeMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
try { // current metalink specification doesn't require size element.
stm->setFileLengthOfEntry int64_t size;
(util::parseULLInt(characters.begin(), characters.end())); if(util::parseLLIntNoThrow(size, characters.begin(), characters.end()) &&
} catch(RecoverableException& e) { size >= 0) {
// current metalink specification doesn't require size element. psm->setFileLengthOfEntry(size);
} }
} }
void VersionMetalinkParserState::endElement void VersionMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setVersionOfEntry(util::strip(characters)); psm->setVersionOfEntry(characters);
} }
void LanguageMetalinkParserState::endElement void LanguageMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setLanguageOfEntry(util::strip(characters)); psm->setLanguageOfEntry(characters);
} }
void OSMetalinkParserState::endElement void OSMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setOSOfEntry(util::strip(characters)); psm->setOSOfEntry(characters);
} }
void VerificationMetalinkParserState::beginElement void VerificationMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri != METALINK3_NAMESPACE_URI) { if(!checkNsUri(nsUri)) {
stm->setSkipTagState(); psm->setSkipTagState();
} else } else
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
if(localname == HASH) { if(strcmp(localname, "hash") == 0) {
stm->setHashState(); psm->setHashState();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE); std::vector<XmlAttr>::const_iterator itr =
if(itr == attrs.end()) { findAttr(attrs, "type", METALINK3_NAMESPACE_URI);
return; if(itr == attrs.end()) {
} else { return;
std::string type = util::strip((*itr).value); } else {
stm->newChecksumTransaction(); psm->newChecksumTransaction();
stm->setTypeOfChecksum(type); psm->setTypeOfChecksum(std::string((*itr).value, (*itr).valueLength));
} }
} else if(localname == PIECES) { } else if(strcmp(localname, "pieces") == 0) {
stm->setPiecesState(); psm->setPiecesState();
try { int32_t length;
size_t length;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LENGTH); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "length", METALINK3_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
return; return;
} else { } else {
length = util::parseInt((*itr).value.begin(), (*itr).value.end()); if(!util::parseIntNoThrow
(length, (*itr).value, (*itr).value+(*itr).valueLength) ||
length < 0) {
return;
}
} }
} }
std::string type; std::string type;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "type", METALINK3_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
return; return;
} else { } else {
type = util::strip((*itr).value); type.assign((*itr).value, (*itr).valueLength);
} }
} }
stm->newChunkChecksumTransaction(); psm->newChunkChecksumTransaction();
stm->setLengthOfChunkChecksum(length); psm->setLengthOfChunkChecksum(length);
stm->setTypeOfChunkChecksum(type); psm->setTypeOfChunkChecksum(type);
} catch(RecoverableException& e) { } else
stm->cancelChunkChecksumTransaction();
}
} else
#endif // ENABLE_MESSAGE_DIGEST #endif // ENABLE_MESSAGE_DIGEST
if(localname == SIGNATURE) { if(strcmp(localname, "signature") == 0) {
stm->setSignatureState(); psm->setSignatureState();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE); std::vector<XmlAttr>::const_iterator itr =
if(itr == attrs.end()) { findAttr(attrs, "type", METALINK3_NAMESPACE_URI);
return; if(itr == attrs.end()) {
} else { return;
stm->newSignatureTransaction(); } else {
stm->setTypeOfSignature(util::strip((*itr).value)); psm->newSignatureTransaction();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, FILE); psm->setTypeOfSignature
if(itr != attrs.end()) { (std::string((*itr).value, (*itr).valueLength));
std::string file = util::strip((*itr).value); std::vector<XmlAttr>::const_iterator itr =
if(!util::detectDirTraversal(file)) { findAttr(attrs, "file", METALINK3_NAMESPACE_URI);
stm->setFileOfSignature(file); if(itr != attrs.end()) {
std::string file((*itr).value, (*itr).valueLength);
if(!util::detectDirTraversal(file)) {
psm->setFileOfSignature(file);
}
} }
} }
} else {
psm->setSkipTagState();
} }
} else {
stm->setSkipTagState();
}
} }
void HashMetalinkParserState::endElement void HashMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setHashOfChecksum(util::strip(characters)); psm->setHashOfChecksum(characters);
stm->commitChecksumTransaction(); psm->commitChecksumTransaction();
} }
void PiecesMetalinkParserState::beginElement void PiecesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri == METALINK3_NAMESPACE_URI && localname == HASH) { if(checkNsUri(nsUri) && strcmp(localname, "hash") == 0) {
stm->setPieceHashState(); psm->setPieceHashState();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, PIECE); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "piece", METALINK3_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
stm->cancelChunkChecksumTransaction(); psm->cancelChunkChecksumTransaction();
} else { } else {
try { int32_t idx;
stm->createNewHashOfChunkChecksum if(util::parseIntNoThrow
(util::parseInt((*itr).value.begin(), (*itr).value.end())); (idx, (*itr).value, (*itr).value+(*itr).valueLength) && idx >= 0) {
} catch(RecoverableException& e) { psm->createNewHashOfChunkChecksum(idx);
stm->cancelChunkChecksumTransaction(); } else {
psm->cancelChunkChecksumTransaction();
} }
} }
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void PiecesMetalinkParserState::endElement void PiecesMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->commitChunkChecksumTransaction(); psm->commitChunkChecksumTransaction();
} }
void PieceHashMetalinkParserState::endElement void PieceHashMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setMessageDigestOfChunkChecksum(util::strip(characters)); psm->setMessageDigestOfChunkChecksum(characters);
stm->addHashOfChunkChecksum(); psm->addHashOfChunkChecksum();
} }
void SignatureMetalinkParserState::endElement void SignatureMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setBodyOfSignature(util::strip(characters)); psm->setBodyOfSignature(characters);
stm->commitSignatureTransaction(); psm->commitSignatureTransaction();
} }
void ResourcesMetalinkParserState::beginElement void ResourcesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri != METALINK3_NAMESPACE_URI) { if(!checkNsUri(nsUri)) {
stm->setSkipTagState(); psm->setSkipTagState();
} else if(localname == URL) { } else if(strcmp(localname, "url") == 0) {
stm->setURLState(); psm->setURLState();
std::string type; std::string type;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "type", METALINK3_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
return; return;
} else { } else {
type = util::strip((*itr).value); type.assign((*itr).value, (*itr).valueLength);
} }
} }
std::string location; std::string location;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LOCATION); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "location", METALINK3_NAMESPACE_URI);
if(itr != attrs.end()) { if(itr != attrs.end()) {
location = util::strip((*itr).value); location.assign((*itr).value, (*itr).valueLength);
} }
} }
int preference; int preference;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, PREFERENCE); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "preference", METALINK3_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
preference = MetalinkResource::getLowestPriority(); preference = MetalinkResource::getLowestPriority();
} else { } else {
try { if(util::parseIntNoThrow
(preference, (*itr).value, (*itr).value+(*itr).valueLength) &&
preference >= 0) {
// In Metalink3Spec, highest prefernce value is 100. We // In Metalink3Spec, highest prefernce value is 100. We
// uses Metalink4Spec priority unit system in which 1 is // use Metalink4Spec priority unit system in which 1 is
// higest. // higest.
preference = preference = 101-preference;
101-util::parseInt((*itr).value.begin(), (*itr).value.end()); } else {
} catch(RecoverableException& e) {
preference = MetalinkResource::getLowestPriority(); preference = MetalinkResource::getLowestPriority();
} }
} }
} }
int maxConnections; int maxConnections;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs,MAXCONNECTIONS); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "maxconnections", METALINK3_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
maxConnections = -1; maxConnections = -1;
} else { } else {
try { if(!util::parseIntNoThrow
maxConnections = (maxConnections, (*itr).value, (*itr).value+(*itr).valueLength) ||
util::parseInt((*itr).value.begin(), (*itr).value.end()); maxConnections <= 0) {
} catch(RecoverableException& e) {
maxConnections = -1; maxConnections = -1;
} }
} }
} }
stm->newResourceTransaction(); psm->newResourceTransaction();
stm->setTypeOfResource(type); psm->setTypeOfResource(type);
stm->setLocationOfResource(location); psm->setLocationOfResource(location);
stm->setPriorityOfResource(preference); psm->setPriorityOfResource(preference);
stm->setMaxConnectionsOfResource(maxConnections); psm->setMaxConnectionsOfResource(maxConnections);
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void URLMetalinkParserState::endElement void URLMetalinkParserState::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setURLOfResource(util::strip(characters)); psm->setURLOfResource(characters);
stm->commitResourceTransaction(); psm->commitResourceTransaction();
} }
} // namespace aria2 } // namespace aria2

View File

@ -40,25 +40,25 @@
namespace aria2 { namespace aria2 {
extern const std::string METALINK3_NAMESPACE_URI; extern const char METALINK3_NAMESPACE_URI[];
class MetalinkMetalinkParserState:public MetalinkParserState class MetalinkMetalinkParserState:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
}; };
class FilesMetalinkParserState:public MetalinkParserState class FilesMetalinkParserState:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -70,16 +70,16 @@ public:
class FileMetalinkParserState:public MetalinkParserState class FileMetalinkParserState:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -91,10 +91,10 @@ public:
class SizeMetalinkParserState:public SkipTagMetalinkParserState class SizeMetalinkParserState:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -106,10 +106,10 @@ public:
class VersionMetalinkParserState:public SkipTagMetalinkParserState class VersionMetalinkParserState:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -121,10 +121,10 @@ public:
class LanguageMetalinkParserState:public SkipTagMetalinkParserState class LanguageMetalinkParserState:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -136,10 +136,10 @@ public:
class OSMetalinkParserState:public SkipTagMetalinkParserState class OSMetalinkParserState:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -151,10 +151,10 @@ public:
class VerificationMetalinkParserState:public MetalinkParserState class VerificationMetalinkParserState:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -166,10 +166,10 @@ public:
class HashMetalinkParserState:public SkipTagMetalinkParserState class HashMetalinkParserState:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -181,16 +181,16 @@ public:
class PiecesMetalinkParserState:public MetalinkParserState class PiecesMetalinkParserState:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -202,10 +202,10 @@ public:
class PieceHashMetalinkParserState:public SkipTagMetalinkParserState class PieceHashMetalinkParserState:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -217,10 +217,10 @@ public:
class SignatureMetalinkParserState:public SkipTagMetalinkParserState class SignatureMetalinkParserState:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -232,10 +232,10 @@ public:
class ResourcesMetalinkParserState:public MetalinkParserState class ResourcesMetalinkParserState:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -247,10 +247,10 @@ public:
class URLMetalinkParserState:public SkipTagMetalinkParserState class URLMetalinkParserState:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const

View File

@ -33,370 +33,343 @@
*/ */
/* copyright --> */ /* copyright --> */
#include "MetalinkParserStateV4Impl.h" #include "MetalinkParserStateV4Impl.h"
#include <cstring>
#include "MetalinkParserStateMachine.h" #include "MetalinkParserStateMachine.h"
#include "RecoverableException.h" #include "RecoverableException.h"
#include "MetalinkResource.h" #include "MetalinkResource.h"
#include "util.h" #include "util.h"
#include "XmlAttr.h"
namespace aria2 { namespace aria2 {
namespace { const char METALINK4_NAMESPACE_URI[] = "urn:ietf:params:xml:ns:metalink";
const std::string FILE("file");
const std::string HASH("hash");
const std::string LANGUAGE("language");
const std::string LENGTH("length");
const std::string LOCATION("location");
const std::string METALINK("metalink");
// Can't use name VERSION because it is used as a macro.
const std::string METALINK_VERSION("version");
const std::string METAURL("metaurl");
const std::string NAME("name");
const std::string OS("os");
const std::string PIECE("piece");
const std::string PIECES("pieces");
const std::string PRIORITY("priority");
const std::string SIGNATURE("signature");
const std::string SIZE("size");
const std::string TYPE("type");
const std::string MEDIATYPE("mediatype");
const std::string URL("url");
} // namespace
const std::string METALINK4_NAMESPACE_URI("urn:ietf:params:xml:ns:metalink");
namespace { namespace {
class FindAttr { bool checkNsUri(const char* nsUri)
private:
const std::string& localname_;
public:
FindAttr(const std::string& localname):localname_(localname) {}
bool operator()(const XmlAttr& attr) const
{
return attr.localname == localname_ &&
(attr.nsUri.empty() || attr.nsUri == METALINK4_NAMESPACE_URI);
}
};
} // namespace
namespace {
template<typename Container>
typename Container::const_iterator findAttr
(const Container& attrs, const std::string& localname)
{ {
return std::find_if(attrs.begin(), attrs.end(), FindAttr(localname)); return nsUri && strcmp(nsUri, METALINK4_NAMESPACE_URI) == 0;
} }
} // namespace } // namespace
void MetalinkMetalinkParserStateV4::beginElement void MetalinkMetalinkParserStateV4::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri == METALINK4_NAMESPACE_URI && localname == FILE) { if(checkNsUri(nsUri) && strcmp(localname, "file") == 0) {
stm->setFileStateV4(); psm->setFileStateV4();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME); std::vector<XmlAttr>::const_iterator itr =
if(itr == attrs.end() || (*itr).value.empty()) { findAttr(attrs, "name", METALINK4_NAMESPACE_URI);
stm->logError("Missing file@name"); if(itr == attrs.end() || (*itr).valueLength == 0) {
return; psm->logError("Missing file@name");
} else if(util::detectDirTraversal((*itr).value)) {
stm->logError("Bad file@name");
return; return;
} }
stm->newEntryTransaction(); std::string name((*itr).value, (*itr).valueLength);
stm->setFileNameOfEntry((*itr).value); if(util::detectDirTraversal(name)) {
psm->logError("Bad file@name");
return;
}
psm->newEntryTransaction();
psm->setFileNameOfEntry(name);
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void FileMetalinkParserStateV4::beginElement void FileMetalinkParserStateV4::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri != METALINK4_NAMESPACE_URI) { if(!checkNsUri(nsUri)) {
stm->setSkipTagState(); psm->setSkipTagState();
} else if(localname == SIZE) { } else if(strcmp(localname, "size") == 0) {
stm->setSizeStateV4(); psm->setSizeStateV4();
} else if(localname == METALINK_VERSION) { } else if(strcmp(localname, "version") == 0) {
stm->setVersionStateV4(); psm->setVersionStateV4();
} else if(localname == LANGUAGE) { } else if(strcmp(localname, "language") == 0) {
stm->setLanguageStateV4(); psm->setLanguageStateV4();
} else if(localname == OS) { } else if(strcmp(localname, "os") == 0) {
stm->setOSStateV4(); psm->setOSStateV4();
} else if(localname == METAURL) { } else if(strcmp(localname, "metaurl") == 0) {
stm->setMetaurlStateV4(); psm->setMetaurlStateV4();
std::string name; std::string name;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "name", METALINK4_NAMESPACE_URI);
if(itr != attrs.end()) { if(itr != attrs.end()) {
if((*itr).value.empty() || util::detectDirTraversal((*itr).value)) { name.assign((*itr).value, (*itr).valueLength);
stm->logError("Bad metaurl@name"); if(name.empty() || util::detectDirTraversal(name)) {
psm->logError("Bad metaurl@name");
return; return;
} else {
name = (*itr).value;
} }
} }
} }
int priority; int priority;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, PRIORITY); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "priority", METALINK4_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
priority = MetalinkResource::getLowestPriority(); priority = MetalinkResource::getLowestPriority();
} else { } else {
try { if(util::parseIntNoThrow
priority = util::parseInt((*itr).value.begin(), (*itr).value.end()); (priority, (*itr).value, (*itr).value+(*itr).valueLength)) {
if(priority < 1 || MetalinkResource::getLowestPriority() < priority) { if(priority < 1 || MetalinkResource::getLowestPriority() < priority) {
stm->logError("metaurl@priority is out of range"); psm->logError("metaurl@priority is out of range");
return; return;
} }
} catch(RecoverableException& e) { } else {
stm->logError("Bad metaurl@priority"); psm->logError("Bad metaurl@priority");
return; return;
} }
} }
} }
std::string mediatype; std::string mediatype;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, MEDIATYPE); std::vector<XmlAttr>::const_iterator itr =
if(itr == attrs.end() || (*itr).value.empty()) { findAttr(attrs, "mediatype", METALINK4_NAMESPACE_URI);
stm->logError("Missing metaurl@mediatype"); if(itr == attrs.end() || (*itr).valueLength == 0) {
psm->logError("Missing metaurl@mediatype");
return; return;
} else { } else {
mediatype = (*itr).value; mediatype.assign((*itr).value, (*itr).valueLength);
} }
} }
stm->newMetaurlTransaction(); psm->newMetaurlTransaction();
stm->setPriorityOfMetaurl(priority); psm->setPriorityOfMetaurl(priority);
stm->setMediatypeOfMetaurl(mediatype); psm->setMediatypeOfMetaurl(mediatype);
stm->setNameOfMetaurl(name); psm->setNameOfMetaurl(name);
} else if(localname == URL) { } else if(strcmp(localname, "url") == 0) {
stm->setURLStateV4(); psm->setURLStateV4();
std::string location; std::string location;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LOCATION); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "location", METALINK4_NAMESPACE_URI);
if(itr != attrs.end()) { if(itr != attrs.end()) {
location = (*itr).value; location.assign((*itr).value, (*itr).valueLength);
} }
} }
int priority; int priority;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, PRIORITY); std::vector<XmlAttr>::const_iterator itr =
findAttr(attrs, "priority", METALINK4_NAMESPACE_URI);
if(itr == attrs.end()) { if(itr == attrs.end()) {
priority = MetalinkResource::getLowestPriority(); priority = MetalinkResource::getLowestPriority();
} else { } else {
try { if(util::parseIntNoThrow
priority = util::parseInt((*itr).value.begin(), (*itr).value.end()); (priority, (*itr).value, (*itr).value+(*itr).valueLength)) {
if(priority < 1 || MetalinkResource::getLowestPriority() < priority) { if(priority < 1 || MetalinkResource::getLowestPriority() < priority) {
stm->logError("url@priority is out of range"); psm->logError("url@priority is out of range");
return; return;
} }
} catch(RecoverableException& e) { } else {
stm->logError("Bad url@priority"); psm->logError("Bad url@priority");
return; return;
} }
} }
} }
stm->newResourceTransaction(); psm->newResourceTransaction();
stm->setLocationOfResource(location); psm->setLocationOfResource(location);
stm->setPriorityOfResource(priority); psm->setPriorityOfResource(priority);
} }
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
else if(localname == HASH) { else if(strcmp(localname, "hash") == 0) {
stm->setHashStateV4(); psm->setHashStateV4();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE); std::vector<XmlAttr>::const_iterator itr =
if(itr == attrs.end() || (*itr).value.empty()) { findAttr(attrs, "type", METALINK4_NAMESPACE_URI);
stm->logError("Missing hash@type"); if(itr == attrs.end() || (*itr).valueLength == 0) {
psm->logError("Missing hash@type");
return; return;
} else { } else {
std::string type = (*itr).value; psm->newChecksumTransaction();
stm->newChecksumTransaction(); psm->setTypeOfChecksum(std::string((*itr).value, (*itr).valueLength));
stm->setTypeOfChecksum(type);
} }
} else if(localname == PIECES) { } else if(strcmp(localname, "pieces") == 0) {
stm->setPiecesStateV4(); psm->setPiecesStateV4();
size_t length; int32_t length;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LENGTH); std::vector<XmlAttr>::const_iterator itr =
if(itr == attrs.end() || (*itr).value.empty()) { findAttr(attrs, "length", METALINK4_NAMESPACE_URI);
stm->logError("Missing pieces@length"); if(itr == attrs.end() || (*itr).valueLength == 0) {
psm->logError("Missing pieces@length");
return;
} else if(!util::parseIntNoThrow
(length, (*itr).value, (*itr).value+(*itr).valueLength) ||
length < 0) {
psm->logError("Bad pieces@length");
return; return;
} else {
try {
length = util::parseInt((*itr).value.begin(), (*itr).value.end());
} catch(RecoverableException& e) {
stm->logError("Bad pieces@length");
return;
}
} }
} }
std::string type; std::string type;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE); std::vector<XmlAttr>::const_iterator itr =
if(itr == attrs.end() || (*itr).value.empty()) { findAttr(attrs, "type", METALINK4_NAMESPACE_URI);
stm->logError("Missing pieces@type"); if(itr == attrs.end() || (*itr).valueLength == 0) {
psm->logError("Missing pieces@type");
return; return;
} else { } else {
type = (*itr).value; type.assign((*itr).value, (*itr).valueLength);
} }
} }
stm->newChunkChecksumTransactionV4(); psm->newChunkChecksumTransactionV4();
stm->setLengthOfChunkChecksumV4(length); psm->setLengthOfChunkChecksumV4(length);
stm->setTypeOfChunkChecksumV4(type); psm->setTypeOfChunkChecksumV4(type);
} }
#endif // ENABLE_MESSAGE_DIGEST #endif // ENABLE_MESSAGE_DIGEST
else if(localname == SIGNATURE) { else if(strcmp(localname, "signature") == 0) {
stm->setSignatureStateV4(); psm->setSignatureStateV4();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, MEDIATYPE); std::vector<XmlAttr>::const_iterator itr =
if(itr == attrs.end() || (*itr).value.empty()) { findAttr(attrs, "mediatype", METALINK4_NAMESPACE_URI);
stm->logError("Missing signature@mediatype"); if(itr == attrs.end() || (*itr).valueLength == 0) {
psm->logError("Missing signature@mediatype");
return; return;
} }
stm->newSignatureTransaction(); psm->newSignatureTransaction();
stm->setTypeOfSignature((*itr).value); psm->setTypeOfSignature(std::string((*itr).value, (*itr).valueLength));
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void FileMetalinkParserStateV4::endElement void FileMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->commitEntryTransaction(); psm->commitEntryTransaction();
} }
void SizeMetalinkParserStateV4::endElement void SizeMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
try { int64_t size;
stm->setFileLengthOfEntry if(util::parseLLIntNoThrow(size, characters.begin(), characters.end()) &&
(util::parseULLInt(characters.begin(), characters.end())); size >= 0) {
} catch(RecoverableException& e) { psm->setFileLengthOfEntry(size);
stm->cancelEntryTransaction(); } else {
stm->logError("Bad size"); psm->cancelEntryTransaction();
psm->logError("Bad size");
} }
} }
void VersionMetalinkParserStateV4::endElement void VersionMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setVersionOfEntry(characters); psm->setVersionOfEntry(characters);
} }
void LanguageMetalinkParserStateV4::endElement void LanguageMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setLanguageOfEntry(characters); psm->setLanguageOfEntry(characters);
} }
void OSMetalinkParserStateV4::endElement void OSMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setOSOfEntry(characters); psm->setOSOfEntry(characters);
} }
void HashMetalinkParserStateV4::endElement void HashMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setHashOfChecksum(characters); psm->setHashOfChecksum(characters);
stm->commitChecksumTransaction(); psm->commitChecksumTransaction();
} }
void PiecesMetalinkParserStateV4::beginElement void PiecesMetalinkParserStateV4::beginElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri == METALINK4_NAMESPACE_URI && localname == HASH) { if(checkNsUri(nsUri) && strcmp(localname, "hash") == 0) {
stm->setPieceHashStateV4(); psm->setPieceHashStateV4();
} else { } else {
stm->setSkipTagState(); psm->setSkipTagState();
} }
} }
void PiecesMetalinkParserStateV4::endElement void PiecesMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->commitChunkChecksumTransactionV4(); psm->commitChunkChecksumTransactionV4();
} }
void PieceHashMetalinkParserStateV4::endElement void PieceHashMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->addHashOfChunkChecksumV4(characters); psm->addHashOfChunkChecksumV4(characters);
} }
void SignatureMetalinkParserStateV4::endElement void SignatureMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setBodyOfSignature(characters); psm->setBodyOfSignature(characters);
stm->commitSignatureTransaction(); psm->commitSignatureTransaction();
} }
void URLMetalinkParserStateV4::endElement void URLMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setURLOfResource(characters); psm->setURLOfResource(characters);
stm->commitResourceTransaction(); psm->commitResourceTransaction();
} }
void MetaurlMetalinkParserStateV4::endElement void MetaurlMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm, (MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters) const std::string& characters)
{ {
stm->setURLOfMetaurl(characters); psm->setURLOfMetaurl(characters);
stm->commitMetaurlTransaction(); psm->commitMetaurlTransaction();
} }
} // namespace aria2 } // namespace aria2

View File

@ -40,31 +40,31 @@
namespace aria2 { namespace aria2 {
extern const std::string METALINK4_NAMESPACE_URI; extern const char METALINK4_NAMESPACE_URI[];
class MetalinkMetalinkParserStateV4:public MetalinkParserState class MetalinkMetalinkParserStateV4:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
}; };
class FileMetalinkParserStateV4:public MetalinkParserState class FileMetalinkParserStateV4:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -76,10 +76,10 @@ public:
class SizeMetalinkParserStateV4:public SkipTagMetalinkParserState class SizeMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -91,10 +91,10 @@ public:
class VersionMetalinkParserStateV4:public SkipTagMetalinkParserState class VersionMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -106,10 +106,10 @@ public:
class LanguageMetalinkParserStateV4:public SkipTagMetalinkParserState class LanguageMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -121,10 +121,10 @@ public:
class OSMetalinkParserStateV4:public SkipTagMetalinkParserState class OSMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -136,10 +136,10 @@ public:
class HashMetalinkParserStateV4:public SkipTagMetalinkParserState class HashMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -151,16 +151,16 @@ public:
class PiecesMetalinkParserStateV4:public MetalinkParserState class PiecesMetalinkParserStateV4:public MetalinkParserState
{ {
public: public:
virtual void beginElement(MetalinkParserStateMachine* stm, virtual void beginElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::vector<XmlAttr>& attrs); const std::vector<XmlAttr>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -172,10 +172,10 @@ public:
class PieceHashMetalinkParserStateV4:public SkipTagMetalinkParserState class PieceHashMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -187,10 +187,10 @@ public:
class SignatureMetalinkParserStateV4:public SkipTagMetalinkParserState class SignatureMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -202,10 +202,10 @@ public:
class URLMetalinkParserStateV4:public SkipTagMetalinkParserState class URLMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const
@ -217,10 +217,10 @@ public:
class MetaurlMetalinkParserStateV4:public SkipTagMetalinkParserState class MetaurlMetalinkParserStateV4:public SkipTagMetalinkParserState
{ {
public: public:
virtual void endElement(MetalinkParserStateMachine* stm, virtual void endElement(MetalinkParserStateMachine* psm,
const std::string& localname, const char* localname,
const std::string& prefix, const char* prefix,
const std::string& nsUri, const char* nsUri,
const std::string& characters); const std::string& characters);
virtual bool needsCharactersBuffering() const virtual bool needsCharactersBuffering() const

70
src/ParserStateMachine.h Normal file
View File

@ -0,0 +1,70 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2011 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 --> */
#ifndef D_PARSER_STATE_MACHINE_H
#define D_PARSER_STATE_MACHINE_H
#include "common.h"
#include <string>
#include <vector>
namespace aria2 {
class XmlAttr;
class ParserStateMachine {
public:
virtual ~ParserStateMachine() {}
virtual bool needsCharactersBuffering() const = 0;
virtual bool finished() const = 0;
virtual void beginElement
(const char* localname,
const char* prefix,
const char* nsUri,
const std::vector<XmlAttr>& attrs) = 0;
virtual void endElement
(const char* localname,
const char* prefix,
const char* nsUri,
const std::string& characters) = 0;
};
} // namespace aria2
#endif // D_PARSER_STATE_MACHINE_H

View File

@ -2,7 +2,7 @@
/* /*
* aria2 - The high speed download utility * aria2 - The high speed download utility
* *
* Copyright (C) 2006 Tatsuhiro Tsujikawa * Copyright (C) 2011 Tatsuhiro Tsujikawa
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -32,75 +32,70 @@
* files in the program, then also delete it here. * files in the program, then also delete it here.
*/ */
/* copyright --> */ /* copyright --> */
#include "XML2SAXMetalinkProcessor.h" #include "XmlParser.h"
#include <cassert> #include <cassert>
#include <cstring>
#include <deque>
#include <libxml/parser.h>
#include "a2io.h"
#include "BinaryStream.h" #include "BinaryStream.h"
#include "MetalinkParserStateMachine.h" #include "ParserStateMachine.h"
#include "Metalinker.h"
#include "MetalinkEntry.h"
#include "util.h"
#include "message.h" #include "message.h"
#include "DlAbortEx.h" #include "DlAbortEx.h"
#include "A2STR.h" #include "A2STR.h"
#include "error_code.h" #include "a2functional.h"
#include "XmlAttr.h"
namespace aria2 { namespace aria2 {
namespace { namespace {
class SessionData { struct SessionData {
public:
SharedHandle<MetalinkParserStateMachine> stm_;
std::deque<std::string> charactersStack_; std::deque<std::string> charactersStack_;
ParserStateMachine* psm_;
SessionData(const SharedHandle<MetalinkParserStateMachine>& stm):stm_(stm) {} SessionData(ParserStateMachine* psm)
: psm_(psm)
{}
}; };
} // namespace } // namespace
namespace { namespace {
void mlStartElement void mlStartElement
(void* userData, (void* userData,
const xmlChar* srcLocalname, const xmlChar* localname,
const xmlChar* srcPrefix, const xmlChar* prefix,
const xmlChar* srcNsUri, const xmlChar* nsUri,
int numNamespaces, int numNamespaces,
const xmlChar **namespaces, const xmlChar** namespaces,
int numAttrs, int numAttrs,
int numDefaulted, int numDefaulted,
const xmlChar **attrs) const xmlChar** attrs)
{ {
SessionData* sd = reinterpret_cast<SessionData*>(userData); SessionData* sd = reinterpret_cast<SessionData*>(userData);
std::vector<XmlAttr> xmlAttrs; std::vector<XmlAttr> xmlAttrs;
size_t index = 0; const char** pattrs = reinterpret_cast<const char**>(attrs);
for(int attrIndex = 0; attrIndex < numAttrs; ++attrIndex, index += 5) { for(size_t i = 0, max = numAttrs*5; i < max; i += 5) {
XmlAttr xmlAttr; XmlAttr xmlAttr;
assert(attrs[index]); assert(pattrs[i]);
xmlAttr.localname = reinterpret_cast<const char*>(attrs[index]); xmlAttr.localname = pattrs[i];
if(attrs[index+1]) { if(pattrs[i+1]) {
xmlAttr.prefix = reinterpret_cast<const char*>(attrs[index+1]); xmlAttr.prefix = pattrs[i+1];
} }
if(attrs[index+2]) { if(attrs[i+2]) {
xmlAttr.nsUri = reinterpret_cast<const char*>(attrs[index+2]); xmlAttr.nsUri = pattrs[i+2];
} }
const char* valueBegin = reinterpret_cast<const char*>(attrs[index+3]); xmlAttr.value = pattrs[i+3];
const char* valueEnd = reinterpret_cast<const char*>(attrs[index+4]); xmlAttr.valueLength = pattrs[i+4]-xmlAttr.value;
xmlAttr.value.assign(valueBegin, valueEnd);
xmlAttrs.push_back(xmlAttr); xmlAttrs.push_back(xmlAttr);
} }
assert(srcLocalname); sd->psm_->beginElement
std::string localname = reinterpret_cast<const char*>(srcLocalname); (reinterpret_cast<const char*>(localname),
std::string prefix; reinterpret_cast<const char*>(prefix),
std::string nsUri; reinterpret_cast<const char*>(nsUri),
if(srcPrefix) { xmlAttrs);
prefix = reinterpret_cast<const char*>(srcPrefix); if(sd->psm_->needsCharactersBuffering()) {
}
if(srcNsUri) {
nsUri = reinterpret_cast<const char*>(srcNsUri);
}
sd->stm_->beginElement(localname, prefix, nsUri, xmlAttrs);
if(sd->stm_->needsCharactersBuffering()) {
sd->charactersStack_.push_front(A2STR::NIL); sd->charactersStack_.push_front(A2STR::NIL);
} }
} }
@ -109,26 +104,21 @@ void mlStartElement
namespace { namespace {
void mlEndElement void mlEndElement
(void* userData, (void* userData,
const xmlChar* srcLocalname, const xmlChar* localname,
const xmlChar* srcPrefix, const xmlChar* prefix,
const xmlChar* srcNsUri) const xmlChar* nsUri)
{ {
SessionData* sd = reinterpret_cast<SessionData*>(userData); SessionData* sd = reinterpret_cast<SessionData*>(userData);
std::string characters; std::string characters;
if(sd->stm_->needsCharactersBuffering()) { if(sd->psm_->needsCharactersBuffering()) {
characters = sd->charactersStack_.front(); characters = sd->charactersStack_.front();
sd->charactersStack_.pop_front(); sd->charactersStack_.pop_front();
} }
std::string localname = reinterpret_cast<const char*>(srcLocalname); sd->psm_->endElement
std::string prefix; (reinterpret_cast<const char*>(localname),
std::string nsUri; reinterpret_cast<const char*>(prefix),
if(srcPrefix) { reinterpret_cast<const char*>(nsUri),
prefix = reinterpret_cast<const char*>(srcPrefix); characters);
}
if(srcNsUri) {
nsUri = reinterpret_cast<const char*>(srcNsUri);
}
sd->stm_->endElement(localname, prefix, nsUri, characters);
} }
} // namespace } // namespace
@ -136,7 +126,7 @@ namespace {
void mlCharacters(void* userData, const xmlChar* ch, int len) void mlCharacters(void* userData, const xmlChar* ch, int len)
{ {
SessionData* sd = reinterpret_cast<SessionData*>(userData); SessionData* sd = reinterpret_cast<SessionData*>(userData);
if(sd->stm_->needsCharactersBuffering()) { if(sd->psm_->needsCharactersBuffering()) {
sd->charactersStack_.front().append(&ch[0], &ch[len]); sd->charactersStack_.front().append(&ch[0], &ch[len]);
} }
} }
@ -180,89 +170,62 @@ xmlSAXHandler mySAXHandler =
}; };
} // namespace } // namespace
MetalinkProcessor::MetalinkProcessor() {} XmlParser::XmlParser(ParserStateMachine* psm)
: psm_(psm)
{}
MetalinkProcessor::~MetalinkProcessor() {} XmlParser::~XmlParser() {}
SharedHandle<Metalinker> bool XmlParser::parseFile(const char* filename)
MetalinkProcessor::parseFile
(const std::string& filename,
const std::string& baseUri)
{ {
stm_.reset(new MetalinkParserStateMachine()); SessionData sessionData(psm_);
stm_->setBaseUri(baseUri);
SharedHandle<SessionData> sessionData(new SessionData(stm_));
// Old libxml2(at least 2.7.6, Ubuntu 10.04LTS) does not read stdin // Old libxml2(at least 2.7.6, Ubuntu 10.04LTS) does not read stdin
// when "/dev/stdin" is passed as filename while 2.7.7 does. So we // when "/dev/stdin" is passed as filename while 2.7.7 does. So we
// convert DEV_STDIN to "-" for compatibility. // convert DEV_STDIN to "-" for compatibility.
std::string nfilename; const char* nfilename;
if(filename == DEV_STDIN) { if(strcmp(filename, DEV_STDIN) == 0) {
nfilename = "-"; nfilename = "-";
} else { } else {
nfilename = filename; nfilename = filename;
} }
int retval = xmlSAXUserParseFile(&mySAXHandler, sessionData.get(), int r = xmlSAXUserParseFile(&mySAXHandler, &sessionData, nfilename);
nfilename.c_str()); return r == 0 && psm_->finished();
if(retval != 0) {
throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
error_code::METALINK_PARSE_ERROR);
}
if(!stm_->finished()) {
throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
error_code::METALINK_PARSE_ERROR);
}
if(!stm_->getErrors().empty()) {
throw DL_ABORT_EX2(stm_->getErrorString(),
error_code::METALINK_PARSE_ERROR);
}
return stm_->getResult();
} }
SharedHandle<Metalinker> bool XmlParser::parseBinaryStream(BinaryStream* bs)
MetalinkProcessor::parseFromBinaryStream
(const SharedHandle<BinaryStream>& binaryStream,
const std::string& baseUri)
{ {
stm_.reset(new MetalinkParserStateMachine()); const size_t bufSize = 4096;
stm_->setBaseUri(baseUri);
size_t bufSize = 4096;
unsigned char buf[bufSize]; unsigned char buf[bufSize];
ssize_t res = bs->readData(buf, 4, 0);
ssize_t res = binaryStream->readData(buf, 4, 0);
if(res != 4) { if(res != 4) {
throw DL_ABORT_EX2("Too small data for parsing XML.", return false;
error_code::METALINK_PARSE_ERROR);
} }
SessionData sessionData(psm_);
SharedHandle<SessionData> sessionData(new SessionData(stm_));
xmlParserCtxtPtr ctx = xmlCreatePushParserCtxt xmlParserCtxtPtr ctx = xmlCreatePushParserCtxt
(&mySAXHandler, sessionData.get(), (&mySAXHandler, &sessionData,
reinterpret_cast<const char*>(buf), res, 0); reinterpret_cast<const char*>(buf), res, 0);
auto_delete<xmlParserCtxtPtr> deleter(ctx, xmlFreeParserCtxt); auto_delete<xmlParserCtxtPtr> deleter(ctx, xmlFreeParserCtxt);
off_t readOffset = res; off_t readOffset = res;
while(1) { while(1) {
ssize_t res = binaryStream->readData(buf, bufSize, readOffset); ssize_t res = bs->readData(buf, bufSize, readOffset);
if(res == 0) { if(res == 0) {
break; break;
} }
if(xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), res, 0) != 0) { if(xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), res, 0) != 0) {
throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK, // TODO we need this? Just break is not suffice?
error_code::METALINK_PARSE_ERROR); return false;
} }
readOffset += res; readOffset += res;
} }
xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), 0, 1); xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), 0, 1);
return psm_->finished();
}
if(!stm_->finished()) { bool XmlParser::parseMemory(const char* xml, size_t len)
throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK, {
error_code::METALINK_PARSE_ERROR); SessionData sessionData(psm_);
} int r = xmlSAXUserParseMemory(&mySAXHandler, &sessionData, xml, len);
if(!stm_->getErrors().empty()) { return r == 0 && psm_->finished();
throw DL_ABORT_EX2(stm_->getErrorString(),
error_code::METALINK_PARSE_ERROR);
}
return stm_->getResult();
} }
} // namespace aria2 } // namespace aria2

View File

@ -2,7 +2,7 @@
/* /*
* aria2 - The high speed download utility * aria2 - The high speed download utility
* *
* Copyright (C) 2006 Tatsuhiro Tsujikawa * Copyright (C) 2011 Tatsuhiro Tsujikawa
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -32,42 +32,30 @@
* files in the program, then also delete it here. * files in the program, then also delete it here.
*/ */
/* copyright --> */ /* copyright --> */
#ifndef D_XML2_SAX_METALINK_PROCESSOR_H #ifndef D_XML2_XML_PARSER_H
#define D_XML2_SAX_METALINK_PROCESSOR_H #define D_XML2_XML_PARSER_H
#include "common.h" #include "common.h"
#include <string> #include <cstdlib>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include "SharedHandle.h"
#include "A2STR.h"
namespace aria2 { namespace aria2 {
class Metalinker;
class BinaryStream; class BinaryStream;
class MetalinkParserStateMachine; class ParserStateMachine;
class MetalinkProcessor { class XmlParser {
private:
SharedHandle<MetalinkParserStateMachine> stm_;
public: public:
MetalinkProcessor(); // This object does not delete psm.
XmlParser(ParserStateMachine* psm);
~MetalinkProcessor(); ~XmlParser();
bool parseFile(const char* filename);
SharedHandle<Metalinker> parseFile bool parseBinaryStream(BinaryStream* binaryStream);
(const std::string& filename, bool parseMemory(const char* xml, size_t size);
const std::string& baseUri = A2STR::NIL); private:
ParserStateMachine* psm_;
SharedHandle<Metalinker> parseFromBinaryStream
(const SharedHandle<BinaryStream>& binaryStream,
const std::string& baseUri = A2STR::NIL);
}; };
} // namespace aria2 } // namespace aria2
#endif // D_XML2_SAX_METALINK_PROCESSOR_H #endif // D_XML2_XML_PARSER_H

47
src/XmlAttr.cc Normal file
View File

@ -0,0 +1,47 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2011 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 "XmlAttr.h"
namespace aria2 {
XmlAttr::XmlAttr()
: localname(0),
prefix(0),
nsUri(0),
value(0),
valueLength(0)
{}
} // namespace aria2

59
src/XmlAttr.h Normal file
View File

@ -0,0 +1,59 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2011 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 --> */
#ifndef D_XML_ATTR_H
#define D_XML_ATTR_H
#include "common.h"
#include <cstdlib>
namespace aria2 {
struct XmlAttr {
const char* localname;
const char* prefix;
const char* nsUri;
const char* value;
size_t valueLength;
XmlAttr();
// XmlAttr(const XmlAttr& attr);
// ~XmlAttr();
// XmlAttr& operator=(const XmlAttr&);
};
} // namespace aria2
#endif // D_XML_ATTR_H

View File

@ -2,7 +2,7 @@
/* /*
* aria2 - The high speed download utility * aria2 - The high speed download utility
* *
* Copyright (C) 2006 Tatsuhiro Tsujikawa * Copyright (C) 2011 Tatsuhiro Tsujikawa
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -32,15 +32,15 @@
* files in the program, then also delete it here. * files in the program, then also delete it here.
*/ */
/* copyright --> */ /* copyright --> */
#ifndef D_METALINK_PROCESSOR_H #ifndef D_XML_PARSER_H
#define D_METALINK_PROCESSOR_H #define D_XML_PARSER_H
#include "common.h" #include "common.h"
#ifdef HAVE_LIBXML2 #ifdef HAVE_LIBXML2
# include "XML2SAXMetalinkProcessor.h" # include "Xml2XmlParser.h"
#elif HAVE_LIBEXPAT #elif HAVE_LIBEXPAT
# include "ExpatMetalinkProcessor.h" # include "Expat2XmlParser.h"
#endif #endif
#endif // D_METALINK_PROCESSOR_H #endif // D_XML_PARSER_H

View File

@ -37,7 +37,7 @@
#include "MetalinkEntry.h" #include "MetalinkEntry.h"
#include "MetalinkParserStateMachine.h" #include "MetalinkParserStateMachine.h"
#include "Metalinker.h" #include "Metalinker.h"
#include "MetalinkProcessor.h" #include "XmlParser.h"
#include "prefs.h" #include "prefs.h"
#include "DlAbortEx.h" #include "DlAbortEx.h"
#include "BinaryStream.h" #include "BinaryStream.h"
@ -68,20 +68,17 @@ void parseAndQuery
const Option* option, const Option* option,
const std::string& baseUri) const std::string& baseUri)
{ {
MetalinkProcessor proc; SharedHandle<Metalinker> metalinker = parseFile(filename, baseUri);
SharedHandle<Metalinker> metalinker = proc.parseFile(filename, baseUri);
query(result, metalinker, option); query(result, metalinker, option);
} }
void parseAndQuery void parseAndQuery
(std::vector<SharedHandle<MetalinkEntry> >& result, (std::vector<SharedHandle<MetalinkEntry> >& result,
const SharedHandle<BinaryStream>& binaryStream, BinaryStream* bs,
const Option* option, const Option* option,
const std::string& baseUri) const std::string& baseUri)
{ {
MetalinkProcessor proc; SharedHandle<Metalinker> metalinker = parseBinaryStream(bs, baseUri);
SharedHandle<Metalinker> metalinker =
proc.parseFromBinaryStream(binaryStream, baseUri);
query(result, metalinker, option); query(result, metalinker, option);
} }
@ -122,6 +119,40 @@ void groupEntryByMetaurlName
} }
} }
SharedHandle<Metalinker> parseFile
(const std::string& filename,
const std::string& baseUri)
{
MetalinkParserStateMachine psm;
psm.setBaseUri(baseUri);
if(!XmlParser(&psm).parseFile(filename.c_str())) {
throw DL_ABORT_EX2("Could not parse Metalink XML document.",
error_code::METALINK_PARSE_ERROR);
}
if(!psm.getErrors().empty()) {
throw DL_ABORT_EX2(psm.getErrorString(),
error_code::METALINK_PARSE_ERROR);
}
return psm.getResult();
}
SharedHandle<Metalinker> parseBinaryStream
(BinaryStream* bs,
const std::string& baseUri)
{
MetalinkParserStateMachine psm;
psm.setBaseUri(baseUri);
if(!XmlParser(&psm).parseBinaryStream(bs)) {
throw DL_ABORT_EX2("Could not parse Metalink XML document.",
error_code::METALINK_PARSE_ERROR);
}
if(!psm.getErrors().empty()) {
throw DL_ABORT_EX2(psm.getErrorString(),
error_code::METALINK_PARSE_ERROR);
}
return psm.getResult();
}
} // namespace metalink } // namespace metalink
} // namespace aria2 } // namespace aria2

View File

@ -60,7 +60,7 @@ void parseAndQuery
void parseAndQuery void parseAndQuery
(std::vector<SharedHandle<MetalinkEntry> >& result, (std::vector<SharedHandle<MetalinkEntry> >& result,
const SharedHandle<BinaryStream>& binaryStream, BinaryStream* bs,
const Option* option, const Option* option,
const std::string& baseUri = A2STR::NIL); const std::string& baseUri = A2STR::NIL);
@ -69,6 +69,14 @@ void groupEntryByMetaurlName
std::pair<std::string, std::vector<SharedHandle<MetalinkEntry> > > >& result, std::pair<std::string, std::vector<SharedHandle<MetalinkEntry> > > >& result,
const std::vector<SharedHandle<MetalinkEntry> >& entries); const std::vector<SharedHandle<MetalinkEntry> >& entries);
SharedHandle<Metalinker> parseFile
(const std::string& filename,
const std::string& baseUri = A2STR::NIL);
SharedHandle<Metalinker> parseBinaryStream
(BinaryStream* bs,
const std::string& baseUri = A2STR::NIL);
} // namespace metalink } // namespace metalink
} // namespace aria2 } // namespace aria2

View File

@ -21,6 +21,7 @@
#include "fmt.h" #include "fmt.h"
#include "RecoverableException.h" #include "RecoverableException.h"
#include "util.h" #include "util.h"
#include "metalink_helper.h"
namespace aria2 { namespace aria2 {
@ -31,7 +32,7 @@ class MetalinkProcessorTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testParseFileV4_attrs); CPPUNIT_TEST(testParseFileV4_attrs);
CPPUNIT_TEST(testParseFile); CPPUNIT_TEST(testParseFile);
CPPUNIT_TEST(testParseFile_dirtraversal); CPPUNIT_TEST(testParseFile_dirtraversal);
CPPUNIT_TEST(testParseFromBinaryStream); CPPUNIT_TEST(testParseBinaryStream);
CPPUNIT_TEST(testMalformedXML); CPPUNIT_TEST(testMalformedXML);
CPPUNIT_TEST(testMalformedXML2); CPPUNIT_TEST(testMalformedXML2);
CPPUNIT_TEST(testBadSize); CPPUNIT_TEST(testBadSize);
@ -57,7 +58,7 @@ public:
void testParseFileV4_attrs(); void testParseFileV4_attrs();
void testParseFile(); void testParseFile();
void testParseFile_dirtraversal(); void testParseFile_dirtraversal();
void testParseFromBinaryStream(); void testParseBinaryStream();
void testMalformedXML(); void testMalformedXML();
void testMalformedXML2(); void testMalformedXML2();
void testBadSize(); void testBadSize();
@ -82,8 +83,7 @@ CPPUNIT_TEST_SUITE_REGISTRATION( MetalinkProcessorTest );
void MetalinkProcessorTest::testParseFileV4() void MetalinkProcessorTest::testParseFileV4()
{ {
MetalinkProcessor proc; SharedHandle<Metalinker> m = metalink::parseFile(A2_TEST_DIR"/metalink4.xml");
SharedHandle<Metalinker> m = proc.parseFile(A2_TEST_DIR"/metalink4.xml");
SharedHandle<MetalinkEntry> e; SharedHandle<MetalinkEntry> e;
SharedHandle<MetalinkResource> r; SharedHandle<MetalinkResource> r;
SharedHandle<MetalinkMetaurl> mu; SharedHandle<MetalinkMetaurl> mu;
@ -152,9 +152,8 @@ void MetalinkProcessorTest::testParseFileV4()
void MetalinkProcessorTest::testParseFileV4_attrs() void MetalinkProcessorTest::testParseFileV4_attrs()
{ {
MetalinkProcessor proc;
SharedHandle<Metalinker> m; SharedHandle<Metalinker> m;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); ByteArrayDiskWriter dw;
{ {
// Testing file@name // Testing file@name
const char* tmpl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" const char* tmpl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
@ -163,27 +162,27 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"<url>http://example.org</url>" "<url>http://example.org</url>"
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "foo")); dw.setString(fmt(tmpl, "foo"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
// empty name // empty name
dw->setString(fmt(tmpl, "")); dw.setString(fmt(tmpl, ""));
try { try {
m = proc.parseFromBinaryStream(dw); metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
} }
// dir traversing // dir traversing
dw->setString(fmt(tmpl, "../doughnuts")); dw.setString(fmt(tmpl, "../doughnuts"));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
} }
} }
{ {
// Testing url@priority // Testing url@priority
@ -193,36 +192,36 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"<url priority=\"%s\">http://example.org</url>" "<url priority=\"%s\">http://example.org</url>"
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "0")); dw.setString(fmt(tmpl, "0"));
try { try {
m = proc.parseFromBinaryStream(dw); metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
} }
dw->setString(fmt(tmpl, "1")); dw.setString(fmt(tmpl, "1"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
dw->setString(fmt(tmpl, "100")); dw.setString(fmt(tmpl, "100"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
dw->setString(fmt(tmpl, "999999")); dw.setString(fmt(tmpl, "999999"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
dw->setString(fmt(tmpl, "1000000")); dw.setString(fmt(tmpl, "1000000"));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
} }
dw->setString(fmt(tmpl, "A")); dw.setString(fmt(tmpl, "A"));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
} }
@ -235,36 +234,36 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"<metaurl priority=\"%s\" mediatype=\"torrent\">http://example.org</metaurl>" "<metaurl priority=\"%s\" mediatype=\"torrent\">http://example.org</metaurl>"
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "0")); dw.setString(fmt(tmpl, "0"));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
} }
dw->setString(fmt(tmpl, "1")); dw.setString(fmt(tmpl, "1"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
dw->setString(fmt(tmpl, "100")); dw.setString(fmt(tmpl, "100"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
dw->setString(fmt(tmpl, "999999")); dw.setString(fmt(tmpl, "999999"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
dw->setString(fmt(tmpl, "1000000")); dw.setString(fmt(tmpl, "1000000"));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
} }
dw->setString(fmt(tmpl, "A")); dw.setString(fmt(tmpl, "A"));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
} }
@ -272,14 +271,14 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
// Testing metaurl@mediatype // Testing metaurl@mediatype
// no mediatype // no mediatype
dw->setString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" dw.setString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">" "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">" "<file name=\"example.ext\">"
"<metaurl>http://example.org</metaurl>" "<metaurl>http://example.org</metaurl>"
"</file>" "</file>"
"</metalink>"); "</metalink>");
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
@ -293,14 +292,14 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "torrent")); dw.setString(fmt(tmpl, "torrent"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
// empty mediatype // empty mediatype
dw->setString(fmt(tmpl, "")); dw.setString(fmt(tmpl, ""));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
@ -316,22 +315,22 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "foo")); dw.setString(fmt(tmpl, "foo"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
// dir traversing // dir traversing
dw->setString(fmt(tmpl, "../doughnuts")); dw.setString(fmt(tmpl, "../doughnuts"));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
} }
// empty name // empty name
dw->setString(fmt(tmpl, "")); dw.setString(fmt(tmpl, ""));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// success // success
@ -341,7 +340,7 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
{ {
// Testing pieces@length // Testing pieces@length
// No pieces@length // No pieces@length
dw->setString dw.setString
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">" "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">" "<file name=\"example.ext\">"
@ -352,7 +351,7 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"); "</metalink>");
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
@ -367,25 +366,25 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "262144")); dw.setString(fmt(tmpl, "262144"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
// empty // empty
try { try {
dw->setString(fmt(tmpl, "")); dw.setString(fmt(tmpl, ""));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
// not a number // not a number
try { try {
dw->setString(fmt(tmpl, "A")); dw.setString(fmt(tmpl, "A"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
} }
{ {
// Testing pieces@type // Testing pieces@type
// No pieces@type // No pieces@type
dw->setString dw.setString
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">" "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">" "<file name=\"example.ext\">"
@ -396,7 +395,7 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"); "</metalink>");
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
@ -411,19 +410,19 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "sha-1")); dw.setString(fmt(tmpl, "sha-1"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
// empty // empty
try { try {
dw->setString(fmt(tmpl, "")); dw.setString(fmt(tmpl, ""));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
} }
{ {
// Testing hash@type // Testing hash@type
// No hash@type // No hash@type
dw->setString dw.setString
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">" "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">" "<file name=\"example.ext\">"
@ -432,7 +431,7 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"); "</metalink>");
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
@ -445,12 +444,12 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "sha-1")); dw.setString(fmt(tmpl, "sha-1"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
// empty // empty
try { try {
dw->setString(fmt(tmpl, "")); dw.setString(fmt(tmpl, ""));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
} }
@ -458,7 +457,7 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
{ {
// Testing signature@mediatype // Testing signature@mediatype
// No hash@type // No hash@type
dw->setString dw.setString
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">" "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">" "<file name=\"example.ext\">"
@ -467,7 +466,7 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"); "</metalink>");
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
@ -480,12 +479,12 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "application/pgp-signature")); dw.setString(fmt(tmpl, "application/pgp-signature"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
// empty // empty
try { try {
dw->setString(fmt(tmpl, "")); dw.setString(fmt(tmpl, ""));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
} }
@ -493,9 +492,9 @@ void MetalinkProcessorTest::testParseFileV4_attrs()
void MetalinkProcessorTest::testParseFile() void MetalinkProcessorTest::testParseFile()
{ {
MetalinkProcessor proc;
try { try {
SharedHandle<Metalinker> metalinker = proc.parseFile(A2_TEST_DIR"/test.xml"); SharedHandle<Metalinker> metalinker =
metalink::parseFile(A2_TEST_DIR"/test.xml");
std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr = std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr =
metalinker->getEntries().begin(); metalinker->getEntries().begin();
@ -516,16 +515,17 @@ void MetalinkProcessorTest::testParseFile()
CPPUNIT_ASSERT_EQUAL(std::string("pgp"), entry1->getSignature()->getType()); CPPUNIT_ASSERT_EQUAL(std::string("pgp"), entry1->getSignature()->getType());
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2.sig"), CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2.sig"),
entry1->getSignature()->getFile()); entry1->getSignature()->getFile());
// Note that last '\n' character is trimmed. // Note that we don't strip anything
CPPUNIT_ASSERT_EQUAL CPPUNIT_ASSERT_EQUAL
(std::string (std::string
("-----BEGIN PGP SIGNATURE-----\n" ("\n-----BEGIN PGP SIGNATURE-----\n"
"Version: GnuPG v1.4.9 (GNU/Linux)\n" "Version: GnuPG v1.4.9 (GNU/Linux)\n"
"\n" "\n"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n" "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
"ffffffffffffffffffffffff\n" "ffffffffffffffffffffffff\n"
"fffff\n" "fffff\n"
"-----END PGP SIGNATURE-----"), "-----END PGP SIGNATURE-----\n"
"\t"),
entry1->getSignature()->getBody()); entry1->getSignature()->getBody());
std::vector<SharedHandle<MetalinkResource> >::iterator resourceItr1 = std::vector<SharedHandle<MetalinkResource> >::iterator resourceItr1 =
@ -600,9 +600,8 @@ void MetalinkProcessorTest::testParseFile()
void MetalinkProcessorTest::testParseFile_dirtraversal() void MetalinkProcessorTest::testParseFile_dirtraversal()
{ {
MetalinkProcessor proc;
SharedHandle<Metalinker> metalinker = SharedHandle<Metalinker> metalinker =
proc.parseFile(A2_TEST_DIR"/metalink3-dirtraversal.xml"); metalink::parseFile(A2_TEST_DIR"/metalink3-dirtraversal.xml");
CPPUNIT_ASSERT_EQUAL((size_t)1, metalinker->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, metalinker->getEntries().size());
SharedHandle<MetalinkEntry> e = metalinker->getEntries()[0]; SharedHandle<MetalinkEntry> e = metalinker->getEntries()[0];
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.3.tar.bz2"), e->getPath()); CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.3.tar.bz2"), e->getPath());
@ -610,15 +609,14 @@ void MetalinkProcessorTest::testParseFile_dirtraversal()
CPPUNIT_ASSERT_EQUAL(std::string(""), e->getSignature()->getFile()); CPPUNIT_ASSERT_EQUAL(std::string(""), e->getSignature()->getFile());
} }
void MetalinkProcessorTest::testParseFromBinaryStream() void MetalinkProcessorTest::testParseBinaryStream()
{ {
MetalinkProcessor proc; DefaultDiskWriter dw(A2_TEST_DIR"/test.xml");
DefaultDiskWriterHandle dw(new DefaultDiskWriter(A2_TEST_DIR"/test.xml")); dw.enableReadOnly();
dw->enableReadOnly(); dw.openExistingFile();
dw->openExistingFile();
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr = std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr =
m->getEntries().begin(); m->getEntries().begin();
@ -631,12 +629,11 @@ void MetalinkProcessorTest::testParseFromBinaryStream()
void MetalinkProcessorTest::testMalformedXML() void MetalinkProcessorTest::testMalformedXML()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\"><files></file></metalink>");
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\"><files></file></metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(Exception& e) { } catch(Exception& e) {
std::cerr << e.stackTrace() << std::endl; std::cerr << e.stackTrace() << std::endl;
@ -645,12 +642,11 @@ void MetalinkProcessorTest::testMalformedXML()
void MetalinkProcessorTest::testMalformedXML2() void MetalinkProcessorTest::testMalformedXML2()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\"><files></files>");
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\"><files></files>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(Exception& e) { } catch(Exception& e) {
std::cerr << e.stackTrace() << std::endl; std::cerr << e.stackTrace() << std::endl;
@ -659,9 +655,8 @@ void MetalinkProcessorTest::testMalformedXML2()
void MetalinkProcessorTest::testBadSizeV4() void MetalinkProcessorTest::testBadSizeV4()
{ {
MetalinkProcessor proc;
SharedHandle<Metalinker> m; SharedHandle<Metalinker> m;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); ByteArrayDiskWriter dw;
const char* tmpl = const char* tmpl =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
@ -672,21 +667,20 @@ void MetalinkProcessorTest::testBadSizeV4()
"</file>" "</file>"
"</metalink>"; "</metalink>";
dw->setString(fmt(tmpl, "9223372036854775807")); dw.setString(fmt(tmpl, "9223372036854775807"));
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
dw->setString(fmt(tmpl, "-1")); dw.setString(fmt(tmpl, "-1"));
try { try {
m = proc.parseFromBinaryStream(dw); m = metalink::parseBinaryStream(&dw);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {} } catch(RecoverableException& e) {}
} }
void MetalinkProcessorTest::testBadSize() void MetalinkProcessorTest::testBadSize()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">" "<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>abc</size>" " <size>abc</size>"
@ -698,7 +692,7 @@ void MetalinkProcessorTest::testBadSize()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr = std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr =
m->getEntries().begin(); m->getEntries().begin();
@ -716,9 +710,8 @@ void MetalinkProcessorTest::testBadSize()
void MetalinkProcessorTest::testBadMaxConn() void MetalinkProcessorTest::testBadMaxConn()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">" "<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>43743838</size>" " <size>43743838</size>"
@ -731,7 +724,7 @@ void MetalinkProcessorTest::testBadMaxConn()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr = std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr =
m->getEntries().begin(); m->getEntries().begin();
@ -744,9 +737,8 @@ void MetalinkProcessorTest::testBadMaxConn()
void MetalinkProcessorTest::testNoName() void MetalinkProcessorTest::testNoName()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file>" "<file>"
" <size>1024</size>" " <size>1024</size>"
@ -764,7 +756,7 @@ void MetalinkProcessorTest::testNoName()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr = std::vector<SharedHandle<MetalinkEntry> >::const_iterator entryItr =
m->getEntries().begin(); m->getEntries().begin();
@ -777,9 +769,8 @@ void MetalinkProcessorTest::testNoName()
void MetalinkProcessorTest::testBadURLPrefs() void MetalinkProcessorTest::testBadURLPrefs()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">" "<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>43743838</size>" " <size>43743838</size>"
@ -795,7 +786,7 @@ void MetalinkProcessorTest::testBadURLPrefs()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
SharedHandle<MetalinkResource> r = e->resources[0]; SharedHandle<MetalinkResource> r = e->resources[0];
CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type); CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type);
@ -809,9 +800,8 @@ void MetalinkProcessorTest::testBadURLPrefs()
void MetalinkProcessorTest::testBadURLMaxConn() void MetalinkProcessorTest::testBadURLMaxConn()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">" "<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>43743838</size>" " <size>43743838</size>"
@ -828,7 +818,7 @@ void MetalinkProcessorTest::testBadURLMaxConn()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
SharedHandle<MetalinkResource> r = e->resources[0]; SharedHandle<MetalinkResource> r = e->resources[0];
CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type); CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type);
@ -843,9 +833,8 @@ void MetalinkProcessorTest::testBadURLMaxConn()
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
void MetalinkProcessorTest::testUnsupportedType() void MetalinkProcessorTest::testUnsupportedType()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">" "<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>43743838</size>" " <size>43743838</size>"
@ -862,7 +851,7 @@ void MetalinkProcessorTest::testUnsupportedType()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
CPPUNIT_ASSERT_EQUAL((size_t)3, e->resources.size()); CPPUNIT_ASSERT_EQUAL((size_t)3, e->resources.size());
SharedHandle<MetalinkResource> r1 = e->resources[0]; SharedHandle<MetalinkResource> r1 = e->resources[0];
@ -878,9 +867,8 @@ void MetalinkProcessorTest::testUnsupportedType()
void MetalinkProcessorTest::testMultiplePieces() void MetalinkProcessorTest::testMultiplePieces()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2.tar.bz2\">" "<file name=\"aria2.tar.bz2\">"
" <verification>" " <verification>"
@ -895,7 +883,7 @@ void MetalinkProcessorTest::testMultiplePieces()
try { try {
// aria2 prefers sha1 // aria2 prefers sha1
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
SharedHandle<ChunkChecksum> c = e->chunkChecksum; SharedHandle<ChunkChecksum> c = e->chunkChecksum;
@ -908,9 +896,8 @@ void MetalinkProcessorTest::testMultiplePieces()
void MetalinkProcessorTest::testBadPieceNo() void MetalinkProcessorTest::testBadPieceNo()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString
dw->setString
("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">" ("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2.tar.bz2\">" "<file name=\"aria2.tar.bz2\">"
@ -928,7 +915,7 @@ void MetalinkProcessorTest::testBadPieceNo()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
SharedHandle<ChunkChecksum> c = e->chunkChecksum; SharedHandle<ChunkChecksum> c = e->chunkChecksum;
@ -942,9 +929,8 @@ void MetalinkProcessorTest::testBadPieceNo()
void MetalinkProcessorTest::testBadPieceLength() void MetalinkProcessorTest::testBadPieceLength()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString
dw->setString
("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">" ("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2.tar.bz2\">" "<file name=\"aria2.tar.bz2\">"
@ -961,7 +947,7 @@ void MetalinkProcessorTest::testBadPieceLength()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
SharedHandle<ChunkChecksum> c = e->chunkChecksum; SharedHandle<ChunkChecksum> c = e->chunkChecksum;
@ -975,9 +961,8 @@ void MetalinkProcessorTest::testBadPieceLength()
void MetalinkProcessorTest::testUnsupportedType_piece() void MetalinkProcessorTest::testUnsupportedType_piece()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString
dw->setString
("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">" ("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"aria2.tar.bz2\">" "<file name=\"aria2.tar.bz2\">"
@ -994,7 +979,7 @@ void MetalinkProcessorTest::testUnsupportedType_piece()
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
SharedHandle<ChunkChecksum> c = e->chunkChecksum; SharedHandle<ChunkChecksum> c = e->chunkChecksum;
@ -1009,21 +994,20 @@ void MetalinkProcessorTest::testUnsupportedType_piece()
void MetalinkProcessorTest::testLargeFileSize() void MetalinkProcessorTest::testLargeFileSize()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">" ("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>" "<files>"
"<file name=\"dvd.iso\">" "<file name=\"dvd.iso\">"
" <size>9223372036854775807</size>" " <size>9223372036854775807</size>"
" <resources>" " <resources>"
" <url type=\"http\">ftp://mirror/</url>" " <url type=\"http\">ftp://mirror/</url>"
" </resources>" " </resources>"
"</file>" "</file>"
"</files>" "</files>"
"</metalink>"); "</metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
CPPUNIT_ASSERT_EQUAL((uint64_t)9223372036854775807ULL, e->getLength()); CPPUNIT_ASSERT_EQUAL((uint64_t)9223372036854775807ULL, e->getLength());
} catch(Exception& e) { } catch(Exception& e) {
@ -1033,9 +1017,8 @@ void MetalinkProcessorTest::testLargeFileSize()
void MetalinkProcessorTest::testXmlPrefixV3() void MetalinkProcessorTest::testXmlPrefixV3()
{ {
MetalinkProcessor proc; ByteArrayDiskWriter dw;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter()); dw.setString("<m:metalink version=\"3.0\" xmlns:m=\"http://www.metalinker.org/\">"
dw->setString("<m:metalink version=\"3.0\" xmlns:m=\"http://www.metalinker.org/\">"
"<m:files>" "<m:files>"
"<m:file name=\"dvd.iso\">" "<m:file name=\"dvd.iso\">"
" <m:size>9223372036854775807</m:size>" " <m:size>9223372036854775807</m:size>"
@ -1047,7 +1030,7 @@ void MetalinkProcessorTest::testXmlPrefixV3()
"</m:metalink>"); "</m:metalink>");
try { try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw); SharedHandle<Metalinker> m = metalink::parseBinaryStream(&dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
SharedHandle<MetalinkEntry> e = m->getEntries()[0]; SharedHandle<MetalinkEntry> e = m->getEntries()[0];
CPPUNIT_ASSERT_EQUAL((uint64_t)9223372036854775807ULL, e->getLength()); CPPUNIT_ASSERT_EQUAL((uint64_t)9223372036854775807ULL, e->getLength());