소스 검색

Rewritten Metalink XML parser.

Now we don't strip white spaces while parsing Metalink V3 document.
Expat implementation does not included in this change.
Tatsuhiro Tsujikawa 14 년 전
부모
커밋
440f29aca3

+ 2 - 4
configure.ac

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

+ 14 - 8
src/Makefile.am

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

+ 1 - 1
src/Metalink2RequestGroup.cc

@@ -136,7 +136,7 @@ Metalink2RequestGroup::generate
  const std::string& baseUri)
 {
   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;
   createRequestGroup(tempgroups, entries, option);
   SharedHandle<MetadataInfo> mi(new MetadataInfo());

+ 0 - 19
src/MetalinkParserState.cc

@@ -36,23 +36,4 @@
 
 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

+ 7 - 18
src/MetalinkParserState.h

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

+ 47 - 14
src/MetalinkParserStateImpl.cc

@@ -33,36 +33,69 @@
  */
 /* copyright --> */
 #include "MetalinkParserStateImpl.h"
+
+#include <cstring>
+
 #include "MetalinkParserStateV3Impl.h"
 #include "MetalinkParserStateV4Impl.h"
 #include "MetalinkParserStateMachine.h"
+#include "XmlAttr.h"
 
 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
-(MetalinkParserStateMachine* stm,
- const std::string& localname,
- const std::string& prefix,
- const std::string& nsUri,
+(MetalinkParserStateMachine* psm,
+ const char* localname,
+ const char* prefix,
+ const char* nsUri,
  const std::vector<XmlAttr>& attrs)
 {
-  if(nsUri == METALINK4_NAMESPACE_URI && localname == "metalink") {
-    stm->setMetalinkStateV4();
-  } else if(nsUri == METALINK3_NAMESPACE_URI && localname == "metalink") {
-    stm->setMetalinkState();
+  if(!nsUri || strcmp(localname, "metalink") != 0) {
+    psm->setSkipTagState();
+  } else if(strcmp(nsUri, METALINK4_NAMESPACE_URI) == 0) {
+    psm->setMetalinkStateV4();
+  } else if(strcmp(nsUri, METALINK3_NAMESPACE_URI) == 0) {
+    psm->setMetalinkState();
   } else {
-    stm->setSkipTagState();
+    psm->setSkipTagState();
   }
 }
 
 void SkipTagMetalinkParserState::beginElement
-(MetalinkParserStateMachine* stm,
- const std::string& localname,
- const std::string& prefix,
- const std::string& nsUri,
+(MetalinkParserStateMachine* psm,
+ const char* localname,
+ const char* prefix,
+ const char* nsUri,
  const std::vector<XmlAttr>& attrs)
 {
-  stm->setSkipTagState();
+  psm->setSkipTagState();
 }
 
 } // namespace aria2

+ 13 - 8
src/MetalinkParserStateImpl.h

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

+ 6 - 6
src/MetalinkParserStateMachine.cc

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

+ 20 - 19
src/MetalinkParserStateMachine.h

@@ -35,7 +35,8 @@
 #ifndef D_METALINK_PARSER_STATE_MACHINE_H
 #define D_METALINK_PARSER_STATE_MACHINE_H
 
-#include "common.h"
+#include "ParserStateMachine.h"
+
 #include <string>
 #include <vector>
 #include <stack>
@@ -48,7 +49,7 @@ namespace aria2 {
 
 class Metalinker;
 
-class MetalinkParserStateMachine {
+class MetalinkParserStateMachine : public ParserStateMachine {
 private:
   SharedHandle<MetalinkParserController> ctrl_;
 
@@ -92,7 +93,23 @@ private:
 public:
   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();
 
@@ -138,20 +155,6 @@ public:
   void setURLStateV4();
   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 setFileNameOfEntry(const std::string& filename);
@@ -250,8 +253,6 @@ public:
 
   void cancelMetaurlTransaction();
 
-  bool needsCharactersBuffering() const;
-
   // Only stores first 10 errors.
   void logError(const std::string& log);
 

+ 213 - 240
src/MetalinkParserStateV3Impl.cc

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

+ 65 - 65
src/MetalinkParserStateV3Impl.h

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

+ 185 - 212
src/MetalinkParserStateV4Impl.cc

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

+ 57 - 57
src/MetalinkParserStateV4Impl.h

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

+ 70 - 0
src/ParserStateMachine.h

@@ -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

+ 73 - 110
src/XML2SAXMetalinkProcessor.cc → src/Xml2XmlParser.cc

@@ -2,7 +2,7 @@
 /*
  * 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
  * 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.
  */
 /* copyright --> */
-#include "XML2SAXMetalinkProcessor.h"
+#include "XmlParser.h"
 
 #include <cassert>
+#include <cstring>
+#include <deque>
 
+#include <libxml/parser.h>
+
+#include "a2io.h"
 #include "BinaryStream.h"
-#include "MetalinkParserStateMachine.h"
-#include "Metalinker.h"
-#include "MetalinkEntry.h"
-#include "util.h"
+#include "ParserStateMachine.h"
 #include "message.h"
 #include "DlAbortEx.h"
 #include "A2STR.h"
-#include "error_code.h"
+#include "a2functional.h"
+#include "XmlAttr.h"
 
 namespace aria2 {
 
 namespace {
-class SessionData {
-public:
-  SharedHandle<MetalinkParserStateMachine> stm_;
-
+struct SessionData {
   std::deque<std::string> charactersStack_;
-
-  SessionData(const SharedHandle<MetalinkParserStateMachine>& stm):stm_(stm) {}
+  ParserStateMachine* psm_;
+  SessionData(ParserStateMachine* psm)
+    : psm_(psm)
+  {}
 };
 } // namespace
 
 namespace {
 void mlStartElement
 (void* userData,
- const xmlChar* srcLocalname,
- const xmlChar* srcPrefix,
- const xmlChar* srcNsUri,
+ const xmlChar* localname,
+ const xmlChar* prefix,
+ const xmlChar* nsUri,
  int numNamespaces,
- const xmlChar **namespaces,
+ const xmlChar** namespaces,
  int numAttrs,
  int numDefaulted,
- const xmlChar **attrs)
+ const xmlChar** attrs)
 {
   SessionData* sd = reinterpret_cast<SessionData*>(userData);
   std::vector<XmlAttr> xmlAttrs;
-  size_t index = 0;
-  for(int attrIndex = 0; attrIndex < numAttrs; ++attrIndex, index += 5) {
+  const char** pattrs = reinterpret_cast<const char**>(attrs);
+  for(size_t i = 0, max = numAttrs*5; i < max; i += 5) {
     XmlAttr xmlAttr;
-    assert(attrs[index]);
-    xmlAttr.localname = reinterpret_cast<const char*>(attrs[index]);
-    if(attrs[index+1]) {
-      xmlAttr.prefix = reinterpret_cast<const char*>(attrs[index+1]);
+    assert(pattrs[i]);
+    xmlAttr.localname = pattrs[i];
+    if(pattrs[i+1]) {
+      xmlAttr.prefix = pattrs[i+1];
     }
-    if(attrs[index+2]) {
-      xmlAttr.nsUri = reinterpret_cast<const char*>(attrs[index+2]);
+    if(attrs[i+2]) {
+      xmlAttr.nsUri = pattrs[i+2];
     }
-    const char* valueBegin = reinterpret_cast<const char*>(attrs[index+3]);
-    const char* valueEnd = reinterpret_cast<const char*>(attrs[index+4]);
-    xmlAttr.value.assign(valueBegin, valueEnd);
+    xmlAttr.value = pattrs[i+3];
+    xmlAttr.valueLength = pattrs[i+4]-xmlAttr.value;
     xmlAttrs.push_back(xmlAttr);
   }
-  assert(srcLocalname);
-  std::string localname = reinterpret_cast<const char*>(srcLocalname);
-  std::string prefix;
-  std::string nsUri;
-  if(srcPrefix) {
-    prefix = reinterpret_cast<const char*>(srcPrefix);
-  }
-  if(srcNsUri) {
-    nsUri = reinterpret_cast<const char*>(srcNsUri);
-  }
-  sd->stm_->beginElement(localname, prefix, nsUri, xmlAttrs);
-  if(sd->stm_->needsCharactersBuffering()) {
+  sd->psm_->beginElement
+    (reinterpret_cast<const char*>(localname),
+     reinterpret_cast<const char*>(prefix),
+     reinterpret_cast<const char*>(nsUri),
+     xmlAttrs);
+  if(sd->psm_->needsCharactersBuffering()) {
     sd->charactersStack_.push_front(A2STR::NIL);
   }
 }
@@ -109,26 +104,21 @@ void mlStartElement
 namespace {
 void mlEndElement
 (void* userData,
- const xmlChar* srcLocalname,
- const xmlChar* srcPrefix,
- const xmlChar* srcNsUri)
+ const xmlChar* localname,
+ const xmlChar* prefix,
+ const xmlChar* nsUri)
 {
   SessionData* sd = reinterpret_cast<SessionData*>(userData);
   std::string characters;
-  if(sd->stm_->needsCharactersBuffering()) {
+  if(sd->psm_->needsCharactersBuffering()) {
     characters = sd->charactersStack_.front();
     sd->charactersStack_.pop_front();
   }
-  std::string localname = reinterpret_cast<const char*>(srcLocalname);
-  std::string prefix;
-  std::string nsUri;
-  if(srcPrefix) {
-    prefix = reinterpret_cast<const char*>(srcPrefix);
-  }
-  if(srcNsUri) {
-    nsUri = reinterpret_cast<const char*>(srcNsUri);
-  }
-  sd->stm_->endElement(localname, prefix, nsUri, characters);
+  sd->psm_->endElement
+    (reinterpret_cast<const char*>(localname),
+     reinterpret_cast<const char*>(prefix),
+     reinterpret_cast<const char*>(nsUri),
+     characters);
 }
 } // namespace
 
@@ -136,7 +126,7 @@ namespace {
 void mlCharacters(void* userData, const xmlChar* ch, int len)
 {
   SessionData* sd = reinterpret_cast<SessionData*>(userData);
-  if(sd->stm_->needsCharactersBuffering()) {
+  if(sd->psm_->needsCharactersBuffering()) {
     sd->charactersStack_.front().append(&ch[0], &ch[len]);
   }
 }
@@ -180,89 +170,62 @@ xmlSAXHandler mySAXHandler =
   };
 } // namespace
 
-MetalinkProcessor::MetalinkProcessor() {}
+XmlParser::XmlParser(ParserStateMachine* psm)
+  : psm_(psm)
+{}
 
-MetalinkProcessor::~MetalinkProcessor() {}
+XmlParser::~XmlParser() {}
 
-SharedHandle<Metalinker>
-MetalinkProcessor::parseFile
-(const std::string& filename,
- const std::string& baseUri)
+bool XmlParser::parseFile(const char* filename)
 {
-  stm_.reset(new MetalinkParserStateMachine());
-  stm_->setBaseUri(baseUri);
-  SharedHandle<SessionData> sessionData(new SessionData(stm_));
+  SessionData sessionData(psm_);
   // 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
   // convert DEV_STDIN to "-" for compatibility.
-  std::string nfilename;
-  if(filename == DEV_STDIN) {
+  const char* nfilename;
+  if(strcmp(filename, DEV_STDIN) == 0) {
     nfilename = "-";
   } else {
     nfilename = filename;
   }
-  int retval = xmlSAXUserParseFile(&mySAXHandler, sessionData.get(),
-                                   nfilename.c_str());
-  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();
+  int r = xmlSAXUserParseFile(&mySAXHandler, &sessionData, nfilename);
+  return r == 0 && psm_->finished();
 }
-         
-SharedHandle<Metalinker>
-MetalinkProcessor::parseFromBinaryStream
-(const SharedHandle<BinaryStream>& binaryStream,
- const std::string& baseUri)
+
+bool XmlParser::parseBinaryStream(BinaryStream* bs)
 {
-  stm_.reset(new MetalinkParserStateMachine());
-  stm_->setBaseUri(baseUri);
-  size_t bufSize = 4096;
+  const size_t bufSize = 4096;
   unsigned char buf[bufSize];
-
-  ssize_t res = binaryStream->readData(buf, 4, 0);
+  ssize_t res = bs->readData(buf, 4, 0);
   if(res != 4) {
-    throw DL_ABORT_EX2("Too small data for parsing XML.",
-                       error_code::METALINK_PARSE_ERROR);
+    return false;
   }
-
-  SharedHandle<SessionData> sessionData(new SessionData(stm_));
+  SessionData sessionData(psm_);
   xmlParserCtxtPtr ctx = xmlCreatePushParserCtxt
-    (&mySAXHandler, sessionData.get(),
+    (&mySAXHandler, &sessionData,
      reinterpret_cast<const char*>(buf), res, 0);
   auto_delete<xmlParserCtxtPtr> deleter(ctx, xmlFreeParserCtxt);
-
   off_t readOffset = res;
   while(1) {
-    ssize_t res = binaryStream->readData(buf, bufSize, readOffset);
+    ssize_t res = bs->readData(buf, bufSize, readOffset);
     if(res == 0) {
       break;
     }
     if(xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), res, 0) != 0) {
-      throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
-                         error_code::METALINK_PARSE_ERROR);
+      // TODO we need this? Just break is not suffice?
+      return false;
     }
     readOffset += res;
   }
   xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), 0, 1);
+  return psm_->finished();
+}
 
-  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();
+bool XmlParser::parseMemory(const char* xml, size_t len)
+{
+  SessionData sessionData(psm_);
+  int r = xmlSAXUserParseMemory(&mySAXHandler, &sessionData, xml, len);
+  return r == 0 && psm_->finished();
 }
 
 } // namespace aria2

+ 15 - 27
src/XML2SAXMetalinkProcessor.h → src/Xml2XmlParser.h

@@ -2,7 +2,7 @@
 /*
  * 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
  * 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.
  */
 /* copyright --> */
-#ifndef D_XML2_SAX_METALINK_PROCESSOR_H
-#define D_XML2_SAX_METALINK_PROCESSOR_H
+#ifndef D_XML2_XML_PARSER_H
+#define D_XML2_XML_PARSER_H
 
 #include "common.h"
 
-#include <string>
-
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-
-#include "SharedHandle.h"
-#include "A2STR.h"
+#include <cstdlib>
 
 namespace aria2 {
 
-class Metalinker;
 class BinaryStream;
-class MetalinkParserStateMachine;
+class ParserStateMachine;
 
-class MetalinkProcessor {
-private:
-  SharedHandle<MetalinkParserStateMachine> stm_;
+class XmlParser {
 public:
-  MetalinkProcessor();
-
-  ~MetalinkProcessor();
-
-  SharedHandle<Metalinker> parseFile
-  (const std::string& filename,
-   const std::string& baseUri = A2STR::NIL);
-
-  SharedHandle<Metalinker> parseFromBinaryStream
-  (const SharedHandle<BinaryStream>& binaryStream,
-   const std::string& baseUri = A2STR::NIL);
+  // This object does not delete psm.
+  XmlParser(ParserStateMachine* psm);
+  ~XmlParser();
+  bool parseFile(const char* filename);
+  bool parseBinaryStream(BinaryStream* binaryStream);
+  bool parseMemory(const char* xml, size_t size);
+private:
+  ParserStateMachine* psm_;
 };
 
 } // namespace aria2
 
-#endif // D_XML2_SAX_METALINK_PROCESSOR_H
+#endif // D_XML2_XML_PARSER_H

+ 47 - 0
src/XmlAttr.cc

@@ -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 - 0
src/XmlAttr.h

@@ -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

+ 6 - 6
src/MetalinkProcessor.h → src/XmlParser.h

@@ -2,7 +2,7 @@
 /*
  * 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
  * 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.
  */
 /* copyright --> */
-#ifndef D_METALINK_PROCESSOR_H
-#define D_METALINK_PROCESSOR_H
+#ifndef D_XML_PARSER_H
+#define D_XML_PARSER_H
 
 #include "common.h"
 
 #ifdef HAVE_LIBXML2
-# include "XML2SAXMetalinkProcessor.h"
+# include "Xml2XmlParser.h"
 #elif HAVE_LIBEXPAT
-# include "ExpatMetalinkProcessor.h"
+# include "Expat2XmlParser.h"
 #endif
 
-#endif // D_METALINK_PROCESSOR_H
+#endif // D_XML_PARSER_H

+ 38 - 7
src/metalink_helper.cc

@@ -37,7 +37,7 @@
 #include "MetalinkEntry.h"
 #include "MetalinkParserStateMachine.h"
 #include "Metalinker.h"
-#include "MetalinkProcessor.h"
+#include "XmlParser.h"
 #include "prefs.h"
 #include "DlAbortEx.h"
 #include "BinaryStream.h"
@@ -68,20 +68,17 @@ void parseAndQuery
  const Option* option,
  const std::string& baseUri)
 {
-  MetalinkProcessor proc;
-  SharedHandle<Metalinker> metalinker = proc.parseFile(filename, baseUri);
+  SharedHandle<Metalinker> metalinker = parseFile(filename, baseUri);
   query(result, metalinker, option);
 }
 
 void parseAndQuery
 (std::vector<SharedHandle<MetalinkEntry> >& result,
- const SharedHandle<BinaryStream>& binaryStream,
+ BinaryStream* bs,
  const Option* option,
  const std::string& baseUri)
 {
-  MetalinkProcessor proc;
-  SharedHandle<Metalinker> metalinker =
-    proc.parseFromBinaryStream(binaryStream, baseUri);
+  SharedHandle<Metalinker> metalinker = parseBinaryStream(bs, baseUri);
   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 aria2

+ 9 - 1
src/metalink_helper.h

@@ -60,7 +60,7 @@ void parseAndQuery
 
 void parseAndQuery
 (std::vector<SharedHandle<MetalinkEntry> >& result,
- const SharedHandle<BinaryStream>& binaryStream,
+ BinaryStream* bs,
  const Option* option,
  const std::string& baseUri = A2STR::NIL);
 
@@ -69,6 +69,14 @@ void groupEntryByMetaurlName
   std::pair<std::string, std::vector<SharedHandle<MetalinkEntry> > > >& result,
  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 aria2

+ 147 - 164
test/MetalinkProcessorTest.cc

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