@@ -41,8 +41,10 @@ static DWORD GetSizeOfAttributesFile(DWORD dwAttrFlags, DWORD dwFileTableSize)
41
41
if (dwAttrFlags & MPQ_ATTRIBUTE_MD5)
42
42
cbAttrFile += dwFileTableSize * MD5_DIGEST_SIZE;
43
43
44
- // Weird: When there's 1 extra bit in the patch bit array, it's ignored
45
- // wow-update-13164.MPQ: BlockTableSize = 0x62E1, but there's only 0xC5C bytes
44
+ // The bit array has been create without the last bit belonging to (attributes)
45
+ // When the number of files is a multiplier of 8 plus one, then the size of (attributes)
46
+ // if 1 byte less than expected.
47
+ // Example: wow-update-13164.MPQ: BlockTableSize = 0x62E1, but there's only 0xC5C bytes
46
48
if (dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
47
49
cbAttrFile += (dwFileTableSize + 6 ) / 8 ;
48
50
@@ -165,7 +167,7 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
165
167
LPBYTE pbAttrFile;
166
168
LPBYTE pbAttrPtr;
167
169
size_t cbAttrFile;
168
- DWORD dwFinalEntries = ha->dwFileTableSize + ha->dwReservedFiles ;
170
+ DWORD dwFinalEntries = ha->dwFileTableSize + ha->dwReservedFiles + 1 ;
169
171
170
172
// Check if we need patch bits in the (attributes) file
171
173
for (pFileEntry = ha->pFileTable ; pFileEntry < pFileTableEnd; pFileEntry++)
@@ -202,7 +204,7 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
202
204
*pArrayCRC32++ = BSWAP_INT32_UNSIGNED (pFileEntry->dwCrc32 );
203
205
204
206
// Skip the reserved entries
205
- pbAttrPtr = (LPBYTE)(pArrayCRC32 + ha->dwReservedFiles );
207
+ pbAttrPtr = (LPBYTE)(pArrayCRC32 + ha->dwReservedFiles + 1 );
206
208
}
207
209
208
210
// Write the array of file time
@@ -215,7 +217,7 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
215
217
*pArrayFileTime++ = BSWAP_INT64_UNSIGNED (pFileEntry->FileTime );
216
218
217
219
// Skip the reserved entries
218
- pbAttrPtr = (LPBYTE)(pArrayFileTime + ha->dwReservedFiles );
220
+ pbAttrPtr = (LPBYTE)(pArrayFileTime + ha->dwReservedFiles + 1 );
219
221
}
220
222
221
223
// Write the array of MD5s
@@ -231,16 +233,15 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
231
233
}
232
234
233
235
// Skip the reserved items
234
- pbAttrPtr = pbArrayMD5 + (ha->dwReservedFiles * MD5_DIGEST_SIZE);
236
+ pbAttrPtr = pbArrayMD5 + (( ha->dwReservedFiles + 1 ) * MD5_DIGEST_SIZE);
235
237
}
236
238
237
239
// Write the array of patch bits
238
240
if (ha->dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
239
241
{
240
242
LPBYTE pbBitArray = pbAttrPtr;
241
- DWORD dwByteSize = (dwFinalEntries + 7 ) / 8 ;
242
243
DWORD dwByteIndex = 0 ;
243
- DWORD dwBitMask = 0x80 ;
244
+ BYTE dwBitMask = 0x80 ;
244
245
245
246
// Copy from file table
246
247
for (pFileEntry = ha->pFileTable ; pFileEntry < pFileTableEnd; pFileEntry++)
@@ -254,14 +255,18 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
254
255
dwBitMask = (dwBitMask << 0x07 ) | (dwBitMask >> 0x01 );
255
256
}
256
257
258
+ // Note: Do not increment the array by the last bit that belongs to (attributes).
259
+ // This might create the array one byte less (if the number of files a multiplier of 8).
260
+ // Blizzard MPQs have the same feature.
261
+
257
262
// Move past the bit array
258
- pbAttrPtr = (pbBitArray + dwByteSize );
263
+ pbAttrPtr = (pbBitArray + dwByteIndex) + ((dwBitMask & 0x7F ) ? 1 : 0 );
259
264
}
260
265
261
266
// Now we expect that current position matches the estimated size
262
267
// Note that if there is 1 extra bit above the byte size,
263
268
// the table is actually 1 byte shorted in Blizzard MPQs. See GetSizeOfAttributesFile
264
- assert ((size_t )(pbAttrPtr - pbAttrFile) == cbAttrFile + ((dwFinalEntries & 0x07 ) == 1 ) ? 1 : 0 );
269
+ assert ((size_t )(pbAttrPtr - pbAttrFile) == cbAttrFile);
265
270
}
266
271
267
272
// Give away the attributes file
@@ -329,18 +334,12 @@ int SAttrFileSaveToMpq(TMPQArchive * ha)
329
334
330
335
// We expect at least one reserved entry to be there
331
336
assert (ha->dwReservedFiles >= 1 );
337
+ ha->dwReservedFiles --;
332
338
333
339
// Create the raw data that is to be written to (attributes)
334
340
// Note: Blizzard MPQs have entries for (listfile) and (attributes),
335
341
// but they are filled empty
336
342
pbAttrFile = CreateAttributesFile (ha, &cbAttrFile);
337
-
338
- // Now we decrement the number of reserved files.
339
- // This frees one slot in the file table, so the subsequent file create operation should succeed
340
- // This must happen even if CreateAttributesFile failed
341
- ha->dwReservedFiles --;
342
-
343
- // If we created something, write the attributes to the MPQ
344
343
if (pbAttrFile != NULL )
345
344
{
346
345
// We expect it to be nonzero size
0 commit comments