Browse Source

2007-12-04 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	Added XML2SAXMetalinkProcessor class, which is a lot faster than
	the predecessor, Xml2MetalinkParser class.
	I tested them against 94KB metalink file with 1234 chunk 
checksums.
	The new one parsed it in 22msec, while it took 6000msec with old 
one.
	* src/XML2SAXMetalinkProcessor.{h, cc}
	* test/XML2SAXMetalinkProcessorTest.cc
	* src/MetalinkParserController.{h, cc}
	* test/MetalinkParserControllerTest.cc
	* src/MetalinkParserState.h: Also added 16 subclasses.
	* src/main.cc
	* src/Metalink2RequestGroup.cc
	* src/MetalinkHelper.cc
	* src/MetalinkEntry.cc
	* src/ChunkChecksum.h
	
	Rewritten Base64 class for better performance.
	* src/Base64.{h, cc}
	* test/Base64Test.cc
	* src/HttpRequest.cc
Tatsuhiro Tsujikawa 18 years ago
parent
commit
936ce09b83
56 changed files with 4281 additions and 165 deletions
  1. 22 0
      ChangeLog
  2. 0 1
      TODO
  3. 136 81
      src/Base64.cc
  4. 43 16
      src/Base64.h
  5. 6 0
      src/ByteArrayDiskWriter.h
  6. 17 0
      src/ChunkChecksum.h
  7. 82 0
      src/FileMetalinkParserState.cc
  8. 50 0
      src/FileMetalinkParserState.h
  9. 59 0
      src/FilesMetalinkParserState.cc
  10. 50 0
      src/FilesMetalinkParserState.h
  11. 45 0
      src/FinMetalinkParserState.cc
  12. 50 0
      src/FinMetalinkParserState.h
  13. 52 0
      src/HashMetalinkParserState.cc
  14. 50 0
      src/HashMetalinkParserState.h
  15. 51 0
      src/InitialMetalinkParserState.cc
  16. 50 0
      src/InitialMetalinkParserState.h
  17. 51 0
      src/LanguageMetalinkParserState.cc
  18. 50 0
      src/LanguageMetalinkParserState.h
  19. 20 2
      src/Makefile.am
  20. 75 13
      src/Makefile.in
  21. 1 1
      src/Metalink2RequestGroup.cc
  22. 1 0
      src/MetalinkEntry.cc
  23. 4 3
      src/MetalinkHelper.cc
  24. 54 0
      src/MetalinkMetalinkParserState.cc
  25. 50 0
      src/MetalinkMetalinkParserState.h
  26. 360 0
      src/MetalinkParserController.cc
  27. 137 0
      src/MetalinkParserController.h
  28. 53 0
      src/MetalinkParserState.h
  29. 327 0
      src/MetalinkParserStateMachine.cc
  30. 178 0
      src/MetalinkParserStateMachine.h
  31. 51 0
      src/OSMetalinkParserState.cc
  32. 50 0
      src/OSMetalinkParserState.h
  33. 52 0
      src/PieceHashMetalinkParserState.cc
  34. 50 0
      src/PieceHashMetalinkParserState.h
  35. 68 0
      src/PiecesMetalinkParserState.cc
  36. 50 0
      src/PiecesMetalinkParserState.h
  37. 105 0
      src/ResourcesMetalinkParserState.cc
  38. 50 0
      src/ResourcesMetalinkParserState.h
  39. 58 0
      src/SizeMetalinkParserState.cc
  40. 50 0
      src/SizeMetalinkParserState.h
  41. 55 0
      src/SkipTagMetalinkParserState.cc
  42. 60 0
      src/SkipTagMetalinkParserState.h
  43. 53 0
      src/URLMetalinkParserState.cc
  44. 50 0
      src/URLMetalinkParserState.h
  45. 92 0
      src/VerificationMetalinkParserState.cc
  46. 50 0
      src/VerificationMetalinkParserState.h
  47. 51 0
      src/VersionMetalinkParserState.cc
  48. 50 0
      src/VersionMetalinkParserState.h
  49. 167 0
      src/XML2SAXMetalinkProcessor.cc
  50. 59 0
      src/XML2SAXMetalinkProcessor.h
  51. 5 3
      src/main.cc
  52. 196 16
      test/Base64Test.cc
  53. 4 4
      test/Makefile.am
  54. 30 25
      test/Makefile.in
  55. 140 0
      test/MetalinkParserControllerTest.cc
  56. 511 0
      test/XML2SAXMetalinkProcessorTest.cc

+ 22 - 0
ChangeLog

@@ -1,3 +1,25 @@
+2007-12-04  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	Added XML2SAXMetalinkProcessor class, which is a lot faster than
+	the predecessor, Xml2MetalinkParser class.
+	I tested them against 94KB metalink file with 1234 chunk checksums.
+	The new one parsed it in 22msec, while it took 6000msec with old one.
+	* src/XML2SAXMetalinkProcessor.{h, cc}
+	* test/XML2SAXMetalinkProcessorTest.cc
+	* src/MetalinkParserController.{h, cc}
+	* test/MetalinkParserControllerTest.cc
+	* src/MetalinkParserState.h: Also added 16 subclasses.
+	* src/main.cc
+	* src/Metalink2RequestGroup.cc
+	* src/MetalinkHelper.cc
+	* src/MetalinkEntry.cc
+	* src/ChunkChecksum.h
+	
+	Rewritten Base64 class for better performance.
+	* src/Base64.{h, cc}
+	* test/Base64Test.cc
+	* src/HttpRequest.cc
+
 2007-12-01  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	Fixed the bug#1841757: aria2 will connect to server to only get

+ 0 - 1
TODO

@@ -53,7 +53,6 @@
     DownloadFailureException .... RequestGroup should halt.
   FatalException .... Program should abort.
 * replace strtol with Util::parseInt
-* do performance tuning against Xml2MetalinkProcessor
 * remove header files from Makefile.am
 * create MetalinkProcessorFactory and get Xml2MetalinkProcessor from it.
 

+ 136 - 81
src/Base64.cc

@@ -34,7 +34,7 @@
 /* copyright --> */
 #include "Base64.h"
 
-static char base64_table[64] = {
+static const char CHAR_TABLE[] = {
   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@@ -45,103 +45,158 @@ static char base64_table[64] = {
   '4', '5', '6', '7', '8', '9', '+', '/',
 };
 
-void Base64::part_encode(const unsigned char* sub, int32_t subLength,
-			 unsigned char* buf)
+static const int INDEX_TABLE[] = {
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 
+  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 
+  -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 
+  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 
+  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 
+  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+void Base64::encode(unsigned char*& result, size_t& rlength,
+			const unsigned char* src, size_t slength)
 {
-  int32_t shift = 2;
-  unsigned char carry = 0;
-  int32_t index;
-  for(index = 0; index < subLength; index++) {
-    unsigned char cur = sub[index] >> shift | carry;
-    carry = (sub[index] << (6-shift)) & 0x3f;
-    shift += 2;
-    buf[index] = base64_table[(uint32_t)cur];
+  if(slength == 0) {
+    rlength = 0;
+    return;
   }
-  if(subLength == 1) {
-    buf[index] = base64_table[(uint32_t)carry];
-    buf[index+1] = buf[index+2] = '=';
-  } else if(subLength == 2) {
-    buf[index] = base64_table[(uint32_t)carry];
-    buf[index+1] = '=';
-  } else {
-    unsigned char cur = sub[subLength-1] & 0x3f;
-    buf[index] = base64_table[(uint32_t)cur];
+  size_t trituple = (slength+2)/3;
+  int r = slength%3;
+  rlength = trituple*4;
+  result = new unsigned char[rlength];
+
+  unsigned char* p = result;
+  const unsigned char* s = src;
+  const unsigned char* smax = s+slength-r;
+  while(s != smax) {
+    int n = *s++ << 16;
+    n += *s++ << 8;
+    n += *s++;
+    *p++ = CHAR_TABLE[n >> 18];
+    *p++ = CHAR_TABLE[n >> 12&0x3f];
+    *p++ = CHAR_TABLE[n >> 6&0x3f];
+    *p++ = CHAR_TABLE[n&0x3f];
+  }
+  if(r == 2) {
+    int n = (*s << 16)+(*(s+1) << 8);
+    *p++ = CHAR_TABLE[n >> 18];
+    *p++ = CHAR_TABLE[n >> 12&0x3f];
+    *p++ = CHAR_TABLE[n >> 6&0x3f];
+    *p++ = '=';
+  } else if(r == 1) {
+    int n = (*s << 16);
+    *p++ = CHAR_TABLE[n >> 18];
+    *p++ = CHAR_TABLE[n >> 12&0x3f];
+    *p++ = '=';
+    *p++ = '=';
   }
 }
 
-string Base64::encode(const string& plainSrc)
+void Base64::removeNonBase64Chars(unsigned char*& nsrc,
+				      size_t& nlength,
+				      const unsigned char* src,
+				      size_t slength)
 {
-  unsigned char* result = 0;
-  int32_t resultLength = 0;
-
-  encode((const unsigned char*)plainSrc.c_str(), plainSrc.size(),
-	 result, resultLength);
-  string encoded(&result[0], &result[resultLength]);
-  delete [] result;
-  return encoded;
-}
-
-void Base64::encode(const unsigned char* src, int32_t srcLength,
-		    unsigned char*& result, int32_t& resultLength) {
-  resultLength = (srcLength+(srcLength%3 == 0 ? 0 : 3-srcLength%3))/3*4;
-  result = new unsigned char[resultLength];
-  unsigned char* tail = result;
-  for(int32_t index = 0; srcLength > index; index += 3) {
-    unsigned char temp[4];
-    part_encode(&src[index],
-		srcLength >= index+3 ? 3 : srcLength-index,
-		temp);
-    memcpy(tail, temp, sizeof(temp)); 
-    tail += sizeof(temp);
+  unsigned char* temp = new unsigned char[slength];
+  const unsigned char* end = src+slength;
+  size_t n = 0;
+  for(const unsigned char*s = src; s != end; ++s) {
+    if(INDEX_TABLE[*s] != -1 || *s == '=') {
+      *(temp+n++) = *s;
+    }
   }
+  unsigned char* ret = new unsigned char[n];
+  memcpy(ret, temp, n);
+  delete [] temp;
+  nlength = n;
+  nsrc = ret;
 }
 
-
-char Base64::getValue(char ch)
+void Base64::decode(unsigned char*& result, size_t& rlength,
+			const unsigned char* src, size_t slength)
 {
-  char retch;
+  if(slength == 0) {
+    rlength = 0;
+    return;
+  }
+  unsigned char* nsrc;
+  size_t nlength;
+  removeNonBase64Chars(nsrc, nlength, src, slength);
 
-  if(ch >= 'A' && ch <= 'Z') {
-    retch = ch-'A';
-  } else if(ch >= 'a' && ch <= 'z') {
-    retch = ch-'a'+26;
-  } else if(ch >= '0' && ch <= '9') {
-    retch = ch-'0'+52;
-  } else if(ch == '+') {
-    retch = 62;
-  } else if(ch == '/') {
-    retch = 63;
-  } else {
-    retch = 0;
+  if(nlength%4 != 0) {
+    delete [] nsrc;
+    rlength = 0;
+    return;
   }
-  return retch;
-}
 
-string Base64::part_decode(const string& subCrypted)
-{
-  int32_t shift = 2;
-  string plain;
+  size_t quadtuple = nlength/4;
+  size_t len;
+  if(nsrc[nlength-1] == '=') {
+    if(nsrc[nlength-2] == '=') {
+      len = nlength-2;
+    } else {
+      len = nlength-1;
+    }
+  } else {
+    len = nlength;
+  }
+  rlength = len-quadtuple;
+  result = new unsigned char[rlength];
+  int r = len%4;
 
-  for(uint32_t index = 0; index < subCrypted.size()-1; ++index) {
-    if(subCrypted.at(index) == '=') break;
-    char cur = getValue(subCrypted.at(index)) << shift;
-    char carry = getValue(subCrypted.at(index+1)) >> (6-shift);
-    shift += 2;
-    plain += cur | carry;
+  unsigned char* p = result;
+  const unsigned char* s = nsrc;
+  const unsigned char* smax = s+len-r;
+  while(s != smax) {
+    int n = INDEX_TABLE[*s++] << 18;
+    n += INDEX_TABLE[*s++] << 12;
+    n += INDEX_TABLE[*s++] << 6;
+    n += INDEX_TABLE[*s++];
+    *p++ = n >> 16;
+    *p++ = n >> 8&0xff;
+    *p++ = n&0xff;
   }
+  if(r == 2) {
+    int n = INDEX_TABLE[*s++] << 18;
+    n += INDEX_TABLE[*s++] << 12;
+    *p++ = n >> 16;
+  } else if(r == 3) {
+    int n = INDEX_TABLE[*s++] << 18;
+    n += INDEX_TABLE[*s++] << 12;
+    n += INDEX_TABLE[*s++] << 6;
+    *p++ = n >> 16;
+    *p++ = n >> 8&0xff;
+  }
+  delete [] nsrc;
+}
 
-  return plain;
+string Base64::encode(const string& s)
+{
+  unsigned char* buf = 0;
+  size_t len;
+  encode(buf, len, s.c_str(), s.size());
+  string r(&buf[0], &buf[len]);
+  delete [] buf;
+  return r;
 }
 
-string Base64::decode(const string& crypted)
+string Base64::decode(const string& s)
 {
-  string plain;
-  int32_t sIndex = 0;
-  for(int32_t index = 0; crypted.size() > (uint32_t)index; index +=4) {
-    string subCrypted = crypted.substr(sIndex, 4);
-    string subPlain = part_decode(subCrypted);
-    sIndex += 4;
-    plain += subPlain;
-  }
-  return plain;
+  unsigned char* buf = 0;
+  size_t len;
+  decode(buf, len, s.c_str(), s.size());
+  string r(&buf[0], &buf[len]);
+  delete [] buf;
+  return r;
 }

+ 43 - 16
src/Base64.h

@@ -32,30 +32,57 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#ifndef _BASE64_H_
-#define _BASE64_H_
+#ifndef _D_BASE64_H_
+#define _D_BASE64_H_
 #include <string>
-#include "common.h"
+
 using namespace std;
 
 class Base64
 {
 private:
-  static void part_encode(const unsigned char* sub, int32_t subLength,
-			  unsigned char* buf);
+  static void removeNonBase64Chars(unsigned char*& nsrc, size_t& nlength,
+				   const unsigned char* src, size_t slength);
 
-  static string part_encode(const string& subplain);
-  static string part_decode(const string& subCrypted);
-  static char getValue(char ch);
 public:
-  static string encode(const string& plain);
-  // caller must deallocate the memory used by result.
-  static void encode(const unsigned char* src, int32_t srcLength,
-		     unsigned char*& result, int32_t& resultLength);
-  static string decode(const string& crypted);
-  // caller must deallocate the memory used by result.
-  static void decode(const unsigned char* src, int32_t srcLength,
-		     unsigned char*& result, int32_t& resultLength);
+  /**
+   * Encods src whose length is slength into base64 encoded data
+   * and stores them to result.
+   * result is allocated in this function and the length is stored to rlength.
+   * If slength is equal to 0, then return with rlength set to 0 and result
+   * is left untouched.
+   * A caller must deallocate the memory used by result.
+   */
+  static void encode(unsigned char*& result, size_t& rlength,
+		     const unsigned char* src, size_t slength);
+
+  static void encode(unsigned char*& result, size_t& rlength,
+		     const char* src, size_t slength)
+  {
+    encode(result, rlength, (const unsigned char*)src, slength);
+  }
+
+  static string encode(const string& s);
+
+  /**
+   * Dencods base64 encoded src whose length is slength and stores them to
+   * result.
+   * result is allocated in this function and the length is stored to rlength.
+   * If slength is equal to 0 or is not multiple of 4, then return with rlength
+   * set to 0 and result is left untouched.
+   * The function removes non-base64 characters before decoding.
+   * A caller must deallocate the memory used by result.
+   */
+  static void decode(unsigned char*& result, size_t& rlength,
+		     const unsigned char* src, size_t slength);
+
+  static void decode(unsigned char*& result, size_t& rlength,
+		     const char* src, size_t slength)
+  {
+    decode(result, rlength, (const unsigned char*)src, slength);
+  }
+
+  static string decode(const string& s);
 };
 
 #endif // _BASE64_H_

+ 6 - 0
src/ByteArrayDiskWriter.h

@@ -69,6 +69,12 @@ public:
   virtual void enableDirectIO() {}
 
   virtual void disableDirectIO() {}
+
+  void setString(const string& s)
+  {
+    buf.str(s);
+  }
 };
 
+typedef SharedHandle<ByteArrayDiskWriter> ByteArrayDiskWriterHandle;
 #endif // _D_BYTE_ARRAY_DISK_WRITER_H_

+ 17 - 0
src/ChunkChecksum.h

@@ -44,6 +44,8 @@ private:
   Strings _checksums;
   int32_t _checksumLength;
 public:
+  ChunkChecksum():_checksumLength(0) {}    
+
   ChunkChecksum(const string& algo,
 		const Strings& checksums,
 		int32_t checksumLength):
@@ -94,6 +96,21 @@ public:
   {
     return _algo;
   }
+
+  void setAlgo(const string& algo)
+  {
+    _algo = algo;
+  }
+
+  void setChecksumLength(int32_t length)
+  {
+    _checksumLength = length;
+  }
+
+  void setChecksums(const Strings& mds)
+  {
+    _checksums = mds;
+  }
 };
 
 typedef SharedHandle<ChunkChecksum> ChunkChecksumHandle;

+ 82 - 0
src/FileMetalinkParserState.cc

@@ -0,0 +1,82 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "FileMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+#include "Util.h"
+#include "RecoverableException.h"
+
+void FileMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					   const string& name,
+					   const map<string, string>& attrs)
+{
+  if(name == "size") {
+    stm->setSizeState();
+  } else if(name == "version") {
+    stm->setVersionState();
+  } else if(name == "language") {
+    stm->setLanguageState();
+  } else if(name == "os") {
+    stm->setOSState();
+  } else if(name == "verification") {
+    stm->setVerificationState();
+  } else if(name == "resources") {
+    stm->setResourcesState();
+    int32_t maxConnections;
+    {
+      map<string, string>::const_iterator itr = attrs.find("maxconnections");
+      if(itr == attrs.end()) {
+	maxConnections = -1;
+      } else {
+	try {
+	  maxConnections = Util::parseInt((*itr).second);
+	} catch(RecoverableException* e) {
+	  delete e;
+	  maxConnections = -1;
+	}
+      }
+    }
+    stm->setMaxConnectionsOfEntry(maxConnections);
+  } else {
+    stm->setSkipTagState(this);
+  }
+}
+
+void FileMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					  const string& name,
+					  const string& characters)
+{
+  stm->commitEntryTransaction();
+  stm->setFilesState();
+}

+ 50 - 0
src/FileMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_FILE_METALINK_PARSER_STATE_H_
+#define _D_FILE_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class FileMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_FILE_METALINK_PARSER_STATE_H_

+ 59 - 0
src/FilesMetalinkParserState.cc

@@ -0,0 +1,59 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "FilesMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void FilesMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					    const string& name,
+					    const map<string, string>& attrs)
+{
+  if(name == "file") {
+    stm->setFileState();
+    map<string, string>::const_iterator itr = attrs.find("name");
+    if(itr != attrs.end()) {
+      stm->newEntryTransaction();
+      stm->setFileNameOfEntry((*itr).second);
+    }
+  } else {
+    stm->setSkipTagState(this);
+  }
+}
+
+void FilesMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					  const string& name,
+					  const string& characters)
+{
+  stm->setMetalinkState();
+}

+ 50 - 0
src/FilesMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_FILES_METALINK_PARSER_STATE_H_
+#define _D_FILES_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class FilesMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_FILES_METALINK_PARSER_STATE_H_

+ 45 - 0
src/FinMetalinkParserState.cc

@@ -0,0 +1,45 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "FinMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void FinMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					  const string& name,
+					  const map<string, string>& attrs)
+{}
+
+void FinMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					const string& name, const string& characters)
+{}

