Current News
Archived News
Search News
Discussion Forum


Old Forum
Install Programs More Downloads...
Troubleshooting
Source Code
Format Specs.
Misc. Information
Non-SF Stuff
Links




ShadowFlare [Tue, 5 Jan 2010 13:05:34 +0000 (06:05 -0700)]
Added limits to buffering reads on larger blocks to keep memory usage down.
Move bitmasks for unsupported compression types from MPQ library to SComp.

SFmpqapi.cpp
SFmpqapi.h

index bd4164d..fecddf9 100644 (file)
@@ -101,9 +101,6 @@ MPQFILE * FirstLastFile[2] = {0,0};
 
 char StormBasePath[MAX_PATH+1];
 
-#define UNSUPPORTED_COMPRESSION   (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08 | 0x10))
-#define UNSUPPORTED_DECOMPRESSION (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08 | 0x10))
-
 typedef BOOL (WINAPI* funcSCompCompress)(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, DWORD dwCompressionType, DWORD dwCompressionSubType, DWORD dwWAVQuality);
 typedef BOOL (WINAPI* funcSCompDecompress)(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
 funcSCompCompress stormSCompCompress = 0;
@@ -567,7 +564,7 @@ BOOL SFMPQAPI WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileN
                }
                DWORD dwMpqStart;
                MPQARCHIVE *mpqOpenArc;
-               dwMpqStart = mpqArcFile.lpBlockEntry->dwFileOffset;
+               dwMpqStart = mpqOpenArc->dwMPQStart + mpqArcFile.lpBlockEntry->dwFileOffset;
                flen = mpqArcFile.lpBlockEntry->dwFullSize;
                dwMpqStart = FindMpqHeaderAtLocation(hFile,dwMpqStart,flen);
                if (dwMpqStart==0xFFFFFFFF) {
@@ -1198,6 +1195,8 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
        DWORD BlockIndex = mpqOpenFile->lpHashEntry->dwBlockTableIndex;
        if (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead>mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize) nNumberOfBytesToRead = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize-mpqOpenFile->dwFilePointer;
        DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_SINGLEBLOCK)
+               blockSize = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
        DWORD dwBlockStart = mpqOpenFile->dwFilePointer - (mpqOpenFile->dwFilePointer % blockSize);
     DWORD blockNum = dwBlockStart / blockSize;
     DWORD nBlocks  = (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) / blockSize;
@@ -1215,12 +1214,18 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                if (lpOverlapped) lpOverlapped->InternalHigh = 0;
                return FALSE;
        }
-       void *blk16Buffer = SFAlloc(blockSize * 16);
-       if (!blk16Buffer) {
-               SFFree(blkBuffer);
-               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
-               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
-               return FALSE;
+       DWORD nBufferCount;
+       for (nBufferCount = 1; nBufferCount < nBlocks - blockNum && blockSize * nBufferCount < 65536; nBufferCount *= 2) {}
+       if (nBufferCount > nBlocks - blockNum) nBufferCount = nBlocks - blockNum;
+       void *blkLargeBuffer = NULL;
+       if (nBufferCount > 1) {
+               blkLargeBuffer = SFAlloc(blockSize * nBufferCount);
+               if (!blkLargeBuffer) {
+                       SFFree(blkBuffer);
+                       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+                       if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+                       return FALSE;
+               }
        }
        DWORD dwCryptKey = mpqOpenFile->dwCryptKey;
        //if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) dwCryptKey = HashString(mpqOpenFile->lpFileName,HASH_KEY);
@@ -1237,13 +1242,13 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
                if (!dwBlockPtrTable) {
 
-                       SFFree(blk16Buffer);
+                       if (blkLargeBuffer) SFFree(blkLargeBuffer);
                        SFFree(blkBuffer);
                        if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
                        if (lpOverlapped) lpOverlapped->InternalHigh = 0;
                        return FALSE;
                }
-               if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2))
+               if (((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)) && !(mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_SINGLEBLOCK))
                {
                        SFSetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,FILE_BEGIN);
                        ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&nBytesRead,0);
@@ -1255,28 +1260,31 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                {
                        for (i=0;i<TotalBlocks+1;i++) {
                                if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
-                               else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+                               else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize - HeaderLength;
                        }
                }
                mpqOpenFile->lpdwBlockOffsets = dwBlockPtrTable;
        }
