@@ -167,14 +167,14 @@ static bool FileWasFoundBefore(
167
167
{
168
168
// If we are in patch MPQ, we check if patch prefix matches
169
169
// and then trim the patch prefix
170
- if (ha->cchPatchPrefix != 0 )
170
+ if (ha->pPatchPrefix != NULL )
171
171
{
172
172
// If the patch prefix doesn't fit, we pretend that the file
173
173
// was there before and it will be skipped
174
- if (_strnicmp (szRealFileName, ha->szPatchPrefix , ha->cchPatchPrefix ))
174
+ if (_strnicmp (szRealFileName, ha->pPatchPrefix -> szPatchPrefix , ha->pPatchPrefix -> nLength ))
175
175
return true ;
176
176
177
- szRealFileName += ha->cchPatchPrefix ;
177
+ szRealFileName += ha->pPatchPrefix -> nLength ;
178
178
}
179
179
180
180
// Calculate the hash to the table
@@ -213,6 +213,14 @@ static bool FileWasFoundBefore(
213
213
return false ;
214
214
}
215
215
216
+ static inline bool FileEntryIsInvalid (
217
+ TMPQArchive * ha,
218
+ TFileEntry * pFileEntry)
219
+ {
220
+ // Spazzler3 protector: Some files are clearly wrong
221
+ return ((ha->dwFlags & MPQ_FLAG_MALFORMED) && (pFileEntry->dwCmpSize & 0xFFFF0000 ) >= 0x7FFF0000 );
222
+ }
223
+
216
224
static TFileEntry * FindPatchEntry (TMPQArchive * ha, TFileEntry * pFileEntry)
217
225
{
218
226
TFileEntry * pPatchEntry = NULL ;
@@ -225,9 +233,11 @@ static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry)
225
233
{
226
234
// Move to the patch archive
227
235
ha = ha->haPatch ;
236
+ szFileName[0 ] = 0 ;
228
237
229
238
// Prepare the prefix for the file name
230
- strcpy (szFileName, ha->szPatchPrefix );
239
+ if (ha->pPatchPrefix != NULL )
240
+ strcpy (szFileName, ha->pPatchPrefix ->szPatchPrefix );
231
241
strcat (szFileName, pFileEntry->szFileName );
232
242
233
243
// Try to find the file there
@@ -261,64 +271,68 @@ static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
261
271
pFileEntry = ha->pFileTable + hs->dwNextIndex ;
262
272
263
273
// Get the length of the patch prefix (0 if none)
264
- nPrefixLength = strlen (ha->szPatchPrefix ) ;
274
+ nPrefixLength = (ha->pPatchPrefix != NULL ) ? ha-> pPatchPrefix -> nLength : 0 ;
265
275
266
276
// Parse the file table
267
277
while (pFileEntry < pFileTableEnd)
268
278
{
269
279
// Increment the next index for subsequent search
270
280
hs->dwNextIndex ++;
271
281
272
- // Is it a file and not a patch file?
282
+ // Is it a file but not a patch file?
273
283
if ((pFileEntry->dwFlags & hs->dwFlagMask ) == MPQ_FILE_EXISTS)
274
284
{
275
- // Now we have to check if this file was not enumerated before
276
- if (!FileWasFoundBefore (ha, hs, pFileEntry))
277
- {
278
- // Find a patch to this file
279
- pPatchEntry = FindPatchEntry (ha, pFileEntry);
280
- if (pPatchEntry == NULL )
281
- pPatchEntry = pFileEntry;
285
+ // Spazzler3 protector: Some files are clearly wrong
286
+ if (!FileEntryIsInvalid (ha, pFileEntry))
287
+ {
288
+ // Now we have to check if this file was not enumerated before
289
+ if (!FileWasFoundBefore (ha, hs, pFileEntry))
290
+ {
291
+ // Find a patch to this file
292
+ pPatchEntry = FindPatchEntry (ha, pFileEntry);
293
+ if (pPatchEntry == NULL )
294
+ pPatchEntry = pFileEntry;
282
295
283
- // Prepare the block index
284
- dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable );
296
+ // Prepare the block index
297
+ dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable );
285
298
286
- // Get the file name. If it's not known, we will create pseudo-name
287
- szFileName = pFileEntry->szFileName ;
288
- if (szFileName == NULL )
289
- {
290
- // Open the file by its pseudo-name.
291
- // This also generates the file name with a proper extension
292
- sprintf (szPseudoName, " File%08u.xxx" , (unsigned int )dwBlockIndex);
293
- if (SFileOpenFileEx ((HANDLE)hs->ha , szPseudoName, SFILE_OPEN_BASE_FILE, &hFile))
299
+ // Get the file name. If it's not known, we will create pseudo-name
300
+ szFileName = pFileEntry->szFileName ;
301
+ if (szFileName == NULL )
294
302
{
295
- szFileName = (pFileEntry->szFileName != NULL ) ? pFileEntry->szFileName : szPseudoName;
296
- SFileCloseFile (hFile);
303
+ // Open the file by its pseudo-name.
304
+ // This also generates the file name with a proper extension
305
+ sprintf (szPseudoName, " File%08u.xxx" , (unsigned int )dwBlockIndex);
306
+ if (SFileOpenFileEx ((HANDLE)hs->ha , szPseudoName, SFILE_OPEN_BASE_FILE, &hFile))
307
+ {
308
+ szFileName = (pFileEntry->szFileName != NULL ) ? pFileEntry->szFileName : szPseudoName;
309
+ SFileCloseFile (hFile);
310
+ }
297
311
}
298
- }
299
312
300
- // If the file name is still NULL, we cannot include the file to the search
301
- if (szFileName != NULL )
302
- {
303
- // Check the file name against the wildcard
304
- if (CheckWildCard (szFileName + nPrefixLength, hs->szSearchMask ))
313
+ // If the file name is still NULL, we cannot include the file to the search
314
+ if (szFileName != NULL )
305
315
{
306
- // Fill the found entry
307
- lpFindFileData->dwHashIndex = pPatchEntry->dwHashIndex ;
308
- lpFindFileData->dwBlockIndex = dwBlockIndex;
309
- lpFindFileData->dwFileSize = pPatchEntry->dwFileSize ;
310
- lpFindFileData->dwFileFlags = pPatchEntry->dwFlags ;
311
- lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize ;
312
- lpFindFileData->lcLocale = pPatchEntry->lcLocale ;
313
-
314
- // Fill the filetime
315
- lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32 );
316
- lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime );
317
-
318
- // Fill the file name and plain file name
319
- strcpy (lpFindFileData->cFileName , szFileName + nPrefixLength);
320
- lpFindFileData->szPlainName = (char *)GetPlainFileName (lpFindFileData->cFileName );
321
- return ERROR_SUCCESS;
316
+ // Check the file name against the wildcard
317
+ if (CheckWildCard (szFileName + nPrefixLength, hs->szSearchMask ))
318
+ {
319
+ // Fill the found entry
320
+ lpFindFileData->dwHashIndex = pPatchEntry->dwHashIndex ;
321
+ lpFindFileData->dwBlockIndex = dwBlockIndex;
322
+ lpFindFileData->dwFileSize = pPatchEntry->dwFileSize ;
323
+ lpFindFileData->dwFileFlags = pPatchEntry->dwFlags ;
324
+ lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize ;
325
+ lpFindFileData->lcLocale = pPatchEntry->lcLocale ;
326
+
327
+ // Fill the filetime
328
+ lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32 );
329
+ lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime );
330
+
331
+ // Fill the file name and plain file name
332
+ strcpy (lpFindFileData->cFileName , szFileName + nPrefixLength);
333
+ lpFindFileData->szPlainName = (char *)GetPlainFileName (lpFindFileData->cFileName );
334
+ return ERROR_SUCCESS;
335
+ }
322
336
}
323
337
}
324
338
}
@@ -327,6 +341,12 @@ static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
327
341
pFileEntry++;
328
342
}
329
343
344
+ // If there is no more patches in the chain, stop it.
345
+ // This also keeps hs->ha non-NULL, which is required
346
+ // for freeing the handle later
347
+ if (ha->haPatch == NULL )
348
+ break ;
349
+
330
350
// Move to the next patch in the patch chain
331
351
hs->ha = ha = ha->haPatch ;
332
352
hs->dwNextIndex = 0 ;
0 commit comments