+ 50 - 0
src/FinMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_FIN_METALINK_PARSER_STATE_H_
+#define _D_FIN_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class FinMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_FIN_METALINK_PARSER_STATE_H_

+ 52 - 0
src/HashMetalinkParserState.cc

@@ -0,0 +1,52 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "HashMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void HashMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					   const string& name,
+					   const map<string, string>& attrs)
+{
+  stm->setSkipTagState(this);
+}
+
+void HashMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					 const string& name,
+					 const string& characters)
+{
+  stm->setHashOfChecksum(characters);
+  stm->commitChecksumTransaction();
+  stm->setVerificationState();
+}

+ 50 - 0
src/HashMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_HASH_METALINK_PARSER_STATE_H_
+#define _D_HASH_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class HashMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_HASH_METALINK_PARSER_STATE_H_

+ 51 - 0
src/InitialMetalinkParserState.cc

@@ -0,0 +1,51 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "InitialMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void InitialMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					      const string& name,
+					      const map<string, string>& attrs)
+{
+  if(name == "metalink") {
+    stm->setMetalinkState();
+  } else {
+    stm->setSkipTagState(this);
+  }
+}
+
+void InitialMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					    const string& name, const string& characters)
+{}

+ 50 - 0
src/InitialMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_INITIAL_METALINK_PARSER_STATE_H_
+#define _D_INITIAL_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class InitialMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_INITIAL_METALINK_PARSER_STATE_H_

+ 51 - 0
src/LanguageMetalinkParserState.cc

@@ -0,0 +1,51 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "LanguageMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void LanguageMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					       const string& name,
+					       const map<string, string>& attrs)
+{
+  stm->setSkipTagState(this);
+}
+
+void LanguageMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					     const string& name,
+					     const string& characters)
+{
+  stm->setLanguageOfEntry(characters);
+  stm->setFileState();
+}

+ 50 - 0
src/LanguageMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_LANGUAGE_METALINK_PARSER_STATE_H_
+#define _D_LANGUAGE_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class LanguageMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_LANGUAGE_METALINK_PARSER_STATE_H_

+ 20 - 2
src/Makefile.am

@@ -46,7 +46,7 @@ SRCS =  Socket.h\
 	DefaultDiskWriter.cc DefaultDiskWriter.h\
 	File.cc File.h\
 	Option.cc Option.h\
-	Base64.cc Base64.h\
+	Base64.cc\
 	CookieBox.cc CookieBox.h\
 	LogFactory.cc LogFactory.h\
 	NullLogger.h\
@@ -255,7 +255,25 @@ SRCS += Metalinker.cc Metalinker.h\
 	MetalinkEntry.cc MetalinkEntry.h\
 	MetalinkResource.cc MetalinkResource.h\
 	MetalinkProcessor.h\
-	Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h\
+	MetalinkParserController.cc\
+	MetalinkParserStateMachine.cc\
+	InitialMetalinkParserState.cc\
+	MetalinkMetalinkParserState.cc\
+	FilesMetalinkParserState.cc\
+	FileMetalinkParserState.cc\
+	SizeMetalinkParserState.cc\
+	VersionMetalinkParserState.cc\
+	LanguageMetalinkParserState.cc\
+	OSMetalinkParserState.cc\
+	VerificationMetalinkParserState.cc\
+	HashMetalinkParserState.cc\
+	PiecesMetalinkParserState.cc\
+	PieceHashMetalinkParserState.cc\
+	ResourcesMetalinkParserState.cc\
+	URLMetalinkParserState.cc\
+	FinMetalinkParserState.cc\
+	SkipTagMetalinkParserState.cc\
+	XML2SAXMetalinkProcessor.cc\
 	Metalink2RequestGroup.cc Metalink2RequestGroup.h\
 	MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h\
 	MetalinkHelper.cc MetalinkHelper.h

+ 75 - 13
src/Makefile.in

@@ -142,7 +142,25 @@ bin_PROGRAMS = aria2c$(EXEEXT)
 @ENABLE_METALINK_TRUE@	MetalinkEntry.cc MetalinkEntry.h\
 @ENABLE_METALINK_TRUE@	MetalinkResource.cc MetalinkResource.h\
 @ENABLE_METALINK_TRUE@	MetalinkProcessor.h\
-@ENABLE_METALINK_TRUE@	Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h\
+@ENABLE_METALINK_TRUE@	MetalinkParserController.cc\
+@ENABLE_METALINK_TRUE@	MetalinkParserStateMachine.cc\
+@ENABLE_METALINK_TRUE@	InitialMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	MetalinkMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	FilesMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	FileMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	SizeMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	VersionMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	LanguageMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	OSMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	VerificationMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	HashMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	PiecesMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	PieceHashMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	ResourcesMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	URLMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	FinMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	SkipTagMetalinkParserState.cc\
+@ENABLE_METALINK_TRUE@	XML2SAXMetalinkProcessor.cc\
 @ENABLE_METALINK_TRUE@	Metalink2RequestGroup.cc Metalink2RequestGroup.h\
 @ENABLE_METALINK_TRUE@	MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h\
 @ENABLE_METALINK_TRUE@	MetalinkHelper.cc MetalinkHelper.h
@@ -208,7 +226,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	ChunkedEncoding.cc ChunkedEncoding.h DiskWriter.h \
 	AbstractDiskWriter.cc AbstractDiskWriter.h \
 	DefaultDiskWriter.cc DefaultDiskWriter.h File.cc File.h \
-	Option.cc Option.h Base64.cc Base64.h CookieBox.cc CookieBox.h \
+	Option.cc Option.h Base64.cc CookieBox.cc CookieBox.h \
 	LogFactory.cc LogFactory.h NullLogger.h TimeA2.cc TimeA2.h \
 	SharedHandle.h HandleRegistry.h FeatureConfig.cc \
 	FeatureConfig.h DownloadEngineFactory.cc \
@@ -338,14 +356,22 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h Metalinker.cc \
 	Metalinker.h MetalinkEntry.cc MetalinkEntry.h \
 	MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \
-	Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h \
-	Metalink2RequestGroup.cc Metalink2RequestGroup.h \
-	MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h \
-	MetalinkHelper.cc MetalinkHelper.h libgen.c libgen.h \
-	getaddrinfo.c getaddrinfo.h gai_strerror.c gai_strerror.h \
-	gettimeofday.c gettimeofday.h inet_aton.c inet_aton.h \
-	localtime_r.c localtime_r.h strptime.c strptime.h timegm.c \
-	timegm.h
+	MetalinkParserController.cc MetalinkParserStateMachine.cc \
+	InitialMetalinkParserState.cc MetalinkMetalinkParserState.cc \
+	FilesMetalinkParserState.cc FileMetalinkParserState.cc \
+	SizeMetalinkParserState.cc VersionMetalinkParserState.cc \
+	LanguageMetalinkParserState.cc OSMetalinkParserState.cc \
+	VerificationMetalinkParserState.cc HashMetalinkParserState.cc \
+	PiecesMetalinkParserState.cc PieceHashMetalinkParserState.cc \
+	ResourcesMetalinkParserState.cc URLMetalinkParserState.cc \
+	FinMetalinkParserState.cc SkipTagMetalinkParserState.cc \
+	XML2SAXMetalinkProcessor.cc Metalink2RequestGroup.cc \
+	Metalink2RequestGroup.h MetalinkPostDownloadHandler.cc \
+	MetalinkPostDownloadHandler.h MetalinkHelper.cc \
+	MetalinkHelper.h libgen.c libgen.h getaddrinfo.c getaddrinfo.h \
+	gai_strerror.c gai_strerror.h gettimeofday.c gettimeofday.h \
+	inet_aton.c inet_aton.h localtime_r.c localtime_r.h strptime.c \
+	strptime.h timegm.c timegm.h
 @ENABLE_MESSAGE_DIGEST_TRUE@am__objects_1 = IteratableChunkChecksumValidator.$(OBJEXT) \
 @ENABLE_MESSAGE_DIGEST_TRUE@	IteratableChecksumValidator.$(OBJEXT) \
 @ENABLE_MESSAGE_DIGEST_TRUE@	CheckIntegrityCommand.$(OBJEXT) \
@@ -409,7 +435,25 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 @ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkEntry.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkResource.$(OBJEXT) \
-@ENABLE_METALINK_TRUE@	Xml2MetalinkProcessor.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	MetalinkParserController.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	MetalinkParserStateMachine.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	InitialMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	MetalinkMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	FilesMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	FileMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	SizeMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	VersionMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	LanguageMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	OSMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	VerificationMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	HashMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	PiecesMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	PieceHashMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	ResourcesMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	URLMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	FinMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	SkipTagMetalinkParserState.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	XML2SAXMetalinkProcessor.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	Metalink2RequestGroup.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkPostDownloadHandler.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkHelper.$(OBJEXT)
@@ -708,7 +752,7 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \
 	ChunkedEncoding.cc ChunkedEncoding.h DiskWriter.h \
 	AbstractDiskWriter.cc AbstractDiskWriter.h \
 	DefaultDiskWriter.cc DefaultDiskWriter.h File.cc File.h \
-	Option.cc Option.h Base64.cc Base64.h CookieBox.cc CookieBox.h \
+	Option.cc Option.h Base64.cc CookieBox.cc CookieBox.h \
 	LogFactory.cc LogFactory.h NullLogger.h TimeA2.cc TimeA2.h \
 	SharedHandle.h HandleRegistry.h FeatureConfig.cc \
 	FeatureConfig.h DownloadEngineFactory.cc \