-       BYTE *compbuffer = (BYTE *)SFAlloc(blockSize+3);
-       if (!compbuffer) {
-               SFFree(blk16Buffer);
-               SFFree(blkBuffer);
-               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
-               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
-               return FALSE;
+       BYTE *compbuffer = NULL;
+       if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)) {
+               compbuffer = (BYTE *)SFAlloc(blockSize+3);
+               if (!compbuffer) {
+                       if (blkLargeBuffer) SFFree(blkLargeBuffer);
+                       SFFree(blkBuffer);
+                       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+                       if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+                       return FALSE;
+               }
        }
        DWORD blk=0,blki=0;
        for (i=blockNum;i<nBlocks;i++) {
-               if (blk==0) {
+               if (blk==0 && blkLargeBuffer) {
                        SFSetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+mpqOpenFile->lpdwBlockOffsets[i],FILE_BEGIN);
                        blki=i;
-                       if (i+16>nBlocks) {
-                               if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[nBlocks]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
-                                       SFFree(compbuffer);
-                                       SFFree(blk16Buffer);
+                       if (i+nBufferCount>nBlocks) {
+                               if (ReadFile(mpqOpenArc->hFile,blkLargeBuffer,mpqOpenFile->lpdwBlockOffsets[nBlocks]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
+                                       if (compbuffer) SFFree(compbuffer);
+                                       SFFree(blkLargeBuffer);
                                        SFFree(blkBuffer);
                                        if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
                                        if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
@@ -1285,9 +1293,9 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
 
                        }
                        else {
-                               if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[i+16]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
-                                       SFFree(compbuffer);
-                                       SFFree(blk16Buffer);
+                               if (ReadFile(mpqOpenArc->hFile,blkLargeBuffer,mpqOpenFile->lpdwBlockOffsets[i+nBufferCount]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
+                                       if (compbuffer) SFFree(compbuffer);
+                                       SFFree(blkLargeBuffer);
                                        SFFree(blkBuffer);
                                        if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
                                        if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
@@ -1295,7 +1303,20 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                                }
                        }
                }
-               memcpy(blkBuffer,((char *)blk16Buffer)+(mpqOpenFile->lpdwBlockOffsets[blki+blk]-mpqOpenFile->lpdwBlockOffsets[blki]),mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+               if (blkLargeBuffer) {
+                       memcpy(blkBuffer,((char *)blkLargeBuffer)+(mpqOpenFile->lpdwBlockOffsets[blki+blk]-mpqOpenFile->lpdwBlockOffsets[blki]),mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+               }
+               else {
+                       SFSetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+mpqOpenFile->lpdwBlockOffsets[i],FILE_BEGIN);
+                       blki=i;
+                       if (ReadFile(mpqOpenArc->hFile,blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
+                               if (compbuffer) SFFree(compbuffer);
+                               SFFree(blkBuffer);
+                               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
+                               if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
+                               return FALSE;
+                       }
+               }
                if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
                {
                        DecryptData((LPBYTE)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i],dwCryptKey+i);
@@ -1367,10 +1388,10 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                                nNumberOfBytesToRead-=nNumberOfBytesToRead;
                        }
                }
-               blk = (blk+1) % 16;
+               blk = (blk+1) % nBufferCount;
        }
-       SFFree(compbuffer);
-       SFFree(blk16Buffer);
+       if (compbuffer) SFFree(compbuffer);
+       if (blkLargeBuffer) SFFree(blkLargeBuffer);
        SFFree(blkBuffer);
        if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
        if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
index 7cef69b..e8c3725 100644 (file)
@@ -230,6 +230,7 @@ long SFMPQAPI __inline SFMpqCompareVersion();
 // MpqAddFileToArchive flags
 #define MAFA_EXISTS           0x80000000 //This flag will be added if not present
 #define MAFA_UNKNOWN40000000  0x40000000 //Unknown flag
+#define MAFA_SINGLEBLOCK      0x01000000 //File is stored as a single unit rather than being split by the block size
 #define MAFA_MODCRYPTKEY      0x00020000 //Used with MAFA_ENCRYPT. Uses an encryption key based on file position and size
 #define MAFA_ENCRYPT          0x00010000 //Encrypts the file. The file is still accessible when using this, so the use of this has depreciated
 #define MAFA_COMPRESS         0x00000200 //File is to be compressed when added. This is used for most of the compression methods