MPQ Archives

The StormLib library



History

When I began to deal with MPQ archives, I hardly played the game of Diablo and looked for a way how to extract a music from the game. In that time was possible to use the Storm.dll library for file extraction without any restrictions. Later, StarCraft was released and no one knew how to extract files from its archives. The DLL from Diablo didn'd work with StarCraft archives and no one was able to use Storm.dll from StarCraft.

Later on, Tom Amigo as the first on the world decrypted the MPQ file format and on his pages published a MPQ Editor, which worked without Storm.dll. He refused requests for sending sources with the reason of violating copyrights of Blizzard Entertainment. (Publishing MPQ editor was obviously not a problem). Opposing him, I started to dissassemble of Storm.dll, to obtain source codes of functions which work with MPQ archives. Later Tom Amigo released some parts of his sources, but the StormLib library was already written.

The StormLib library

The StormLib library is a pack of modules, written in C++, which are able to read and also to write files from/to the MPQ archives. The original version was written for the Win32 platform, but Marko Friedemann has ported it also to Linux. It's free library, you can download it from the Downloads section. When you make any bug fixes or improvements, please, send me the fixed version.

StormLib or Storm.dll ?

When writing an own application, working with MPQ archves, it's necessary to decide, whether to use StormLib library or to link the Storm.dll. The following table briefly shows (dis)advantages of both libraries

  StormLib Storm.dll
Using
The StormLib is very small and it's possible to link it to the application. It's not necessary to deploy any additional DLLs. When using Storm.dll, you have to deploy Storm.dll with your app.
Stability
During work on the last version, I made stress tests of StormLib. The code is very stable. Stability of Storm.dll is good, when you don't try to use older versions to new archives.
Compatibility
StormLib is compatible with all currently released Blizzard games (up to World of Warcraft - The Burning Crusade). Since World of Warcraft, There is no standalone Storm.dll.
File opening
StormLib can use both file names and file ordinal numbers to open them. Storm.dll requires file name for opening an archived file.
Function set
Archive opening and creating
File searching, opening, reading, adding, renaming, deleting.
Archive opening
File opening and reading.
Portability
StormLib is written in C++, so it's easy portable to other platforms. Currently, also Linux version exist. Storm.dll is available only on Windows and on Linux with WINE.

StormLib funtions

Function prototypes correspond with the prototypes used in the Storm.dll library. When it is necessary to rewrite a program to use StormLib instead of Storm.dll (and vice versa), it't usually not a great problem.


SFileSetLocale

Ordinal number for Diablo 1.00 :
Ordinal number for StarCraft : 272 (0x110)

Function SFileSetLocale sets preferred language version of files that will be opened. From the moment of call, all atempts to open a file from archives will try the language version first. If required version will not be found, open function uses languale neutral function.

LCID WINAPI SFileSetLocale(
  LCID lcLocale           // Required locale version
);
Parameters
lcLocale
[in] Identifier of language version. Function does not test validity of the parameter.
Return value

Function always succeeds and returns lcLocale.


SFileGetLocale

Ordinal number for Diablo 1.00 :
Ordinal number for StarCraft : N/A

Function SFileGetLocale simply returns the currently selected locale ID.

LCID WINAPI SFileGetLocale();
Parameters
None.
Return value

Function always succeeds and returns the currently selected locale ID.


SFileOpenArchive

Ordinal number for Diablo 1.00 : 77 (0x04D)
Ordinal number for StarCraft : 266 (0x10A)

Function SFileOpenArchive opens a MPQ archive for reading.

BOOL WINAPI SFileOpenArchive(
  const char * szMpqName, // Archive file name
  DWORD dwPriority,       // Archive priority
  DWORD dwFlags,          // Open flags
  HANDLE * phMPQ          // Pointer to result HANDLE
);
Parameters
szMpqName
[in] Archive file name to open.
dwPriority
[in] Priority of the archive for later search. StormLib does not use this parameter, set it to zero
dwFlags
[in] Flags that specify conditions for opening the archive. They can have these values: StormLib does not use this parameter, set it to zero.
phMPQ
[out] Pointer to a variable of HANDLE type, where the opened archive handle will be stored.
Return value

