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__