浏览代码

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());