When the function succeeds, it returns nonzero and phMPQ contains the handle of the opened archive. When the archive cannot be open, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().


SFileCloseArchive

Ordinal number for Diablo 1.00 : 63 (0x03F)
Ordinal number for StarCraft : 252 (0x0FC)

Function SFileCloseArchive closes an open archive.

BOOL WINAPI SFileOpenArchive(
  HANDLE hMPQ           // Handle of open archive
);
Parameters
hMPQ
[in] Handle of open archive. Must be a handle obtained by a call of SFileOpenArchive or SFileCreateArchiveEx.
Return value

When the function succeeds, it returns nonzero and the arhive is closed. If fails, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().

Remarks

If the archive was modified since it was open, the function implemented in StormLib also updates the MPQ header, hash table and block table.


SFileOpenFileEx

Ordinal number for Diablo 1.00 : 79 (0x04F)
Ordinal number for StarCraft : 268 (0x10C)

Function SFileOpenFileEx opens a file from within an archive.

BOOL WINAPI SFileOpenFileEx(
  HANDLE hMPQ,             // Handle of open archive
  const char * szFileName, // Name of a file to open.
  DWORD dwSearchScope,     // Search scope for the file.
  HANDLE phFile            // Pointer to result HANDLE.
);
Parameters
hMPQ
[in] Handle of open archive. Must be a handle obtained by a call of SFileOpenArchive or SFileCreateArchiveEx.
szFileName
[in] Name of a file, which has to be open. The version implemented by StormLib supports also opening a file by its ordinal number (so its not possible to know the file name).
dwSearchScope
[in] Tells the search scope for the file. Can be these values:
phFile
[in] A pointer to a HANDLE variable, which receives the handle of the open file.
Return value

When the function succeeds, it returns nonzero and phFile contains handle of open file. If fails, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().


SFileCloseFile

Ordinal number for Diablo 1.00 : 64 (0x040)
Ordinal number for StarCraft : 253 (0x0FD)

Function SFileCloseFile closes an archived file.

BOOL WINAPI SFileCloseFile(
  HANDLE hFile             // Handle of open file
);
Parameters
hFile
[in] Handle of an open file. Must be a handle obtained by a call of SFileOpenFileEx
Return value

When the function succeeds, it returns nonzero and the file is closed. If fails, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().


SFileGetFileSize

Ordinal number for Diablo 1.00 : 76 (0x04C)
Ordinal number for StarCraft : 265 (0x109)

Function SFileGetFileSize returns the size of an open file.

DWORD WINAPI SFileGetFileSize(
  HANDLE hFile,            // Handle of open file
  DWORD * pdwFileSizeHigh  // For storing upper 32 bitsof the file size
);
Parameters
hFile
[in] Handle of open file. Must be a handle obtained by a call of SFileOpenFileEx
pdwFileSizeHigh
[out] Pointer to a variable of DWORD type, which receives upper 32 bits of thefile size. Can be NULL.
Return value

When the function succeeds, it returns the file size. If fails, return value is 0xFFFFFFFF. More informations about the error can be obtained from return value of GetLastError().

Remarks

Upper 32 bits (the pdwFileSizeHigh parametr) isnot used by both Storm.dll and StormLib. When the pointer is valid, the function fills the variable with zero.


SFileSetFilePointer

Ordinal number for Diablo 1.00 : 82 (0x052)
Ordinal number for StarCraft : 271 (0x10F)

Function SFileSetFilePointer sets a new position of file pointer.