@@ -950,7 +994,10 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAllocationEntry.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAllocationMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileEntry.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileMetalinkParserState.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FilesMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FillRequestGroupCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FinMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpConnection.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpDownloadCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpInitiateConnectionCommand.Po@am__quote@
@@ -958,6 +1005,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpTunnelRequestCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpTunnelResponseCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrowSegment.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HashMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveEraseCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpConnection.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpDownloadCommand.Po@am__quote@
@@ -970,9 +1018,11 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpRequestCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpResponse.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpResponseCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InitialMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InitiateConnectionCommandFactory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChecksumValidator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChunkChecksumValidator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LanguageMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/List.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LogFactory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemoryBufferPreDownloadHandler.Po@am__quote@
@@ -981,6 +1031,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalink2RequestGroup.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntry.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkHelper.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkMetalinkParserState.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkParserController.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkParserStateMachine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkPostDownloadHandler.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkResource.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalinker.Po@am__quote@
@@ -990,6 +1043,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NameResolver.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Netrc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetrcAuthResolver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OSMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Option.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionHandlerFactory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionParser.Po@am__quote@
@@ -1007,7 +1061,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerReceiveHandshakeCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Piece.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceHashCheckIntegrityEntry.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceHashMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PiecedSegment.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PiecesMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Platform.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RealtimeCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Request.Po@am__quote@
@@ -1016,6 +1072,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupEntry.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestSlot.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ResourcesMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SeedCheckCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitor.Po@am__quote@
@@ -1023,6 +1080,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleLogger.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleRandomizer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SingleFileAllocationIterator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SizeMetalinkParserState.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SkipTagMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SleepCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketCore.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SpeedCalc.Po@am__quote@
@@ -1032,10 +1091,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeBasedCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransferStat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/URLMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnknownLengthPieceStorage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParser.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VerificationMetalinkParserState.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VersionMetalinkParserState.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XML2SAXMetalinkProcessor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gai_strerror.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getaddrinfo.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettimeofday.Po@am__quote@

+ 1 - 1
src/Metalink2RequestGroup.cc

@@ -37,7 +37,6 @@
 #include "Option.h"
 #include "LogFactory.h"
 #include "prefs.h"
-#include "Xml2MetalinkProcessor.h"
 #include "Util.h"
 #include "message.h"
 #include "SingleFileDownloadContext.h"
@@ -45,6 +44,7 @@
 #include "BinaryStream.h"
 #include "MemoryBufferPreDownloadHandler.h"
 #include "TrueRequestGroupCriteria.h"
+#include "MetalinkEntry.h"
 #ifdef ENABLE_BITTORRENT
 # include "BtDependency.h"
 #endif // ENABLE_BITTORRENT

+ 1 - 0
src/MetalinkEntry.cc

@@ -37,6 +37,7 @@
 #include <algorithm>
 
 MetalinkEntry::MetalinkEntry():
+  file(0),
   maxConnections(-1)
 #ifdef ENABLE_MESSAGE_DIGEST
   ,

+ 4 - 3
src/MetalinkHelper.cc

@@ -35,7 +35,8 @@
 #include "MetalinkHelper.h"
 #include "Option.h"
 #include "MetalinkEntry.h"
-#include "Xml2MetalinkProcessor.h"
+#include "XML2SAXMetalinkProcessor.h"
+#include "MetalinkParserStateMachine.h"
 #include "Metalinker.h"
 #include "prefs.h"
 #include "DlAbortEx.h"
@@ -47,7 +48,7 @@ MetalinkHelper::~MetalinkHelper() {}
 
 MetalinkEntries MetalinkHelper::parseAndQuery(const string& filename, const Option* option)
 {
-  Xml2MetalinkProcessor proc;
+  XML2SAXMetalinkProcessor proc;
 
   MetalinkerHandle metalinker = proc.parseFile(filename);
   return query(metalinker, option);
@@ -55,7 +56,7 @@ MetalinkEntries MetalinkHelper::parseAndQuery(const string& filename, const Opti
 
 MetalinkEntries MetalinkHelper::parseAndQuery(const BinaryStreamHandle& binaryStream, const Option* option)
 {
-  Xml2MetalinkProcessor proc;
+  XML2SAXMetalinkProcessor proc;
 
   MetalinkerHandle metalinker = proc.parseFromBinaryStream(binaryStream);
   return query(metalinker, option);

+ 54 - 0
src/MetalinkMetalinkParserState.cc

@@ -0,0 +1,54 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "MetalinkMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void MetalinkMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					       const string& name,
+					       const map<string, string>& attrs)
+{
+  if(name == "files") {
+    stm->setFilesState();
+  } else {
+    stm->setSkipTagState(this);
+  }
+}
+
+void MetalinkMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					     const string& name,
+					     const string& characters)
+{
+  stm->setFinState();
+}

+ 50 - 0
src/MetalinkMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_METALINK_METALINK_PARSER_STATE_H_
+#define _D_METALINK_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class MetalinkMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_METALINK_METALINK_PARSER_STATE_H_

+ 360 - 0
src/MetalinkParserController.cc

@@ -0,0 +1,360 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "MetalinkParserController.h"
+#include "Metalinker.h"
+#include "MetalinkEntry.h"
+#include "MetalinkResource.h"
+#include "Checksum.h"
+#include "ChunkChecksum.h"
+
+MetalinkParserController::MetalinkParserController():
+  _metalinker(new Metalinker()),
+  _tEntry(0),
+  _tResource(0),
+  _tChecksum(0),
+  _tChunkChecksum(0) {}
+
+MetalinkParserController::~MetalinkParserController() {}
+
+MetalinkerHandle MetalinkParserController::getResult() const
+{
+  return _metalinker;
+}
+
+void MetalinkParserController::newEntryTransaction()
+{
+  _tEntry = new MetalinkEntry();
+  _tResource = 0;
+  _tChecksum = 0;
+  _tChunkChecksum = 0;
+}
+
+void MetalinkParserController::setFileNameOfEntry(const string& filename)
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  if(_tEntry->file.isNull()) {
+    _tEntry->file = new FileEntry(filename, 0, 0);
+  } else {
+    _tEntry->file->setPath(filename);
+  }
+}
+
+void MetalinkParserController::setFileLengthOfEntry(int64_t length)
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  if(_tEntry->file.isNull()) {
+    _tEntry->file = new FileEntry("", length, 0);
+  } else {
+    _tEntry->file->setLength(length);
+  }
+}
+
+void MetalinkParserController::setVersionOfEntry(const string& version)
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  _tEntry->version = version;
+}
+
+void MetalinkParserController::setLanguageOfEntry(const string& language)
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  _tEntry->language = language;
+}
+
+void MetalinkParserController::setOSOfEntry(const string& os)
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  _tEntry->os = os;
+}
+
+void MetalinkParserController::setMaxConnectionsOfEntry(int32_t maxConnections)
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  _tEntry->maxConnections = maxConnections;
+}
+
+void MetalinkParserController::commitEntryTransaction()
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  commitResourceTransaction();
+  commitChecksumTransaction();
+  commitChunkChecksumTransaction();
+  _metalinker->entries.push_back(_tEntry);
+  _tEntry = 0;
+}
+
+void MetalinkParserController::cancelEntryTransaction()
+{
+  cancelResourceTransaction();
+  cancelChecksumTransaction();
+  cancelChunkChecksumTransaction();
+  _tEntry = 0;
+}
+
+void MetalinkParserController::newResourceTransaction()
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  _tResource = new MetalinkResource();
+}
+
+void MetalinkParserController::setURLOfResource(const string& url)
+{
+  if(_tResource.isNull()) {
+    return;
+  }
+  _tResource->url = url;
+}
+
+void MetalinkParserController::setTypeOfResource(const string& type)
+{
+  if(_tResource.isNull()) {
+    return;
+  }
+  if(type == "ftp") {
+    _tResource->type = MetalinkResource::TYPE_FTP;
+  } else if(type == "http") {
+    _tResource->type = MetalinkResource::TYPE_HTTP;
+  } else if(type == "https") {
+    _tResource->type = MetalinkResource::TYPE_HTTPS;
+  } else if(type == "bittorrent") {
+    _tResource->type = MetalinkResource::TYPE_BITTORRENT;
+  } else {
+    _tResource->type = MetalinkResource::TYPE_NOT_SUPPORTED;
+  }
+}
+
+void MetalinkParserController::setLocationOfResource(const string& location)
+{
+  if(_tResource.isNull()) {
+    return;
+  }
+  _tResource->location = location;
+}
+
+void MetalinkParserController::setPreferenceOfResource(int32_t preference)
+{
+  if(_tResource.isNull()) {
+    return;
+  }
+  _tResource->preference = preference;
+}
+
+void MetalinkParserController::setMaxConnectionsOfResource(int32_t maxConnections)
+{
+  if(_tResource.isNull()) {
+    return;
+  }
+  _tResource->maxConnections = maxConnections;
+}
+
+void MetalinkParserController::commitResourceTransaction()
+{
+  if(_tResource.isNull()) {
+    return;
+  }
+  _tEntry->resources.push_back(_tResource);
+  _tResource = 0;
+}
+
+void MetalinkParserController::cancelResourceTransaction()
+{
+  _tResource = 0;
+}
+
+void MetalinkParserController::newChecksumTransaction()
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  _tChecksum = new Checksum();
+}
+
+void MetalinkParserController::setTypeOfChecksum(const string& type)
+{
+  if(_tChecksum.isNull()) {
+    return;
+  }
+  if(MessageDigestContext::supports(type)) {
+    _tChecksum->setAlgo(type);
+  } else {
+    cancelChecksumTransaction();
+  }
+}
+
+void MetalinkParserController::setHashOfChecksum(const string& md)
+{
+  if(_tChecksum.isNull()) {
+    return;
+  }
+  _tChecksum->setMessageDigest(md);
+}
+
+void MetalinkParserController::commitChecksumTransaction()
+{
+  if(_tChecksum.isNull()) {
+    return;
+  }
+  if(_tEntry->checksum.isNull() || _tEntry->checksum->getAlgo() != "sha1") {
+    _tEntry->checksum = _tChecksum;
+  }
+  _tChecksum = 0;
+}
+
+void MetalinkParserController::cancelChecksumTransaction()
+{
+  _tChecksum = 0;
+}
+  
+void MetalinkParserController::newChunkChecksumTransaction()
+{
+  if(_tEntry.isNull()) {
+    return;
+  }
+  _tChunkChecksum = new ChunkChecksum();
+  _tempChunkChecksums.clear();
+}
+
+void MetalinkParserController::setTypeOfChunkChecksum(const string& type)
+{
+  if(_tChunkChecksum.isNull()) {
+    return;
+  }
+  if(MessageDigestContext::supports(type)) {
+    _tChunkChecksum->setAlgo(type);
+  } else {
+    cancelChunkChecksumTransaction();
+  }
+}
+
+void MetalinkParserController::setLengthOfChunkChecksum(int32_t length)
+{
+  if(_tChunkChecksum.isNull()) {
+    return;
+  }
+  if(length > 0) {
+    _tChunkChecksum->setChecksumLength(length);
+  } else {
+    cancelChunkChecksumTransaction();
+  }
+}
+
+void MetalinkParserController::addHashOfChunkChecksum(int32_t order, const string& md)
+{
+  if(_tChunkChecksum.isNull()) {
+    return;
+  }
+  _tempChunkChecksums.push_back(pair<int32_t, string>(order, md));
+}
+
+void MetalinkParserController::createNewHashOfChunkChecksum(int32_t order)
+{
+  if(_tChunkChecksum.isNull()) {
+    return;
+  }
+  _tempHashPair.first = order;
+}
+
+void MetalinkParserController::setMessageDigestOfChunkChecksum(const string& md)
+{
+  if(_tChunkChecksum.isNull()) {
+    return;
+  }
+  _tempHashPair.second = md;
+}
+
+void MetalinkParserController::addHashOfChunkChecksum()
+{
+  if(_tChunkChecksum.isNull()) {
+    return;
+  }
+  _tempChunkChecksums.push_back(_tempHashPair);
+}
+
+bool firstAsc(const pair<int32_t, string>& p1, const pair<int32_t, string>& p2)
+{
+  return p1.first < p2.first;
+}
+
+class GetSecond
+{
+private:
+  Strings& ss;
+public:
+  GetSecond(Strings& s):ss(s) {}
+
+  void operator()(const pair<int32_t, string>& p)
+  {
+    ss.push_back(p.second);
+  }
+};
+
+void MetalinkParserController::commitChunkChecksumTransaction()
+{
+  if(_tChunkChecksum.isNull()) {
+    return;
+  }
+  if(_tEntry->chunkChecksum.isNull() || _tEntry->chunkChecksum->getAlgo() != "sha1") {
+    sort(_tempChunkChecksums.begin(), _tempChunkChecksums.end(), firstAsc);
+    Strings checksums;
+    for_each(_tempChunkChecksums.begin(), _tempChunkChecksums.end(), GetSecond(checksums));
+    
+    _tChunkChecksum->setChecksums(checksums);
+    _tEntry->chunkChecksum = _tChunkChecksum;
+  }
+  _tChunkChecksum = 0;
+}
+
+void MetalinkParserController::cancelChunkChecksumTransaction()
+{
+  _tChunkChecksum = 0;
+}
+
+

+ 137 - 0
src/MetalinkParserController.h

@@ -0,0 +1,137 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_METALINK_PARSER_CONTROLLER_H_
+#define _D_METALINK_PARSER_CONTROLLER_H_
+
+#include "common.h"
+
+class Metalinker;
+typedef SharedHandle<Metalinker> MetalinkerHandle;
+class MetalinkEntry;
+typedef SharedHandle<MetalinkEntry> MetalinkEntryHandle;
+class MetalinkResource;
+typedef SharedHandle<MetalinkResource> MetalinkResourceHandle;
+class Checksum;
+typedef SharedHandle<Checksum> ChecksumHandle;
+class ChunkChecksum;
+typedef SharedHandle<ChunkChecksum> ChunkChecksumHandle;
+
+class MetalinkParserController {
+private:
+  MetalinkerHandle _metalinker;
+
+  MetalinkEntryHandle _tEntry;
+
+  MetalinkResourceHandle _tResource;
+
+  ChecksumHandle _tChecksum;
+
+  ChunkChecksumHandle _tChunkChecksum;
+
+  deque<pair<int32_t, string> > _tempChunkChecksums;
+  
+  pair<int32_t, string> _tempHashPair;
+
+public:
+  MetalinkParserController();
+
+  ~MetalinkParserController();
+
+  MetalinkerHandle getResult() const;
+
+  void newEntryTransaction();
+
+  void setFileNameOfEntry(const string& filename);
+
+  void setFileLengthOfEntry(int64_t length);
+
+  void setVersionOfEntry(const string& version);
+
+  void setLanguageOfEntry(const string& language);
+
+  void setOSOfEntry(const string& os);
+
+  void setMaxConnectionsOfEntry(int32_t maxConnections);
+
+  void commitEntryTransaction();
+
+  void cancelEntryTransaction();
+
+  void newResourceTransaction();
+
+  void setURLOfResource(const string& url);
+
+  void setTypeOfResource(const string& type);
+
+  void setLocationOfResource(const string& location);
+
+  void setPreferenceOfResource(int32_t preference);
+
+  void setMaxConnectionsOfResource(int32_t maxConnections);
+
+  void commitResourceTransaction();
+
+  void cancelResourceTransaction();
+
+  void newChecksumTransaction();
+
+  void setTypeOfChecksum(const string& type);
+
+  void setHashOfChecksum(const string& md);
+
+  void commitChecksumTransaction();
+
+  void cancelChecksumTransaction();
+  
+  void newChunkChecksumTransaction();
+
+  void setTypeOfChunkChecksum(const string& type);
+
+  void setLengthOfChunkChecksum(int32_t length);
+
+  void addHashOfChunkChecksum(int32_t order, const string& md);
+
+  void createNewHashOfChunkChecksum(int32_t order);
+
+  void setMessageDigestOfChunkChecksum(const string& md);
+
+  void addHashOfChunkChecksum();
+
+  void commitChunkChecksumTransaction();
+
+  void cancelChunkChecksumTransaction();
+};
+
+#endif // _D_METALINK_PARSER_CONTROLLER_H_

