Archivy MPQ
Knihovna StormLib
V době, kdy jsem se začal zabývat archivy MPQ, jsem pařil hru Diablo a pátral jsem po tom, jak je možné z Diabla vytáhnout hudbu. Tehdy bylo ještě možné použít knihovnu Storm.dll k extrakci souborů. Později se objevil StarCraft a nikdo nevěděl jak extrahovat soubory z jeho archivů. Knihovna Storm.dll z Diabla na archivy ve StarCraftu nefungovala a tu ze StarCraftu nebylo možné použít.
Později Tom Amigo jako první na světě rozkódoval formát souborů MPQ a na svých stránkách publikoval MPQ Editor, který nepotřeboval knihovnu Storm.dll. Prosby o zaslání zdrojových kódů funkcí odmítal s odůvodněním, že by tím porušil copyright společnosti Blizzard. (Uveřejnění MPQ editoru mu evidentně nevadilo). Tehdy jsem se tak trochu natruc dal do dissassemblování knihovny Storm.dll, abych získal zdrojové kódy funkcí, které pracují s archivy MPQ. Později Tom Amigo sice zveřejnil část svých zdrojových kódů, ale až v době, kdy byla knihovna StormLib na světě.
Knihovna StormLib je soubor modulů napsaných v C++, které umožňují číst a také zapisovat soubory z/do archivů MPQ. Původní verze bylo určena pro platformu Win32, díky Markovi Friedemannovi je nyní portovaná i do Linuxu. Její použití je zdarma, můžete si ji stáhnout v sekci Downloads. Pokud v kódu opravíte nějaké chyby, zašlete mi, prosím, opravenou verzi.
Při psaní vlastní aplikace, která pracuje s archivy MPQ je nutné se rozhodnout, zda použít knihovnu StormLib nebo k programu přilinkovat knihovnu Storm.dll. Následující tabulka stručně shrnuje výhody a nevýhody obou případů
| StormLib | Storm.dll | |
|---|---|---|
| Knihovna StormLib je velice malá a je ji možné přímo přilinkovat k programu. Není nutné distribuovat žádnou knihovnu DLL. | Při použití Storm.dll je nutné tuto knihovnu distribuovat s programem. | |
| Během psaní poslední verze knihovny StormLib jsem ji podrobil zátěžovým testům, takže její stabilita je velice dobrá. | Stabilita Storm.dll je dobrá, pokud není použita starší verze na novější soubory. | |
| Knihovna StormLib je kompatibilní se všemi aktuálně vydanými hrami společnosti Blizzard. | Počínaje hrou World of Warcraft, Blizzard upustil od použití knihovny Storm.lib ve formě dynamicky linkované knihovny (DLL). | |
| Knihovna StormLib podporuje jak otevírání souborů podle jména, tak podle ordinálního čísla. | Storm.dll vyžaduje pro otevření jméno souboru. | |
|
Otevírání a vytváření archivů Hledání, otevírání, čtení, ukládání, přejmenovávání a mazání souborů v archivech. |
Otevírání archivů Otevírání a čtení souborů. |
|
| Knihovna StormLib je napsaná v C++, je tedy portovatelná i na jiné platformy. V současnosti existuje i verze pro Linux. | Storm.dll je k dispozici pouze ve Windows a na Linuxu pod WINE. |
Prototypy funkcí v knihovně StormLib odpovídají funkcím obsaženým přímo ve Storm.dll. Pokud je nutné přepsat program tak, aby namísto knihovny Storm.dll používal StormLib nebo obráceně, není to velký problém.
Funkce SFileSetLocale nastavuje preferovanou jazykovou verzi otevíraných souborů. Od okamžiku volání bude při pokusu o otevření souboru hledána přednostně zadaná jazyková verze. Pokud nebude použita daná jazyková verze, bude použita jazykově neutrální verze.
LCID WINAPI SFileSetLocale( LCID lcLocale // Požadovaný jazyk );Parametry
Funkce vždy skončí úspěšně a vrací lcLocale.
Funkce SFileGetLocale vrací aktuálně nastavenou jazykovou verzi pro otevírané soubory.
LCID WINAPI SFileGetLocale();Parametry
Funkce vždy skončí s úspěchem a vrací aktuálně nastavenou jazykovou verzi.
Funkce SFileOpenArchive otevře archiv MPQ pro čtení.
BOOL WINAPI SFileOpenArchive( const char * szMpqName, // Jméno archivního souboru DWORD dwPriority, // Priorita archivu DWORD dwFlags, // Podmínka pro otevření HANDLE * phMPQ // Ukazatel na výsledný HANDLE );Parametry
Pokud funkce skončí úspěšně, vrací nenulovou hodnotu a do proměnné phMPQ je uložen handle otevřeného archivu. Pokud se archiv nepodaří otevřít, návratová hodnota je FALSE. Podrobnější informace o chybě vrací funkce GetLastError().
Funkce SFileCloseArchive uzavírá otevřený archivní soubor.
BOOL WINAPI SFileOpenArchive( HANDLE hMPQ // Handle otevřeného archivu );Parametry
Pokud funkce skončí úspěšně, vrací nenulovou hodnotu a archiv je uzavřen. Pokud funkce selže, návratová hodnota je FALSE. Podrobnější informace o chybě vrací funkce GetLastError().
PoznámkyPokud byl archiv od posledního otevření modifikován, funkce implementovaná knihovnou StormLib aktualizuje hlavičku MPQ, hash tabulku a block tabulku v archivu.
Funkce SFileOpenFileEx otevírá soubor uvnitř archivu.
BOOL WINAPI SFileOpenFileEx( HANDLE hMPQ, // Handle otevřeného archivu const char * szFileName, // Jméno souboru, který má být otevřen. DWORD dwSearchScope, // Umístění, kde se soubor bude hledat HANDLE phFile // Ukazatel na výsledný HANDLE. );Parametry
Pokud funkce skončí úspěšně, vrací nenulovou hodnotu a do proměnné phFile je uložen handle otevřeného souboru. Pokud funkce selže, návratová hodnota je FALSE. Podrobnější informace o chybě vrací funkce GetLastError().
Funkce SFileCloseFile uzavírá archivovaný soubor.
BOOL WINAPI SFileCloseFile( HANDLE hFile // Handle otevřeného souboru );Parametry
Pokud funkce skončí úspěšně, vrací nenulovou hodnotu a soubor je uzavřen. Pokud funkce selže, návratová hodnota je FALSE. Podrobnější informace o chybě vrací funkce GetLastError().
Funkce SFileGetFileSize vrací velikost otevřeného souboru.
DWORD WINAPI SFileGetFileSize( HANDLE hFile, // Handle otevřeného souboru DWORD * pdwFileSizeHigh // Pro uložení horních 32 bitů );Parametry
Pokud funkce skončí úspěšně, vrací velikost souboru. Pokud funkce selže, návratová hodnota je 0xFFFFFFFF. Podrobnější informace o chybě vrací funkce GetLastError().
PoznámkyHorních 32 bitů (parametr pdwFileSizeHigh) zatím není podporován knihovnou Storm.dll ani StormLib. Pokud obsahuje platnou hodnotu, funkce naplní proměnnou nulou.
Funkce SFileSetFilePointer nastavuje pozici v souboru.
LONG WINAPI SFileSetFilePointer( HANDLE hFile, // Handle otevřeného souboru LONG lFilePos // Nová pozice v souboru LONG * plFilePosHigh // Pro uložení horních 32 bitů DWORD dwMethod // Relativní bod, ke kterému se vztahuje posun );Parametry
Pokud funkce skončí úspěšně, vrací novou pozici v souboru. Pokud funkce selže, návratová hodnota je 0xFFFFFFFF. Podrobnější informace o chybě vrací funkce GetLastError().
Funkce SFileReadFile čte data z otevřeného archivovaného souboru.
BOOL WINAPI SFileReadFile( HANDLE hFile, // Handle otevřeného souboru void * pBuffer, // Buffer pro čtení DWORD dwToRead, // Počet bytů k načtení DWORD * pdwRead, // Počet bytů, které byly načteny LPOVERLAPPED lpOverlapped // Pro asynchronní čtení );Parametry
Pokud funkce skončí úspěšně, vrací nenulovou hodnotu. Buffer, na který ukazuje pBuffer obsahuje načtená data a proměnná, na kterou ukazuje pdwRead obsahuje počet načtených bytů. Pokud funkce selže, návratová hodnota je FALSE. Podrobnější informace o chybě vrací funkce GetLastError().
PoznámkyNásledující funkce jsou implementovány pouze v knihovně StormLib. Storm.dll tyto funkce nepodporuje.
Funkce SFileExtractFile extrahuje celý soubor z archivu. Je to "pomocník", který se hodí skoro v každé aplikaci, která pracuje s archivy MPQ.
BOOL WINAPI SFileExtractFile( HANDLE hMpq, // Handle otevřeného archivu const char * szToExtract, // Jméno extrahovaného souboru const char * szExtracted // Jméno lokálního souboru (na disku) );Parametry
Pokud funkce skončí s úspěchem, vrací nenulovou hodnotu. V takovém případě byl soubor úspěšně vytvořen a zapsán. V případě chyby vrací nulu a podrobnější informace o chybě vrací funkce GetLastError().
Funkce SFileCreateArchiveEx otevírá nebo vytváří nový archivní soubor. Umí také zkonvertovat existující soubor na MPQ archiv. Archiv je po otevření/vytvoření přístupný také pro zápis.
BOOL WINAPI SFileCreateArchiveEx( const char * szMpqName, // Jméno archivního souboru DWORD dwCreationDisposition, // Otevřít nebo vytvořit DWORD dwHashTableSize, // Velikost hashové tabulky HANDLE * phMPQ // Ukazatel na výsledný HANDLE );Parametry
| Hodnota | Pokud archiv neexistuje | Pokud archiv již existuje |
|---|---|---|
| CREATE_NEW | Vytvoří nový archiv MPQ | Vrátí chybu |
| CREATE_ALWAYS | Vytvoří nový archiv MPQ | Stávající soubor bude přepsán a funkce vytvoří nový archiv. |
| OPEN_EXISTING | Vrátí chybu | Otevře archiv |
| OPEN_ALWAYS | Otevře archiv nebo zkonvertuje existující soubor na MPQ archiv | Otevře archiv |
Pokud funkce skončí úspěšně, vrací nenulovou hodnotu a do proměnné phMPQ je uložen handle otevřeného archivu. Pokud se archiv nepodaří otevřít, návratová hodnota je FALSE. Podrobnější informace o chybě vrací funkce GetLastError().
Funkce SFileAddFile přidá soubor do archivu. Archiv musí být otevřen pro zápis (Použitím funkce SFileCreateArchiveEx.
BOOL WINAPI SFileAddFile( HANDLE hMPQ, // Handle otevřeného archivu const char * szFileName, // Jméno přidávaného souboru const char * szArchivedName, // Jméno archivovaného souboru DWORD dwFlags // Způsob uložení souboru v archivu );Parametry
Funkce vrací nenulovou hodnotu, pokud se povedlo soubor přidat do archivu. Při chybě vrací FALSE, bližší informace o chybě vrací návratová hodnota funkce GetLastError().
PoznámkyNení možné kombinovat příznaky MPQ_FILE_COMPRESS_PKWARE a MPQ_FILE_COMPRESS_MULTI. Pokud bude funkce zavolána s oběma nastavenými příznaky, vrátí chybu.
Jazyková verze souboru v archivu bude nastavena na hodnotu naposled specifikovanou voláním funkce SFileSetLocale.
Funkce SFileAddWave přidá soubor do archivu. Archiv musí být otevřen pro zápis (Použitím funkce SFileCreateArchiveEx). Na rozdíl od SFileAddFile, tato funkce optimalizuje kompresi pro strukturu WAVE souborů a umožňuje tak lepší kompresi než při ukládání funkcí SFileAddFile.
BOOL WINAPI SFileAddFile( HANDLE hMPQ, // Handle otevřeného archivu const char * szFileName, // Jméno přidávaného souboru const char * szArchivedName, // Jméno archivovaného souboru DWORD dwFlags, // Způsob uložení souboru v archivu DWORD dwQuality // Kvalita uloženého zvukového souboru );Parametry
Funkce vrací nenulovou hodnotu, pokud se povedlo soubor přidat do archivu. Při chybě vrací FALSE, bližší informace o chybě vrací návratová hodnota funkce GetLastError().
PoznámkyNení možné kombinovat příznaky MPQ_FILE_COMPRESS_PKWARE a MPQ_FILE_COMPRESS_MULTI. Pokud bude funkce zavolána s oběma nastavenými příznaky, vrátí chybu.
Jazyková verze souboru v archivu bude nastavena na hodnotu naposled specifikovanou voláním funkce SFileSetLocale.
Funkce SFileRemoveFile odstraní soubor z archivu. Archiv musí být otevřen pro zápis (Použitím funkce SFileCreateArchiveEx.
BOOL WINAPI SFileRemoveFile( HANDLE hMPQ, // Handle otevřeného archivu const char * szFileName // Jméno odstraňovaného souboru );Parametry
Funkce vrací nenulovou hodnotu, pokud se povedlo soubor z archivu odstranit. Při chybě vrací FALSE. Podrobnější informace o chybě udává návratová hodnota funkce GetLastError().
Funkce SFileRenameFile přejmenuje v archivu MPQ. Archiv musí být otevřen pro zápis použitím funkce SFileCreateArchiveEx.
BOOL WINAPI SFileRenameFile( HANDLE hMPQ, // Handle otevřeného archivu const char * szOldFileName, // Původní jméno souboru const char * szNewFileName, // Nové jméno souboru );Parametry
Funkce vrací nenulovou hodnotu, pokud byl soubor úspěšně přejmenován. Při chybě vrací FALSE. Podrobnější informace o chybě udává návratová hodnota funkce GetLastError().
Funkce SFileFindFirstFile a SFileFindFirstFileEx hledají soubory v MPQ archivu. Protože archivy neobsahují jména souborů, obě funkce vyžadují pro úspěšné hledání seznam souborů.
BOOL WINAPI SFileFindFirstFileEx( HANDLE hMPQ, // Handle of otevřeného archivu const char * szMask, // Vyhledávací maska SFILE_FIND_DATA * lpFindFileData, // Struktura s výsledky hledání const char * szFileList, // Seznam souborů BOOL bCheckIfExist // Kontrolovat zda soubor existuje ); BOOL WINAPI SFileFindFirstFile( HANDLE hMPQ, // Handle of otevřeného archivu const char * szMask, // Vyhledávací maska SFILE_FIND_DATA * lpFindFileData, // Struktura s výsledky hledání const char * szFileList // Seznam souborů );Parametry
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)
};
Návratová hodnota
Funkce vrací vyhledávací handle, pokud byl v archivu nalezen aspoň jeden soubor. Tento handle musí byt uvolněn voláním SFileFindClose. V případě chyby vrací NULL. Více informací o chybě vrací funkce GetLastError().
PoznámkyPokud v archivu existuje více jazykových verzí, funkce vrátí položku pro každou jazykovou verzi jako úspěšný výsledek hledání.
Volající aplikace by měla ověřit, zda soubor nebyl vrácen vícekrát. Protože chování funkce závisí na předaném seznamu souborů, funkce nemusí najít všechny soubory v archivu a také může jeden soubor vrátit vícekrát.
Volající aplikace nesmí modifikovat strukturu během prohledávání.
Funkce SFileFindNextFile pokračuje v hledání započatém funkcí SFileFindFirstFile(Ex).
BOOL WINAPI SFileFindNextFile( HANDLE hFind, // Prohledávací handle WIN32_FIND_DATA * lpFindFileData // Struktura s výsledky hledání );Parametry
Function vrací nenulovou hodnotu, pokud byl v archivu nalezen odpovídající soubor. V případě chyby vrací FALSE. Více informací o chybě vrací funkce GetLastError().
Funkce SFileFindClose končí hledání započaté funkcí SFileFindFirstFile(Ex). Musí být zavolána, jakmile je hledání ukončeno.
BOOL WINAPI SFileFindClose( HANDLE hFind // Prohledávací handle );Parametry
Function vrací nenulovou hodnotu, pokud byl v archivu nalezen odpovídající soubor. V případě chyby vrací FALSE. Více informací o chybě vrací funkce GetLastError().