LONG WINAPI SFileSetFilePointer(
  HANDLE hFile,         // Handle of open file
  LONG lFilePos         // New file position
  LONG * plFilePosHigh  // Upper 32 bits of file position
  DWORD dwMethod        // File position on which the move is relative to
);
Parameters
hFile
[in] Handle of open file. Must be a handle obtained by a call of SFileOpenFileEx
lFilePos
[in] The new file position.
plFilePosHigh
[in, out] Pointer to a LONG value, which receives upper 32 bits of movement offset.
dwMethod
[in] Relative point, which the movement is relative to. Can have the following values
Return value

When the function succeeds, it returns the new file position. If fails, it returns 0xFFFFFFFF. More informations about the error can be obtained from return value of GetLastError().


SFileReadFile

Ordinal number for Diablo 1.00 : 80 (0x050)
Ordinal number for StarCraft : 269 (0x10D)

Function SFileReadFile reads data from an open archived file.

BOOL WINAPI SFileReadFile(
  HANDLE hFile,              // Handle of open file
  void * pBuffer,            // Buffer for storing read data
  DWORD dwToRead,            // Number of bytes to read
  DWORD * pdwRead,           // Number of bytes read
  LPOVERLAPPED lpOverlapped  // Pointer to OVERLAPPED structure
);
Parameters
hFile
[in] Handle of open file. Must be a handle obtained by a call of SFileOpenFileEx
pBuffer
[in] Pointer to a buffer which receives the read data.
dwToRead
[in] Number of bytes which shall be read from the file.
pdwRead
[out] When not NULL, the function stores number of bytes actually read to the variable pointed by this parameter.
lpOverlapped
[out] Use this parameter for asynchronous file reading (NT systems only). StormLib ignores this parameter when reads data from an archived file.
Return value

When the function succeeds, it returns nonzero. Buffer pointed by pBuffer contains the read bytes and pdwRead contains number of bytes read. If fails, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().

Remarks

Functions not exported by Storm.dll

The following functions are implemented only in StormLib. Storm.dll does not support these functions.


SFileExtractFile

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Function SFileExtractFile extract complete file from an archive. It is a "helper", useful in nearly each application working with MPQs.

BOOL WINAPI SFileExtractFile(
  HANDLE hMpq,                 // Archive handle
  const char * szToExtract,    // Name of file to extract
  const char * szExtracted     // Name of local (disk) file
);
Parameters
hMpq
[in] Handle of open archive. Must be a handle obtained by a call of SFileOpenArchive or SFileCreateArchiveEx
szToExtract
[in] Pointer to name of archived file which is to be extracted.
szExtracted
[in] Pointer to name of local file, into which will be the content of the file written. If the file already exists, it will be overwritten.
Return value

When the function succeeds, it returns nonzero. In this case, the file has been successfully created and its content successfully written. If an error, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().


SFileCreateArchiveEx

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Function SFileCreateArchiveEx opens or creates an archive file. It can also convert an existing file to MPQ archive. After the archive is open/created, it is accessible for reading and writing.

BOOL WINAPI SFileCreateArchiveEx(
  const char * szMpqName,      // Archive file name
  DWORD dwCreationDisposition, // Open or create
  DWORD dwHashTableSize,       // Size of hash table
  HANDLE * phMPQ               // Pointer to result HANDLE
);
Parameters
szMpqName
[in] Name of an archive, which is to be open.
dwCreationDisposition
[in] Specifies, what the function should exactly do. The following table specifies the parameter values
Value When the archive does not exist When an archive already exists
CREATE_NEW Creates new MPQ archive Returns error
CREATE_ALWAYS Creates new MPQ archive Existing file will be overwritten and function creates a new MPQ archive.
OPEN_EXISTING Returns error Opens the archive
OPEN_ALWAYS Opens archive or converts the file to MPQ archive Opens the archive

dwHashTableSize
[in] When a new archive will be created, this parameter contains hash table size for the new archive. Value of this parameter is corrected to be the nearest greater power of two in the range <0x2; 0x40000>. When opening existing archive, the parameter is ignored.
phMPQ
[out] A pointer to a HANDLE variable, where the handle of created/open archive will be stored.
Return value