+ 53 - 0
src/MetalinkParserState.h

@@ -0,0 +1,53 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_METALINK_PARSER_STATE_H_
+#define _D_METALINK_PARSER_STATE_H_
+
+#include "common.h"
+#include <map>
+
+class MetalinkParserStateMachine;
+
+class MetalinkParserState
+{
+public:
+  virtual void beginElement(MetalinkParserStateMachine* stm,
+			    const string& name, const map<string, string>& attrs) = 0;
+  
+  virtual void endElement(MetalinkParserStateMachine* stm,
+			  const string& name, const string& characters) = 0;
+};
+
+#endif // _D_METALINK_PARSER_STATE_H_

+ 327 - 0
src/MetalinkParserStateMachine.cc

@@ -0,0 +1,327 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "MetalinkParserStateMachine.h"
+#include "MetalinkParserController.h"
+#include "InitialMetalinkParserState.h"
+#include "MetalinkMetalinkParserState.h"
+#include "FilesMetalinkParserState.h"
+#include "FileMetalinkParserState.h"
+#include "SizeMetalinkParserState.h"
+#include "VersionMetalinkParserState.h"
+#include "LanguageMetalinkParserState.h"
+#include "OSMetalinkParserState.h"
+#include "VerificationMetalinkParserState.h"
+#include "HashMetalinkParserState.h"
+#include "PiecesMetalinkParserState.h"
+#include "PieceHashMetalinkParserState.h"
+#include "ResourcesMetalinkParserState.h"
+#include "URLMetalinkParserState.h"
+#include "FinMetalinkParserState.h"
+#include "SkipTagMetalinkParserState.h"
+#include "Metalinker.h"
+
+MetalinkParserState* MetalinkParserStateMachine::_initialState = new InitialMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_metalinkState = new MetalinkMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_filesState = new FilesMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_fileState = new FileMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_sizeState = new SizeMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_versionState = new VersionMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_languageState = new LanguageMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_osState = new OSMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_verificationState = new VerificationMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_hashState = new HashMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_piecesState = new PiecesMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_pieceHashState = new PieceHashMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_resourcesState = new ResourcesMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_urlState = new URLMetalinkParserState();
+MetalinkParserState* MetalinkParserStateMachine::_finState = new FinMetalinkParserState();
+
+MetalinkParserStateMachine::MetalinkParserStateMachine():
+  _ctrl(new MetalinkParserController()),
+  _state(_initialState),
+  _skipTagState(0) {}
+
+MetalinkParserStateMachine::~MetalinkParserStateMachine()
+{
+  delete _skipTagState;
+}
+
+void MetalinkParserStateMachine::setMetalinkState()
+{
+  _state = _metalinkState;
+}
+
+void MetalinkParserStateMachine::setFilesState()
+{
+  _state = _filesState;
+}
+
+void MetalinkParserStateMachine::setFileState()
+{
+  _state = _fileState;
+}
+
+void MetalinkParserStateMachine::setSizeState()
+{
+  _state = _sizeState;
+}
+
+void MetalinkParserStateMachine::setVersionState()
+{
+  _state = _versionState;
+}
+
+void MetalinkParserStateMachine::setLanguageState()
+{
+  _state = _languageState;
+}
+
+void MetalinkParserStateMachine::setOSState()
+{
+  _state = _osState;
+}
+
+void MetalinkParserStateMachine::setVerificationState()
+{
+  _state = _verificationState;
+}
+
+void MetalinkParserStateMachine::setHashState()
+{
+  _state = _hashState;
+}
+
+void MetalinkParserStateMachine::setPiecesState()
+{
+  _state = _piecesState;
+}
+
+void MetalinkParserStateMachine::setPieceHashState()
+{
+  _state = _pieceHashState;
+}
+
+void MetalinkParserStateMachine::setResourcesState()
+{
+  _state = _resourcesState;
+}
+
+void MetalinkParserStateMachine::setURLState()
+{
+  _state = _urlState;
+}
+
+void MetalinkParserStateMachine::setFinState()
+{
+  _state = _finState;
+}
+
+void MetalinkParserStateMachine::setSkipTagState(MetalinkParserState* prevSate)
+{
+  _state = new SkipTagMetalinkParserState(prevSate);
+}
+
+void MetalinkParserStateMachine::restoreSavedState()
+{
+  _state = ((SkipTagMetalinkParserState*)_state)->getPreviousState();
+  delete _skipTagState;
+  _skipTagState = 0;
+}
+
+bool MetalinkParserStateMachine::finished() const
+{
+  return _state == _finState;
+}
+
+void MetalinkParserStateMachine::newEntryTransaction()
+{
+  _ctrl->newEntryTransaction();
+}
+
+void MetalinkParserStateMachine::setFileNameOfEntry(const string& filename)
+{
+  _ctrl->setFileNameOfEntry(filename);
+}
+
+void MetalinkParserStateMachine::setFileLengthOfEntry(int64_t length)
+{
+  _ctrl->setFileLengthOfEntry(length);
+}
+
+void MetalinkParserStateMachine::setVersionOfEntry(const string& version)
+{
+  _ctrl->setVersionOfEntry(version);
+}
+
+void MetalinkParserStateMachine::setLanguageOfEntry(const string& language)
+{
+  _ctrl->setLanguageOfEntry(language);
+}
+
+void MetalinkParserStateMachine::setOSOfEntry(const string& os)
+{
+  _ctrl->setOSOfEntry(os);
+}
+
+void MetalinkParserStateMachine::setMaxConnectionsOfEntry(int32_t maxConnections)
+{
+  _ctrl->setMaxConnectionsOfEntry(maxConnections);
+}
+
+void MetalinkParserStateMachine::commitEntryTransaction()
+{
+  _ctrl->commitEntryTransaction();
+}
+
+void MetalinkParserStateMachine::newResourceTransaction()
+{
+  _ctrl->newResourceTransaction();
+}
+
+void MetalinkParserStateMachine::setURLOfResource(const string& url)
+{
+  _ctrl->setURLOfResource(url);
+}
+
+void MetalinkParserStateMachine::setTypeOfResource(const string& type)
+{
+  _ctrl->setTypeOfResource(type);
+}
+
+void MetalinkParserStateMachine::setLocationOfResource(const string& location)
+{
+  _ctrl->setLocationOfResource(location);
+}
+
+void MetalinkParserStateMachine::setPreferenceOfResource(int32_t preference)
+{
+  _ctrl->setPreferenceOfResource(preference);
+}
+
+void MetalinkParserStateMachine::setMaxConnectionsOfResource(int32_t maxConnections)
+{
+  _ctrl->setMaxConnectionsOfResource(maxConnections);
+}
+
+void MetalinkParserStateMachine::commitResourceTransaction()
+{
+  _ctrl->commitResourceTransaction();
+}
+
+void MetalinkParserStateMachine::cancelResourceTransaction()
+{
+  _ctrl->cancelResourceTransaction();
+}
+
+void MetalinkParserStateMachine::newChecksumTransaction()
+{
+  _ctrl->newChecksumTransaction();
+}
+
+void MetalinkParserStateMachine::setTypeOfChecksum(const string& type)
+{
+  _ctrl->setTypeOfChecksum(type);
+}
+
+void MetalinkParserStateMachine::setHashOfChecksum(const string& md)
+{
+  _ctrl->setHashOfChecksum(md);
+}
+
+void MetalinkParserStateMachine::commitChecksumTransaction()
+{
+  _ctrl->commitChecksumTransaction();
+}
+
+void MetalinkParserStateMachine::cancelChecksumTransaction()
+{
+  _ctrl->cancelChecksumTransaction();
+}
+
+void MetalinkParserStateMachine::newChunkChecksumTransaction()
+{
+  _ctrl->newChunkChecksumTransaction();
+}
+
+void MetalinkParserStateMachine::setLengthOfChunkChecksum(int32_t length)
+{
+  _ctrl->setLengthOfChunkChecksum(length);
+}
+
+void MetalinkParserStateMachine::setTypeOfChunkChecksum(const string& type)
+{
+  _ctrl->setTypeOfChunkChecksum(type);
+}
+
+void MetalinkParserStateMachine::createNewHashOfChunkChecksum(int32_t order)
+{
+  _ctrl->createNewHashOfChunkChecksum(order);
+}
+
+void MetalinkParserStateMachine::setMessageDigestOfChunkChecksum(const string& md)
+{
+  _ctrl->setMessageDigestOfChunkChecksum(md);
+}
+
+void MetalinkParserStateMachine::addHashOfChunkChecksum()
+{
+  _ctrl->addHashOfChunkChecksum();
+}
+
+void MetalinkParserStateMachine::commitChunkChecksumTransaction()
+{
+  _ctrl->commitChunkChecksumTransaction();
+}
+
+void MetalinkParserStateMachine::cancelChunkChecksumTransaction()
+{
+  _ctrl->cancelChunkChecksumTransaction();
+}
+
+void MetalinkParserStateMachine::beginElement(const string& name,
+					      const map<string, string>& attrs)
+{
+  _state->beginElement(this, name, attrs);
+}
+  
+void MetalinkParserStateMachine::endElement(const string& name, const string& characters)
+{
+  _state->endElement(this, name, characters);
+}
+
+MetalinkerHandle MetalinkParserStateMachine::getResult() const
+{
+  return _ctrl->getResult();
+}

+ 178 - 0
src/MetalinkParserStateMachine.h

@@ -0,0 +1,178 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_METALINK_PARSER_STATE_MACHINE_H_
+#define _D_METALINK_PARSER_STATE_MACHINE_H_
+
+#include "common.h"
+#include <map>
+
+class MetalinkParserController;
+typedef SharedHandle<MetalinkParserController> MetalinkParserControllerHandle;
+class MetalinkParserState;
+class SkipTagMetalinkParserState;
+class Metalinker;
+typedef SharedHandle<Metalinker> MetalinkerHandle;
+
+class MetalinkParserStateMachine {
+private:
+  MetalinkParserControllerHandle _ctrl;
+
+  MetalinkParserState* _state;
+
+  static MetalinkParserState* _initialState;
+  static MetalinkParserState* _metalinkState;
+  static MetalinkParserState* _filesState;
+  static MetalinkParserState* _fileState;
+  static MetalinkParserState* _sizeState;
+  static MetalinkParserState* _versionState;
+  static MetalinkParserState* _languageState;
+  static MetalinkParserState* _osState;
+  static MetalinkParserState* _verificationState;
+  static MetalinkParserState* _hashState;
+  static MetalinkParserState* _piecesState;
+  static MetalinkParserState* _pieceHashState;
+  static MetalinkParserState* _resourcesState;
+  static MetalinkParserState* _urlState;
+  static MetalinkParserState* _finState;
+
+  SkipTagMetalinkParserState* _skipTagState;
+public:
+  MetalinkParserStateMachine();
+
+  ~MetalinkParserStateMachine();
+
+  void setMetalinkState();
+
+  void setFilesState();
+
+  void setFileState();
+
+  void setSizeState();
+
+  void setVersionState();
+
+  void setLanguageState();
+  
+  void setOSState();
+
+  void setVerificationState();
+
+  void setHashState();
+
+  void setPiecesState();
+
+  void setPieceHashState();
+
+  void setResourcesState();
+
+  void setURLState();
+
+  void setFinState();
+
+  void setSkipTagState(MetalinkParserState* prevSate);
+
+  void restoreSavedState();
+  
+  bool finished() const;
+
+  bool error() const;
+
+  void beginElement(const string& name, const map<string, string>& attrs);
+  
+  void endElement(const string& name, const string& characters);
+
+  void newEntryTransaction();
+
+  void setFileNameOfEntry(const string& filename);
+
+  void setFileLengthOfEntry(int64_t length);
+
+  void setVersionOfEntry(const string& version);
+
+  void setLanguageOfEntry(const string& language);
+
+  void setOSOfEntry(const string& os);
+
+  void setMaxConnectionsOfEntry(int32_t maxConnections);
+
+  void commitEntryTransaction();
+
+  void newResourceTransaction();
+
+  void setURLOfResource(const string& url);
+
+  void setTypeOfResource(const string& type);
+
+  void setLocationOfResource(const string& location);
+
+  void setPreferenceOfResource(int32_t preference);
+
+  void setMaxConnectionsOfResource(int32_t maxConnections);
+
+  void commitResourceTransaction();
+
+  void cancelResourceTransaction();
+
+  void newChecksumTransaction();
+
+  void setTypeOfChecksum(const string& type);
+
+  void setHashOfChecksum(const string& md);
+
+  void commitChecksumTransaction();
+
+  void cancelChecksumTransaction();
+
+  void newChunkChecksumTransaction();
+
+  void setLengthOfChunkChecksum(int32_t length);
+
+  void setTypeOfChunkChecksum(const string& type);
+
+  void createNewHashOfChunkChecksum(int32_t order);
+
+  void setMessageDigestOfChunkChecksum(const string& md);
+
+  void addHashOfChunkChecksum();
+
+  void commitChunkChecksumTransaction();
+
+  void cancelChunkChecksumTransaction();
+
+  MetalinkerHandle getResult() const;
+};
+
+typedef SharedHandle<MetalinkParserStateMachine> MetalinkParserStateMachineHandle;
+#endif // _D_METALINK_PARSER_STATE_MACHINE_H_

+ 51 - 0
src/OSMetalinkParserState.cc

@@ -0,0 +1,51 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "OSMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void OSMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					 const string& name,
+					 const map<string, string>& attrs)
+{
+  stm->setSkipTagState(this);
+}
+
+void OSMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+				       const string& name,
+				       const string& characters)
+{
+  stm->setOSOfEntry(characters);
+  stm->setFileState();
+}

+ 50 - 0
src/OSMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_OS_METALINK_PARSER_STATE_H_
+#define _D_OS_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class OSMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_OS_METALINK_PARSER_STATE_H_

+ 52 - 0
src/PieceHashMetalinkParserState.cc

@@ -0,0 +1,52 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "PieceHashMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void PieceHashMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+						const string& name,
+						const map<string, string>& attrs)
+{
+  stm->setSkipTagState(this);
+}
+
+void PieceHashMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					      const string& name,
+					      const string& characters)
+{
+  stm->setMessageDigestOfChunkChecksum(characters);
+  stm->addHashOfChunkChecksum();
+  stm->setPiecesState();
+}

