hashsetmaker.cpp

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** \file hashsetmaker.cpp Implementation of HashSet generation classes */
00020 
00021 #include <hn/hnprec.h>
00022 #include <hn/hashsetmaker.h>
00023 
00024 // HashSetMaker - abstract base - Implementaiton
00025 // ---------------------------------------------
00026 // Constructor
00027 HashSetMaker::HashSetMaker() {
00028 }
00029 
00030 // Destructor
00031 HashSetMaker::~HashSetMaker() {
00032 }
00033 
00034 // ED2KHashSetMaker Implementation
00035 // --------------------------------
00036 // Constructor
00037 ED2KHashMaker::ED2KHashMaker()
00038 : m_completed(false), m_transformer(new Md4Transform()), m_dataCount(0) {
00039 }
00040 
00041 // Destructor
00042 ED2KHashMaker::~ED2KHashMaker() {
00043         if (!m_completed) {
00044                 delete m_transformer;
00045         }
00046 }
00047 
00048 // Continue generating hash
00049 void ED2KHashMaker::sumUp(const char *data, uint32_t length) {
00050         CHECK_THROW(data);                       // Data may not be null
00051         if (m_dataCount + length >= ED2K_PARTSIZE) {
00052                 // About to complete a part - hash up to partsize
00053                 m_transformer->sumUp(data, ED2K_PARTSIZE - m_dataCount);
00054                 // Get the hash
00055                 m_chunks.push_back(m_transformer->getHash());
00056                 // Reset the transformer
00057                 delete m_transformer;
00058                 m_transformer = new Md4Transform();
00059                 // Hash the remainder of this data chunk
00060                 data   += ED2K_PARTSIZE - m_dataCount;
00061                 length -= ED2K_PARTSIZE - m_dataCount;
00062                 if (length) {
00063                         m_transformer->sumUp(data, length);
00064                 }
00065                 m_dataCount = length;
00066         } else {
00067                 m_transformer->sumUp(data, length);
00068                 m_dataCount += length;
00069         }
00070 }
00071 
00072 // Retrieve results
00073 HashSetBase* ED2KHashMaker::getHashSet() {
00074         CHECK_THROW(m_transformer);        // Transformer must be alive
00075         CHECK_THROW(!m_completed);         // Retrieving twice is an error
00076 
00077         // Finalize the ed2k hashset generation
00078         // 1. Retrieve the last part hash
00079         m_chunks.push_back(m_transformer->getHash());
00080 
00081         // 2. Generate Md4 over the part hashes. This is rather
00082         //    fast operation and can be done in-place here.
00083         //    Note - Only do this if we have more than one part hash.
00084         //    ED2K Protocol specifies that for files that are less than
00085         //    9728000 bytes, the only part hash is also the file hash, and
00086         //    is omitted (e.g. parthashcount == 0)
00087         delete m_transformer;
00088         if (m_chunks.size() > 1) {
00089                 m_transformer = new Md4Transform();
00090                 for (Iter i = m_chunks.begin(); i != m_chunks.end(); ++i) {
00091                         m_transformer->sumUp((*i).getData().get(), (*i).size());
00092                 }
00093                 m_fileHash = m_transformer->getHash();
00094                 delete m_transformer;
00095         } else {
00096                 m_fileHash = m_chunks[0];
00097                 m_chunks.pop_back();
00098         }
00099 
00100         // 3. Construct HashSet object, copy data there and return it.
00101         ED2KHashSet *hs = new ED2KHashSet();
00102         for (uint32_t i = 0; i < m_chunks.size(); ++i) {
00103                 hs->addChunkHash(m_chunks[i]);
00104         }
00105 
00106         // Ok, we know that ED2KHash comes from MD4Hash, but the rest of the
00107         // world doesn't need to know that - copy it over manually to the
00108         // right type.
00109         hs->setFileHash(Hash<ED2KHash>(m_fileHash.getData()));
00110         m_completed = true;
00111         return hs;
00112 }
00113 
00114 // BTHashSetMaker Implementation
00115 // -----------------------------
00116 // Constructor
00117 BTHashMaker::BTHashMaker(uint32_t chunkSize)
00118 : m_completed(false), m_transformer(new Sha1Transform()),
00119 m_chunkSize(chunkSize) {
00120 }
00121 
00122 // Destructor
00123 BTHashMaker::~BTHashMaker() {
00124         if (!m_completed) {
00125                 delete m_transformer;
00126         }
00127 }
00128 
00129 // Continue generating hash
00130 void BTHashMaker::sumUp(const char *data, uint32_t length) {
00131         CHECK_THROW(!m_completed);                // Shouldn't have finished
00132         CHECK_THROW(data);                        // Shouldn't be null
00133         static uint32_t dataCount = 0;
00134 
00135         if (dataCount + length >= m_chunkSize) {
00136                 // Sum until end of part
00137                 m_transformer->sumUp(
00138                         data, m_chunkSize - dataCount
00139                 );
00140                 data   += (m_chunkSize - dataCount);
00141                 length -= (m_chunkSize - dataCount);
00142 
00143                 m_partHashes.push_back(m_transformer->getHash());
00144                 // Reset transformer
00145                 delete m_transformer;
00146                 m_transformer = new Sha1Transform();
00147 
00148                 // Sum remainder of data with new transformer
00149                 if (length) {
00150                         m_transformer->sumUp(data, length);
00151                 }
00152 
00153                 // Reset the counter
00154                 dataCount = length;
00155         } else {
00156                 m_transformer->sumUp(data, length);
00157                 dataCount += length;
00158         }
00159 }
00160 
00161 // Retrieve results
00162 HashSetBase* BTHashMaker::getHashSet() {
00163         CHECK_THROW(m_transformer);            // Should be alive
00164         CHECK_THROW(!m_completed);             // Shouldn't be completed yet
00165 
00166         // Retrieve the last hash
00167         m_partHashes.push_back(m_transformer->getHash());
00168         delete m_transformer;
00169 
00170         // Copy data to new object and return it.
00171         HashSet<SHA1Hash> *hs = new HashSet<SHA1Hash>(m_chunkSize);
00172         for (
00173                 Iter i = m_partHashes.begin();
00174                 i != m_partHashes.end(); ++i
00175         ) {
00176                 hs->addChunkHash(*i);
00177         }
00178 
00179         m_completed = true;
00180         return hs;
00181 }
00182 
00183 // MD5HashMaker implementation
00184 // ------------------------------
00185 MD5HashMaker::MD5HashMaker() : m_completed(false) {}
00186 MD5HashMaker::~MD5HashMaker() {}
00187 void MD5HashMaker::sumUp(const char *data, uint32_t length) {
00188         m_transformer.sumUp(data, length);
00189 }
00190 HashSetBase* MD5HashMaker::getHashSet() {
00191         CHECK_THROW(!m_completed);
00192 
00193         HashSet<MD5Hash> *hs = new HashSet<MD5Hash>();
00194         hs->setFileHash(m_transformer.getHash());
00195         m_completed = true;
00196         return hs;
00197 }
00198 
00199 // SHA1HashMaker implementation
00200 // ----------------------------
00201 SHA1HashMaker::SHA1HashMaker() : m_completed(false) {}
00202 SHA1HashMaker::~SHA1HashMaker() {}
00203 void SHA1HashMaker::sumUp(const char *data, uint32_t length) {
00204         m_transformer.sumUp(data, length);
00205 }
00206 HashSetBase* SHA1HashMaker::getHashSet() {
00207         CHECK_THROW(!m_completed);
00208         HashSet<SHA1Hash> *hs = new HashSet<SHA1Hash>();
00209         hs->setFileHash(m_transformer.getHash());
00210         m_completed = true;
00211         return hs;
00212 }
00213 
00214 // MD4HashMaker implementation
00215 // ---------------------------
00216 MD4HashMaker::MD4HashMaker() : m_completed(false) {}
00217 MD4HashMaker::~MD4HashMaker() {}
00218 void MD4HashMaker::sumUp(const char *data, uint32_t length) {
00219         m_transformer.sumUp(data, length);
00220 }
00221 HashSetBase* MD4HashMaker::getHashSet() {
00222         CHECK_THROW(!m_completed);
00223         HashSet<MD4Hash> *hs = new HashSet<MD4Hash>();
00224         hs->setFileHash(m_transformer.getHash());
00225         m_completed = true;
00226         return hs;
00227 }