When the function succeeds, it returns nonzero and phMPQ contains the handle of open archive. When the archive cannot be open/created, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().


SFileAddFile

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Function SFileAddFile adds a file into the archive. The archive must be open for writing by SFileCreateArchiveEx.

BOOL WINAPI SFileAddFile(
  HANDLE hMPQ,                 // Handle of open archive
  const char * szFileName,     // Name of a file to add
  const char * szArchivedName, // Archived file name
  DWORD dwFlags                // A way of file storing in the archive
);
Parameters
hMPQ
[in] Handle of open archive. Must be a handle obtained by a call of SFileCreateArchiveEx
szFileName
[in] Name of a file which is to be added into the archive.
szArchivedName
[in] Name under which the file will be stored in the archive.
dwFlags
[in] Bit mask, which controls the way of storing file in the archive
Return value

Function returns nonzero, when the file was successfully added into the archive. On error, functions return FALSE. More informations about the error could be returned by GetLastError().

Remarks

It is not possible to combine flags MPQ_FILE_COMPRESS_PKWARE and MPQ_FILE_COMPRESS_MULTI. If the function is called with both flags, returns error.

Locale ID of the file will be set to value recently set using SFileSetLocale.


SFileAddWave

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Function SFileAddWave adds a WAVE file into the archive. The archive must be open for writing by SFileCreateArchiveEx. Unlike SFileAddFile, function optimizes the compression for pattern of WAVE files, doing better compression than if they were added using SFileAddFile.

BOOL WINAPI SFileAddWave(
  HANDLE hMPQ,                 // Handle of open archive
  const char * szFileName,     // Name of a file to add
  const char * szArchivedName, // Archived file name
  DWORD dwFlags                // A way of file storing in the archive
  DWORD dwQuality              // Required quality
);
Parameters
hMPQ
[in] Handle of open archive. Must be a handle obtained by a call of SFileCreateArchiveEx
szFileName
[in] Name of a file which is to be added into the archive.
szArchivedName
[in] Name under which the file will be stored in the archive.
dwFlags
[in] Bit mask, which controls the way of storing file in the archive
dwQuality
[in] Bit mask, which controls the quality of stored file in the archive
Return value

Function returns nonzero, when the file was successfully added into the archive. On error, functions return FALSE. More informations about the error could be returned by GetLastError().

Remarks

It is not possible to combine flags MPQ_FILE_COMPRESS_PKWARE and MPQ_FILE_COMPRESS_MULTI. If the function is called with both flags, returns error.

Locale ID of the file will be set to value recently set using SFileSetLocale.


SFileRemoveFile

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Function SFileRemoveFile removes a file from the archive. The archive must be open for writing using SFileCreateArchiveEx.

BOOL WINAPI SFileRemoveFile(
  HANDLE hMPQ,              // Handle of open archive
  const char * szFileName   // Name of file to remove
);
Parameters
hMPQ
[in] Handle of open archive. Must be a handle obtained by a call of SFileCreateArchiveEx
szFileName
[in] Name of the file which has to be removed from the archive.
Return value

Function returns nonzero, if the file was successfully removed from the archive. On error returns FALSE. More informations about the error returns the GetLastError() function.


SFileRenameFile

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Function SFileRenameFile renames a file within MPQ archive. The archive must be open for writing using SFileCreateArchiveEx.

BOOL WINAPI SFileRenameFile(
  HANDLE hMPQ,                // Handle of open archive
  const char * szOldFileName, // Original name of the file
  const char * szNewFileName, // New name of the file
);
Parameters
hMPQ
[in] Handle of open archive. Must be a handle obtained by a call of SFileCreateArchiveEx.
szOldFileName
[in] Name of an existing file within the archive.
szNewFileName
[in] New name of that file. The file can have another directory name (since directories are virtual in MPQ archives).
Return value