+ 50 - 0
src/PieceHashMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_PIECE_HASH_METALINK_PARSER_STATE_H_
+#define _D_PIECE_HASH_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class PieceHashMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_PIECE_HASH_METALINK_PARSER_STATE_H_

+ 68 - 0
src/PiecesMetalinkParserState.cc

@@ -0,0 +1,68 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "PiecesMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+#include "RecoverableException.h"
+#include "Util.h"
+
+void PiecesMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					     const string& name,
+					     const map<string, string>& attrs)
+{
+  if(name == "hash") {
+    stm->setPieceHashState();
+    map<string, string>::const_iterator itr = attrs.find("piece");
+    if(itr == attrs.end()) {
+      stm->cancelChunkChecksumTransaction();
+    } else {
+      try {
+	stm->createNewHashOfChunkChecksum(Util::parseInt((*itr).second));
+      } catch(RecoverableException* e) {
+	delete e;
+	stm->cancelChunkChecksumTransaction();
+      }
+    }
+  } else {
+    stm->setSkipTagState(this);
+  }
+}
+
+void PiecesMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					   const string& name,
+					   const string& characters)
+{
+  stm->commitChunkChecksumTransaction();
+  stm->setVerificationState();
+}

+ 50 - 0
src/PiecesMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_PIECES_METALINK_PARSER_STATE_H_
+#define _D_PIECES_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class PiecesMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_PIECES_METALINK_PARSER_STATE_H_

+ 105 - 0
src/ResourcesMetalinkParserState.cc

@@ -0,0 +1,105 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "ResourcesMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+#include "Util.h"
+#include "RecoverableException.h"
+
+void ResourcesMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+						const string& name,
+						const map<string, string>& attrs)
+{
+  if(name == "url") {
+    stm->setURLState();
+    string type;
+    {
+      map<string, string>::const_iterator itr = attrs.find("type");
+      if(itr == attrs.end()) {
+	return;
+      } else {
+	type = (*itr).second;
+      }
+    }
+    string location;
+    {
+      map<string, string>::const_iterator itr = attrs.find("location");
+      if(itr != attrs.end()) {
+	location = Util::toUpper((*itr).second);
+      }
+    }
+    int32_t preference;
+    {
+      map<string, string>::const_iterator itr = attrs.find("preference");
+      if(itr == attrs.end()) {
+	preference = 0;
+      } else {
+	try {
+	  preference = Util::parseInt((*itr).second);
+	} catch(RecoverableException* e) {
+	  delete e;
+	  preference = 0;
+	}
+      }
+    }
+    int32_t maxConnections;
+    {
+      map<string, string>::const_iterator itr = attrs.find("maxconnections");
+      if(itr == attrs.end()) {
+	maxConnections = -1;
+      } else {
+	try {
+	  maxConnections = Util::parseInt((*itr).second);
+	} catch(RecoverableException* e) {
+	  delete e;
+	  maxConnections = -1;
+	}
+      }
+    }
+    stm->newResourceTransaction();
+    stm->setTypeOfResource(type);
+    stm->setLocationOfResource(location);
+    stm->setPreferenceOfResource(preference);
+    stm->setMaxConnectionsOfResource(maxConnections);
+  } else {
+    stm->setSkipTagState(this);
+  }
+}
+
+void ResourcesMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					      const string& name,
+					      const string& characters)
+{
+  stm->setFileState();
+}

+ 50 - 0
src/ResourcesMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_RESOURCES_METALINK_PARSER_STATE_H_
+#define _D_RESOURCES_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class ResourcesMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_RESOURCES_METALINK_PARSER_STATE_H_

+ 58 - 0
src/SizeMetalinkParserState.cc

@@ -0,0 +1,58 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "SizeMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+#include "Util.h"
+#include "RecoverableException.h"
+
+void SizeMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					   const string& name,
+					   const map<string, string>& attrs)
+{
+  stm->setSkipTagState(this);
+}
+
+void SizeMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					  const string& name,
+					  const string& characters)
+{
+  try {
+    stm->setFileLengthOfEntry(Util::parseInt(characters));
+  } catch(RecoverableException* e) {
+    delete e;
+    // current metalink specification doesn't require size element.
+  }
+  stm->setFileState();
+}

+ 50 - 0
src/SizeMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_SIZE_METALINK_PARSER_STATE_H_
+#define _D_SIZE_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class SizeMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_SIZE_METALINK_PARSER_STATE_H_

+ 55 - 0
src/SkipTagMetalinkParserState.cc

@@ -0,0 +1,55 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "SkipTagMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+SkipTagMetalinkParserState::SkipTagMetalinkParserState(MetalinkParserState* prevState):
+  _prevState(prevState), _depth(1) {}
+
+void SkipTagMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					      const string& name,
+					      const map<string, string>& attrs)
+{
+  ++_depth;
+}
+
+void SkipTagMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					    const string& name,
+					    const string& characters)
+{
+  if(--_depth == 0) {
+    stm->restoreSavedState();
+  }
+}

+ 60 - 0
src/SkipTagMetalinkParserState.h

@@ -0,0 +1,60 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_SKIP_TAG_METALINK_PARSER_STATE_H_
+#define _D_SKIP_TAG_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class SkipTagMetalinkParserState:public MetalinkParserState
+{
+private:
+  MetalinkParserState* _prevState;
+  int32_t _depth;
+public:
+  SkipTagMetalinkParserState(MetalinkParserState* prevState);
+
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+
+  MetalinkParserState* getPreviousState() const
+  {
+    return _prevState;
+  }
+};
+
+#endif // _D_SKIP_TAG_METALINK_PARSER_STATE_H_

+ 53 - 0
src/URLMetalinkParserState.cc

@@ -0,0 +1,53 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "URLMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void URLMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					  const string& name,
+					  const map<string, string>& attrs)
+{
+  stm->setSkipTagState(this);
+
+}
+
+void URLMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					const string& name,
+					const string& characters)
+{
+  stm->setURLOfResource(characters);
+  stm->commitResourceTransaction();
+  stm->setResourcesState();
+}

+ 50 - 0
src/URLMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_URL_METALINK_PARSER_STATE_H_
+#define _D_URL_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class URLMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_URL_METALINK_PARSER_STATE_H_

+ 92 - 0
src/VerificationMetalinkParserState.cc

@@ -0,0 +1,92 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "VerificationMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+#include "DlAbortEx.h"
+#include "Util.h"
+
+void VerificationMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+						   const string& name,
+						   const map<string, string>& attrs)
+{
+  if(name == "hash") {
+    stm->setHashState();
+    map<string, string>::const_iterator itr = attrs.find("type");
+    if(itr == attrs.end()) {
+      return;
+    } else {
+      string type = (*itr).second;
+      stm->newChecksumTransaction();
+      stm->setTypeOfChecksum(type);
+    }
+  } else if(name == "pieces") {
+    stm->setPiecesState();
+    try {
+      int32_t length;
+      {
+	map<string, string>::const_iterator itr = attrs.find("length");
+	if(itr == attrs.end()) {
+	  return;
+	} else {
+	  length = Util::parseInt((*itr).second);
+	}
+      }
+      string type;
+      {
+	map<string, string>::const_iterator itr = attrs.find("type");
+	if(itr == attrs.end()) {
+	  return;
+	} else {
+	  type = (*itr).second;
+	}
+      }
+      stm->newChunkChecksumTransaction();
+      stm->setLengthOfChunkChecksum(length);
+      stm->setTypeOfChunkChecksum(type);
+    } catch(RecoverableException* e) {
+      delete e;
+      stm->cancelChunkChecksumTransaction();
+    }
+  } else {
+    stm->setSkipTagState(this);
+  }
+}
+
+void VerificationMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+						 const string& name,
+						 const string& characters)
+{
+  stm->setFileState();
+}

+ 50 - 0
src/VerificationMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_VERIFICATION_METALINK_PARSER_STATE_H_
+#define _D_VERIFICATION_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class VerificationMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_VERIFICATION_METALINK_PARSER_STATE_H_

+ 51 - 0
src/VersionMetalinkParserState.cc

@@ -0,0 +1,51 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "VersionMetalinkParserState.h"
+#include "MetalinkParserStateMachine.h"
+
+void VersionMetalinkParserState::beginElement(MetalinkParserStateMachine* stm,
+					      const string& name,
+					      const map<string, string>& attrs)
+{
+  stm->setSkipTagState(this);
+}
+
+void VersionMetalinkParserState::endElement(MetalinkParserStateMachine* stm,
+					    const string& name,
+					    const string& characters)
+{
+  stm->setVersionOfEntry(characters);
+  stm->setFileState();
+}

+ 50 - 0
src/VersionMetalinkParserState.h

@@ -0,0 +1,50 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_VERSION_METALINK_PARSER_STATE_H_
+#define _D_VERSION_METALINK_PARSER_STATE_H_
+
+#include "MetalinkParserState.h"
+
+class VersionMetalinkParserState:public MetalinkParserState
+{
+public:
+  void beginElement(MetalinkParserStateMachine* stm,
+		    const string& name, const map<string, string>& attrs);
+
+  void endElement(MetalinkParserStateMachine* stm,
+		  const string& name, const string& characters);
+};
+
+#endif // _D_VERSION_METALINK_PARSER_STATE_H_

+ 167 - 0
src/XML2SAXMetalinkProcessor.cc

@@ -0,0 +1,167 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "XML2SAXMetalinkProcessor.h"
+#include "BinaryStream.h"
+#include "MetalinkParserStateMachine.h"
+#include "Util.h"
+
+class SessionData {
+public:
+  MetalinkParserStateMachineHandle _stm;
+
+  Strings _charactersStack;
+
+  SessionData(const MetalinkParserStateMachineHandle& stm):_stm(stm) {}
+};
+
+typedef SharedHandle<SessionData> SessionDataHandle;
+
+static void mlStartElement(void* userData, const xmlChar* name, const xmlChar** attrs)
+{
+  ((SessionData*)userData)->_charactersStack.push_front(string());
+  map<string, string> attrmap;
+  if(attrs) {
+    const xmlChar** p = attrs;
+    while(*p != 0) {
+      string name = (const char*)*p++;
+      if(*p == 0) {
+	break;
+      }
+      string value = Util::trim((const char*)*p++);
+      attrmap[name] = value;
+    }
+  }
+  ((SessionData*)userData)->_stm->beginElement((const char*)name, attrmap);
+}
+
+static void mlEndElement(void* userData, const xmlChar* name)
+{
+  SessionData* sd = (SessionData*)userData;
+
+  sd->_stm->endElement((const char*)name, Util::trim(sd->_charactersStack.front()));
+  sd->_charactersStack.pop_front();
+}
+
+static void mlCharacters(void* userData, const xmlChar* ch, int len)
+{
+  ((SessionData*)userData)->_charactersStack.front() += string(&ch[0], &ch[len]);
+}
+
+static xmlSAXHandler mySAXHandler =
+{
+  0, // internalSubsetSAXFunc
+  0, // isStandaloneSAXFunc
+  0, // hasInternalSubsetSAXFunc
+  0, // hasExternalSubsetSAXFunc
+  0, // resolveEntitySAXFunc
+  0, // getEntitySAXFunc
+  0, // entityDeclSAXFunc
+  0, // notationDeclSAXFunc
+  0, // attributeDeclSAXFunc
+  0, // elementDeclSAXFunc
+  0, //   unparsedEntityDeclSAXFunc
+  0, //   setDocumentLocatorSAXFunc
+  0, //   startDocumentSAXFunc
+  0, //   endDocumentSAXFunc
+  &mlStartElement, //   startElementSAXFunc
+  &mlEndElement, //   endElementSAXFunc
+  0, //   referenceSAXFunc
+  &mlCharacters, //   charactersSAXFunc
+  0, //   ignorableWhitespaceSAXFunc
+  0, //   processingInstructionSAXFunc
+  0, //   commentSAXFunc
+  0, //   warningSAXFunc
+  0, //   errorSAXFunc
+  0, //   fatalErrorSAXFunc
+  0, //   getParameterEntitySAXFunc
+  0, //   cdataBlockSAXFunc
+  0, //   externalSubsetSAXFunc
+  0, //   unsigned int	initialized
+  0, //   void *	_private
+  0, //   startElementNsSAX2Func
+  0, //   endElementNsSAX2Func
+  0, //   xmlStructuredErrorFunc
+};
+
+XML2SAXMetalinkProcessor::XML2SAXMetalinkProcessor():
+  _stm(0)
+{}
+	 
+	 
+MetalinkerHandle XML2SAXMetalinkProcessor::parseFile(const string& filename)
+{
+  _stm = new MetalinkParserStateMachine();
+  SessionDataHandle sessionData = new SessionData(_stm);
+  int32_t retval = xmlSAXUserParseFile(&mySAXHandler, sessionData.get(),
+				       filename.c_str());
+  if(retval != 0) {
+    throw new DlAbortEx("Cannot parse metalink XML file. XML may be malformed.");
+  }
+  return _stm->getResult();
+}
+	 
+MetalinkerHandle XML2SAXMetalinkProcessor::parseFromBinaryStream(const BinaryStreamHandle& binaryStream)
+{
+  _stm = new MetalinkParserStateMachine();
+  int32_t bufSize = 4096;
+  unsigned char buf[bufSize];
+
+  int32_t res = binaryStream->readData(buf, 4, 0);
+  if(res != 4) {
+    throw new DlAbortEx("Too small data for parsing XML.");
+  }
+
+  SessionDataHandle sessionData = new SessionData(_stm);
+  xmlParserCtxtPtr ctx = xmlCreatePushParserCtxt(&mySAXHandler, sessionData.get(), (const char*)buf, res, 0);
+
+  int64_t readOffset = res;
+  while(1) {
+    int32_t res = binaryStream->readData(buf, bufSize, readOffset);
+    if(res == 0) {
+      break;
+    }
+    if(xmlParseChunk(ctx, (const char*)buf, res, 0) != 0) {
+      throw new DlAbortEx("Cannot parse metalink XML file. XML may be malformed.");
+    }
+    readOffset += res;
+  }
+  xmlParseChunk(ctx, (const char*)buf, 0, 1);
+  xmlFreeParserCtxt(ctx);
+
+  if(!_stm->finished()) {
+    throw new DlAbortEx("Cannot parse metalink XML file. XML may be malformed.");
+  }
+  return _stm->getResult();
+}

+ 59 - 0
src/XML2SAXMetalinkProcessor.h

@@ -0,0 +1,59 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML2_SAX_METALINK_PROCESSOR_H_
+#define _D_XML2_SAX_METALINK_PROCESSOR_H_
+
+#include "MetalinkProcessor.h"
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+class MetalinkParserStateMachine;
+typedef SharedHandle<MetalinkParserStateMachine> MetalinkParserStateMachineHandle;
+
+class XML2SAXMetalinkProcessor:public MetalinkProcessor {
+private:
+  MetalinkParserStateMachineHandle _stm;
+
+public:
+  XML2SAXMetalinkProcessor();
+
+  virtual ~XML2SAXMetalinkProcessor() {}
+
+  virtual MetalinkerHandle parseFile(const string& filename);
+
+  virtual MetalinkerHandle parseFromBinaryStream(const BinaryStreamHandle& binaryStream);
+};
+
+#endif // _D_XML2_SAX_METALINK_PROCESSOR_H_

