Archivy MPQ
Knihovna StormLib
Po vydání hry Diablo, mnoho hráčů hledalo nástroj, který by umožnil přehrávat hudbu a zvuky ze hry. Krátce poté se začaly objevovat nástroje, které používaly knihovnu Storm.dll (součást hry) ke čtení dat z archivů hry. Společnost Blizzard si toho byla vědoma a od verze 1.04 obsahovala knihovna Storm.dll triky pro zabránění snadného použití ke čtení Blizzardovských archivů. Přestože tyto triky jsou snadno překonatelné, komunita hledala alternativu pro čtení a vytváření archivů MPQ bez pomoci Blizzardí knihovny.
První knihovna, ktera umožňovala vytváření archivů MPQ, byla LMPQAPI, vytvořena ruským programátorem Andrejem Lelikovem. Tato knihovna interně používala StarEdit.exe a umožňovala volat interní funkce, které uměly vytvářet archivy MPQ a přidávat soubory.
Tom Amigo byl první, kdo uveřejnil Stormless MPQ Editor, který uměl číst (a později i zapisovat) archivy MPQ bez použití Storm.dll. Zhruba ve stejné době (rok 2000) jsem začal reverzovat Storm.dll, abych získal funkční kód napsaný v C++, ktery umí číst archivy MPQ. Výsledkem byla knihovna StormLib v 1.0. Ke dnešnímu dni (rok 2010) je knihovna pořád udržovaná, a umí číst a přidávat soubory do archivů MPQ.
Knihovna StormLib je skupina modulů, napsaných v C++, které umí číst a také zapisovat soubory z archivů MPQ. Původní verze byla napsaná pro platformu Win32. Existuje i verze pro Linux, napsaná Markem Friedemannem a verze pro Mac, kterou napsal Sam Wilkins. Knihovna je volně ke stažení, a k použití ve vlastních projektech není třeba licence. Stáhnout se dá v sekci Ke stažení. Pokud byste našli jakoukoliv chybu, nebo odhalili něco nefunkčního, dejte mi prosím vědět, a také mi pošlete archiv MPQ, který problém způsobil.
Veškeré potřebné funkce jsou k dispozici v hlavičkovém souboru StormLib.h. Dokumentaci je také možné stáhnout.
Funkce | Popis |
---|---|
SFileOpenArchive | Otevře archiv MPQ |
SFileCreateArchive | Vytvoří nový archiv MPQ |
SFileCreateArchive2 | Vytvoří nový archiv MPQ. Umožňuje více nastavení než SFileCreateArchive. |
SFileCreateArchiveEx | Funkce odstraněna |
SFileAddListFile | Přidá další listfile do otevřeného archivu MPQ pro zlepšení vyhledávání |
SFileSetLocale | Změní nastavení jazyka pro přidávání nových souborů |
SFileGetLocale | Vrací aktuální jazyk nově přidávaných souborů |
SFileFlushArchive | Uloží všechna data MPQ archivu na disk |
SFileCloseArchive | Uzavře archiv MPQ |
SFileSetMaxFileCount | Změní limit pro počet souborů v archivu |
SFileSignArchive | Podepíše archiv slabou digitální signaturou |
SFileCompactArchive | Defragmentuje (přebalí) celý archiv. Slouží k uvolnění všech mezer, které vznikly ukládáním do archivu |
SFileSetCompactCallback | Umožňuje nastavit callback funkci, která informuje o průběhu defragmentace archivu MPQ |
Funkce | Popis |
---|---|
SFileOpenPatchArchive | Přidá aktualizaci k otevřenému archivu |
SFileIsPatchedArchive | Zjistí, zda otevřený archiv obsahuje aktualizace |
Funkce | Popis |
---|---|
SFileOpenFileEx | Otevře soubor v archivu MPQ |
SFileGetFileSize | Vrací velikost souboru v MPQ archivu |
SFileSetFilePointer | Nastaví nový ukazatel pozice v souboru. |
SFileReadFile | Čte data ze souboru |
SFileCloseFile | Uzavře soubor |
SFileHasFile | Rychlé ověření, zda soubor v archivu existuje |
SFileGetFileName | Zjistí jméno otevřeného souboru |
SFileGetFileInfo | Zjistí jméno otevřeného souboru |
SFileVerifyFile | Ověří integritu souboru oproti rozšířeným atributům |
SFileVerifyArchive | Ověří digitální podpis archivu |
SFileExtractFile | Vybalí soubor z archivu MPQ |
Funkce | Popis |
---|---|
SFileFindFirstFile | Najde první soubor, který vyhovuje specifikaci |
SFileFindNextFile | Najde další soubor, který vyhovuje specifikaci |
SFileFindClose | Ukončí hledání v MPQ |
SListFileFindFirstFile | Najde první soubor v listfile, který vyhovuje specifikaci |
SListFileFindNextFile | Najde další soubor v listfile, který vyhovuje specifikaci |
SListFileFindClose | Ukončí hledání v listfile |
SFileEnumLocales | Enumeruje všechny jazykové verze daného souboru |
Funkce | Popis |
---|---|
SFileCreateFile | Vytvoří nový soubor v archivu a připraví jej pro zápis dat |
SFileWriteFile | Zapíše data do souboru v archivu |
SFileFinishFile | Dokončí vytváření souboru v archivu |
SFileAddFileEx | Přidá soubor do archivu |
SFileAddFile | Přidá datový soubor do archivu (zastaralá funkce) |
SFileAddWave | Přidá zvukový soubor VAWE do archivu (zastaralá funkce) |
SFileRemoveFile | Odstraní soubor z archivu MPQ |
SFileRenameFile | Přejmenuje soubor v archivu MPQ |
SFileSetFileLocale | Změní jazyk souboru v archivu |
SFileSetDataCompression | Nastaví kompresní metodu pro soubory přidávané pomocí SFileAddFile |
SFileSetAddFileCallback | Nastaví ukazatel na funkci, pomocí které je aplikace informována o postupu přidávání souboru do MPQ |
Funkce | Popis |
---|---|
SCompImplode | Komprimuje blok dat metodou IMPLODE (Pkware Data Compression Library) |
SCompExplode | Dekomprimuje block dat zkomprimovaný funkcí SCompImplode |
SCompCompress | Komprimuje blok dat použitím některé z kompresních metod použitých v MPQ |
SCompDecompress | Dekomprimuje blok dat zkomprimovaný funkcí SCompCompress |
Zde je příklad funkce, která extrahuje jeden soubor z archivu MPQ.
//----------------------------------------------------------------------------- // Extracts an archived file and saves it to the disk. // // Parameters : // // char * szArchiveName - Archive file name // char * szArchivedFile - Name/number of archived file. // char * szFileName - Name of the target disk file. static int ExtractFile(char * szArchiveName, char * szArchivedFile, char * szFileName) { HANDLE hMpq = NULL; // Open archive handle HANDLE hFile = NULL; // Archived file handle HANDLE handle = NULL; // Disk file handle int nError = ERROR_SUCCESS; // Result value // Open an archive, e.g. "d2music.mpq" if(nError == ERROR_SUCCESS) { if(!SFileOpenArchive(szArchiveName, 0, 0, &hMpq)) nError = GetLastError(); } // Open a file in the archive, e.g. "data\global\music\Act1\tristram.wav" if(nError == ERROR_SUCCESS) { if(!SFileOpenFileEx(hMpq, szArchivedFile, 0, &hFile)) nError = GetLastError() } // Create the target file if(nError == ERROR_SUCCESS) { handle = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if(handle == INVALID_HANDLE_VALUE) nError = GetLastError(); } // Read the file from the archive if(nError == ERROR_SUCCESS) { char szBuffer[0x10000]; DWORD dwBytes = 1; while(dwBytes > 0) { SFileReadFile(hFile, szBuffer, sizeof(szBuffer), &dwBytes, NULL); if(dwBytes > 0) WriteFile(handle, szBuffer, dwBytes, &dwBytes, NULL); } } // Cleanup and exit if(handle != NULL) CloseHandle(handle); if(hFile != NULL) SFileCloseFile(hFile); if(hMpq != NULL) SFileCloseArchive(hMpq); return nError; }
Copyright (c) Ladislav Zezula 2003 - 2010