Function returns nonzero, if the file was successfully renamed. On error returns FALSE. More informations about the error returns the GetLastError() function.


SFileFindFirstFile(Ex)

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Functions SFileFindFirstFile and SFileFindFirstFileEx search files in MPQ archive. Because MPQ archives do not contain file names, these functions need file list for successfull search.

BOOL WINAPI SFileFindFirstFileEx(
  HANDLE hMPQ,                      // Handle of open archive
  const char * szMask,              // Wildcard mask
  SFILE_FIND_DATA * lpFindFileData, // Struct with search result
  const char * szFileList,          // File list name
  BOOL bCheckIfExist                // Check if the file exists
);

BOOL WINAPI SFileFindFirstFile(
  HANDLE hMPQ,                      // Handle of open archive
  const char * szMask,              // Wildcard mask
  SFILE_FIND_DATA * lpFindFileData, // Struct with search result
  const char * szFileList           // File list name
);
Parameters
hMPQ
[in] Handle of open archive. Must be a handle obtained by a call of SFileOpenArchive or SFileCreateArchiveEx. Can be NULL, if the bCheckIfExist is set to FALSE.
szMask
[in] Search mask for the files. Example: "*.wav".
lpFindFileData
[out] Pointer to the SFILE_FIND_DATA structure which receives information about found file.
szFileList
[in] Name of a text file with file list. This file must contain file names with their full paths, one file per line. If this parameter is NULL, the function searches the internal listfile stored in the MPQ archive. hMPQ may not be NULL if szListFile is also NULL.
bCheckIfExist
[in] If set to FALSE, the search functions do not test if the file really exists in the archive. The function simply returns the file name from the next line in the filelist. Use if you need to make your custom testing, if the file exists in the archive.
The SFILE_FIND_DATA structure
struct SFILE_FIND_DATA
{
    char   cFileName[MAX_PATH];         // Full name of the found file
    char * szPlainName;                 // Pointer to file part
    LCID   lcLocale;                    // Locale version
    DWORD  dwFileSize;                  // File size in bytes
    DWORD  dwFileFlags;                 // File flags (compressed or encrypted)
};
Return value

Function returns a search handle, if a match file was found in the archive. This search handle must be freed by calling SFileFindClose. On error returns NULL. More informations about the error returns the GetLastError() function.

Remarks

If there are more language versions of the same file, file search will return one entry for each language version as successfull search result.

An application should correctly test if a file was not returned multiple times. Depending on the given file list, the function may not return all files in the archive and also can return one file multiple times.

An application may not modify the structure during search.


SFileFindNextFile

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Function SFileFindNextFile continues search began by SFileFindFirstFile(Ex).

BOOL WINAPI SFileFindNextFile(
  HANDLE hFind,                    // Search handle
  SFILE_FIND_DATA * lpFindFileData // Struct with search result
);
Parameters
hFind
[in] Handle of search. Must be a handle obtained by a call of SFileFindFirstFile(Ex).
lpFindFileData
[out] Pointer to the SFILE_FIND_DATA structure which receives information about found file.
Return value

Function returns nonzero, if a matching file was successfully found in the archive. On error returns FALSE. More informations about the error returns the GetLastError() function.



SFileFindClose

Ordinal number for Diablo 1.00 : N/A
Ordinal number for StarCraft : N/A

Function SFileFindClose ends the search started by SFileFindFirstFile(Ex). Must be used when the search is done.

BOOL WINAPI SFileFindClose(
  HANDLE hFind                    // Search handle
);
Parameters
hFind
[in] Handle of search. Must be a handle obtained by a call of SFileFindFirstFile(Ex).
Return value

Function returns nonzero, if a matching file was successfully found in the archive. On error returns FALSE. More informations about the error returns the GetLastError() function.



Copyright (c) Ladislav Zezula 2003 - 2006