+ 5 - 3
src/main.cc

@@ -72,9 +72,11 @@ extern int optind, opterr, optopt;
 #include <getopt.h>
 
 #ifdef ENABLE_METALINK
-#include "Xml2MetalinkProcessor.h"
-#include "Metalink2RequestGroup.h"
-#endif
+# include "Metalink2RequestGroup.h"
+# include "MetalinkEntry.h"
+# include <libxml/parser.h>
+# include <libxml/xpath.h>
+#endif // ENABLE_METALINK
 
 #ifdef HAVE_LIBSSL
 // for SSL

+ 196 - 16
test/Base64Test.cc

@@ -1,14 +1,14 @@
 #include "Base64.h"
-#include <string>
 #include <cppunit/extensions/HelperMacros.h>
 
-using namespace std;
-
 class Base64Test:public CppUnit::TestFixture {
 
   CPPUNIT_TEST_SUITE(Base64Test);
   CPPUNIT_TEST(testEncode);
   CPPUNIT_TEST(testDecode);
+  CPPUNIT_TEST(testEncode_string);
+  CPPUNIT_TEST(testDecode_string);
+  CPPUNIT_TEST(testLongString);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -18,25 +18,205 @@ public:
 
   void testEncode();
   void testDecode();
+  void testEncode_string();
+  void testDecode_string();
+  void testLongString();
 };
 
 
 CPPUNIT_TEST_SUITE_REGISTRATION( Base64Test );
 
 void Base64Test::testEncode() {
-  CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybGQh"),
-		       Base64::encode("Hello World!"));
-  CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybGQ="),
-		       Base64::encode("Hello World"));
-  CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybA=="),
-		       Base64::encode("Hello Worl"));
-  CPPUNIT_ASSERT_EQUAL(string("YQ=="),
-		       Base64::encode("a"));
-  CPPUNIT_ASSERT_EQUAL(string(""),
-		       Base64::encode(""));
+  unsigned char* buf = 0;
+  size_t len;
+  string s1 = "Hello World!";
+  Base64::encode(buf, len, s1.c_str(), s1.size());
+  CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybGQh"), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  string s2 = "Hello World";
+  Base64::encode(buf, len, s2.c_str(), s2.size());
+  CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybGQ="), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  string s3 = "Hello Worl";
+  Base64::encode(buf, len, s3.c_str(), s3.size());
+  CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybA=="), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  string s4 = "Man";
+  Base64::encode(buf, len, s4.c_str(), s4.size());
+  CPPUNIT_ASSERT_EQUAL(string("TWFu"), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  string s5 = "M";
+  Base64::encode(buf, len, s5.c_str(), s5.size());
+  CPPUNIT_ASSERT_EQUAL(string("TQ=="), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  buf = 0;
+  string s6 = "";
+  Base64::encode(buf, len, s6.c_str(), s6.size());
+  CPPUNIT_ASSERT_EQUAL(string(""), string(&buf[0], &buf[len]));
+  CPPUNIT_ASSERT_EQUAL((size_t)0, len);
+  CPPUNIT_ASSERT(0 == buf);
+
+  {
+    const char temp[] = { -1 };
+    Base64::encode(buf, len, temp, 1);
+    CPPUNIT_ASSERT_EQUAL(string("/w=="), string(&buf[0], &buf[len]));
+    delete [] buf;
+  }
+}
+
+void Base64Test::testEncode_string()
+{
+  string s1 = "Hello World!";
+  CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybGQh"), Base64::encode(s1));
+
+  string s2 = "";
+  CPPUNIT_ASSERT_EQUAL(string(""), Base64::encode(s2));
+
+
+  
+}
+
+void Base64Test::testDecode()
+{
+  unsigned char* buf;
+  size_t len;
+
+  string s1 = "SGVsbG8gV29ybGQh";
+  Base64::decode(buf, len, s1.c_str(), s1.size());
+  CPPUNIT_ASSERT_EQUAL(string("Hello World!"), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  string s2 = "SGVsbG8gV29ybGQ=";
+  Base64::decode(buf, len, s2.c_str(), s2.size());
+  CPPUNIT_ASSERT_EQUAL(string("Hello World"), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  string s3 = "SGVsbG8gV29ybA==";
+  Base64::decode(buf, len, s3.c_str(), s3.size());
+  CPPUNIT_ASSERT_EQUAL(string("Hello Worl"), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  string s4 = "TWFu";
+  Base64::decode(buf, len, s4.c_str(), s4.size());
+  CPPUNIT_ASSERT_EQUAL(string("Man"), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  string s5 = "TQ==";
+  Base64::decode(buf, len, s5.c_str(), s5.size());
+  CPPUNIT_ASSERT_EQUAL(string("M"), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  buf = 0;
+  string s6 = "";
+  Base64::decode(buf, len, s6.c_str(), s6.size());
+  CPPUNIT_ASSERT_EQUAL(string(""), string(&buf[0], &buf[len]));
+  CPPUNIT_ASSERT_EQUAL((size_t)0, len);
+  CPPUNIT_ASSERT(!buf);
+
+  string s7 = "SGVsbG8\ngV2*9ybGQ=";
+  Base64::decode(buf, len, s7.c_str(), s7.size());
+  CPPUNIT_ASSERT_EQUAL(string("Hello World"), string(&buf[0], &buf[len]));
+  delete [] buf;
+
+  buf = 0;
+  string s8 = "SGVsbG8\ngV2*9ybGQ";
+  Base64::decode(buf, len, s8.c_str(), s8.size());
+  CPPUNIT_ASSERT_EQUAL(string(""), string(&buf[0], &buf[len]));
+  CPPUNIT_ASSERT_EQUAL((size_t)0, len);
+  CPPUNIT_ASSERT(!buf);
+
+  {
+    string s = "/w==";
+    Base64::decode(buf, len, s.c_str(), s.size());
+    CPPUNIT_ASSERT_EQUAL((unsigned char)-1, buf[0]);
+    delete [] buf;
+  }
+
+}
+
+void Base64Test::testDecode_string()
+{
+  string s1 = "SGVsbG8gV29ybGQh";
+  CPPUNIT_ASSERT_EQUAL(string("Hello World!"), Base64::decode(s1));
+
+  string s2 = "";
+  CPPUNIT_ASSERT_EQUAL(string(""), Base64::decode(s2));
 }
 
-void Base64Test::testDecode() {
-  CPPUNIT_ASSERT_EQUAL(string("Hello World!"),
-		       Base64::decode("SGVsbG8gV29ybGQh"));
+void Base64Test::testLongString()
+{
+  string s =
+    "LyogPCEtLSBjb3B5cmlnaHQgKi8KLyoKICogYXJpYTIgLSBUaGUgaGlnaCBzcGVlZCBkb3dubG9h"
+    "ZCB1dGlsaXR5CiAqCiAqIENvcHlyaWdodCAoQykgMjAwNiBUYXRzdWhpcm8gVHN1amlrYXdhCiAq"
+    "CiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBp"
+    "dCBhbmQvb3IgbW9kaWZ5CiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwg"
+    "UHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5CiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5k"
+    "YXRpb247IGVpdGhlciB2ZXJzaW9uIDIgb2YgdGhlIExpY2Vuc2UsIG9yCiAqIChhdCB5b3VyIG9w"
+    "dGlvbikgYW55IGxhdGVyIHZlcnNpb24uCiAqCiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRl"
+    "ZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAogKiBidXQgV0lUSE9VVCBBTlkg"
+    "V0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgogKiBNRVJDSEFO"
+    "VEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlCiAq"
+    "IEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCiAqCiAqIFlvdSBz"
+    "aG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNl"
+    "bnNlCiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVl"
+    "IFNvZnR3YXJlCiAqIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGgg"
+    "Rmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQQogKgogKiBJbiBhZGRpdGlvbiwgYXMg"
+    "YSBzcGVjaWFsIGV4Y2VwdGlvbiwgdGhlIGNvcHlyaWdodCBob2xkZXJzIGdpdmUKICogcGVybWlz"
+    "c2lvbiB0byBsaW5rIHRoZSBjb2RlIG9mIHBvcnRpb25zIG9mIHRoaXMgcHJvZ3JhbSB3aXRoIHRo"
+    "ZQogKiBPcGVuU1NMIGxpYnJhcnkgdW5kZXIgY2VydGFpbiBjb25kaXRpb25zIGFzIGRlc2NyaWJl"
+    "ZCBpbiBlYWNoCiAqIGluZGl2aWR1YWwgc291cmNlIGZpbGUsIGFuZCBkaXN0cmlidXRlIGxpbmtl"
+    "ZCBjb21iaW5hdGlvbnMKICogaW5jbHVkaW5nIHRoZSB0d28uCiAqIFlvdSBtdXN0IG9iZXkgdGhl"
+    "IEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGluIGFsbCByZXNwZWN0cwogKiBmb3IgYWxsIG9m"
+    "IHRoZSBjb2RlIHVzZWQgb3RoZXIgdGhhbiBPcGVuU1NMLiAgSWYgeW91IG1vZGlmeQogKiBmaWxl"
+    "KHMpIHdpdGggdGhpcyBleGNlcHRpb24sIHlvdSBtYXkgZXh0ZW5kIHRoaXMgZXhjZXB0aW9uIHRv"
+    "IHlvdXIKICogdmVyc2lvbiBvZiB0aGUgZmlsZShzKSwgYnV0IHlvdSBhcmUgbm90IG9ibGlnYXRl"
+    "ZCB0byBkbyBzby4gIElmIHlvdQogKiBkbyBub3Qgd2lzaCB0byBkbyBzbywgZGVsZXRlIHRoaXMg"
+    "ZXhjZXB0aW9uIHN0YXRlbWVudCBmcm9tIHlvdXIKICogdmVyc2lvbi4gIElmIHlvdSBkZWxldGUg"
+    "dGhpcyBleGNlcHRpb24gc3RhdGVtZW50IGZyb20gYWxsIHNvdXJjZQogKiBmaWxlcyBpbiB0aGUg"
+    "cHJvZ3JhbSwgdGhlbiBhbHNvIGRlbGV0ZSBpdCBoZXJlLgogKi8KLyogY29weXJpZ2h0IC0tPiAq"
+    "Lwo=";
+  string d =
+    "/* <!-- copyright */\n"
+    "/*\n"
+    " * aria2 - The high speed download utility\n"
+    " *\n"
+    " * Copyright (C) 2006 Tatsuhiro Tsujikawa\n"
+    " *\n"
+    " * This program is free software; you can redistribute it and/or modify\n"
+    " * it under the terms of the GNU General Public License as published by\n"
+    " * the Free Software Foundation; either version 2 of the License, or\n"
+    " * (at your option) any later version.\n"
+    " *\n"
+    " * This program is distributed in the hope that it will be useful,\n"
+    " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+    " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+    " * GNU General Public License for more details.\n"
+    " *\n"
+    " * You should have received a copy of the GNU General Public License\n"
+    " * along with this program; if not, write to the Free Software\n"
+    " * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n"
+    " *\n"
+    " * In addition, as a special exception, the copyright holders give\n"
+    " * permission to link the code of portions of this program with the\n"
+    " * OpenSSL library under certain conditions as described in each\n"
+    " * individual source file, and distribute linked combinations\n"
+    " * including the two.\n"
+    " * You must obey the GNU General Public License in all respects\n"
+    " * for all of the code used other than OpenSSL.  If you modify\n"
+    " * file(s) with this exception, you may extend this exception to your\n"
+    " * version of the file(s), but you are not obligated to do so.  If you\n"
+    " * do not wish to do so, delete this exception statement from your\n"
+    " * version.  If you delete this exception statement from all source\n"
+    " * files in the program, then also delete it here.\n"
+    " */\n"
+    "/* copyright --> */\n";
+  CPPUNIT_ASSERT_EQUAL(d,
+		       Base64::decode(s));  
+  CPPUNIT_ASSERT_EQUAL(s,
+		       Base64::encode(d));  
 }

+ 4 - 4
test/Makefile.am

@@ -1,6 +1,7 @@
 TESTS = aria2c
 check_PROGRAMS = $(TESTS)
 aria2c_SOURCES = AllTest.cc\
+	Base64Test.cc\
 	SequenceTest.cc\
 	a2functionalTest.cc\
 	FileEntryTest.cc\
@@ -38,7 +39,6 @@ aria2c_SOURCES = AllTest.cc\
 	ChunkedEncodingTest.cc\
 	FileTest.cc\
 	OptionTest.cc\
-	Base64Test.cc\
 	DefaultDiskWriterTest.cc\
 	FeatureConfigTest.cc\
 	SpeedCalcTest.cc\
@@ -101,13 +101,13 @@ endif # ENABLE_BITTORRENT
 if ENABLE_METALINK
 aria2c_SOURCES += MetalinkerTest.cc\
 	MetalinkEntryTest.cc\
-	Xml2MetalinkProcessorTest.cc\
 	Metalink2RequestGroupTest.cc\
 	MetalinkPostDownloadHandlerTest.cc\
-	MetalinkHelperTest.cc
+	MetalinkHelperTest.cc\
+	MetalinkParserControllerTest.cc\
+	XML2SAXMetalinkProcessorTest.cc
 endif # ENABLE_METALINK
 
-
 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
 

+ 30 - 25
test/Makefile.in

@@ -87,10 +87,11 @@ check_PROGRAMS = $(am__EXEEXT_1)
 
 @ENABLE_METALINK_TRUE@am__append_3 = MetalinkerTest.cc\
 @ENABLE_METALINK_TRUE@	MetalinkEntryTest.cc\
-@ENABLE_METALINK_TRUE@	Xml2MetalinkProcessorTest.cc\
 @ENABLE_METALINK_TRUE@	Metalink2RequestGroupTest.cc\
 @ENABLE_METALINK_TRUE@	MetalinkPostDownloadHandlerTest.cc\
-@ENABLE_METALINK_TRUE@	MetalinkHelperTest.cc
+@ENABLE_METALINK_TRUE@	MetalinkHelperTest.cc\
+@ENABLE_METALINK_TRUE@	MetalinkParserControllerTest.cc\
+@ENABLE_METALINK_TRUE@	XML2SAXMetalinkProcessorTest.cc
 
 subdir = test
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
@@ -113,7 +114,7 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 am__EXEEXT_1 = aria2c$(EXEEXT)
-am__aria2c_SOURCES_DIST = AllTest.cc SequenceTest.cc \
+am__aria2c_SOURCES_DIST = AllTest.cc Base64Test.cc SequenceTest.cc \
 	a2functionalTest.cc FileEntryTest.cc PieceTest.cc \
 	SegmentTest.cc GrowSegmentTest.cc \
 	SingleFileAllocationIteratorTest.cc \
@@ -129,10 +130,10 @@ am__aria2c_SOURCES_DIST = AllTest.cc SequenceTest.cc \
 	OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \
 	NetrcTest.cc SingletonHolderTest.cc HttpHeaderTest.cc \
 	HttpResponseTest.cc SharedHandleTest.cc ChunkedEncodingTest.cc \
-	FileTest.cc OptionTest.cc Base64Test.cc \
-	DefaultDiskWriterTest.cc FeatureConfigTest.cc SpeedCalcTest.cc \
-	FixedNumberRandomizer.h MultiDiskAdaptorTest.cc \
-	MultiFileAllocationIteratorTest.cc MessageDigestHelperTest.cc \
+	FileTest.cc OptionTest.cc DefaultDiskWriterTest.cc \
+	FeatureConfigTest.cc SpeedCalcTest.cc FixedNumberRandomizer.h \
+	MultiDiskAdaptorTest.cc MultiFileAllocationIteratorTest.cc \
+	MessageDigestHelperTest.cc \
 	IteratableChunkChecksumValidatorTest.cc \
 	IteratableChecksumValidatorTest.cc BtAllowedFastMessageTest.cc \
 	BtBitfieldMessageTest.cc BtCancelMessageTest.cc \
@@ -155,8 +156,10 @@ am__aria2c_SOURCES_DIST = AllTest.cc SequenceTest.cc \
 	BtRegistryTest.cc BtDependencyTest.cc \
 	BtPostDownloadHandlerTest.cc DownloadHandlerFactoryTest.cc \
 	TimeSeedCriteriaTest.cc MetalinkerTest.cc MetalinkEntryTest.cc \
-	Xml2MetalinkProcessorTest.cc Metalink2RequestGroupTest.cc \
-	MetalinkPostDownloadHandlerTest.cc MetalinkHelperTest.cc
+	Metalink2RequestGroupTest.cc \
+	MetalinkPostDownloadHandlerTest.cc MetalinkHelperTest.cc \
+	MetalinkParserControllerTest.cc \
+	XML2SAXMetalinkProcessorTest.cc
 @ENABLE_MESSAGE_DIGEST_TRUE@am__objects_1 =  \
 @ENABLE_MESSAGE_DIGEST_TRUE@	MessageDigestHelperTest.$(OBJEXT) \
 @ENABLE_MESSAGE_DIGEST_TRUE@	IteratableChunkChecksumValidatorTest.$(OBJEXT) \
@@ -203,14 +206,15 @@ am__aria2c_SOURCES_DIST = AllTest.cc SequenceTest.cc \
 @ENABLE_BITTORRENT_TRUE@	TimeSeedCriteriaTest.$(OBJEXT)
 @ENABLE_METALINK_TRUE@am__objects_3 = MetalinkerTest.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkEntryTest.$(OBJEXT) \
-@ENABLE_METALINK_TRUE@	Xml2MetalinkProcessorTest.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	Metalink2RequestGroupTest.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkPostDownloadHandlerTest.$(OBJEXT) \
-@ENABLE_METALINK_TRUE@	MetalinkHelperTest.$(OBJEXT)
-am_aria2c_OBJECTS = AllTest.$(OBJEXT) SequenceTest.$(OBJEXT) \
-	a2functionalTest.$(OBJEXT) FileEntryTest.$(OBJEXT) \
-	PieceTest.$(OBJEXT) SegmentTest.$(OBJEXT) \
-	GrowSegmentTest.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	MetalinkHelperTest.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	MetalinkParserControllerTest.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@	XML2SAXMetalinkProcessorTest.$(OBJEXT)
+am_aria2c_OBJECTS = AllTest.$(OBJEXT) Base64Test.$(OBJEXT) \
+	SequenceTest.$(OBJEXT) a2functionalTest.$(OBJEXT) \
+	FileEntryTest.$(OBJEXT) PieceTest.$(OBJEXT) \
+	SegmentTest.$(OBJEXT) GrowSegmentTest.$(OBJEXT) \
 	SingleFileAllocationIteratorTest.$(OBJEXT) \
 	DefaultBtProgressInfoFileTest.$(OBJEXT) \
 	SingleFileDownloadContextTest.$(OBJEXT) \
@@ -229,7 +233,7 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) SequenceTest.$(OBJEXT) \
 	NetrcTest.$(OBJEXT) SingletonHolderTest.$(OBJEXT) \
 	HttpHeaderTest.$(OBJEXT) HttpResponseTest.$(OBJEXT) \
 	SharedHandleTest.$(OBJEXT) ChunkedEncodingTest.$(OBJEXT) \
-	FileTest.$(OBJEXT) OptionTest.$(OBJEXT) Base64Test.$(OBJEXT) \
+	FileTest.$(OBJEXT) OptionTest.$(OBJEXT) \
 	DefaultDiskWriterTest.$(OBJEXT) FeatureConfigTest.$(OBJEXT) \
 	SpeedCalcTest.$(OBJEXT) MultiDiskAdaptorTest.$(OBJEXT) \
 	MultiFileAllocationIteratorTest.$(OBJEXT) $(am__objects_1) \
@@ -420,9 +424,10 @@ target_cpu = @target_cpu@
 target_os = @target_os@
 target_vendor = @target_vendor@
 TESTS = aria2c
-aria2c_SOURCES = AllTest.cc SequenceTest.cc a2functionalTest.cc \
-	FileEntryTest.cc PieceTest.cc SegmentTest.cc \
-	GrowSegmentTest.cc SingleFileAllocationIteratorTest.cc \
+aria2c_SOURCES = AllTest.cc Base64Test.cc SequenceTest.cc \
+	a2functionalTest.cc FileEntryTest.cc PieceTest.cc \
+	SegmentTest.cc GrowSegmentTest.cc \
+	SingleFileAllocationIteratorTest.cc \
 	DefaultBtProgressInfoFileTest.cc \
 	SingleFileDownloadContextTest.cc RequestGroupTest.cc \
 	PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \
@@ -435,11 +440,10 @@ aria2c_SOURCES = AllTest.cc SequenceTest.cc a2functionalTest.cc \
 	OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \
 	NetrcTest.cc SingletonHolderTest.cc HttpHeaderTest.cc \
 	HttpResponseTest.cc SharedHandleTest.cc ChunkedEncodingTest.cc \
-	FileTest.cc OptionTest.cc Base64Test.cc \
-	DefaultDiskWriterTest.cc FeatureConfigTest.cc SpeedCalcTest.cc \
-	FixedNumberRandomizer.h MultiDiskAdaptorTest.cc \
-	MultiFileAllocationIteratorTest.cc $(am__append_1) \
-	$(am__append_2) $(am__append_3)
+	FileTest.cc OptionTest.cc DefaultDiskWriterTest.cc \
+	FeatureConfigTest.cc SpeedCalcTest.cc FixedNumberRandomizer.h \
+	MultiDiskAdaptorTest.cc MultiFileAllocationIteratorTest.cc \
+	$(am__append_1) $(am__append_2) $(am__append_3)
 
 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
@@ -564,6 +568,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalink2RequestGroupTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntryTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkHelperTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkParserControllerTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkPostDownloadHandlerTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkerTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskAdaptorTest.Po@am__quote@
@@ -593,7 +598,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StreamUriListParserTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessorTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XML2SAXMetalinkProcessorTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/a2functionalTest.Po@am__quote@
 
 .cc.o:

+ 140 - 0
test/MetalinkParserControllerTest.cc

@@ -0,0 +1,140 @@
+#include "MetalinkParserController.h"
+#include "Metalinker.h"
+#include "MetalinkEntry.h"
+#include "MetalinkResource.h"
+#include "Checksum.h"
+#include "ChunkChecksum.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class MetalinkParserControllerTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(MetalinkParserControllerTest);
+  CPPUNIT_TEST(testEntryTransaction);
+  CPPUNIT_TEST(testResourceTransaction);
+  CPPUNIT_TEST(testChecksumTransaction);
+  CPPUNIT_TEST(testChunkChecksumTransaction);
+
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {}
+
+  void tearDown() {}
+
+  void testEntryTransaction();
+  void testResourceTransaction();
+  void testChecksumTransaction();
+  void testChunkChecksumTransaction();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( MetalinkParserControllerTest );
+
+void MetalinkParserControllerTest::testEntryTransaction()
+{
+  MetalinkParserController ctrl;
+
+  ctrl.newEntryTransaction();
+  ctrl.setFileNameOfEntry("aria2.tar.bz2");
+  ctrl.setFileLengthOfEntry(1024*1024);
+  ctrl.setVersionOfEntry("1.0");
+  ctrl.setLanguageOfEntry("ja_JP");
+  ctrl.setOSOfEntry("Linux");
+  ctrl.commitEntryTransaction();
+  {
+    MetalinkerHandle m = ctrl.getResult();
+    CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
+    MetalinkEntryHandle e = m->entries.front();
+    CPPUNIT_ASSERT_EQUAL(string("aria2.tar.bz2"), e->file->getPath());
+    CPPUNIT_ASSERT_EQUAL((int64_t)1024*1024, e->file->getLength());
+    CPPUNIT_ASSERT_EQUAL((int64_t)0, e->file->getOffset());
+    CPPUNIT_ASSERT_EQUAL(string("1.0"), e->version);
+    CPPUNIT_ASSERT_EQUAL(string("ja_JP"), e->language);
+    CPPUNIT_ASSERT_EQUAL(string("Linux"), e->os);
+  }
+  ctrl.newEntryTransaction();
+  ctrl.cancelEntryTransaction();
+  CPPUNIT_ASSERT_EQUAL((size_t)1, ctrl.getResult()->entries.size());
+}
+
+void MetalinkParserControllerTest::testResourceTransaction()
+{
+  MetalinkParserController ctrl;
+  ctrl.newEntryTransaction();
+  ctrl.newResourceTransaction();
+  ctrl.setURLOfResource("http://mirror/aria2.tar.bz2");
+  ctrl.setTypeOfResource("http");
+  ctrl.setLocationOfResource("US");
+  ctrl.setPreferenceOfResource(100);
+  ctrl.setMaxConnectionsOfResource(1);
+  ctrl.commitEntryTransaction();
+  {
+    MetalinkerHandle m = ctrl.getResult();
+    CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.front()->resources.size());
+    MetalinkResourceHandle res = m->entries.front()->resources[0];
+    CPPUNIT_ASSERT_EQUAL(string("http://mirror/aria2.tar.bz2"), res->url);
+    CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_HTTP, res->type);
+    CPPUNIT_ASSERT_EQUAL(string("US"), res->location);
+    CPPUNIT_ASSERT_EQUAL(100, res->preference);
+    CPPUNIT_ASSERT_EQUAL(1, res->maxConnections);
+  }
+  ctrl.newEntryTransaction();
+  ctrl.newResourceTransaction();
+  ctrl.cancelResourceTransaction();
+  ctrl.commitEntryTransaction();
+  CPPUNIT_ASSERT_EQUAL((size_t)1, ctrl.getResult()->entries.front()->resources.size());
+}
+
+void MetalinkParserControllerTest::testChecksumTransaction()
+{
+  MetalinkParserController ctrl;
+  ctrl.newEntryTransaction();
+  ctrl.newChecksumTransaction();
+  ctrl.setTypeOfChecksum("md5");
+  ctrl.setHashOfChecksum("hash");
+  ctrl.commitEntryTransaction();
+  {
+    MetalinkerHandle m = ctrl.getResult();
+    ChecksumHandle md = m->entries.front()->checksum;
+    CPPUNIT_ASSERT_EQUAL(string("md5"), md->getAlgo());
+    CPPUNIT_ASSERT_EQUAL(string("hash"), md->getMessageDigest());
+  }
+  ctrl.newEntryTransaction();
+  ctrl.newChecksumTransaction();
+  ctrl.cancelChecksumTransaction();
+  ctrl.commitEntryTransaction();
+  CPPUNIT_ASSERT(ctrl.getResult()->entries[1]->checksum.isNull());
+}
+
+void MetalinkParserControllerTest::testChunkChecksumTransaction()
+{
+  MetalinkParserController ctrl;
+  ctrl.newEntryTransaction();
+  ctrl.newChunkChecksumTransaction();
+  ctrl.setTypeOfChunkChecksum("md5");
+  ctrl.setLengthOfChunkChecksum(256*1024);
+  ctrl.addHashOfChunkChecksum(4, "hash4");
+  ctrl.addHashOfChunkChecksum(1, "hash1");
+  ctrl.addHashOfChunkChecksum(3, "hash3");
+  ctrl.addHashOfChunkChecksum(2, "hash2");
+  ctrl.addHashOfChunkChecksum(5, "hash5");
+  ctrl.commitEntryTransaction();
+  {
+    MetalinkerHandle m = ctrl.getResult();
+    ChunkChecksumHandle md = m->entries.front()->chunkChecksum;
+    CPPUNIT_ASSERT_EQUAL(string("md5"), md->getAlgo());
+    CPPUNIT_ASSERT_EQUAL(256*1024, md->getChecksumLength());
+    CPPUNIT_ASSERT_EQUAL(5, md->countChecksum());
+    CPPUNIT_ASSERT_EQUAL(string("hash1"), md->getChecksums()[0]);
+    CPPUNIT_ASSERT_EQUAL(string("hash2"), md->getChecksums()[1]);
+    CPPUNIT_ASSERT_EQUAL(string("hash3"), md->getChecksums()[2]);
+    CPPUNIT_ASSERT_EQUAL(string("hash4"), md->getChecksums()[3]);
+    CPPUNIT_ASSERT_EQUAL(string("hash5"), md->getChecksums()[4]);
+  }
+  ctrl.newEntryTransaction();
+  ctrl.newChunkChecksumTransaction();
+  ctrl.cancelChunkChecksumTransaction();
+  ctrl.commitEntryTransaction();
+  CPPUNIT_ASSERT(ctrl.getResult()->entries[1]->chunkChecksum.isNull());
+}

+ 511 - 0
test/XML2SAXMetalinkProcessorTest.cc

@@ -0,0 +1,511 @@
+#include "XML2SAXMetalinkProcessor.h"
+#include "MetalinkParserStateMachine.h"
+#include "Exception.h"
+#include "DefaultDiskWriter.h"
+#include "ByteArrayDiskWriter.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class XML2SAXMetalinkProcessorTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(XML2SAXMetalinkProcessorTest);
+  CPPUNIT_TEST(testParseFile);
+  CPPUNIT_TEST(testParseFromBinaryStream);
+  CPPUNIT_TEST(testMalformedXML);
+  CPPUNIT_TEST(testMalformedXML2);
+  CPPUNIT_TEST(testBadSize);
+  CPPUNIT_TEST(testBadMaxConn);
+  CPPUNIT_TEST(testNoName);
+  CPPUNIT_TEST(testBadURLPrefs);
+  CPPUNIT_TEST(testBadURLMaxConn);
+  CPPUNIT_TEST(testUnsupportedType);
+  CPPUNIT_TEST(testMultiplePieces);
+  CPPUNIT_TEST(testBadPieceNo);
+  CPPUNIT_TEST(testBadPieceLength);
+  CPPUNIT_TEST(testUnsupportedType_piece);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+    xmlInitParser();
+  }
+  void tearDown() {
+    xmlCleanupParser();
+  }
+
+  void testParseFile();
+  void testParseFromBinaryStream();
+  void testMalformedXML();
+  void testMalformedXML2();
+  void testBadSize();
+  void testBadMaxConn();
+  void testNoName();
+  void testBadURLPrefs();
+  void testBadURLMaxConn();
+  void testUnsupportedType();
+  void testMultiplePieces();
+  void testBadPieceNo();
+  void testBadPieceLength();
+  void testUnsupportedType_piece();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( XML2SAXMetalinkProcessorTest );
+
+void XML2SAXMetalinkProcessorTest::testParseFile()
+{
+  XML2SAXMetalinkProcessor proc;
+  try {
+    MetalinkerHandle metalinker = proc.parseFile("test.xml");
+
+    MetalinkEntries::iterator entryItr = metalinker->entries.begin();
+
+    MetalinkEntryHandle entry1 = *entryItr;
+    CPPUNIT_ASSERT_EQUAL(string("aria2-0.5.2.tar.bz2"), entry1->getPath());
+    CPPUNIT_ASSERT_EQUAL((int64_t)0, entry1->getLength());
+    CPPUNIT_ASSERT_EQUAL(string("0.5.2"), entry1->version);
+    CPPUNIT_ASSERT_EQUAL(string("en-US"), entry1->language);
+    CPPUNIT_ASSERT_EQUAL(string("Linux-x86"), entry1->os);
+    CPPUNIT_ASSERT_EQUAL((int32_t)1, entry1->maxConnections);
+#ifdef ENABLE_MESSAGE_DIGEST
+    CPPUNIT_ASSERT_EQUAL(string("a96cf3f0266b91d87d5124cf94326422800b627d"),
+			 entry1->checksum->getMessageDigest());
+    CPPUNIT_ASSERT_EQUAL(string("sha1"), entry1->checksum->getAlgo());
+#endif // ENABLE_MESSAGE_DIGEST
+    MetalinkResources::iterator resourceItr1 = entry1->resources.begin();
+    MetalinkResourceHandle resource1 = *resourceItr1;
+    CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, resource1->type);
+    CPPUNIT_ASSERT_EQUAL(string("JP"), resource1->location);
+    CPPUNIT_ASSERT_EQUAL((int32_t)100, resource1->preference);
+    CPPUNIT_ASSERT_EQUAL(string("ftp://ftphost/aria2-0.5.2.tar.bz2"),
+			 resource1->url);
+    CPPUNIT_ASSERT_EQUAL((int32_t)1, resource1->maxConnections);
+
+    resourceItr1++;
+    MetalinkResourceHandle resource2 = *resourceItr1;
+    CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_HTTP, resource2->type);
+    CPPUNIT_ASSERT_EQUAL(string("US"), resource2->location);
+    CPPUNIT_ASSERT_EQUAL((int32_t)100, resource2->preference);
+    CPPUNIT_ASSERT_EQUAL(string("http://httphost/aria2-0.5.2.tar.bz2"),
+			 resource2->url);
+    CPPUNIT_ASSERT_EQUAL((int32_t)-1, resource2->maxConnections);
+
+    entryItr++;
+
+    MetalinkEntryHandle entry2 = *entryItr;
+    CPPUNIT_ASSERT_EQUAL(string("aria2-0.5.1.tar.bz2"), entry2->getPath());
+    CPPUNIT_ASSERT_EQUAL((int64_t)345689, entry2->getLength());
+    CPPUNIT_ASSERT_EQUAL(string("0.5.1"), entry2->version);
+    CPPUNIT_ASSERT_EQUAL(string("ja-JP"), entry2->language);
+    CPPUNIT_ASSERT_EQUAL(string("Linux-m68k"), entry2->os);
+    CPPUNIT_ASSERT_EQUAL((int32_t)-1, entry2->maxConnections);
+#ifdef ENABLE_MESSAGE_DIGEST
+    CPPUNIT_ASSERT_EQUAL(string("4c255b0ed130f5ea880f0aa061c3da0487e251cc"),
+			 entry2->checksum->getMessageDigest());
+    CPPUNIT_ASSERT_EQUAL((int32_t)2, entry2->chunkChecksum->countChecksum());
+    CPPUNIT_ASSERT_EQUAL((int32_t)262144, entry2->chunkChecksum->getChecksumLength());
+    CPPUNIT_ASSERT_EQUAL(string("179463a88d79cbf0b1923991708aead914f26142"),
+			 entry2->chunkChecksum->getChecksum(0));
+    CPPUNIT_ASSERT_EQUAL(string("fecf8bc9a1647505fe16746f94e97a477597dbf3"),
+			 entry2->chunkChecksum->getChecksum(1));
+    CPPUNIT_ASSERT_EQUAL(string("sha1"), entry2->checksum->getAlgo());
+#endif // ENABLE_MESSAGE_DIGEST
+
+    entryItr++;
+
+    // test case: verification hash is not provided
+    MetalinkEntryHandle entry3 = *entryItr;
+    CPPUNIT_ASSERT_EQUAL(string("NoVerificationHash"), entry3->getPath());
+#ifdef ENABLE_MESSAGE_DIGEST
+    CPPUNIT_ASSERT(entry3->checksum.isNull());
+    CPPUNIT_ASSERT(entry3->chunkChecksum.isNull());
+#endif // ENABLE_MESSAGE_DIGEST
+
+    entryItr++;
+
+    // test case: unsupported verification hash is included
+    MetalinkEntryHandle entry4 = *entryItr;
+    CPPUNIT_ASSERT_EQUAL(string("UnsupportedVerificationHashTypeIncluded"), entry4->getPath());
+#ifdef ENABLE_MESSAGE_DIGEST
+    CPPUNIT_ASSERT_EQUAL(string("sha1"),
+			 entry4->checksum->getAlgo());
+    CPPUNIT_ASSERT_EQUAL(string("4c255b0ed130f5ea880f0aa061c3da0487e251cc"),
+			 entry4->checksum->getMessageDigest());
+    CPPUNIT_ASSERT_EQUAL(string("sha1"),
+			 entry4->chunkChecksum->getAlgo());
+#endif // ENABLE_MESSAGE_DIGEST
+
+
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testParseFromBinaryStream()
+{
+  XML2SAXMetalinkProcessor proc;
+  DefaultDiskWriterHandle dw = new DefaultDiskWriter();
+  dw->openExistingFile("test.xml");
+  
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+
+    MetalinkEntries::iterator entryItr = m->entries.begin();
+    MetalinkEntryHandle entry1 = *entryItr;
+    CPPUNIT_ASSERT_EQUAL(string("aria2-0.5.2.tar.bz2"), entry1->getPath());
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testMalformedXML()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink><files></file></metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    CPPUNIT_FAIL("exception must be thrown.");
+  } catch(Exception* e) {
+    cerr << *e << endl;
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testMalformedXML2()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink><files></files>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    CPPUNIT_FAIL("exception must be thrown.");
+  } catch(Exception* e) {
+    cerr << *e << endl;
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testBadSize()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2-0.5.2.tar.bz2\">"
+		"  <size>abc</size>"
+		"  <version>0.5.2</version>"
+		"  <language>en-US</language>"
+		"  <os>Linux-x86</os>"
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+
+    MetalinkEntries::iterator entryItr = m->entries.begin();
+    MetalinkEntryHandle e = *entryItr;
+    CPPUNIT_ASSERT_EQUAL(string("aria2-0.5.2.tar.bz2"), e->getPath());
+    CPPUNIT_ASSERT_EQUAL((int64_t)0, e->getLength());
+    CPPUNIT_ASSERT_EQUAL(string("0.5.2"), e->version);
+    CPPUNIT_ASSERT_EQUAL(string("en-US"), e->language);
+    CPPUNIT_ASSERT_EQUAL(string("Linux-x86"), e->os);
+
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testBadMaxConn()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2-0.5.2.tar.bz2\">"
+		"  <size>43743838</size>"
+		"  <version>0.5.2</version>"
+		"  <language>en-US</language>"
+		"  <os>Linux-x86</os>"
+		"  <resources maxconnections=\"abc\"/>"
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+
+    MetalinkEntries::iterator entryItr = m->entries.begin();
+    MetalinkEntryHandle e = *entryItr;
+    CPPUNIT_ASSERT_EQUAL((int64_t)43743838, e->getLength());
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testNoName()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file>"
+		"  <size>1024</size>"
+		"  <version>0.0.1</version>"
+		"  <language>GB</language>"
+		"  <os>Linux-x64</os>"
+		"</file>"
+		"<file name=\"aria2-0.5.2.tar.bz2\">"
+		"  <size>43743838</size>"
+		"  <version>0.5.2</version>"
+		"  <language>en-US</language>"
+		"  <os>Linux-x86</os>"
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
+    MetalinkEntries::iterator entryItr = m->entries.begin();
+    MetalinkEntryHandle e = *entryItr;
+    CPPUNIT_ASSERT_EQUAL(string("aria2-0.5.2.tar.bz2"), e->getPath());
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testBadURLPrefs()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2-0.5.2.tar.bz2\">"
+		"  <size>43743838</size>"
+		"  <version>0.5.2</version>"
+		"  <language>en-US</language>"
+		"  <os>Linux-x86</os>"
+		"  <resources>"
+		"    <url type=\"ftp\" maxconnections=\"1\" preference=\"xyz\" location=\"JP\">ftp://mirror/</url>"
+		"  </resources>"		
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    MetalinkEntryHandle e = m->entries[0];
+    MetalinkResourceHandle r = e->resources[0];
+    CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type);
+    CPPUNIT_ASSERT_EQUAL(0, r->preference);
+    CPPUNIT_ASSERT_EQUAL(1, r->maxConnections);
+    CPPUNIT_ASSERT_EQUAL(string("JP"), r->location);
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testBadURLMaxConn()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2-0.5.2.tar.bz2\">"
+		"  <size>43743838</size>"
+		"  <version>0.5.2</version>"
+		"  <language>en-US</language>"
+		"  <os>Linux-x86</os>"
+		"  <resources>"
+		"    <url maxconnections=\"xyz\" type=\"ftp\" preference=\"100\" location=\"JP\">ftp://mirror/</url>"
+		"  </resources>"		
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    MetalinkEntryHandle e = m->entries[0];
+    MetalinkResourceHandle r = e->resources[0];
+    CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type);
+    CPPUNIT_ASSERT_EQUAL(100, r->preference);
+    CPPUNIT_ASSERT_EQUAL(-1, r->maxConnections);
+    CPPUNIT_ASSERT_EQUAL(string("JP"), r->location);
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testUnsupportedType()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2-0.5.2.tar.bz2\">"
+		"  <size>43743838</size>"
+		"  <version>0.5.2</version>"
+		"  <language>en-US</language>"
+		"  <os>Linux-x86</os>"
+		"  <resources>"
+		"    <url type=\"ftp\">ftp://mirror/</url>"
+		"    <url type=\"magnet\">magnet:xt=XYZ</url>"
+		"    <url type=\"http\">http://mirror/</url>"
+		"  </resources>"		
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    MetalinkEntryHandle e = m->entries[0];
+    CPPUNIT_ASSERT_EQUAL((size_t)3, e->resources.size());
+    MetalinkResourceHandle r1 = e->resources[0];
+    CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r1->type);
+    MetalinkResourceHandle r2 = e->resources[1];
+    CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_NOT_SUPPORTED, r2->type);
+    MetalinkResourceHandle r3 = e->resources[2];
+    CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_HTTP, r3->type);
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testMultiplePieces()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2.tar.bz2\">"
+		"  <verification>"
+		"    <pieces length=\"512\" type=\"md5\">"
+		"    </pieces>"
+		"    <pieces length=\"1024\" type=\"sha1\">"
+		"    </pieces>"
+		"    <pieces length=\"2048\" type=\"sha256\">"
+		"    </pieces>"
+		"  </verification>"
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    // aria2 prefers sha1
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    MetalinkEntryHandle e = m->entries[0];
+    ChunkChecksumHandle c = e->chunkChecksum;
+ 
+    CPPUNIT_ASSERT_EQUAL(string("sha1"), c->getAlgo());
+    CPPUNIT_ASSERT_EQUAL(1024, c->getChecksumLength());
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testBadPieceNo()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2.tar.bz2\">"
+		"  <verification>"
+		"    <pieces length=\"512\" type=\"sha1\">"
+		"      <hash piece=\"0\">abc</hash>"
+		"      <hash piece=\"xyz\">xyz</hash>"
+		"    </pieces>"
+		"    <pieces length=\"512\" type=\"sha256\">"
+		"      <hash piece=\"0\">abc</hash>"
+		"    </pieces>"
+		"  </verification>"
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    MetalinkEntryHandle e = m->entries[0];
+    ChunkChecksumHandle c = e->chunkChecksum;
+ 
+    CPPUNIT_ASSERT_EQUAL(string("sha256"), c->getAlgo());
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testBadPieceLength()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2.tar.bz2\">"
+		"  <verification>"
+		"    <pieces length=\"xyz\" type=\"sha1\">"
+		"      <hash piece=\"0\">abc</hash>"
+		"    </pieces>"
+		"    <pieces length=\"1024\" type=\"sha256\">"
+		"      <hash piece=\"0\">abc</hash>"
+		"    </pieces>"
+		"  </verification>"
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    MetalinkEntryHandle e = m->entries[0];
+    ChunkChecksumHandle c = e->chunkChecksum;
+ 
+    CPPUNIT_ASSERT_EQUAL(string("sha256"), c->getAlgo());
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}
+
+void XML2SAXMetalinkProcessorTest::testUnsupportedType_piece()
+{
+  XML2SAXMetalinkProcessor proc;
+  ByteArrayDiskWriterHandle dw = new ByteArrayDiskWriter();
+  dw->setString("<metalink>"
+		"<files>"
+		"<file name=\"aria2.tar.bz2\">"
+		"  <verification>"
+		"    <pieces length=\"512\" type=\"ARIA2\">"
+		"      <hash piece=\"0\">abc</hash>"
+		"    </pieces>"
+		"    <pieces length=\"1024\" type=\"sha256\">"
+		"      <hash piece=\"0\">abc</hash>"
+		"    </pieces>"
+		"  </verification>"
+		"</file>"
+		"</files>"
+		"</metalink>");
+
+  try {
+    MetalinkerHandle m = proc.parseFromBinaryStream(dw);
+    MetalinkEntryHandle e = m->entries[0];
+    ChunkChecksumHandle c = e->chunkChecksum;
+ 
+    CPPUNIT_ASSERT_EQUAL(string("sha256"), c->getAlgo());
+  } catch(Exception* e) {
+    CPPUNIT_FAIL(e->getMsg());
+    delete e;
+  }
+}