00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 #ifndef __VERIFICATIONHASHTABLE_H__
00021 #define __VERIFICATIONHASHTABLE_H__
00022 
00023 class Par2RepairerSourceFile;
00024 class VerificationHashTable;
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 class VerificationHashEntry
00033 {
00034 public:
00035   VerificationHashEntry(Par2RepairerSourceFile *_sourcefile,
00036                         DataBlock *_datablock,
00037                         bool _firstblock,
00038                         const FILEVERIFICATIONENTRY *_verificationentry)
00039   {
00040     sourcefile = _sourcefile;
00041     datablock = _datablock;
00042     firstblock = _firstblock;
00043 
00044     crc = _verificationentry->crc;
00045     hash = _verificationentry->hash;
00046 
00047     left = right = same = next = 0;
00048   }
00049 
00050   ~VerificationHashEntry(void)
00051   {
00052     delete left;
00053     delete right;
00054     delete same;
00055   }
00056 
00057   
00058   void Insert(VerificationHashEntry **parent);
00059 
00060   
00061   static const VerificationHashEntry* Search(const VerificationHashEntry *entry, u32 crc);
00062 
00063   
00064   static const VerificationHashEntry* Search(const VerificationHashEntry *entry, const MD5Hash &hash);
00065 
00066   
00067   bool operator const VerificationHashEntry &r) const 
00068  {
00069     return crc 00070   }
00071   bool operator >(const VerificationHashEntry &r) const 
00072  {
00073     return crc > r.crc || crc == r.crc && hash > r.hash;
00074   }
00075   bool operator ==(const VerificationHashEntry &r) const 
00076  {
00077     return crc == r.crc && hash == r.hash;
00078   }
00079   bool operator const VerificationHashEntry &r) const {return !operator>(r);}
00080   bool operator >=(const VerificationHashEntry &r) const {return !operator00081   bool operator !=(const VerificationHashEntry &r) const {return !operator==(r);}
00082 
00083   
00084   Par2RepairerSourceFile* SourceFile(void) const {return sourcefile;}
00085   const DataBlock* GetDataBlock(void) const {return datablock;}
00086   bool FirstBlock(void) const {return firstblock;}
00087   
00088   
00089   void SetBlock(DiskFile *diskfile, u64 offset) const;
00090   bool IsSet(void) const;
00091 
00092   u32 Checksum(void) const {return crc;}
00093   const MD5Hash& Hash(void) const {return hash;}
00094 
00095   VerificationHashEntry* Same(void) const {return same;}
00096   VerificationHashEntry* Next(void) const {return next;}
00097   void Next(VerificationHashEntry *_next) {next = _next;}
00098 
00099 protected:
00100   
00101   Par2RepairerSourceFile       *sourcefile;
00102   DataBlock                    *datablock;
00103   bool                          firstblock;
00104 
00105   u32                           crc;
00106   MD5Hash                       hash;
00107 
00108 protected:
00109   
00110   VerificationHashEntry *left;
00111   VerificationHashEntry *right;
00112 
00113   
00114   VerificationHashEntry *same;
00115 
00116   
00117   VerificationHashEntry *next;
00118 };
00119 
00120 inline void VerificationHashEntry::SetBlock(DiskFile *diskfile, u64 offset) const
00121 {
00122   datablock->SetLocation(diskfile, offset);
00123 }
00124 
00125 inline bool VerificationHashEntry::IsSet(void) const
00126 {
00127   return datablock->IsSet();
00128 }
00129 
00130 
00131 inline void VerificationHashEntry::Insert(VerificationHashEntry **parent)
00132 {
00133   while (*parent)
00134   {
00135     if (**parent this)
00136     {
00137       parent = &(*parent)->right;
00138     }
00139     else if (**parent > *this)
00140     {
00141       parent = &(*parent)->left;
00142     }
00143     else
00144     {
00145       break;
00146     }
00147   }
00148 
00149   while (*parent)
00150   {
00151     parent = &(*parent)->same;
00152   }
00153 
00154   *parent = this;
00155 }
00156 
00157 
00158 inline const VerificationHashEntry* VerificationHashEntry::Search(const VerificationHashEntry *entry, u32 crc)
00159 {
00160   while (entry)
00161   {
00162     if (entry->crc 00163     {
00164       entry = entry->right;
00165     }
00166     else if (entry->crc > crc)
00167     {
00168       entry = entry->left;
00169     }
00170     else
00171     {
00172       break;
00173     }
00174   }
00175 
00176   return entry;
00177 }
00178 
00179 
00180 inline const VerificationHashEntry* VerificationHashEntry::Search(const VerificationHashEntry *entry, const MD5Hash &hash)
00181 {
00182   u32 crc = entry->crc;
00183 
00184   while (entry)
00185   {
00186     if (entry->crc crc == crc && entry->hash 00187     {
00188       entry = entry->right;
00189     }
00190     else if (entry->crc > crc || entry->crc == crc && entry->hash > hash)
00191     {
00192       entry = entry->left;
00193     }
00194     else
00195     {
00196       break;
00197     }
00198   }
00199 
00200   return entry;
00201 }
00202 
00203 
00204 
00205 
00206 
00207 
00208 
00209 
00210 class VerificationHashTable
00211 {
00212 public:
00213   VerificationHashTable(void);
00214   ~VerificationHashTable(void);
00215 
00216   void SetLimit(u32 limit);
00217 
00218   
00219   void Load(Par2RepairerSourceFile *sourcefile, u64 blocksize);
00220 
00221   
00222   
00223   
00224   
00225   
00226   
00227   
00228   
00229   
00230   const VerificationHashEntry* FindMatch(const VerificationHashEntry *nextentry,
00231                                          const Par2RepairerSourceFile *sourcefile,
00232                                          FileCheckSummer &checksummer,
00233                                          bool &duplicate) const;
00234 
00235   
00236   const VerificationHashEntry* Lookup(u32 crc) const;
00237 
00238   
00239   const VerificationHashEntry* Lookup(const VerificationHashEntry *entry,
00240                                       const MD5Hash &hash) const;
00241 
00242 protected:
00243   VerificationHashEntry **hashtable;
00244   unsigned int hashmask;
00245 };
00246 
00247 
00248 inline const VerificationHashEntry* VerificationHashTable::Lookup(u32 crc) const
00249 {
00250   if (hashmask)
00251   {
00252     return VerificationHashEntry::Search(hashtable[crc & hashmask], crc);
00253   }
00254 
00255   return 0;
00256 }
00257 
00258 
00259 inline const VerificationHashEntry* VerificationHashTable::Lookup(const VerificationHashEntry *entry,
00260                                                                   const MD5Hash &hash) const
00261 {
00262   return VerificationHashEntry::Search(entry, hash);
00263 }
00264 
00265 inline const VerificationHashEntry* VerificationHashTable::FindMatch(const VerificationHashEntry *suggestedentry,
00266                                                                      const Par2RepairerSourceFile *sourcefile,
00267                                                                      FileCheckSummer &checksummer,
00268                                                                      bool &duplicate) const
00269 {
00270   duplicate = false;
00271 
00272   
00273   u32 crc = checksummer.Checksum();
00274 
00275   MD5Hash hash;
00276   bool havehash = false;
00277 
00278   
00279   if (0 != suggestedentry)
00280   {
00281     
00282     if (suggestedentry->Next() == 0)
00283     {
00284       
00285       u64 length = suggestedentry->GetDataBlock()->GetLength();
00286 
00287       
00288       u32 checksum = checksummer.ShortChecksum(length);
00289 
00290       
00291       if (checksum == suggestedentry->Checksum())
00292       {
00293         
00294         hash = checksummer.ShortHash(length);
00295 
00296         
00297         if (hash == suggestedentry->Hash())
00298         {
00299           return suggestedentry;
00300         }
00301       }
00302     }
00303     
00304     else if (!suggestedentry->IsSet() && suggestedentry->Checksum() == crc)
00305     {
00306       
00307       havehash = true;
00308       hash = checksummer.Hash();
00309 
00310       
00311       if (hash == suggestedentry->Hash())
00312       {
00313         return suggestedentry;
00314       }
00315     }
00316   }
00317 
00318   
00319   const VerificationHashEntry *nextentry = VerificationHashEntry::Search(hashtable[crc & hashmask], crc);
00320   if (0 == nextentry)
00321     return 0;
00322 
00323   
00324   if (!havehash)
00325   {
00326     hash = checksummer.Hash();
00327   }
00328 
00329   
00330   nextentry = VerificationHashEntry::Search(nextentry, hash);
00331   if (0 == nextentry)
00332     return 0;
00333 
00334   
00335   if (nextentry->Same() == 0)
00336   {
00337     
00338     
00339     
00340     if (nextentry->SourceFile()->GetCompleteFile() != 0)
00341     {
00342       duplicate = true;
00343       return 0;
00344     }
00345 
00346     
00347     
00348     
00349     if (checksummer.ShortBlock() && checksummer.BlockLength() != nextentry->GetDataBlock()->GetLength())
00350     {
00351       return 0;
00352     }
00353 
00354     
00355     
00356     if (nextentry->FirstBlock() && checksummer.Offset() == 0)
00357     {
00358       return nextentry;
00359     }
00360 
00361     
00362     
00363     if (nextentry == suggestedentry)
00364     {
00365       
00366       if (nextentry->IsSet() && 
00367           nextentry->GetDataBlock()->GetDiskFile() == checksummer.GetDiskFile())
00368       {
00369         
00370         duplicate = true;
00371         return 0;
00372       }
00373       else
00374       {
00375         
00376         
00377         
00378         
00379         return nextentry;
00380       }
00381     }
00382     else
00383     {
00384       
00385       if (nextentry->IsSet())
00386       {
00387         duplicate = true;
00388         return 0;
00389       }
00390 
00391       return nextentry;
00392     }
00393   }
00394 
00395   
00396   if (0 != sourcefile)
00397   {
00398     const VerificationHashEntry *currententry = nextentry;
00399     nextentry = 0;
00400 
00401     
00402     
00403     while (currententry && (currententry->SourceFile() != sourcefile || 
00404                             currententry->IsSet() ||
00405                             checksummer.ShortBlock() && checksummer.BlockLength() != currententry->GetDataBlock()->GetLength()
00406                            )
00407           )
00408     {
00409       
00410       
00411       if (0 == nextentry && !(currententry->IsSet() || 
00412                               checksummer.ShortBlock() && checksummer.BlockLength() != currententry->GetDataBlock()->GetLength()
00413                              )
00414          )
00415       {
00416         nextentry = currententry;
00417       }
00418 
00419       currententry = currententry->Same();
00420     }
00421 
00422     
00423     if (0 != currententry)
00424       return currententry;
00425   }
00426 
00427   
00428   while (nextentry && (nextentry->IsSet() ||
00429                        checksummer.ShortBlock() && checksummer.BlockLength() != nextentry->GetDataBlock()->GetLength()
00430                       )
00431         )
00432   {
00433     nextentry = nextentry->Same();
00434   }
00435 
00436   
00437   if (nextentry == 0)
00438   {
00439     duplicate = true;
00440   }
00441 
00442   return nextentry;
00443 }
00444 
00445 #endif // __VERIFICATIONHASHTABLE_H__