* huge changes:
* few script changes; added new func "ScriptExists". * started an extractor tool; using StormLib (thx to Ladislaw Zezula!). for now convert some dbc files to scp. more stuff will follow. * some changes to the realm/world connect code; still needs a rewrite. * support conf parameters for GUI (check conf/gui.conf/gui.conf[.default] )
This commit is contained in:
parent
71e2f7f224
commit
c92f1ea824
14
PseuWoW.sln
14
PseuWoW.sln
@ -26,6 +26,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "src\dep\src\irr
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} = {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StuffExtract", "src\tools\stuffextract.vcproj", "{EFFE60F4-DA39-41E8-9E53-E462000A2D91}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} = {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}
|
||||
{F548FC51-24A4-45FF-A381-BEBC39F18270} = {F548FC51-24A4-45FF-A381-BEBC39F18270}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
@ -74,6 +80,14 @@ Global
|
||||
{E08E042A-6C45-411B-92BE-3CC31331019F}.Release.Build.0 = Release|Win32
|
||||
{E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU DebugInfo.ActiveCfg = Release - Fast FPU DebugInfo|Win32
|
||||
{E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU DebugInfo.Build.0 = Release - Fast FPU DebugInfo|Win32
|
||||
{EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Debug.ActiveCfg = Debug|Win32
|
||||
{EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Debug.Build.0 = Debug|Win32
|
||||
{EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Relase - Fast FPU.ActiveCfg = Release|Win32
|
||||
{EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Relase - Fast FPU.Build.0 = Release|Win32
|
||||
{EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Release.ActiveCfg = Release|Win32
|
||||
{EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Release.Build.0 = Release|Win32
|
||||
{EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Release - Fast FPU DebugInfo.ActiveCfg = Release|Win32
|
||||
{EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Release - Fast FPU DebugInfo.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
|
||||
@ -99,7 +99,7 @@ cmdchar=.
|
||||
// set this to 1 if you want to have a 3D-window showing stuff
|
||||
// NOTE: this is only to activate the window for now, 3D-stuff will come later!!
|
||||
// until some frame-limiter is implemented, it will always use 100% CPU usage when
|
||||
// the GUI is enabled and activated. (if its in background - 0% CPU load.)
|
||||
// the GUI is enabled and activated. (if its in background - way less CPU load.)
|
||||
enablegui=0
|
||||
|
||||
|
||||
|
||||
24
bin/conf/gui.conf.default
Normal file
24
bin/conf/gui.conf.default
Normal file
@ -0,0 +1,24 @@
|
||||
[#uppercase]
|
||||
[GUI]
|
||||
|
||||
// drivers:
|
||||
// 0: Nulldevice (no graphics)
|
||||
// 1: fast but crappy software driver
|
||||
// 2: good software driver, but slower
|
||||
// 3: OpenGL
|
||||
// 4: DirectX 8.1
|
||||
// 5: DirectX 9.0c
|
||||
driver=5
|
||||
|
||||
// resolution and more
|
||||
resx=1024
|
||||
resy=768
|
||||
windowed=1
|
||||
vsync=0
|
||||
|
||||
// use realtime shadows?
|
||||
// works only with DirectX or OpenGL
|
||||
shadows=1
|
||||
|
||||
// color depth; 16 or 32 bit
|
||||
depth=32
|
||||
@ -1,31 +0,0 @@
|
||||
[1]
|
||||
defaultlang=7
|
||||
name=Human
|
||||
|
||||
[2]
|
||||
defaultlang=1
|
||||
name=Orc
|
||||
|
||||
[3]
|
||||
defaultlang=7
|
||||
name=Dwarf
|
||||
|
||||
[4]
|
||||
defaultlang=7
|
||||
name=Night Elf
|
||||
|
||||
[5]
|
||||
defaultlang=1
|
||||
name=Undead
|
||||
|
||||
[6]
|
||||
defaultlang=1
|
||||
name=Tauren
|
||||
|
||||
[7]
|
||||
defaultlang=7
|
||||
name=Gnome
|
||||
|
||||
[8]
|
||||
defaultlang=1
|
||||
name=Troll
|
||||
35
bin/data/scp/race.scp
Normal file
35
bin/data/scp/race.scp
Normal file
@ -0,0 +1,35 @@
|
||||
// note that the faction is equal to the default language id:
|
||||
// 1: Horde, Orcish
|
||||
// 7: Alliance, Common
|
||||
|
||||
[1]
|
||||
faction=7
|
||||
name=Human
|
||||
|
||||
[2]
|
||||
faction=1
|
||||
name=Orc
|
||||
|
||||
[3]
|
||||
faction=7
|
||||
name=Dwarf
|
||||
|
||||
[4]
|
||||
faction=7
|
||||
name=Night Elf
|
||||
|
||||
[5]
|
||||
faction=1
|
||||
name=Undead
|
||||
|
||||
[6]
|
||||
faction=1
|
||||
name=Tauren
|
||||
|
||||
[7]
|
||||
faction=7
|
||||
name=Gnome
|
||||
|
||||
[8]
|
||||
faction=1
|
||||
name=Troll
|
||||
@ -3,4 +3,4 @@
|
||||
// EXECUTED EVERYTIME A WHISPER IS BEEING RECIEVED
|
||||
|
||||
// comment out the following line if you dont need it
|
||||
//REPLY,0 No need to whisper me, i am not yet programmed for it!
|
||||
//REPLY,0 [BOT] No need to whisper, nobody is here who could read what you wrote.
|
||||
@ -3,12 +3,16 @@
|
||||
LOADCONF PseuWoW.conf
|
||||
LOADCONF users.conf
|
||||
|
||||
// Apply the configureation
|
||||
// Apply the configuration
|
||||
APPLYCONF
|
||||
|
||||
// Apply user permissions
|
||||
APPLYPERMISSIONS
|
||||
|
||||
IF ${#ENABLEGUI}
|
||||
LOADCONF gui.conf
|
||||
ENDIF
|
||||
|
||||
// remove dangerous variables
|
||||
CLEANUPVARS
|
||||
|
||||
|
||||
6
bin/scripts/exloadscp.def
Normal file
6
bin/scripts/exloadscp.def
Normal file
@ -0,0 +1,6 @@
|
||||
#permission=255
|
||||
if ?{fileexists ${@def}}
|
||||
loadscp,{${@0}} ${@def}
|
||||
else
|
||||
logdebug skipped loading of non-existent file '${@def}'
|
||||
endif
|
||||
@ -5,11 +5,16 @@ LOG * Loading SCP data storages...
|
||||
// example:
|
||||
// LOADSCP,test data/test.scp
|
||||
|
||||
LOADSCP,class data/class.scp
|
||||
LOADSCP,gender data/gender.scp
|
||||
LOADSCP,language data/language.scp
|
||||
LOADSCP,map data/map.scp
|
||||
LOADSCP,race data/race.scp
|
||||
// load default databases
|
||||
LOADSCP,class data/scp/class.scp
|
||||
LOADSCP,gender data/scp/gender.scp
|
||||
LOADSCP,language data/scp/language.scp
|
||||
LOADSCP,map data/scp/map.scp
|
||||
LOADSCP,race data/scp/race.scp
|
||||
|
||||
// load extended databases if present.
|
||||
EXLOADSCP,sound data/scp/sound.scp
|
||||
EXLOADSCP,emote data/scp/emote.scp
|
||||
|
||||
LOG * SCP loaded.
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
SET,lang ${@0}
|
||||
SET,msg ${@def}
|
||||
|
||||
DEFAULT,#DEFAULTLANG ?{GETSCPVALUE,race,{${@myrace}} defaultlang}
|
||||
DEFAULT,#DEFAULTLANG ?{GETSCPVALUE,race,{${@myrace}} faction}
|
||||
DEFAULT,lang ${#DEFAULTLANG}
|
||||
|
||||
LOGDEBUG * Saying '${msg}' in lang ${lang}
|
||||
|
||||
@ -5,7 +5,7 @@ SET,msg ${@def}
|
||||
SET,player ${@0}
|
||||
SET,lang ${@1}
|
||||
|
||||
DEFAULT,#DEFAULTLANG ?{GETSCPVALUE,race,{${@myrace}} defaultlang}
|
||||
DEFAULT,#DEFAULTLANG ?{GETSCPVALUE,race,{${@myrace}} faction}
|
||||
DEFAULT,lang ${#DEFAULTLANG}
|
||||
|
||||
LOGDEBUG * Whisp to '{${player}}' '{${msg}}' in lang '${lang}'
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
SET,lang ${@0}
|
||||
SET,msg ${@def}
|
||||
|
||||
DEFAULT,#DEFAULTLANG ?{GETSCPVALUE,race,{${@myrace}} defaultlang}
|
||||
DEFAULT,#DEFAULTLANG ?{GETSCPVALUE,race,{${@myrace}} faction}
|
||||
DEFAULT,lang ${#DEFAULTLANG}
|
||||
|
||||
LOGDEBUG * Yelling '${msg}' in lang ${lang}
|
||||
|
||||
@ -87,6 +87,7 @@ void DefScriptPackage::_InitFunctions(void)
|
||||
AddFunc("uppercase",&DefScriptPackage::func_uppercase);
|
||||
AddFunc("lowercase",&DefScriptPackage::func_lowercase);
|
||||
AddFunc("random",&DefScriptPackage::func_random);
|
||||
AddFunc("fileexists",&DefScriptPackage::func_fileexists);
|
||||
}
|
||||
|
||||
void DefScriptPackage::AddFunc(std::string n,DefReturnResult (DefScriptPackage::*f)(CmdSet& Set))
|
||||
|
||||
@ -177,6 +177,7 @@ private:
|
||||
DefReturnResult func_uppercase(CmdSet&);
|
||||
DefReturnResult func_lowercase(CmdSet&);
|
||||
DefReturnResult func_random(CmdSet&);
|
||||
DefReturnResult func_fileexists(CmdSet&);
|
||||
// setup own function declarations here
|
||||
# include "DefScriptInterfaceInclude.h"
|
||||
|
||||
|
||||
@ -453,5 +453,17 @@ DefReturnResult DefScriptPackage::func_random(CmdSet& Set)
|
||||
return r;
|
||||
}
|
||||
|
||||
DefReturnResult DefScriptPackage::func_fileexists(CmdSet& Set)
|
||||
{
|
||||
std::fstream f;
|
||||
f.open(Set.defaultarg.c_str(),std::ios_base::in);
|
||||
if (f.is_open())
|
||||
{
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -43,11 +43,14 @@ void DefScript_DynamicEventMgr::Remove(std::string name)
|
||||
if(name.empty())
|
||||
return;
|
||||
for(DefDynamicEventList::iterator i = _storage.begin(); i != _storage.end(); i++)
|
||||
{
|
||||
if((*i)->name == name)
|
||||
{
|
||||
delete *i;
|
||||
_storage.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -102,7 +102,7 @@ void PseuGUI::UseShadows(bool b)
|
||||
_shadows = b;
|
||||
}
|
||||
|
||||
// if this fuction is called fom another thread the device will not work correctly. o_O
|
||||
// if this fuction is called from another thread the device will not work correctly. o_O
|
||||
void PseuGUI::_Init(void)
|
||||
{
|
||||
_device = createDevice(_driverType,dimension2d<s32>(_xres,_yres),_colordepth,!_windowed,_shadows,_vsync);
|
||||
@ -116,6 +116,7 @@ void PseuGUI::_Init(void)
|
||||
|
||||
void PseuGUI::Shutdown(void)
|
||||
{
|
||||
DEBUG(logdebug("PseuGUI::Shutdown()"));
|
||||
_mustdie = true;
|
||||
if(_device)
|
||||
{
|
||||
@ -135,8 +136,10 @@ void PseuGUI::Run(void)
|
||||
|
||||
while(_device && _device->run() && !_mustdie)
|
||||
{
|
||||
if (_device->isWindowActive())
|
||||
if (!_device->isWindowActive())
|
||||
{
|
||||
_device->sleep(10); // save cpu & gpu power if not focused
|
||||
}
|
||||
_driver->beginScene(true, true, 0);
|
||||
|
||||
_smgr->drawAll();
|
||||
@ -152,7 +155,6 @@ void PseuGUI::Run(void)
|
||||
str += "] FPS:";
|
||||
str += fps;
|
||||
|
||||
// this call does actually lock up the whole window, and i just dont know why; but definitely a threading issue.
|
||||
_device->setWindowCaption(str.c_str());
|
||||
|
||||
lastFPS = fps;
|
||||
@ -160,12 +162,6 @@ void PseuGUI::Run(void)
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_device->setWindowCaption(L"PseuWoW - Halted");
|
||||
_device->yield();
|
||||
}
|
||||
}
|
||||
DEBUG(logdebug("PseuGUI::Run() finished"));
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
@ -3,11 +3,10 @@
|
||||
#include <time.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "Auth/ByteBuffer.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "DefScript/DefScript.h"
|
||||
#include "DefScriptInterface.h"
|
||||
#include "Auth/BigNumber.h"
|
||||
#include "Auth/ByteBuffer.h"
|
||||
#include "DefScript/DefScript.h"
|
||||
#include "Realm/RealmSocket.h"
|
||||
#include "World/WorldSession.h"
|
||||
@ -132,6 +131,36 @@ bool PseuInstance::Init(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: find a better loaction where to place this block!
|
||||
if(GetConf()->enablegui)
|
||||
{
|
||||
uint16 x,y,depth;
|
||||
uint8 driver;
|
||||
bool shadows,vsync,win;
|
||||
|
||||
driver=(uint8)atoi(GetScripts()->variables.Get("GUI::DRIVER").c_str());
|
||||
vsync=(bool)atoi(GetScripts()->variables.Get("GUI::VSYNC").c_str());
|
||||
depth=(uint8)atoi(GetScripts()->variables.Get("GUI::DEPTH").c_str());
|
||||
x=(uint16)atoi(GetScripts()->variables.Get("GUI::RESX").c_str());
|
||||
y=(uint16)atoi(GetScripts()->variables.Get("GUI::RESY").c_str());
|
||||
win=(bool)atoi(GetScripts()->variables.Get("GUI::WINDOWED").c_str());
|
||||
shadows=(bool)atoi(GetScripts()->variables.Get("GUI::SHADOWS").c_str());
|
||||
log("GUI settings: driver=%u, depth=%u, res=%ux%u, windowed=%u, shadows=%u",driver,depth,x,y,win,shadows);
|
||||
if(x>0 && y>0 && (depth==16 || depth==32) && driver>0 && driver<=5)
|
||||
{
|
||||
PseuGUIRunnable *rgui = new PseuGUIRunnable();
|
||||
PseuGUI *gui = rgui->GetGUI();
|
||||
gui->SetInstance(this);
|
||||
gui->SetDriver(driver);
|
||||
gui->SetResolution(x,y,depth);
|
||||
gui->SetVSync(vsync);
|
||||
gui->UseShadows(shadows);
|
||||
ZThread::Thread *t = new ZThread::Thread(rgui);
|
||||
}
|
||||
else
|
||||
logerror("GUI: incorrect settings!");
|
||||
}
|
||||
|
||||
if(GetConf()->enablecli)
|
||||
{
|
||||
log("Starting CLI...");
|
||||
@ -139,16 +168,6 @@ bool PseuInstance::Init(void) {
|
||||
ZThread::Thread t(_cli);
|
||||
}
|
||||
|
||||
// TODO: find a better loaction where to place this block!
|
||||
if(GetConf()->enablegui)
|
||||
{
|
||||
PseuGUIRunnable *rgui = new PseuGUIRunnable();
|
||||
PseuGUI *gui = rgui->GetGUI();
|
||||
gui->SetInstance(this);
|
||||
// TODO: set resolution, shadows(on/off) and more here...
|
||||
ZThread::Thread *t = new ZThread::Thread(rgui);
|
||||
}
|
||||
|
||||
if(_error)
|
||||
{
|
||||
logcritical("Errors while initializing!");
|
||||
@ -220,7 +239,14 @@ void PseuInstance::Run(void)
|
||||
void PseuInstance::Update()
|
||||
{
|
||||
if(_sh.GetCount())
|
||||
{
|
||||
_sh.Select(0,0); // update the realmsocket
|
||||
if(deleterealm)
|
||||
{
|
||||
deleterealm=false;
|
||||
_rsession = NULL; // was deleted by SocketHandler already!
|
||||
}
|
||||
}
|
||||
|
||||
if(createWorldSession && (!_wsession))
|
||||
{
|
||||
@ -301,10 +327,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
|
||||
notifyping=(bool)atoi(v.Get("NOTIFYPING").c_str());
|
||||
showmyopcodes=(bool)atoi(v.Get("SHOWMYOPCODES").c_str());
|
||||
disablespellcheck=(bool)atoi(v.Get("DISABLESPELLCHECK").c_str());
|
||||
|
||||
// gui related
|
||||
enablegui=(bool)atoi(v.Get("ENABLEGUI").c_str());
|
||||
// TODO: add configs for resolution, fullscreen, etc. see PseuGUI::... for a list of functions.
|
||||
|
||||
// clientversion is a bit more complicated to add
|
||||
{
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#define _PSEUWOW_H
|
||||
|
||||
#include "common.h"
|
||||
#include "HelperDefs.h"
|
||||
#include "log.h"
|
||||
#include "Auth/BigNumber.h"
|
||||
#include "DefScript/DefScript.h"
|
||||
@ -88,6 +89,7 @@ class PseuInstance
|
||||
void Sleep(uint32 msecs);
|
||||
|
||||
bool createWorldSession;
|
||||
bool deleterealm;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "common.h"
|
||||
#include "PseuWoW.h"
|
||||
#include "Auth/ByteBuffer.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Auth/Sha1.h"
|
||||
#include "Auth/BigNumber.h"
|
||||
#include "RealmSocket.h"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#define _WORLDPACKET_H
|
||||
|
||||
#include "SysDefs.h"
|
||||
#include "Auth/ByteBuffer.h"
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
class WorldPacket : public ByteBuffer
|
||||
{
|
||||
|
||||
@ -48,7 +48,11 @@ void WorldSession::Start(void)
|
||||
{
|
||||
log("Connecting to '%s' on port %u",GetInstance()->GetConf()->worldhost.c_str(),GetInstance()->GetConf()->worldport);
|
||||
_socket->Open(GetInstance()->GetConf()->worldhost,GetInstance()->GetConf()->worldport);
|
||||
if(GetInstance()->GetRSession())
|
||||
{
|
||||
GetInstance()->GetRSession()->SetCloseAndDelete(); // realm socket is no longer needed
|
||||
GetInstance()->deleterealm=true;
|
||||
}
|
||||
_valid=true;
|
||||
_sh.Add(_socket);
|
||||
_socket->SetDeleteByHandler();
|
||||
@ -85,7 +89,7 @@ void WorldSession::Update(void)
|
||||
if( _socket && _sh.GetCount() )
|
||||
_sh.Select(0,0);
|
||||
|
||||
if(!_socket)
|
||||
/*if(!_socket)
|
||||
{
|
||||
if(_valid)
|
||||
{
|
||||
@ -93,8 +97,17 @@ void WorldSession::Update(void)
|
||||
}
|
||||
_logged=_authed=_valid=false;
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
if(!_socket)
|
||||
{
|
||||
if(_valid)
|
||||
{
|
||||
this->Start();
|
||||
}
|
||||
_logged=_authed=_valid=false;
|
||||
return;
|
||||
}
|
||||
|
||||
OpcodeHandler *table = _GetOpcodeHandlerTable();
|
||||
bool known=false;
|
||||
|
||||
@ -18,6 +18,8 @@ void WorldSocket::OnConnect()
|
||||
void WorldSocket::OnConnectFailed()
|
||||
{
|
||||
logerror("WorldSocket::OnConnectFailed()\n");
|
||||
if(_session)
|
||||
_session->SetSocket(NULL);
|
||||
}
|
||||
|
||||
void WorldSocket::OnDelete()
|
||||
@ -29,6 +31,7 @@ void WorldSocket::OnDelete()
|
||||
|
||||
void WorldSocket::OnException()
|
||||
{
|
||||
DEBUG(logdebug("WorldSocket::OnException()"));
|
||||
this->SetCloseAndDelete();
|
||||
}
|
||||
|
||||
|
||||
@ -216,9 +216,6 @@
|
||||
<File
|
||||
RelativePath=".\Client\Auth\BigNumber.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Client\Auth\ByteBuffer.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Client\Auth\md5.c">
|
||||
</File>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#ifndef _ZCOMPRESSOR_H
|
||||
#define _ZCOMPRESSOR_H
|
||||
|
||||
#include "Auth/ByteBuffer.h"
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
|
||||
class ZCompressor : public ByteBuffer
|
||||
|
||||
@ -16,18 +16,19 @@
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#define SDL_THREADS_DISABLED true
|
||||
|
||||
//#include "SDL/SDL.h" // disabled for now until needed
|
||||
#ifndef _COMMON_SKIP_THREADS
|
||||
# include "zthread/FastMutex.h"
|
||||
# include "zthread/LockedQueue.h"
|
||||
# include "zthread/Runnable.h"
|
||||
# include "zthread/Thread.h"
|
||||
#endif
|
||||
|
||||
#include "SysDefs.h"
|
||||
#include "DebugStuff.h"
|
||||
#include "HelperDefs.h"
|
||||
#include "tools.h"
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include <fstream>
|
||||
#include "tools.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -128,9 +129,22 @@ std::deque<std::string> GetFileList(std::string path)
|
||||
|
||||
# endif
|
||||
|
||||
while(files.front()=="." || files.front()=="..")
|
||||
while(files.size() && (files.front()=="." || files.front()==".."))
|
||||
files.pop_front();
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
bool FileExists(char *fn)
|
||||
{
|
||||
std::fstream f;
|
||||
f.open(fn,std::ios_base::in);
|
||||
if (f.is_open())
|
||||
{
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -16,5 +16,6 @@ std::string getDateString(void);
|
||||
uint64 toInt(std::string);
|
||||
std::string toHexDump(uint8* array,uint32 size,bool spaces=true);
|
||||
std::deque<std::string> GetFileList(std::string);
|
||||
bool FileExists(char*);
|
||||
|
||||
#endif
|
||||
298
src/tools/stuffextract.vcproj
Normal file
298
src/tools/stuffextract.vcproj
Normal file
@ -0,0 +1,298 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="StuffExtract"
|
||||
ProjectGUID="{EFFE60F4-DA39-41E8-9E53-E462000A2D91}"
|
||||
RootNamespace="StuffExtract"
|
||||
SccProjectName=""
|
||||
SccLocalPath="">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)/bin"
|
||||
IntermediateDirectory="$(SolutionDir)/temp/$(ProjectName)/$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="FALSE"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="TRUE">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
GlobalOptimizations="TRUE"
|
||||
InlineFunctionExpansion="2"
|
||||
ImproveFloatingPointConsistency="FALSE"
|
||||
FavorSizeOrSpeed="1"
|
||||
AdditionalIncludeDirectories="../shared;../dep/include;../dep/include/zlib;StormLib"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
StringPooling="TRUE"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="FALSE"
|
||||
EnableFunctionLevelLinking="FALSE"
|
||||
EnableEnhancedInstructionSet="0"
|
||||
PrecompiledHeaderFile=".\Release/StuffExtract.pch"
|
||||
AssemblerListingLocation="$(SolutionDir)/temp/$(ProjectName)/$(ConfigurationName)/"
|
||||
ObjectFile="$(SolutionDir)/temp/$(ProjectName)/$(ConfigurationName)/"
|
||||
ProgramDataBaseFileName="$(SolutionDir)/temp/$(ProjectName)/$(ConfigurationName)/"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="TRUE"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib libeay32MT.lib WS2_32.LIB"
|
||||
ShowProgress="0"
|
||||
OutputFile="$(OutDir)/$(InputName).exe"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
AdditionalLibraryDirectories=""
|
||||
IgnoreAllDefaultLibraries="FALSE"
|
||||
AssemblyDebug="0"
|
||||
ProgramDatabaseFile="$(SolutionDir)/temp/$(ProjectName)/Release/StuffExtract.pdb"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
SetChecksum="TRUE"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TypeLibraryName=".\Release/StuffExtract.tlb"
|
||||
HeaderFileName=""/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
Culture="0"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)/bin"
|
||||
IntermediateDirectory="$(SolutionDir)/temp/$(ProjectName)/$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="FALSE"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
ImproveFloatingPointConsistency="FALSE"
|
||||
OptimizeForProcessor="0"
|
||||
AdditionalIncludeDirectories="../shared;../dep/include;../dep/include/zlib;StormLib"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
PrecompiledHeaderFile=""
|
||||
AssemblerListingLocation="$(SolutionDir)/temp/$(ProjectName)/$(ConfigurationName)/"
|
||||
ObjectFile="$(SolutionDir)/temp/$(ProjectName)/$(ConfigurationName)/"
|
||||
ProgramDataBaseFileName="$(SolutionDir)/temp/$(ProjectName)/$(ConfigurationName)/"
|
||||
BrowseInformation="1"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib libeay32MT.lib WS2_32.LIB"
|
||||
OutputFile="$(OutDir)/$(InputName)_debug.exe"
|
||||
LinkIncremental="2"
|
||||
SuppressStartupBanner="TRUE"
|
||||
AdditionalLibraryDirectories=""
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(SolutionDir)/temp/$(ProjectName)/StuffExtract.pdb"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TypeLibraryName=".\Debug/StuffExtract.tlb"
|
||||
HeaderFileName=""/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
Culture="0"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
|
||||
<File
|
||||
RelativePath=".\stuffextract\DBCFieldData.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\dbcfile.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\dbcfile.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\MPQFile.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\MPQFile.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\MPQHelper.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\MPQHelper.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StuffExtract.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StuffExtract.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="StormLib"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SCommon.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SCommon.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SCompression.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SFileCompactArchive.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SFileCreateArchiveEx.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SFileExtractFile.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SFileFindFile.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SFileOpenArchive.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SFileOpenFileEx.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SFileReadFile.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\SListFile.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\StormLib.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\StormPort.h">
|
||||
</File>
|
||||
<Filter
|
||||
Name="wave"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\wave\wave.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\wave\wave.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="bzip2"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\blocksort.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\bzlib.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\bzlib.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\bzlib_private.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\compress.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\crctable.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\decompress.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\huffman.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\bzip2\randtable.c">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="pklib"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\pklib\crc32_pk.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\pklib\explode.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\pklib\implode.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\pklib\pklib.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="huffman"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\huffman\huff.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stuffextract\StormLib\huffman\huff.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
191
src/tools/stuffextract/DBCFieldData.h
Normal file
191
src/tools/stuffextract/DBCFieldData.h
Normal file
@ -0,0 +1,191 @@
|
||||
#ifndef DBCFIELDDATA_H
|
||||
#define DBCFIELDDATA_H
|
||||
|
||||
// NOTE: fields checked for 1.12.2 deDE
|
||||
|
||||
// defines fields numbers in EmotesText.dbc
|
||||
// unk fields are always 0, EMOTESTEXT_EMOTE_STRING is string and the rest is uint32.
|
||||
enum EmotesTextEnum
|
||||
{
|
||||
EMOTESTEXT_EMOTE_ID = 0,
|
||||
EMOTESTEXT_EMOTE_STRING,
|
||||
EMOTESTEXT_ANIM,
|
||||
EMOTESTEXT_SOMEONE_TO_SOMEONE,
|
||||
EMOTESTEXT_SOMEONE_TO_ME,
|
||||
EMOTESTEXT_ME_TO_SOMEONE,
|
||||
EMOTESTEXT_UNK_1,
|
||||
EMOTESTEXT_SOMEONE_TO_NONE,
|
||||
EMOTESTEXT_UNK_2,
|
||||
EMOTESTEXT_ME_TO_NONE,
|
||||
EMOTESTEXT_UNK_3,
|
||||
EMOTESTEXT_SOMEONE_TO_SOMEONE_FEMALE,
|
||||
EMOTESTEXT_SOMEONE_TO_ME_FEMALE,
|
||||
EMOTESTEXT_UNK_4, // me to someone (female)? dbc is empty.
|
||||
EMOTESTEXT_UNK_5,
|
||||
EMOTESTEXT_SOMEONE_TO_NONE_FEMALE,
|
||||
EMOTESTEXT_UNK_6,
|
||||
EMOTESTEXT_UNK_7, // me to none (female)? dbc is empty.
|
||||
EMOTESTEXT_UNK_8,
|
||||
EMOTESTEXT_END
|
||||
};
|
||||
|
||||
static const char *EmotesTextFieldNames[] =
|
||||
{
|
||||
"", // EMOTESTEXT_EMOTE_ID
|
||||
"", // EMOTESTEXT_EMOTE_STRING
|
||||
"", // EMOTESTEXT_ANIM
|
||||
"OneToOne", // EMOTESTEXT_SOMEONE_TO_SOMEONE
|
||||
"OneToMe", // EMOTESTEXT_SOMEONE_TO_ME
|
||||
"MeToOne", // EMOTESTEXT_ME_TO_SOMEONE
|
||||
"", // EMOTESTEXT_UNK_1
|
||||
"OneGeneral", // EMOTESTEXT_SOMEONE_TO_NONE
|
||||
"", // EMOTESTEXT_UNK_2
|
||||
"MeGeneral", // EMOTESTEXT_ME_TO_NONE
|
||||
"", // EMOTESTEXT_UNK_3
|
||||
"OneToOneFemale", // EMOTESTEXT_SOMEONE_TO_SOMEONE_FEMALE
|
||||
"OneToMeFemale", // EMOTESTEXT_SOMEONE_TO_ME_FEMALE
|
||||
"", // EMOTESTEXT_UNK_4
|
||||
"", // EMOTESTEXT_UNK_5
|
||||
"OneGeneralFemale", // EMOTESTEXT_SOMEONE_TO_NONE_FEMALE
|
||||
"", // EMOTESTEXT_UNK_6
|
||||
"", // EMOTESTEXT_UNK_7
|
||||
"", // EMOTESTEXT_UNK_8
|
||||
"" // EMOTESTEXT_END
|
||||
};
|
||||
|
||||
enum EmotesTextDataEnum
|
||||
{
|
||||
EMOTESTEXTDATA_TEXTID = 0,
|
||||
EMOTESTEXTDATA_STRING = 4
|
||||
// rest of the fields is 0 always
|
||||
};
|
||||
|
||||
enum EmotesTextSoundEnum
|
||||
{
|
||||
EMOTESTEXTSOUND_TEXTID = 0,
|
||||
EMOTESTEXTSOUND_EMOTEID,
|
||||
EMOTESTEXTSOUND_RACE,
|
||||
EMOTESTEXTSOUND_ISFEMALE,
|
||||
EMOTESTEXTSOUND_SOUNDID,
|
||||
EMOTESTEXTSOUND_END
|
||||
};
|
||||
|
||||
enum SoundEntriesEnum
|
||||
{
|
||||
SOUNDENTRY_SOUNDID = 0,
|
||||
SOUNDENTRY_UNK_1, // seems to be a flag or something
|
||||
SOUNDENTRY_NAME_STRING,
|
||||
SOUNDENTRY_FILE_1,
|
||||
SOUNDENTRY_FILE_2,
|
||||
SOUNDENTRY_FILE_3,
|
||||
SOUNDENTRY_FILE_4,
|
||||
SOUNDENTRY_FILE_5,
|
||||
SOUNDENTRY_FILE_6,
|
||||
SOUNDENTRY_FILE_7,
|
||||
SOUNDENTRY_FILE_8,
|
||||
SOUNDENTRY_FILE_9,
|
||||
SOUNDENTRY_FILE_10,
|
||||
SOUNDENTRY_BOOL_1, // these fields store either 0 or 1
|
||||
SOUNDENTRY_BOOL_2, // no idea what they are good for..
|
||||
SOUNDENTRY_BOOL_3,
|
||||
SOUNDENTRY_BOOL_4,
|
||||
SOUNDENTRY_BOOL_5,
|
||||
SOUNDENTRY_BOOL_6,
|
||||
SOUNDENTRY_BOOL_7,
|
||||
SOUNDENTRY_BOOL_8,
|
||||
SOUNDENTRY_BOOL_9,
|
||||
SOUNDENTRY_BOOL_10,
|
||||
SOUNDENTRY_PATH, // path where SOUNDENTRY_FILE_x is stored. has no trailing '\'.
|
||||
SOUNDENTRY_UNK_2, // seems to be a float between 0...1 (sound volume?)
|
||||
SOUNDENTRY_UNK_3, // another field storing flags?
|
||||
SOUNDENTRY_UNK_4, // probably float data
|
||||
SOUNDENTRY_UNK_5, // probably float data
|
||||
SOUNDENTRY_UNK_6, // int value, mostly 0 or 2. only 2 cases where this field is 1
|
||||
SOUNDENTRY_END
|
||||
};
|
||||
|
||||
static const char *SoundEntriesFormat = "ixsssssssssssiiiiiiiiiisxxxxx";
|
||||
|
||||
static const char *SoundEntriesFieldNames[] =
|
||||
{
|
||||
"",
|
||||
"",
|
||||
"name",
|
||||
"file1", "file2", "file3", "file4", "file5", "file6", "file7", "file8", "file9", "file10", // 10 file names
|
||||
"","","","","","","","","","", // 10 unk bools
|
||||
"path",
|
||||
"volume", // ok lets just assume its volume (unk2)
|
||||
"", "", "", "", "" // unk3 - unk6
|
||||
};
|
||||
|
||||
enum ChrRacesEnum
|
||||
{
|
||||
CHRRACES_RACEID = 0,
|
||||
CHRRACES_UNK_1,
|
||||
CHRRACES_UNK_2,
|
||||
CHRRACES_UNK_3,
|
||||
CHRRACES_MODELM, // model for male player
|
||||
CHRRACES_MODELF, // model for female player
|
||||
CHRRACES_NAME_SHORT, // 2 chars name abbrev (Hu,Or,Tr, etc)
|
||||
CHRRACES_UNK_4,
|
||||
CHRRACES_FACTION, // 1=Alliance, 7=Horde
|
||||
CHRRACES_UNK_5,
|
||||
CHRRACES_UNK_6,
|
||||
CHRRACES_UNK_7,
|
||||
CHRRACES_UNK_8,
|
||||
CHRRACES_UNK_9,
|
||||
CHRRACES_UNK_10,
|
||||
CHRRACES_NAME_GENERAL, // always the english(?) name (without spaces). used in texture names etc.
|
||||
CHRRACES_UNK_11,
|
||||
CHRRACES_UNK_12,
|
||||
CHRRACES_UNK_13,
|
||||
CHRRACES_UNK_14,
|
||||
CHRRACES_NAME_LOCAL, // localized(?) name (spanish,german or whatever)
|
||||
CHRRACES_UNK_15,
|
||||
CHRRACES_UNK_16,
|
||||
CHRRACES_UNK_17,
|
||||
CHRRACES_UNK_18,
|
||||
CHRRACES_UNK_19,
|
||||
CHRRACES_UNK_20,
|
||||
CHRRACES_TRAITS, // string that defines the face decorations on char create
|
||||
CHRRACES_UNK_21,
|
||||
CHARRACES_END
|
||||
};
|
||||
|
||||
static const char *ChrRacesFormat = "ixxxiisxixxxxxxsxxxxsxxxxxxsx";
|
||||
|
||||
static const char *ChrRacesFieldNames[] =
|
||||
{
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"model_m",
|
||||
"model_f",
|
||||
"name_short",
|
||||
"",
|
||||
"faction",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"name_general",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"name",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"traits",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
#endif
|
||||
36
src/tools/stuffextract/MPQFile.cpp
Normal file
36
src/tools/stuffextract/MPQFile.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "MPQFile.h"
|
||||
|
||||
// MPQ file to be opened
|
||||
MPQFile::MPQFile(const char *fn)
|
||||
{
|
||||
_mpq = NULL;
|
||||
_isopen = SFileOpenArchive(fn,0,0,&_mpq);
|
||||
}
|
||||
|
||||
bool MPQFile::HasFile(char *fn)
|
||||
{
|
||||
return SFileHasFile(_mpq,fn);
|
||||
}
|
||||
|
||||
// get size of a file within an mpq archive
|
||||
ByteBuffer MPQFile::ReadFile(char *fn)
|
||||
{
|
||||
ByteBuffer bb;
|
||||
HANDLE fh;
|
||||
if(!SFileOpenFileEx(_mpq, fn, 0, &fh))
|
||||
return bb;
|
||||
uint32 size = SFileGetFileSize(fh);
|
||||
bb.resize(size);
|
||||
SFileReadFile(fh, (void*)bb.contents(), size, NULL, NULL);
|
||||
return bb;
|
||||
}
|
||||
|
||||
uint32 MPQFile::GetFileSize(char *fn)
|
||||
{
|
||||
HANDLE fh;
|
||||
if(!SFileOpenFileEx(_mpq, fn, 0, &fh))
|
||||
return 0;
|
||||
uint32 size = SFileGetFileSize(fh);
|
||||
SFileCloseFile(fh);
|
||||
return size;
|
||||
}
|
||||
24
src/tools/stuffextract/MPQFile.h
Normal file
24
src/tools/stuffextract/MPQFile.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef MPQFILE_H
|
||||
#define MPQFILE_H
|
||||
|
||||
#define _COMMON_NO_THREADS
|
||||
#include "common.h"
|
||||
#include "StormLib/StormLib.h"
|
||||
#include "StormLib/SCommon.h"
|
||||
|
||||
class MPQFile
|
||||
{
|
||||
public:
|
||||
MPQFile(const char*);
|
||||
inline bool IsOpen(void) { return _isopen; }
|
||||
ByteBuffer ReadFile(char*);
|
||||
uint32 GetFileSize(char*);
|
||||
bool HasFile(char*);
|
||||
|
||||
private:
|
||||
HANDLE _mpq;
|
||||
bool _isopen;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
52
src/tools/stuffextract/MPQHelper.cpp
Normal file
52
src/tools/stuffextract/MPQHelper.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "common.h"
|
||||
#include "MPQHelper.h"
|
||||
#include "MPQFile.h"
|
||||
|
||||
|
||||
MPQHelper::MPQHelper()
|
||||
{
|
||||
}
|
||||
|
||||
bool MPQHelper::AssignArchive(char *fn)
|
||||
{
|
||||
// first, check which patch files are avalible.
|
||||
// store patches in reversed order, that patch-9.mpq is checked first, and patch.mpq checked last
|
||||
if(FileExists("Data/patch.MPQ"))
|
||||
_patches.push_front("Data/patch.MPQ");
|
||||
for(uint32 i=1; i<MAX_PATCH_NUMBER; i++)
|
||||
{
|
||||
char buf[20];
|
||||
sprintf(buf,"patch-%u.MPQ",i);
|
||||
if(FileExists(buf))
|
||||
_patches.push_front(buf);
|
||||
}
|
||||
// then assign the original archive name
|
||||
_archive = fn;
|
||||
return FileExists(fn);
|
||||
}
|
||||
|
||||
ByteBuffer MPQHelper::ExtractFile(char* fn)
|
||||
{
|
||||
ByteBuffer bb;
|
||||
for(std::list<std::string>::iterator i = _patches.begin(); i != _patches.end(); i++)
|
||||
{
|
||||
MPQFile mpq((*i).c_str());
|
||||
if(mpq.IsOpen() && mpq.HasFile(fn))
|
||||
{
|
||||
printf("MPQE: Using %s from %s\n",fn,i->c_str());
|
||||
bb = mpq.ReadFile(fn);
|
||||
return bb;
|
||||
}
|
||||
}
|
||||
MPQFile arch(_archive.c_str());
|
||||
if(arch.IsOpen() && arch.HasFile(fn))
|
||||
{
|
||||
printf("MPQE: Using %s from %s\n",fn,_archive.c_str());
|
||||
bb = arch.ReadFile(fn);
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
17
src/tools/stuffextract/MPQHelper.h
Normal file
17
src/tools/stuffextract/MPQHelper.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef MPQHELPER_H
|
||||
#define MPQHELPER_H
|
||||
|
||||
#define MAX_PATCH_NUMBER 9
|
||||
|
||||
class MPQHelper
|
||||
{
|
||||
public:
|
||||
MPQHelper();
|
||||
bool AssignArchive(char*);
|
||||
ByteBuffer ExtractFile(char*);
|
||||
private:
|
||||
std::list<std::string> _patches; // patch.mpq - patch-9.mpq
|
||||
std::string _archive;
|
||||
};
|
||||
|
||||
#endif
|
||||
1074
src/tools/stuffextract/StormLib/SCommon.cpp
Normal file
1074
src/tools/stuffextract/StormLib/SCommon.cpp
Normal file
File diff suppressed because it is too large
Load Diff
88
src/tools/stuffextract/StormLib/SCommon.h
Normal file
88
src/tools/stuffextract/StormLib/SCommon.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*****************************************************************************/
|
||||
/* SCommon.h Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Common functions for encryption/decryption from Storm.dll. Included by */
|
||||
/* SFile*** functions, do not include and do not use this file directly */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 24.03.03 1.00 Lad The first version of SFileCommon.h */
|
||||
/* 12.06.04 1.00 Lad Renamed to SCommon.h */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __SCOMMON_H__
|
||||
#define __SCOMMON_H__
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// StormLib private defines
|
||||
|
||||
#define SFILE_TYPE_DATA 0 // Process the file as data file
|
||||
#define SFILE_TYPE_WAVE 1 // Process the file as WAVe file
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// External variables
|
||||
|
||||
extern TMPQArchive * pFirstOpen;
|
||||
extern LCID lcLocale;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Encryption and decryption functions
|
||||
|
||||
int PrepareStormBuffer();
|
||||
|
||||
void EncryptHashTable(DWORD * pdwTable, BYTE * pbKey, DWORD dwLength);
|
||||
void DecryptHashTable(DWORD * pdwTable, BYTE * pbKey, DWORD dwLength);
|
||||
TMPQHash * FindFreeHashEntry(TMPQArchive * ha, const char * szFileName);
|
||||
|
||||
void EncryptBlockTable(DWORD * pdwTable, BYTE * pbKey, DWORD dwLength);
|
||||
void DecryptBlockTable(DWORD * pdwTable, BYTE * pbKey, DWORD dwLength);
|
||||
|
||||
DWORD DetectFileSeed(DWORD * block, DWORD decrypted);
|
||||
DWORD DetectFileSeed2(DWORD * block, UINT nDwords, ...);
|
||||
void EncryptMPQBlock(DWORD * pdwBlock, DWORD dwLength, DWORD dwSeed1);
|
||||
void DecryptMPQBlock(DWORD * pdwBlock, DWORD dwLength, DWORD dwSeed1);
|
||||
|
||||
DWORD DecryptHashIndex(TMPQArchive * ha, const char * szFileName);
|
||||
DWORD DecryptName1 (const char * szFileName);
|
||||
DWORD DecryptName2 (const char * szFileName);
|
||||
DWORD DecryptFileSeed (const char * szFileName);
|
||||
|
||||
TMPQHash * GetHashEntry (TMPQArchive * ha, const char * szFileName);
|
||||
TMPQHash * GetHashEntryEx(TMPQArchive * ha, const char * szFileName, LCID lcLocale);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compression and decompression functions
|
||||
|
||||
int Compress_pklib (char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int * pCmpType, int nCmpLevel);
|
||||
int Decompress_pklib(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Checking functions
|
||||
|
||||
BOOL IsValidMpqHandle(TMPQArchive * ha);
|
||||
BOOL IsValidFileHandle(TMPQFile * hf);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Other functions
|
||||
|
||||
BOOL SFileOpenArchiveEx(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMPQ, DWORD dwAccessMode = GENERIC_READ);
|
||||
int AddFileToArchive(TMPQArchive * ha, HANDLE hFile, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality, int nFileType, BOOL * pbReplaced);
|
||||
int SetDataCompression(int nDataCompression);
|
||||
int SaveMPQTables(TMPQArchive * ha);
|
||||
void FreeMPQArchive(TMPQArchive *& ha);
|
||||
|
||||
BOOL CheckWildCard(const char * szString, const char * szWildCard);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Listfile functions
|
||||
|
||||
int SListFileCreateListFile(TMPQArchive * ha);
|
||||
int SListFileAddNode(TMPQArchive * ha, const char * szAddedFile);
|
||||
int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName);
|
||||
int SListFileRenameNode(TMPQArchive * ha, const char * szOldFileName, const char * szNewFileName);
|
||||
int SListFileFreeListFile(TMPQArchive * ha);
|
||||
|
||||
int SListFileSaveToMpq(TMPQArchive * ha);
|
||||
|
||||
#endif // __SCOMMON_H__
|
||||
|
||||
715
src/tools/stuffextract/StormLib/SCompression.cpp
Normal file
715
src/tools/stuffextract/StormLib/SCompression.cpp
Normal file
@ -0,0 +1,715 @@
|
||||
/*****************************************************************************/
|
||||
/* SCompression.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* This module serves as a bridge between StormLib code and (de)compression */
|
||||
/* functions. All (de)compression calls go (and should only go) through this */
|
||||
/* module. No system headers should be included in this module to prevent */
|
||||
/* compile-time problems. */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 01.04.03 1.00 Lad The first version of SCompression.cpp */
|
||||
/* 19.11.03 1.01 Dan Big endian handling */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// Include functions from Pkware Data Compression Library
|
||||
#include "pklib/pklib.h"
|
||||
|
||||
// Include functions from zlib
|
||||
#ifndef __SYS_ZLIB
|
||||
#include "zlib/zlib.h" // Include functions from zlib
|
||||
#else
|
||||
#include <zlib.h> // If zlib is available on system, use this instead
|
||||
#endif
|
||||
|
||||
// Include functions from Huffmann compression
|
||||
#include "huffman/huff.h"
|
||||
|
||||
// Include functions from WAVe compression
|
||||
#include "wave/wave.h"
|
||||
|
||||
// Include functions from BZip2 compression library
|
||||
#ifndef __SYS_BZLIB
|
||||
#include "bzip2/bzlib.h" // Include functions from bzlib
|
||||
#else
|
||||
#include <bzlib.h> // If bzlib is available on system, use this instead
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local structures
|
||||
|
||||
// Information about the input and output buffers for pklib
|
||||
typedef struct
|
||||
{
|
||||
char * pInBuff; // Pointer to input data buffer
|
||||
int nInPos; // Current offset in input data buffer
|
||||
int nInBytes; // Number of bytes in the input buffer
|
||||
char * pOutBuff; // Pointer to output data buffer
|
||||
int nOutPos; // Position in the output buffer
|
||||
int nMaxOut; // Maximum number of bytes in the output buffer
|
||||
} TDataInfo;
|
||||
|
||||
// Table of compression functions
|
||||
typedef int (*COMPRESS)(char *, int *, char *, int, int *, int);
|
||||
typedef struct
|
||||
{
|
||||
unsigned long dwMask; // Compression mask
|
||||
COMPRESS Compress; // Compression function
|
||||
} TCompressTable;
|
||||
|
||||
// Table of decompression functions
|
||||
typedef int (*DECOMPRESS)(char *, int *, char *, int);
|
||||
typedef struct
|
||||
{
|
||||
unsigned long dwMask; // Decompression bit
|
||||
DECOMPRESS Decompress; // Decompression function
|
||||
} TDecompressTable;
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Support functions for Pkware Data Compression Library */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Function loads data from the input buffer. Used by Pklib's "implode"
|
||||
// and "explode" function as user-defined callback
|
||||
// Returns number of bytes loaded
|
||||
//
|
||||
// char * buf - Pointer to a buffer where to store loaded data
|
||||
// unsigned int * size - Max. number of bytes to read
|
||||
// void * param - Custom pointer, parameter of implode/explode
|
||||
|
||||
static unsigned int ReadInputData(char * buf, unsigned int * size, void * param)
|
||||
{
|
||||
TDataInfo * pInfo = (TDataInfo *)param;
|
||||
unsigned int nMaxAvail = (pInfo->nInBytes - pInfo->nInPos);
|
||||
unsigned int nToRead = *size;
|
||||
|
||||
// Check the case when not enough data available
|
||||
if(nToRead > nMaxAvail)
|
||||
nToRead = nMaxAvail;
|
||||
|
||||
// Load data and increment offsets
|
||||
memcpy(buf, pInfo->pInBuff + pInfo->nInPos, nToRead);
|
||||
pInfo->nInPos += nToRead;
|
||||
|
||||
return nToRead;
|
||||
}
|
||||
|
||||
// Function for store output data. Used by Pklib's "implode" and "explode"
|
||||
// as user-defined callback
|
||||
//
|
||||
// char * buf - Pointer to data to be written
|
||||
// unsigned int * size - Number of bytes to write
|
||||
// void * param - Custom pointer, parameter of implode/explode
|
||||
|
||||
static void WriteOutputData(char * buf, unsigned int * size, void * param)
|
||||
{
|
||||
TDataInfo * pInfo = (TDataInfo *)param;
|
||||
unsigned int nMaxWrite = (pInfo->nMaxOut - pInfo->nOutPos);
|
||||
unsigned int nToWrite = *size;
|
||||
|
||||
// Check the case when not enough space in the output buffer
|
||||
if(nToWrite > nMaxWrite)
|
||||
nToWrite = nMaxWrite;
|
||||
|
||||
// Write output data and increments offsets
|
||||
memcpy(pInfo->pOutBuff + pInfo->nOutPos, buf, nToWrite);
|
||||
pInfo->nOutPos += nToWrite;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* "80" is IMA ADPCM stereo (de)compression */
|
||||
/* "40" is IMA ADPCM mono (de)compression */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
int Compress_wave_mono(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int * pCmpType, int nCmpLevel)
|
||||
{
|
||||
// Prepare the compression level for the next compression
|
||||
// (After us, the Huffmann compression will be called)
|
||||
if(0 < nCmpLevel && nCmpLevel <= 2)
|
||||
{
|
||||
nCmpLevel = 4;
|
||||
*pCmpType = 6;
|
||||
}
|
||||
else if(nCmpLevel == 3)
|
||||
{
|
||||
nCmpLevel = 6;
|
||||
*pCmpType = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCmpLevel = 5;
|
||||
*pCmpType = 7;
|
||||
}
|
||||
*pdwOutLength = CompressWave((unsigned char *)pbOutBuffer, *pdwOutLength, (short *)pbInBuffer, dwInLength, 1, nCmpLevel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Decompress_wave_mono(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
|
||||
{
|
||||
*pdwOutLength = DecompressWave((unsigned char *)pbOutBuffer, *pdwOutLength, (unsigned char *)pbInBuffer, dwInLength, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Compress_wave_stereo(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int * pCmpType, int nCmpLevel)
|
||||
{
|
||||
// Prepare the compression type for the next compression
|
||||
// (After us, the Huffmann compression will be called)
|
||||
if(0 < nCmpLevel && nCmpLevel <= 2)
|
||||
{
|
||||
nCmpLevel = 4;
|
||||
*pCmpType = 6;
|
||||
}
|
||||
else if(nCmpLevel == 3)
|
||||
{
|
||||
nCmpLevel = 6;
|
||||
*pCmpType = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCmpLevel = 5;
|
||||
*pCmpType = 7;
|
||||
}
|
||||
*pdwOutLength = CompressWave((unsigned char *)pbOutBuffer, *pdwOutLength, (short *)pbInBuffer, dwInLength, 2, nCmpLevel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Decompress_wave_stereo(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
|
||||
{
|
||||
*pdwOutLength = DecompressWave((unsigned char *)pbOutBuffer, *pdwOutLength, (unsigned char *)pbInBuffer, dwInLength, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* The "01" (de)compression is the Huffman (de)compression */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
// 1500F4C0
|
||||
int Compress_huff(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int * pCmpType, int /* nCmpLevel */)
|
||||
{
|
||||
THuffmannTree ht; // Huffmann tree for compression
|
||||
TOutputStream os; // Output stream
|
||||
|
||||
// Initialize output stream
|
||||
os.pbOutBuffer = (unsigned char *)pbOutBuffer;
|
||||
os.dwOutSize = *pdwOutLength;
|
||||
os.pbOutPos = (unsigned char *)pbOutBuffer;
|
||||
os.dwBitBuff = 0;
|
||||
os.nBits = 0;
|
||||
|
||||
// Initialize the Huffmann tree for compression
|
||||
ht.InitTree(true);
|
||||
|
||||
*pdwOutLength = ht.DoCompression(&os, (unsigned char *)pbInBuffer, dwInLength, *pCmpType);
|
||||
|
||||
// The following code is not necessary to run, because it has no
|
||||
// effect on the output data. It only clears the huffmann tree, but when
|
||||
// the tree is on the stack, who cares ?
|
||||
// ht.UninitTree();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 1500F5F0
|
||||
int Decompress_huff(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int /* dwInLength */)
|
||||
{
|
||||
THuffmannTree ht;
|
||||
TInputStream is;
|
||||
|
||||
// Initialize input stream
|
||||
// is.pbInBuffer = (unsigned char *)pbInBuffer;
|
||||
is.dwBitBuff = BSWAP_INT32_UNSIGNED(*(unsigned long *)pbInBuffer);
|
||||
pbInBuffer += sizeof(unsigned long);
|
||||
is.pbInBuffer = (unsigned char *)pbInBuffer;
|
||||
is.nBits = 32;
|
||||
|
||||
// Initialize the Huffmann tree for compression
|
||||
ht.InitTree(false);
|
||||
*pdwOutLength = ht.DoDecompression((unsigned char *)pbOutBuffer, *pdwOutLength, &is);
|
||||
|
||||
// The following code is not necessary to run, because it has no
|
||||
// effect on the output data. It only clears the huffmann tree, but when
|
||||
// the tree is on the stack, who cares ?
|
||||
// ht.UninitTree();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* The "02" (de)compression is the ZLIB (de)compression */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
int Compress_zlib(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int * /* pCmpType */, int /* nCmpLevel */)
|
||||
{
|
||||
z_stream z; // Stream information for zlib
|
||||
int nResult;
|
||||
|
||||
// Fill the stream structure for zlib
|
||||
z.next_in = (Bytef *)pbInBuffer;
|
||||
z.avail_in = (uInt)dwInLength;
|
||||
z.total_in = dwInLength;
|
||||
z.next_out = (Bytef *)pbOutBuffer;
|
||||
z.avail_out = *pdwOutLength;
|
||||
z.total_out = 0;
|
||||
z.zalloc = NULL;
|
||||
z.zfree = NULL;
|
||||
|
||||
// Initialize the compression structure. Storm.dll uses zlib version 1.1.3
|
||||
*pdwOutLength = 0;
|
||||
if((nResult = deflateInit(&z, Z_DEFAULT_COMPRESSION)) == 0)
|
||||
{
|
||||
// Call zlib to compress the data
|
||||
nResult = deflate(&z, Z_FINISH);
|
||||
|
||||
if(nResult == Z_OK || nResult == Z_STREAM_END)
|
||||
*pdwOutLength = z.total_out;
|
||||
|
||||
deflateEnd(&z);
|
||||
}
|
||||
return nResult;
|
||||
}
|
||||
|
||||
int Decompress_zlib(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
|
||||
{
|
||||
z_stream z; // Stream information for zlib
|
||||
int nResult;
|
||||
|
||||
// Fill the stream structure for zlib
|
||||
z.next_in = (Bytef *)pbInBuffer;
|
||||
z.avail_in = (uInt)dwInLength;
|
||||
z.total_in = dwInLength;
|
||||
z.next_out = (Bytef *)pbOutBuffer;
|
||||
z.avail_out = *pdwOutLength;
|
||||
z.total_out = 0;
|
||||
z.zalloc = NULL;
|
||||
z.zfree = NULL;
|
||||
|
||||
// Initialize the decompression structure. Storm.dll uses zlib version 1.1.3
|
||||
if((nResult = inflateInit(&z)) == 0)
|
||||
{
|
||||
// Call zlib to decompress the data
|
||||
nResult = inflate(&z, Z_FINISH);
|
||||
*pdwOutLength = z.total_out;
|
||||
inflateEnd(&z);
|
||||
}
|
||||
return nResult;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* The "08" (de)compression is the Pkware DCL (de)compression */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
int Compress_pklib(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int * pCmpType, int /* nCmpLevel */)
|
||||
{
|
||||
TDataInfo Info; // Data information
|
||||
char * work_buf = ALLOCMEM(char, CMP_BUFFER_SIZE);// Pklib's work buffer
|
||||
unsigned int dict_size; // Dictionary size
|
||||
unsigned int ctype; // Compression type
|
||||
|
||||
// Fill data information structure
|
||||
Info.pInBuff = pbInBuffer;
|
||||
Info.nInPos = 0;
|
||||
Info.nInBytes = dwInLength;
|
||||
Info.pOutBuff = pbOutBuffer;
|
||||
Info.nOutPos = 0;
|
||||
Info.nMaxOut = *pdwOutLength;
|
||||
|
||||
// Set the compression type and dictionary size
|
||||
ctype = (*pCmpType == 2) ? CMP_ASCII : CMP_BINARY;
|
||||
if (dwInLength < 0x600)
|
||||
dict_size = 0x400;
|
||||
else if(0x600 <= dwInLength && dwInLength < 0xC00)
|
||||
dict_size = 0x800;
|
||||
else
|
||||
dict_size = 0x1000;
|
||||
|
||||
// Do the compression
|
||||
implode(ReadInputData, WriteOutputData, work_buf, &Info, &ctype, &dict_size);
|
||||
*pdwOutLength = Info.nOutPos;
|
||||
FREEMEM(work_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Decompress_pklib(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
|
||||
{
|
||||
TDataInfo Info; // Data information
|
||||
char * work_buf = ALLOCMEM(char, EXP_BUFFER_SIZE);// Pklib's work buffer
|
||||
|
||||
// Fill data information structure
|
||||
Info.pInBuff = pbInBuffer;
|
||||
Info.nInPos = 0;
|
||||
Info.nInBytes = dwInLength;
|
||||
Info.pOutBuff = pbOutBuffer;
|
||||
Info.nOutPos = 0;
|
||||
Info.nMaxOut = *pdwOutLength;
|
||||
|
||||
// Do the decompression
|
||||
explode(ReadInputData, WriteOutputData, work_buf, &Info);
|
||||
|
||||
// Fix: If PKLIB is unable to decompress the data, they are uncompressed
|
||||
if(Info.nOutPos == 0)
|
||||
{
|
||||
Info.nOutPos = min(*pdwOutLength, dwInLength);
|
||||
memcpy(pbOutBuffer, pbInBuffer, Info.nOutPos);
|
||||
}
|
||||
|
||||
*pdwOutLength = Info.nOutPos;
|
||||
FREEMEM(work_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* The "10" (de)compression is the Bzip2 (de)compression */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
int Compress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int * pCmpType, int nCmpLevel)
|
||||
{
|
||||
bz_stream strm;
|
||||
int blockSize100k;
|
||||
int workFactor = 30;
|
||||
|
||||
// Keep compiler happy
|
||||
nCmpLevel = nCmpLevel;
|
||||
|
||||
// Initialize the BZLIB compression
|
||||
strm.bzalloc = NULL;
|
||||
strm.bzfree = NULL;
|
||||
|
||||
// Adjust the block size
|
||||
blockSize100k = *pCmpType;
|
||||
if(blockSize100k < 1 || blockSize100k > 9)
|
||||
blockSize100k = 9;
|
||||
|
||||
// Blizzard uses 9 as blockSize100k, (0 as workFactor)
|
||||
if(BZ2_bzCompressInit(&strm, blockSize100k, 0, workFactor) == 0)
|
||||
{
|
||||
strm.next_in = pbInBuffer;
|
||||
strm.avail_in = dwInLength;
|
||||
strm.next_out = pbOutBuffer;
|
||||
strm.avail_out = *pdwOutLength;
|
||||
|
||||
// Perform the compression
|
||||
while(BZ2_bzCompress(&strm, (strm.avail_in != 0) ? BZ_RUN : BZ_FINISH) != BZ_STREAM_END);
|
||||
|
||||
// Put the stream into idle state
|
||||
BZ2_bzCompressEnd(&strm);
|
||||
*pdwOutLength = strm.total_out_lo32;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pdwOutLength = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Decompress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
|
||||
{
|
||||
bz_stream strm;
|
||||
|
||||
// Initialize the BZLIB decompression
|
||||
strm.bzalloc = NULL;
|
||||
strm.bzfree = NULL;
|
||||
if(BZ2_bzDecompressInit(&strm, 0, 0) == 0)
|
||||
{
|
||||
strm.next_in = pbInBuffer;
|
||||
strm.avail_in = dwInLength;
|
||||
strm.next_out = pbOutBuffer;
|
||||
strm.avail_out = *pdwOutLength;
|
||||
|
||||
// Perform the decompression
|
||||
while(BZ2_bzDecompress(&strm) != BZ_STREAM_END);
|
||||
|
||||
// Put the stream into idle state
|
||||
BZ2_bzDecompressEnd(&strm);
|
||||
*pdwOutLength = strm.total_out_lo32;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set zero output length
|
||||
*pdwOutLength = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* SCompCompress */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
// This table contains compress functions which can be applied to
|
||||
// uncompressed blocks. Each bit set means the corresponding
|
||||
// compression method/function must be applied.
|
||||
//
|
||||
// WAVes compression Data compression
|
||||
// ------------------ -------------------
|
||||
// 1st block - 0x08 0x08 (D, HF, W2, SC, D2)
|
||||
// Rest blocks - 0x81 0x02 (W3)
|
||||
|
||||
static TCompressTable cmp_table[] =
|
||||
{
|
||||
{MPQ_COMPRESSION_WAVE_MONO, Compress_wave_mono}, // IMA ADPCM mono compression
|
||||
{MPQ_COMPRESSION_WAVE_STEREO, Compress_wave_stereo}, // IMA ADPCM stereo compression
|
||||
{MPQ_COMPRESSION_HUFFMANN, Compress_huff}, // Huffmann compression
|
||||
{MPQ_COMPRESSION_ZLIB, Compress_zlib}, // Compression with the "zlib" library
|
||||
{MPQ_COMPRESSION_PKWARE, Compress_pklib}, // Compression with Pkware DCL
|
||||
{MPQ_COMPRESSION_BZIP2, Compress_bzip2} // Compression Bzip2 library
|
||||
};
|
||||
|
||||
int WINAPI SCompCompress(char * pbCompressed, int * pdwOutLength, char * pbUncompressed, int dwInLength,
|
||||
int uCompressions, int nCmpType, int nCmpLevel)
|
||||
{
|
||||
char * pbTempBuff = NULL; // Temporary storage for decompressed data
|
||||
char * pbOutput = pbCompressed; // Current output buffer
|
||||
char * pbInput; // Current input buffer
|
||||
int uCompressions2;
|
||||
int dwCompressCount = 0;
|
||||
int dwDoneCount = 0;
|
||||
int dwOutSize = 0;
|
||||
int dwInSize = dwInLength;
|
||||
int dwEntries = (sizeof(cmp_table) / sizeof(TCompressTable));
|
||||
int nResult = 1;
|
||||
int i;
|
||||
|
||||
// Check for valid parameters
|
||||
if(!pdwOutLength || *pdwOutLength < dwInLength || !pbCompressed || !pbUncompressed)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Count the compressions
|
||||
for(i = 0, uCompressions2 = uCompressions; i < dwEntries; i++)
|
||||
{
|
||||
if(uCompressions & cmp_table[i].dwMask)
|
||||
dwCompressCount++;
|
||||
|
||||
uCompressions2 &= ~cmp_table[i].dwMask;
|
||||
}
|
||||
|
||||
// If a compression remains, do nothing
|
||||
if(uCompressions2 != 0)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If more that one compression, allocate intermediate buffer
|
||||
if(dwCompressCount >= 2)
|
||||
pbTempBuff = ALLOCMEM(char, *pdwOutLength + 1);
|
||||
|
||||
// Perform the compressions
|
||||
pbInput = pbUncompressed;
|
||||
dwInSize = dwInLength;
|
||||
for(i = 0, uCompressions2 = uCompressions; i < dwEntries; i++)
|
||||
{
|
||||
if(uCompressions2 & cmp_table[i].dwMask)
|
||||
{
|
||||
// Set the right output buffer
|
||||
dwCompressCount--;
|
||||
pbOutput = (dwCompressCount & 1) ? pbTempBuff : pbCompressed;
|
||||
|
||||
// Perform the partial compression
|
||||
dwOutSize = *pdwOutLength - 1;
|
||||
|
||||
cmp_table[i].Compress(pbOutput + 1, &dwOutSize, pbInput, dwInSize, &nCmpType, nCmpLevel);
|
||||
if(dwOutSize == 0)
|
||||
{
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
*pdwOutLength = 0;
|
||||
nResult = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the compression failed, copy the block instead
|
||||
if(dwOutSize >= dwInSize - 1)
|
||||
{
|
||||
if(dwDoneCount > 0)
|
||||
pbOutput++;
|
||||
|
||||
memcpy(pbOutput, pbInput, dwInSize);
|
||||
pbInput = pbOutput;
|
||||
uCompressions &= ~cmp_table[i].dwMask;
|
||||
dwOutSize = dwInSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
pbInput = pbOutput + 1;
|
||||
dwInSize = dwOutSize;
|
||||
dwDoneCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the compressed data to the correct output buffer
|
||||
if(nResult != 0)
|
||||
{
|
||||
if(uCompressions && (dwInSize + 1) < *pdwOutLength)
|
||||
{
|
||||
if(pbOutput != pbCompressed && pbOutput != pbCompressed + 1)
|
||||
memcpy(pbCompressed, pbOutput, dwInSize);
|
||||
*pbCompressed = (char)uCompressions;
|
||||
*pdwOutLength = dwInSize + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(pbCompressed, pbUncompressed, dwInSize);
|
||||
*pdwOutLength = dwInSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup and return
|
||||
if(pbTempBuff != NULL)
|
||||
FREEMEM(pbTempBuff);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* SCompDecompress */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
// This table contains decompress functions which can be applied to
|
||||
// uncompressed blocks. The compression mask is stored in the first byte
|
||||
// of compressed block
|
||||
static TDecompressTable dcmp_table[] =
|
||||
{
|
||||
{MPQ_COMPRESSION_BZIP2, Decompress_bzip2}, // Decompression with Bzip2 library
|
||||
{MPQ_COMPRESSION_PKWARE, Decompress_pklib}, // Decompression with Pkware Data Compression Library
|
||||
{MPQ_COMPRESSION_ZLIB, Decompress_zlib}, // Decompression with the "zlib" library
|
||||
{MPQ_COMPRESSION_HUFFMANN, Decompress_huff}, // Huffmann decompression
|
||||
{MPQ_COMPRESSION_WAVE_STEREO, Decompress_wave_stereo}, // IMA ADPCM stereo decompression
|
||||
{MPQ_COMPRESSION_WAVE_MONO, Decompress_wave_mono} // IMA ADPCM mono decompression
|
||||
};
|
||||
|
||||
int WINAPI SCompDecompress(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
|
||||
{
|
||||
char * pbTempBuff = NULL; // Temporary storage for decompressed data
|
||||
char * pbWorkBuff = NULL; // Where to store decompressed data
|
||||
int dwOutLength = *pdwOutLength; // For storage number of output bytes
|
||||
unsigned fDecompressions1; // Decompressions applied to the block
|
||||
unsigned fDecompressions2; // Just another copy of decompressions applied to the block
|
||||
int dwCount = 0; // Counter for every use
|
||||
int dwEntries = (sizeof(dcmp_table) / sizeof(TDecompressTable));
|
||||
int nResult = 1;
|
||||
int i;
|
||||
|
||||
// If the input length is the same as output, do nothing.
|
||||
if(dwInLength == dwOutLength)
|
||||
{
|
||||
if(pbInBuffer == pbOutBuffer)
|
||||
return 1;
|
||||
|
||||
memcpy(pbOutBuffer, pbInBuffer, dwInLength);
|
||||
*pdwOutLength = dwInLength;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get applied compression types and decrement data length
|
||||
fDecompressions1 = fDecompressions2 = (unsigned char)*pbInBuffer++;
|
||||
dwInLength--;
|
||||
|
||||
// Search decompression table type and get all types of compression
|
||||
for(i = 0; i < dwEntries; i++)
|
||||
{
|
||||
// We have to apply this decompression ?
|
||||
if(fDecompressions1 & dcmp_table[i].dwMask)
|
||||
dwCount++;
|
||||
|
||||
// Clear this flag from temporary variable.
|
||||
fDecompressions2 &= ~dcmp_table[i].dwMask;
|
||||
}
|
||||
|
||||
// Check if there is some method unhandled
|
||||
// (E.g. compressed by future versions)
|
||||
if(fDecompressions2 != 0)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If there is more than only one compression, we have to allocate extra buffer
|
||||
if(dwCount >= 2)
|
||||
pbTempBuff = ALLOCMEM(char, dwOutLength);
|
||||
|
||||
// Apply all decompressions
|
||||
for(i = 0, dwCount = 0; i < dwEntries; i++)
|
||||
{
|
||||
// If not used this kind of compression, skip the loop
|
||||
if(fDecompressions1 & dcmp_table[i].dwMask)
|
||||
{
|
||||
// If odd case, use target buffer for output, otherwise use allocated tempbuffer
|
||||
pbWorkBuff = (dwCount++ & 1) ? pbTempBuff : pbOutBuffer;
|
||||
dwOutLength = *pdwOutLength;
|
||||
|
||||
// Decompress buffer using corresponding function
|
||||
dcmp_table[i].Decompress(pbWorkBuff, &dwOutLength, pbInBuffer, dwInLength);
|
||||
if(dwOutLength == 0)
|
||||
{
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
nResult = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Move output length to src length for next compression
|
||||
dwInLength = dwOutLength;
|
||||
pbInBuffer = pbWorkBuff;
|
||||
}
|
||||
}
|
||||
|
||||
// If output buffer is not the same like target buffer, we have to copy data
|
||||
if(nResult != 0)
|
||||
{
|
||||
if(pbWorkBuff != pbOutBuffer)
|
||||
memcpy(pbOutBuffer, pbInBuffer, dwOutLength);
|
||||
|
||||
}
|
||||
|
||||
// Delete temporary buffer, if necessary
|
||||
if(pbTempBuff != NULL)
|
||||
FREEMEM(pbTempBuff);
|
||||
|
||||
*pdwOutLength = dwOutLength;
|
||||
return nResult;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* SCompSetDataCompression */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
int WINAPI SCompSetDataCompression(int nDataCompression)
|
||||
{
|
||||
int nValidMask = (MPQ_COMPRESSION_ZLIB | MPQ_COMPRESSION_PKWARE | MPQ_COMPRESSION_BZIP2);
|
||||
|
||||
if((nDataCompression & nValidMask) != nDataCompression)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SetDataCompression(nDataCompression);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
691
src/tools/stuffextract/StormLib/SFileCompactArchive.cpp
Normal file
691
src/tools/stuffextract/StormLib/SFileCompactArchive.cpp
Normal file
@ -0,0 +1,691 @@
|
||||
/*****************************************************************************/
|
||||
/* SFileCompactArchive.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Archive compacting function */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 14.04.03 1.00 Lad Splitted from SFileCreateArchiveEx.cpp */
|
||||
/* 19.11.03 1.01 Dan Big endian handling */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Local structures */
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Local variables */
|
||||
/*****************************************************************************/
|
||||
|
||||
static COMPACTCB CompactCB = NULL;
|
||||
static void * lpUserData = NULL;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Local functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Creates a copy of hash table
|
||||
static TMPQHash * CopyHashTable(TMPQArchive * ha)
|
||||
{
|
||||
TMPQHash * pHashTableCopy = ALLOCMEM(TMPQHash, ha->pHeader->dwHashTableSize);
|
||||
|
||||
if(pHashTableCopy != NULL)
|
||||
memcpy(pHashTableCopy, ha->pHashTable, sizeof(TMPQHash) * ha->pHeader->dwHashTableSize);
|
||||
|
||||
return pHashTableCopy;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD * pFileSeeds)
|
||||
{
|
||||
TMPQHash * pHashTableCopy = NULL; // Copy of the hash table
|
||||
TMPQHash * pHash;
|
||||
TMPQHash * pHashEnd = NULL; // End of the hash table
|
||||
DWORD dwFileCount = 0;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// First of all, create a copy of hash table
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((pHashTableCopy = CopyHashTable(ha)) == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
pHashEnd = pHashTableCopy + ha->pHeader->dwHashTableSize;
|
||||
|
||||
// Notify the user
|
||||
if(CompactCB != NULL)
|
||||
CompactCB(lpUserData, CCB_CHECKING_FILES, 0, ha->pHeader->dwBlockTableSize);
|
||||
}
|
||||
|
||||
// Now check all the files from the filelist
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
SFILE_FIND_DATA wf;
|
||||
HANDLE hFind = SFileFindFirstFile((HANDLE)ha, "*", &wf, szListFile);
|
||||
BOOL bResult = TRUE;
|
||||
|
||||
// Do while some files have been found
|
||||
while(hFind != NULL && bResult)
|
||||
{
|
||||
TMPQHash * pHash = GetHashEntry(ha, wf.cFileName);
|
||||
|
||||
// If the hash table entry has been found, find it's position
|
||||
// in the hash table copy
|
||||
if(pHash != NULL)
|
||||
{
|
||||
pHash = pHashTableCopy + (pHash - ha->pHashTable);
|
||||
if(pHash->dwName1 != (DWORD)-1 && pHash->dwName2 != (DWORD)-1)
|
||||
{
|
||||
TMPQBlock * pBlock = ha->pBlockTable + pHash->dwBlockIndex;
|
||||
DWORD dwSeed = 0;
|
||||
|
||||
// Resolve the file seed. Use plain file name for it
|
||||
if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED)
|
||||
{
|
||||
char * szFileName = strrchr(wf.cFileName, '\\');
|
||||
|
||||
if(szFileName == NULL)
|
||||
szFileName = wf.cFileName;
|
||||
else
|
||||
szFileName++;
|
||||
|
||||
dwSeed = DecryptFileSeed(szFileName);
|
||||
if(pBlock->dwFlags & MPQ_FILE_FIXSEED)
|
||||
dwSeed = (dwSeed + pBlock->dwFilePos) ^ pBlock->dwFSize;
|
||||
}
|
||||
pFileSeeds[pHash->dwBlockIndex] = dwSeed;
|
||||
|
||||
pHash->dwName1 = 0xFFFFFFFF;
|
||||
pHash->dwName2 = 0xFFFFFFFF;
|
||||
pHash->lcLocale = 0xFFFF;
|
||||
pHash->wPlatform = 0xFFFF;
|
||||
pHash->dwBlockIndex = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
// Notify the user
|
||||
if(CompactCB != NULL)
|
||||
CompactCB(lpUserData, CCB_CHECKING_FILES, ++dwFileCount, ha->pHeader->dwBlockTableSize);
|
||||
|
||||
// Find the next file in the archive
|
||||
bResult = SFileFindNextFile(hFind, &wf);
|
||||
}
|
||||
|
||||
if(hFind != NULL)
|
||||
SFileFindClose(hFind);
|
||||
}
|
||||
|
||||
// When the filelist checking is complete, parse the hash table copy and find the
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Notify the user about checking hash table
|
||||
dwFileCount = 0;
|
||||
if(CompactCB != NULL)
|
||||
CompactCB(lpUserData, CCB_CHECKING_HASH_TABLE, dwFileCount, ha->pHeader->dwBlockTableSize);
|
||||
|
||||
for(pHash = pHashTableCopy; pHash < pHashEnd; pHash++)
|
||||
{
|
||||
// If there is an unresolved entry, try to detect its seed. If it fails,
|
||||
// we cannot complete the work
|
||||
if(pHash->dwName1 != (DWORD)-1 && pHash->dwName2 != (DWORD)-1)
|
||||
{
|
||||
HANDLE hFile = NULL;
|
||||
DWORD dwFlags = 0;
|
||||
DWORD dwSeed = 0;
|
||||
|
||||
if(SFileOpenFileEx((HANDLE)ha, (char *)(DWORD_PTR)pHash->dwBlockIndex, 0, &hFile))
|
||||
{
|
||||
TMPQFile * hf = (TMPQFile *)hFile;
|
||||
dwFlags = hf->pBlock->dwFlags;
|
||||
dwSeed = hf->dwSeed1;
|
||||
SFileCloseFile(hFile);
|
||||
}
|
||||
|
||||
// If the file is encrypted, we have to check
|
||||
// If we can apply the file decryption seed
|
||||
if(dwFlags & MPQ_FILE_ENCRYPTED && dwSeed == 0)
|
||||
{
|
||||
nError = ERROR_CAN_NOT_COMPLETE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Remember the seed
|
||||
pFileSeeds[pHash->dwBlockIndex] = dwSeed;
|
||||
|
||||
// Notify the user
|
||||
if(CompactCB != NULL)
|
||||
CompactCB(lpUserData, CCB_CHECKING_HASH_TABLE, ++dwFileCount, ha->pHeader->dwBlockTableSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the copy of hash table
|
||||
if(pHashTableCopy != NULL)
|
||||
FREEMEM(pHashTableCopy);
|
||||
return nError;
|
||||
}
|
||||
|
||||
// Copies all file blocks into another archive.
|
||||
// TODO: Test for archives > 4GB
|
||||
static int CopyMpqFileBlocks(
|
||||
HANDLE hFile,
|
||||
TMPQArchive * ha,
|
||||
TMPQBlockEx * pBlockEx,
|
||||
TMPQBlock * pBlock,
|
||||
DWORD dwSeed)
|
||||
{
|
||||
LARGE_INTEGER FilePos = {0};
|
||||
DWORD * pdwBlockPos2 = NULL; // File block positions to be written to target file
|
||||
DWORD * pdwBlockPos = NULL; // File block positions (unencrypted)
|
||||
BYTE * pbBlock = NULL; // Buffer for the file block
|
||||
DWORD dwTransferred; // Number of bytes transferred
|
||||
DWORD dwCSize = 0; // Compressed file size
|
||||
DWORD dwBytes = 0; // Number of bytes
|
||||
DWORD dwSeed1 = 0; // File seed used for decryption
|
||||
DWORD dwSeed2 = 0; // File seed used for encryption
|
||||
DWORD nBlocks = 0; // Number of file blocks
|
||||
DWORD nBlock = 0; // Currently processed file block
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// When file length is zero, do nothing
|
||||
if(pBlock->dwFSize == 0)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// Calculate number of blocks in the file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
nBlocks = pBlock->dwFSize / ha->dwBlockSize;
|
||||
if(pBlock->dwFSize % ha->dwBlockSize)
|
||||
nBlocks++;
|
||||
pbBlock = ALLOCMEM(BYTE, ha->dwBlockSize);
|
||||
if(pbBlock == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// Set the position to the begin of the file within archive
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
FilePos.HighPart = pBlockEx->wFilePosHigh;
|
||||
FilePos.LowPart = pBlock->dwFilePos;
|
||||
FilePos.QuadPart += ha->MpqPos.QuadPart;
|
||||
if(SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN) != FilePos.LowPart)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Remember the position in the destination file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
FilePos.HighPart = 0;
|
||||
FilePos.LowPart = SetFilePointer(hFile, 0, &FilePos.HighPart, FILE_CURRENT);
|
||||
}
|
||||
|
||||
// Resolve decryption seeds. The 'dwSeed' parameter is the decryption
|
||||
// seed for the file.
|
||||
if(nError == ERROR_SUCCESS && (pBlock->dwFlags & MPQ_FILE_ENCRYPTED))
|
||||
{
|
||||
dwSeed1 = dwSeed;
|
||||
if(pBlock->dwFlags & MPQ_FILE_FIXSEED)
|
||||
dwSeed = (dwSeed1 ^ pBlock->dwFSize) - pBlock->dwFilePos;
|
||||
|
||||
dwSeed2 = dwSeed;
|
||||
if(pBlock->dwFlags & MPQ_FILE_FIXSEED)
|
||||
dwSeed2 = (dwSeed + (DWORD)(FilePos.QuadPart - ha->MpqPos.QuadPart)) ^ pBlock->dwFSize;
|
||||
}
|
||||
|
||||
// Load the file positions from the archive and save it to the target file
|
||||
// (only if the file is compressed)
|
||||
if(pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
||||
{
|
||||
// Allocate buffers
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
pdwBlockPos = ALLOCMEM(DWORD, nBlocks + 2);
|
||||
pdwBlockPos2 = ALLOCMEM(DWORD, nBlocks + 2);
|
||||
|
||||
if(pdwBlockPos == NULL || pdwBlockPos2 == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// Load the block positions
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
dwBytes = (nBlocks + 1) * sizeof(DWORD);
|
||||
if(pBlock->dwFlags & MPQ_FILE_HAS_EXTRA)
|
||||
dwBytes += sizeof(DWORD);
|
||||
|
||||
ReadFile(ha->hFile, pdwBlockPos, dwBytes, &dwTransferred, NULL);
|
||||
if(dwTransferred != dwBytes)
|
||||
nError = ERROR_FILE_CORRUPT;
|
||||
}
|
||||
|
||||
// Re-encrypt the block table positions
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
BSWAP_ARRAY32_UNSIGNED(pdwBlockPos, dwBytes / sizeof(DWORD));
|
||||
if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED)
|
||||
{
|
||||
DecryptMPQBlock(pdwBlockPos, dwBytes, dwSeed1 - 1);
|
||||
if(pdwBlockPos[0] != dwBytes)
|
||||
nError = ERROR_FILE_CORRUPT;
|
||||
|
||||
memcpy(pdwBlockPos2, pdwBlockPos, dwBytes);
|
||||
EncryptMPQBlock(pdwBlockPos2, dwBytes, dwSeed2 - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pdwBlockPos2, pdwBlockPos, dwBytes);
|
||||
}
|
||||
BSWAP_ARRAY32_UNSIGNED(pdwBlockPos2, dwBytes / sizeof(DWORD));
|
||||
}
|
||||
|
||||
// Write to the target file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
WriteFile(hFile, pdwBlockPos2, dwBytes, &dwTransferred, NULL);
|
||||
dwCSize += dwTransferred;
|
||||
if(dwTransferred != dwBytes)
|
||||
nError = ERROR_DISK_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we have to copy all file block. We will do it without
|
||||
// recompression, because re-compression is not necessary in this case
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
for(nBlock = 0; nBlock < nBlocks; nBlock++)
|
||||
{
|
||||
// Fix: The last block must not be exactly the size of one block.
|
||||
dwBytes = ha->dwBlockSize;
|
||||
if(nBlock == nBlocks - 1)
|
||||
{
|
||||
dwBytes = pBlock->dwFSize - (ha->dwBlockSize * (nBlocks - 1));
|
||||
}
|
||||
|
||||
if(pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
||||
dwBytes = pdwBlockPos[nBlock+1] - pdwBlockPos[nBlock];
|
||||
|
||||
// Read the file block
|
||||
ReadFile(ha->hFile, pbBlock, dwBytes, &dwTransferred, NULL);
|
||||
if(dwTransferred != dwBytes)
|
||||
{
|
||||
nError = ERROR_FILE_CORRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
// If necessary, re-encrypt the block
|
||||
// Note: Recompression is not necessary here. Unlike encryption,
|
||||
// the compression does not depend on the position of the file in MPQ.
|
||||
if((pBlock->dwFlags & MPQ_FILE_ENCRYPTED) && dwSeed1 != dwSeed2)
|
||||
{
|
||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)pbBlock, dwBytes/sizeof(DWORD));
|
||||
DecryptMPQBlock((DWORD *)pbBlock, dwBytes, dwSeed1 + nBlock);
|
||||
EncryptMPQBlock((DWORD *)pbBlock, dwBytes, dwSeed2 + nBlock);
|
||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)pbBlock, dwBytes/sizeof(DWORD));
|
||||
}
|
||||
|
||||
// Now write the block back to the file
|
||||
WriteFile(hFile, pbBlock, dwBytes, &dwTransferred, NULL);
|
||||
dwCSize += dwTransferred;
|
||||
if(dwTransferred != dwBytes)
|
||||
{
|
||||
nError = ERROR_DISK_FULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the file extras, if any
|
||||
// These extras does not seem to be encrypted, and their purpose is unknown
|
||||
if(nError == ERROR_SUCCESS && (pBlock->dwFlags & MPQ_FILE_HAS_EXTRA))
|
||||
{
|
||||
dwBytes = pdwBlockPos[nBlocks + 1] - pdwBlockPos[nBlocks];
|
||||
if(dwBytes != 0)
|
||||
{
|
||||
ReadFile(ha->hFile, pbBlock, dwBytes, &dwTransferred, NULL);
|
||||
if(dwTransferred == dwBytes)
|
||||
{
|
||||
WriteFile(hFile, pbBlock, dwBytes, &dwTransferred, NULL);
|
||||
dwCSize += dwTransferred;
|
||||
if(dwTransferred != dwBytes)
|
||||
nError = ERROR_DISK_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
nError = ERROR_FILE_CORRUPT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update file position in the block table
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// At this point, number of bytes written should be exactly
|
||||
// the same like the compressed file size. If it isn't, there's something wrong
|
||||
// (maybe new archive version ?)
|
||||
assert(dwCSize == pBlock->dwCSize);
|
||||
|
||||
// Update file pos in the block table
|
||||
FilePos.QuadPart -= ha->MpqPos.QuadPart;
|
||||
pBlockEx->wFilePosHigh = (USHORT)FilePos.HighPart;
|
||||
pBlock->dwFilePos = FilePos.LowPart;
|
||||
}
|
||||
|
||||
// Cleanup and return
|
||||
if(pdwBlockPos2 != NULL)
|
||||
FREEMEM(pdwBlockPos2);
|
||||
if(pdwBlockPos != NULL)
|
||||
FREEMEM(pdwBlockPos);
|
||||
if(pbBlock != NULL)
|
||||
FREEMEM(pbBlock);
|
||||
return nError;
|
||||
}
|
||||
|
||||
|
||||
static int CopyNonMpqData(
|
||||
HANDLE hSrcFile,
|
||||
HANDLE hTrgFile,
|
||||
LARGE_INTEGER & DataSizeToCopy)
|
||||
{
|
||||
LARGE_INTEGER DataSize = DataSizeToCopy;
|
||||
DWORD dwTransferred;
|
||||
DWORD dwToRead;
|
||||
char DataBuffer[0x1000];
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
while(DataSize.QuadPart > 0)
|
||||
{
|
||||
// Get the proper size of data
|
||||
dwToRead = sizeof(DataBuffer);
|
||||
if(DataSize.HighPart == 0 && DataSize.LowPart < dwToRead)
|
||||
dwToRead = DataSize.LowPart;
|
||||
|
||||
// Read the source file
|
||||
ReadFile(hSrcFile, DataBuffer, dwToRead, &dwTransferred, NULL);
|
||||
if(dwTransferred != dwToRead)
|
||||
{
|
||||
nError = ERROR_CAN_NOT_COMPLETE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Write to the target file
|
||||
WriteFile(hTrgFile, DataBuffer, dwToRead, &dwTransferred, NULL);
|
||||
if(dwTransferred != dwToRead)
|
||||
{
|
||||
nError = ERROR_DISK_FULL;
|
||||
break;
|
||||
}
|
||||
|
||||
// Decrement the number of data to be copied
|
||||
DataSize.QuadPart -= dwTransferred;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
static int CopyMpqFiles(HANDLE hFile, TMPQArchive * ha, DWORD * pFileSeeds)
|
||||
{
|
||||
TMPQBlockEx * pBlockEx;
|
||||
TMPQBlock * pBlock;
|
||||
DWORD dwSeed1;
|
||||
DWORD dwIndex;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Walk through all files and write them to the destination MPQ archive
|
||||
for(dwIndex = 0; dwIndex < ha->pHeader->dwBlockTableSize; dwIndex++)
|
||||
{
|
||||
pBlockEx = ha->pExtBlockTable + dwIndex;
|
||||
pBlock = ha->pBlockTable + dwIndex;
|
||||
dwSeed1 = pFileSeeds[dwIndex];
|
||||
|
||||
// Notify the caller about work
|
||||
if(CompactCB != NULL)
|
||||
CompactCB(lpUserData, CCB_COMPACTING_FILES, dwIndex, ha->pHeader->dwBlockTableSize);
|
||||
|
||||
// if(dwIndex == 0x1B9)
|
||||
// DebugBreak();
|
||||
|
||||
// Copy all the file blocks
|
||||
// Debug: Break at (dwIndex == 5973)
|
||||
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
|
||||
{
|
||||
nError = CopyMpqFileBlocks(hFile, ha, pBlockEx, pBlock, dwSeed1);
|
||||
if(nError != ERROR_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup and exit
|
||||
return nError;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Public functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
BOOL WINAPI SFileSetCompactCallback(HANDLE /* hMPQ */, COMPACTCB aCompactCB, void * lpData)
|
||||
{
|
||||
CompactCB = aCompactCB;
|
||||
lpUserData = lpData;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Archive compacting (incomplete)
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bReserved */)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
DWORD * pFileSeeds = NULL;
|
||||
char szTempFile[MAX_PATH] = "";
|
||||
char * szTemp = NULL;
|
||||
DWORD dwTransferred;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Test the valid parameters
|
||||
if(!IsValidMpqHandle(ha))
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
|
||||
// Create the table with file seeds
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((pFileSeeds = ALLOCMEM(DWORD, ha->pHeader->dwBlockTableSize)) != NULL)
|
||||
memset(pFileSeeds, 0, sizeof(DWORD) * ha->pHeader->dwBlockTableSize);
|
||||
else
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// First of all, we have to check of we are able to decrypt all files.
|
||||
// If not, sorry, but the archive cannot be compacted.
|
||||
if(nError == ERROR_SUCCESS)
|
||||
nError = CheckIfAllFilesKnown(ha, szListFile, pFileSeeds);
|
||||
|
||||
// Get the temporary file name and create it
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(CompactCB != NULL)
|
||||
CompactCB(lpUserData, CCB_COPYING_NON_MPQ_DATA, 0, 0);
|
||||
|
||||
strcpy(szTempFile, ha->szFileName);
|
||||
if((szTemp = strrchr(szTempFile, '.')) != NULL)
|
||||
strcpy(szTemp + 1, "mp_");
|
||||
else
|
||||
strcat(szTempFile, "_");
|
||||
|
||||
hFile = CreateFile(szTempFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Write the data before MPQ header (if any)
|
||||
if(nError == ERROR_SUCCESS && ha->MpqPos.QuadPart > 0)
|
||||
{
|
||||
SetFilePointer(ha->hFile, 0, NULL, FILE_BEGIN);
|
||||
if(ha->pShunt != NULL)
|
||||
nError = CopyNonMpqData(ha->hFile, hFile, ha->ShuntPos);
|
||||
else
|
||||
nError = CopyNonMpqData(ha->hFile, hFile, ha->MpqPos);
|
||||
}
|
||||
|
||||
// Write the MPQ shunt (if any)
|
||||
if(nError == ERROR_SUCCESS && ha->pShunt != NULL)
|
||||
{
|
||||
BSWAP_TMPQSHUNT(ha->pShunt);
|
||||
WriteFile(hFile, ha->pShunt, sizeof(TMPQShunt), &dwTransferred, NULL);
|
||||
BSWAP_TMPQSHUNT(ha->pShunt);
|
||||
|
||||
if(dwTransferred != sizeof(TMPQShunt))
|
||||
nError = ERROR_DISK_FULL;
|
||||
}
|
||||
|
||||
// Write the data between MPQ shunt and the MPQ header (if any)
|
||||
if(nError == ERROR_SUCCESS && ha->pShunt != NULL)
|
||||
{
|
||||
LARGE_INTEGER BytesToCopy;
|
||||
|
||||
BytesToCopy.QuadPart = ha->MpqPos.QuadPart - (ha->ShuntPos.QuadPart + sizeof(TMPQShunt));
|
||||
nError = CopyNonMpqData(ha->hFile, hFile, BytesToCopy);
|
||||
}
|
||||
|
||||
// Write the MPQ header
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
BSWAP_TMPQHEADER(ha->pHeader);
|
||||
WriteFile(hFile, ha->pHeader, ha->pHeader->dwHeaderSize, &dwTransferred, NULL);
|
||||
BSWAP_TMPQHEADER(ha->pHeader);
|
||||
if(dwTransferred != ha->pHeader->dwHeaderSize)
|
||||
nError = ERROR_DISK_FULL;
|
||||
}
|
||||
|
||||
// Write the data between the header and between the first file
|
||||
// For this, we have to determine where the first file begins
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
LARGE_INTEGER FirstFilePos;
|
||||
LARGE_INTEGER TempPos;
|
||||
TMPQBlockEx * pBlockEx = ha->pExtBlockTable;
|
||||
TMPQBlock * pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize;
|
||||
TMPQBlock * pBlock = ha->pBlockTable;
|
||||
|
||||
// Maximum file position
|
||||
FirstFilePos.HighPart = 0x7FFFFFFF;
|
||||
FirstFilePos.LowPart = 0xFFFFFFFF;
|
||||
|
||||
// Find the block with the least position in the MPQ
|
||||
while(pBlock < pBlockEnd)
|
||||
{
|
||||
TempPos.HighPart = pBlockEx->wFilePosHigh;
|
||||
TempPos.LowPart = pBlock->dwFilePos;
|
||||
if(TempPos.QuadPart < FirstFilePos.QuadPart)
|
||||
FirstFilePos = TempPos;
|
||||
|
||||
pBlockEx++;
|
||||
pBlock++;
|
||||
}
|
||||
|
||||
// Set the position in the source file right after the file header
|
||||
TempPos.QuadPart = ha->MpqPos.QuadPart + ha->pHeader->dwHeaderSize;
|
||||
SetFilePointer(ha->hFile, TempPos.LowPart, &TempPos.HighPart, FILE_BEGIN);
|
||||
|
||||
// Get the number of bytes to copy
|
||||
FirstFilePos.QuadPart -= ha->pHeader->dwHeaderSize;
|
||||
nError = CopyNonMpqData(ha->hFile, hFile, FirstFilePos);
|
||||
}
|
||||
|
||||
// Now write all file blocks.
|
||||
if(nError == ERROR_SUCCESS)
|
||||
nError = CopyMpqFiles(hFile, ha, pFileSeeds);
|
||||
|
||||
// Now we need to update the tables positions
|
||||
// (but only if the tables are at the end of the file)
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
LARGE_INTEGER RelativePos;
|
||||
LARGE_INTEGER FilePos = {0};
|
||||
|
||||
// Set the hash table position
|
||||
FilePos.LowPart = SetFilePointer(hFile, 0, &FilePos.HighPart, FILE_CURRENT);
|
||||
RelativePos.QuadPart = FilePos.QuadPart - ha->MpqPos.QuadPart;
|
||||
ha->pHeader->wHashTablePosHigh = (USHORT)RelativePos.HighPart;
|
||||
ha->pHeader->dwHashTablePos = RelativePos.LowPart;
|
||||
ha->HashTablePos = FilePos;
|
||||
|
||||
// Set the block table position
|
||||
RelativePos.QuadPart += ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
|
||||
FilePos.QuadPart += ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
|
||||
ha->pHeader->wBlockTablePosHigh = (USHORT)RelativePos.HighPart;
|
||||
ha->pHeader->dwBlockTablePos = RelativePos.LowPart;
|
||||
ha->BlockTablePos = FilePos;
|
||||
|
||||
// Set the extended block table position
|
||||
RelativePos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
||||
FilePos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
||||
if(ha->ExtBlockTablePos.QuadPart != 0)
|
||||
{
|
||||
ha->pHeader->ExtBlockTablePos = RelativePos;
|
||||
ha->ExtBlockTablePos = FilePos;
|
||||
|
||||
RelativePos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx);
|
||||
FilePos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx);
|
||||
}
|
||||
|
||||
// Set the archive size
|
||||
ha->pHeader->dwArchiveSize = RelativePos.LowPart;
|
||||
ha->MpqSize = RelativePos;
|
||||
}
|
||||
|
||||
// If succeeded, update the tables in the file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
CloseHandle(ha->hFile);
|
||||
ha->FilePointer.QuadPart = 0;
|
||||
ha->hFile = hFile;
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
nError = SaveMPQTables(ha);
|
||||
}
|
||||
|
||||
// If all succeeded, switch the archives
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(CompactCB != NULL)
|
||||
CompactCB(lpUserData, CCB_CLOSING_ARCHIVE, 0, 0);
|
||||
|
||||
if(!DeleteFile(ha->szFileName) || // Delete the old archive
|
||||
!CloseHandle(ha->hFile) || // Close the new archive
|
||||
!MoveFile(szTempFile, ha->szFileName)) // Rename the temporary archive
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Now open the freshly renamed archive file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
ha->hFile = CreateFile(ha->szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if(ha->hFile == INVALID_HANDLE_VALUE)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Invalidate the positions of the archive
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
ha->FilePointer.QuadPart = 0;
|
||||
ha->pLastFile = NULL;
|
||||
ha->dwBlockPos = 0;
|
||||
ha->dwBuffPos = 0;
|
||||
}
|
||||
|
||||
// Cleanup and return
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hFile);
|
||||
if(pFileSeeds != NULL)
|
||||
FREEMEM(pFileSeeds);
|
||||
if(nError != ERROR_SUCCESS)
|
||||
SetLastError(nError);
|
||||
DeleteFile(szTempFile);
|
||||
CompactCB = NULL;
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
530
src/tools/stuffextract/StormLib/SFileCreateArchiveEx.cpp
Normal file
530
src/tools/stuffextract/StormLib/SFileCreateArchiveEx.cpp
Normal file
@ -0,0 +1,530 @@
|
||||
/*****************************************************************************/
|
||||
/* SFileCreateArchiveEx.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* MPQ Editing functions */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 24.03.03 1.00 Lad Splitted from SFileOpenArchive.cpp */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define DEFAULT_BLOCK_SIZE 3 // Default size of the block
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local tables
|
||||
|
||||
static DWORD PowersOfTwo[] =
|
||||
{
|
||||
0x0000002, 0x0000004, 0x0000008,
|
||||
0x0000010, 0x0000020, 0x0000040, 0x0000080,
|
||||
0x0000100, 0x0000200, 0x0000400, 0x0000800,
|
||||
0x0001000, 0x0002000, 0x0004000, 0x0008000,
|
||||
0x0010000, 0x0020000, 0x0040000, 0x0080000,
|
||||
0x0000000
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Public functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Opens or creates a (new) MPQ archive.
|
||||
//
|
||||
// szMpqName - Name of the archive to be created.
|
||||
//
|
||||
// dwCreationDisposition:
|
||||
//
|
||||
// Value Archive exists Archive doesn't exist
|
||||
// ---------- --------------------- ---------------------
|
||||
// CREATE_NEW Fails Creates new archive
|
||||
// CREATE_ALWAYS Overwrites existing Creates new archive
|
||||
// OPEN_EXISTING Opens the archive Fails
|
||||
// OPEN_ALWAYS Opens the archive Creates new archive
|
||||
//
|
||||
// The above mentioned values can be combined with the following flags:
|
||||
//
|
||||
// MPQ_CREATE_ARCHIVE_V1 - Creates MPQ archive version 1
|
||||
// MPQ_CREATE_ARCHIVE_V2 - Creates MPQ archive version 2
|
||||
//
|
||||
// dwHashTableSize - Size of the hash table (only if creating a new archive).
|
||||
// Must be between 2^4 (= 16) and 2^18 (= 262 144)
|
||||
//
|
||||
// phMpq - Receives handle to the archive
|
||||
//
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposition, DWORD dwHashTableSize, HANDLE * phMPQ)
|
||||
{
|
||||
LARGE_INTEGER MpqPos = {0}; // Position of MPQ header in the file
|
||||
TMPQArchive * ha = NULL; // MPQ archive handle
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE; // File handle
|
||||
DWORD dwTransferred = 0; // Number of bytes written into the archive
|
||||
USHORT wFormatVersion;
|
||||
BOOL bFileExists = FALSE;
|
||||
int nIndex = 0;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Pre-initialize the result value
|
||||
if(phMPQ != NULL)
|
||||
*phMPQ = NULL;
|
||||
|
||||
// Check the parameters, if they are valid
|
||||
if(szMpqName == NULL || *szMpqName == 0 || phMPQ == NULL)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check the value of dwCreationDisposition against file existence
|
||||
bFileExists = (GetFileAttributes(szMpqName) != 0xFFFFFFFF);
|
||||
|
||||
// Extract format version from the "dwCreationDisposition"
|
||||
wFormatVersion = (USHORT)(dwCreationDisposition >> 0x10);
|
||||
dwCreationDisposition &= 0x0000FFFF;
|
||||
|
||||
// If the file exists and open required, do it.
|
||||
if(bFileExists && (dwCreationDisposition == OPEN_EXISTING || dwCreationDisposition == OPEN_ALWAYS))
|
||||
{
|
||||
// Try to open the archive normal way. If it fails, it means that
|
||||
// the file exist, but it is not a MPQ archive.
|
||||
if(SFileOpenArchiveEx(szMpqName, 0, 0, phMPQ, GENERIC_READ | GENERIC_WRITE))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Two error cases
|
||||
if(dwCreationDisposition == CREATE_NEW && bFileExists)
|
||||
{
|
||||
SetLastError(ERROR_ALREADY_EXISTS);
|
||||
return FALSE;
|
||||
}
|
||||
if(dwCreationDisposition == OPEN_EXISTING && bFileExists == FALSE)
|
||||
{
|
||||
SetLastError(ERROR_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// At this point, we have to create the archive. If the file exists,
|
||||
// we will convert it to MPQ archive.
|
||||
// Check the value of hash table size. It has to be a power of two
|
||||
// and must be between HASH_TABLE_SIZE_MIN and HASH_TABLE_SIZE_MAX
|
||||
if(dwHashTableSize < HASH_TABLE_SIZE_MIN)
|
||||
dwHashTableSize = HASH_TABLE_SIZE_MIN;
|
||||
if(dwHashTableSize > HASH_TABLE_SIZE_MAX)
|
||||
dwHashTableSize = HASH_TABLE_SIZE_MAX;
|
||||
|
||||
// Round the hash table size up to the nearest power of two
|
||||
for(nIndex = 0; PowersOfTwo[nIndex] != 0; nIndex++)
|
||||
{
|
||||
if(dwHashTableSize <= PowersOfTwo[nIndex])
|
||||
{
|
||||
dwHashTableSize = PowersOfTwo[nIndex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the buffer for decryption engine
|
||||
if(nError == ERROR_SUCCESS)
|
||||
nError = PrepareStormBuffer();
|
||||
|
||||
// Get the position where the MPQ header will begin.
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
hFile = CreateFile(szMpqName,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
dwCreationDisposition,
|
||||
0,
|
||||
NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Retrieve the file size and round it up to 0x200 bytes
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
MpqPos.LowPart = GetFileSize(hFile, (LPDWORD)&MpqPos.HighPart);
|
||||
MpqPos.QuadPart += 0x1FF;
|
||||
MpqPos.LowPart &= 0xFFFFFE00;
|
||||
|
||||
if(wFormatVersion == MPQ_FORMAT_VERSION_1 && MpqPos.HighPart != 0)
|
||||
nError = ERROR_DISK_FULL;
|
||||
if(wFormatVersion == MPQ_FORMAT_VERSION_2 && MpqPos.HighPart > 0x0000FFFF)
|
||||
nError = ERROR_DISK_FULL;
|
||||
}
|
||||
|
||||
// Move to the end of the file (i.e. begin of the MPQ)
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(SetFilePointer(hFile, MpqPos.LowPart, &MpqPos.HighPart, FILE_BEGIN) == 0xFFFFFFFF)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Set the new end of the file to the MPQ header position
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!SetEndOfFile(hFile))
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Create the archive handle
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((ha = ALLOCMEM(TMPQArchive, 1)) == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// Fill the MPQ archive handle structure and create the header,
|
||||
// block buffer, hash table and block table
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
memset(ha, 0, sizeof(TMPQArchive));
|
||||
strcpy(ha->szFileName, szMpqName);
|
||||
ha->hFile = hFile;
|
||||
ha->dwBlockSize = 0x200 << DEFAULT_BLOCK_SIZE;
|
||||
ha->MpqPos = MpqPos;
|
||||
ha->FilePointer = MpqPos;
|
||||
ha->pHeader = &ha->Header;
|
||||
ha->pHashTable = ALLOCMEM(TMPQHash, dwHashTableSize);
|
||||
ha->pBlockTable = ALLOCMEM(TMPQBlock, dwHashTableSize);
|
||||
ha->pExtBlockTable = ALLOCMEM(TMPQBlockEx, dwHashTableSize);
|
||||
ha->pbBlockBuffer = ALLOCMEM(BYTE, ha->dwBlockSize);
|
||||
ha->pListFile = NULL;
|
||||
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
||||
|
||||
if(!ha->pHashTable || !ha->pBlockTable || !ha->pExtBlockTable || !ha->pbBlockBuffer)
|
||||
nError = GetLastError();
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// Fill the MPQ header and all buffers
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
LARGE_INTEGER TempPos;
|
||||
TMPQHeader2 * pHeader = ha->pHeader;
|
||||
DWORD dwHeaderSize = (wFormatVersion == MPQ_FORMAT_VERSION_2) ? sizeof(TMPQHeader2) : sizeof(TMPQHeader);
|
||||
|
||||
memset(pHeader, 0, sizeof(TMPQHeader2));
|
||||
pHeader->dwID = ID_MPQ;
|
||||
pHeader->dwHeaderSize = dwHeaderSize;
|
||||
pHeader->dwArchiveSize = pHeader->dwHeaderSize + dwHashTableSize * sizeof(TMPQHash);
|
||||
pHeader->wFormatVersion = wFormatVersion;
|
||||
pHeader->wBlockSize = 3; // 0x1000 bytes per block
|
||||
pHeader->dwHashTableSize = dwHashTableSize;
|
||||
|
||||
// Set proper hash table positions
|
||||
ha->HashTablePos.QuadPart = ha->MpqPos.QuadPart + pHeader->dwHeaderSize;
|
||||
ha->pHeader->dwHashTablePos = pHeader->dwHeaderSize;
|
||||
ha->pHeader->wHashTablePosHigh = 0;
|
||||
|
||||
// Set proper block table positions
|
||||
ha->BlockTablePos.QuadPart = ha->HashTablePos.QuadPart +
|
||||
(ha->pHeader->dwHashTableSize * sizeof(TMPQHash));
|
||||
TempPos.QuadPart = ha->BlockTablePos.QuadPart - ha->MpqPos.QuadPart;
|
||||
ha->pHeader->dwBlockTablePos = TempPos.LowPart;
|
||||
ha->pHeader->wBlockTablePosHigh = (USHORT)TempPos.HighPart;
|
||||
|
||||
// For now, we set extended block table positioon top zero unless we add enough
|
||||
// files to cause the archive size exceed 4 GB
|
||||
ha->ExtBlockTablePos.QuadPart = 0;
|
||||
|
||||
// Clear all tables
|
||||
memset(ha->pBlockTable, 0, sizeof(TMPQBlock) * dwHashTableSize);
|
||||
memset(ha->pExtBlockTable, 0, sizeof(TMPQBlockEx) * dwHashTableSize);
|
||||
memset(ha->pHashTable, 0xFF, sizeof(TMPQHash) * dwHashTableSize);
|
||||
}
|
||||
|
||||
// Write the MPQ header to the file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD dwHeaderSize = ha->pHeader->dwHeaderSize;
|
||||
|
||||
BSWAP_TMPQHEADER(ha->pHeader);
|
||||
WriteFile(ha->hFile, ha->pHeader, dwHeaderSize, &dwTransferred, NULL);
|
||||
BSWAP_TMPQHEADER(ha->pHeader);
|
||||
|
||||
if(dwTransferred != ha->pHeader->dwHeaderSize)
|
||||
nError = ERROR_DISK_FULL;
|
||||
|
||||
ha->FilePointer.QuadPart = ha->MpqPos.QuadPart + dwTransferred;
|
||||
ha->MpqSize.QuadPart += dwTransferred;
|
||||
}
|
||||
|
||||
// Create the internal listfile
|
||||
if(nError == ERROR_SUCCESS)
|
||||
nError = SListFileCreateListFile(ha);
|
||||
|
||||
// Try to add the internal listfile
|
||||
if(nError == ERROR_SUCCESS)
|
||||
SFileAddListFile((HANDLE)ha, NULL);
|
||||
|
||||
// Cleanup : If an error, delete all buffers and return
|
||||
if(nError != ERROR_SUCCESS)
|
||||
{
|
||||
FreeMPQArchive(ha);
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hFile);
|
||||
SetLastError(nError);
|
||||
}
|
||||
|
||||
// Return the values
|
||||
*phMPQ = (HANDLE)ha;
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Changes locale ID of a file
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
|
||||
{
|
||||
TMPQFile * hf = (TMPQFile *)hFile;
|
||||
|
||||
// Invalid handle => do nothing
|
||||
if(IsValidFileHandle(hf) == FALSE || IsValidMpqHandle(hf->ha) == FALSE)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If the file has not been open for writing, do nothing.
|
||||
if(hf->ha->pListFile == NULL)
|
||||
return ERROR_ACCESS_DENIED;
|
||||
|
||||
hf->pHash->lcLocale = (USHORT)lcNewLocale;
|
||||
hf->ha->dwFlags |= MPQ_FLAG_CHANGED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Adds a file into the archive
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality, int nFileType)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
BOOL bReplaced = FALSE; // TRUE if replacing file in the archive
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Check valid parameters
|
||||
if(IsValidMpqHandle(ha) == FALSE || szFileName == NULL || *szFileName == 0 || szArchivedName == NULL || *szArchivedName == 0)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
|
||||
// Check the values of dwFlags
|
||||
if((dwFlags & MPQ_FILE_COMPRESS_PKWARE) && (dwFlags & MPQ_FILE_COMPRESS_MULTI))
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// If anyone is trying to add listfile, and the archive already has a listfile,
|
||||
// deny the operation, but return success.
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(ha->pListFile != NULL && !_stricmp(szFileName, LISTFILE_NAME))
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Open added file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
nError = AddFileToArchive(ha, hFile, szArchivedName, dwFlags, dwQuality, nFileType, &bReplaced);
|
||||
|
||||
// Add the file into listfile also
|
||||
if(nError == ERROR_SUCCESS && bReplaced == FALSE)
|
||||
nError = SListFileAddNode(ha, szArchivedName);
|
||||
|
||||
// Cleanup and exit
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hFile);
|
||||
if(nError != ERROR_SUCCESS)
|
||||
SetLastError(nError);
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
// Adds a data file into the archive
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileAddFile(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags)
|
||||
{
|
||||
return SFileAddFileEx(hMPQ, szFileName, szArchivedName, dwFlags, 0, SFILE_TYPE_DATA);
|
||||
}
|
||||
|
||||
// Adds a WAVE file into the archive
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileAddWave(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality)
|
||||
{
|
||||
return SFileAddFileEx(hMPQ, szFileName, szArchivedName, dwFlags, dwQuality, SFILE_TYPE_WAVE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// BOOL SFileRemoveFile(HANDLE hMPQ, char * szFileName)
|
||||
//
|
||||
// This function removes a file from the archive. The file content
|
||||
// remains there, only the entries in the hash table and in the block
|
||||
// table are updated.
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
TMPQBlockEx * pBlockEx = NULL; // Block entry of deleted file
|
||||
TMPQBlock * pBlock = NULL; // Block entry of deleted file
|
||||
TMPQHash * pHash = NULL; // Hash entry of deleted file
|
||||
DWORD dwBlockIndex = 0;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Check the parameters
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(IsValidMpqHandle(ha) == FALSE)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
if(dwSearchScope != SFILE_OPEN_BY_INDEX && *szFileName == 0)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Do not allow to remove listfile
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(dwSearchScope != SFILE_OPEN_BY_INDEX && !_stricmp(szFileName, LISTFILE_NAME))
|
||||
nError = ERROR_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
// Get hash entry belonging to this file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((pHash = GetHashEntryEx(ha, (char *)szFileName, lcLocale)) == NULL)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// If index was not found, or is greater than number of files, exit.
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((dwBlockIndex = pHash->dwBlockIndex) > ha->pHeader->dwBlockTableSize)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Get block and test if the file is not already deleted
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
pBlockEx = ha->pExtBlockTable + dwBlockIndex;
|
||||
pBlock = ha->pBlockTable + dwBlockIndex;
|
||||
if((pBlock->dwFlags & MPQ_FILE_EXISTS) == 0)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Now invalidate the block entry and the hash entry. Do not make any
|
||||
// relocations and file copying, use SFileCompactArchive for it.
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
pBlockEx->wFilePosHigh = 0;
|
||||
pBlock->dwFilePos = 0;
|
||||
pBlock->dwFSize = 0;
|
||||
pBlock->dwCSize = 0;
|
||||
pBlock->dwFlags = 0;
|
||||
pHash->dwName1 = 0xFFFFFFFF;
|
||||
pHash->dwName2 = 0xFFFFFFFF;
|
||||
pHash->lcLocale = 0xFFFF;
|
||||
pHash->wPlatform = 0xFFFF;
|
||||
pHash->dwBlockIndex = HASH_ENTRY_DELETED;
|
||||
|
||||
// Update MPQ archive
|
||||
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
||||
}
|
||||
|
||||
// Remove the file from the list file
|
||||
if(nError == ERROR_SUCCESS && lcLocale == LANG_NEUTRAL)
|
||||
nError = SListFileRemoveNode(ha, szFileName);
|
||||
|
||||
// Resolve error and exit
|
||||
if(nError != ERROR_SUCCESS)
|
||||
SetLastError(nError);
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
// Renames the file within the archive.
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * szNewFileName)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
TMPQHash * pOldHash = NULL; // Hash entry for the original file
|
||||
TMPQHash * pNewHash = NULL; // Hash entry for the renamed file
|
||||
DWORD dwBlockIndex = 0;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Test the valid parameters
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(hMPQ == NULL || szNewFileName == NULL || *szNewFileName == 0)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
if(szFileName == NULL || *szFileName == 0)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Do not allow to rename listfile
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!_stricmp(szFileName, LISTFILE_NAME))
|
||||
nError = ERROR_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
// Test if the file already exists in the archive
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((pNewHash = GetHashEntryEx(ha, szNewFileName, lcLocale)) != NULL)
|
||||
nError = ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
// Get the hash table entry for the original file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((pOldHash = GetHashEntryEx(ha, szFileName, lcLocale)) == NULL)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Get the hash table entry for the renamed file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Save block table index and remove the hash table entry
|
||||
dwBlockIndex = pOldHash->dwBlockIndex;
|
||||
pOldHash->dwName1 = 0xFFFFFFFF;
|
||||
pOldHash->dwName2 = 0xFFFFFFFF;
|
||||
pOldHash->lcLocale = 0xFFFF;
|
||||
pOldHash->wPlatform = 0xFFFF;
|
||||
pOldHash->dwBlockIndex = HASH_ENTRY_DELETED;
|
||||
|
||||
if((pNewHash = FindFreeHashEntry(ha, szNewFileName)) == NULL)
|
||||
nError = ERROR_CAN_NOT_COMPLETE;
|
||||
}
|
||||
|
||||
// Save the block index and clear the hash entry
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Copy the block table index
|
||||
pNewHash->dwBlockIndex = dwBlockIndex;
|
||||
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
||||
}
|
||||
|
||||
// Rename the file in the list file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
nError = SListFileRenameNode(ha, szFileName, szNewFileName);
|
||||
|
||||
// Resolve error and return
|
||||
if(nError != ERROR_SUCCESS)
|
||||
SetLastError(nError);
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
63
src/tools/stuffextract/StormLib/SFileExtractFile.cpp
Normal file
63
src/tools/stuffextract/StormLib/SFileExtractFile.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/*****************************************************************************/
|
||||
/* SFileExtractFile.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Simple extracting utility */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 20.06.03 1.00 Lad The first version of SFileExtractFile.cpp */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char * szExtracted)
|
||||
{
|
||||
HANDLE hLocalFile = INVALID_HANDLE_VALUE;
|
||||
HANDLE hMpqFile = NULL;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Create the local file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
hLocalFile = CreateFile(szExtracted, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if(hLocalFile == INVALID_HANDLE_VALUE)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Open the MPQ file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!SFileOpenFileEx(hMpq, szToExtract, 0, &hMpqFile))
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Copy the file's content
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
char szBuffer[0x1000];
|
||||
DWORD dwTransferred = 1;
|
||||
|
||||
while(dwTransferred > 0)
|
||||
{
|
||||
SFileReadFile(hMpqFile, szBuffer, sizeof(szBuffer), &dwTransferred, NULL);
|
||||
if(dwTransferred == 0)
|
||||
break;
|
||||
|
||||
WriteFile(hLocalFile, szBuffer, dwTransferred, &dwTransferred, NULL);
|
||||
if(dwTransferred == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the files
|
||||
if(hMpqFile != NULL)
|
||||
SFileCloseFile(hMpqFile);
|
||||
if(hLocalFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hLocalFile);
|
||||
if(nError != ERROR_SUCCESS)
|
||||
SetLastError(nError);
|
||||
return (BOOL)(nError == ERROR_SUCCESS);
|
||||
}
|
||||
291
src/tools/stuffextract/StormLib/SFileFindFile.cpp
Normal file
291
src/tools/stuffextract/StormLib/SFileFindFile.cpp
Normal file
@ -0,0 +1,291 @@
|
||||
/*****************************************************************************/
|
||||
/* SFileFindFile.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* A module for file searching within MPQs */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 25.03.03 1.00 Lad The first version of SFileFindFile.cpp */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define LISTFILE_CACHE_SIZE 0x1000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local functions
|
||||
|
||||
static BOOL IsValidSearchHandle(TMPQSearch * hs)
|
||||
{
|
||||
if(hs == NULL || IsBadReadPtr(hs, sizeof(TMPQSearch)))
|
||||
return FALSE;
|
||||
|
||||
if(!IsValidMpqHandle(hs->ha))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// This function compares a string with a wildcard search string.
|
||||
// returns TRUE, when the string matches with the wildcard.
|
||||
BOOL CheckWildCard(const char * szString, const char * szWildCard)
|
||||
{
|
||||
char * szTemp; // Temporary helper pointer
|
||||
int nResult = 0; // For memcmp return values
|
||||
int nMustNotMatch = 0; // Number of following chars int szString,
|
||||
// which must not match with szWildCard
|
||||
int nMustMatch = 0; // Number of the following characters,
|
||||
// which must match
|
||||
|
||||
// When the string is empty, it does not match with every wildcard
|
||||
if(*szString == 0)
|
||||
return FALSE;
|
||||
|
||||
// When the mask is empty, it matches to every wildcard
|
||||
if(szWildCard == NULL || *szWildCard == 0)
|
||||
return FALSE;
|
||||
|
||||
// Do normal test
|
||||
for(;;)
|
||||
{
|
||||
switch(*szWildCard)
|
||||
{
|
||||
case '*': // Means "every number of characters"
|
||||
// Skip all asterisks
|
||||
while(*szWildCard == '*')
|
||||
szWildCard++;
|
||||
|
||||
// When no more characters in wildcard, it means that the strings match
|
||||
if(*szWildCard == 0)
|
||||
return TRUE;
|
||||
|
||||
// The next N characters must not agree
|
||||
nMustNotMatch |= 0x70000000;
|
||||
break;
|
||||
|
||||
case '?': // Means "One or no character"
|
||||
while(*szWildCard == '?')
|
||||
{
|
||||
nMustNotMatch++;
|
||||
szWildCard++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// If the two characters match
|
||||
if(toupper(*szString) == toupper(*szWildCard))
|
||||
{
|
||||
// When end of string, they agree
|
||||
if(*szString == 0)
|
||||
return TRUE;
|
||||
|
||||
nMustNotMatch = 0;
|
||||
szWildCard++;
|
||||
szString++;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the next character must match, the string does not match
|
||||
if(nMustNotMatch == 0)
|
||||
return FALSE;
|
||||
|
||||
// Count the characters which must match after characters
|
||||
// that must not match
|
||||
szTemp = (char *)szWildCard;
|
||||
nMustMatch = 0;
|
||||
while(*szTemp != 0 && *szTemp != '*' && *szTemp != '?')
|
||||
{
|
||||
nMustMatch++;
|
||||
szTemp++;
|
||||
}
|
||||
|
||||
// Now skip characters from szString up to number of chars
|
||||
// that must not match
|
||||
nResult = -1;
|
||||
while(nMustNotMatch > 0 && *szString != 0)
|
||||
{
|
||||
if((nResult = _strnicmp(szString, szWildCard, nMustMatch)) == 0)
|
||||
break;
|
||||
|
||||
szString++;
|
||||
nMustNotMatch--;
|
||||
}
|
||||
|
||||
// Make one more comparison
|
||||
if(nMustNotMatch == 0)
|
||||
nResult = _strnicmp(szString, szWildCard, nMustMatch);
|
||||
|
||||
// If a match has been found, continue the search
|
||||
if(nResult == 0)
|
||||
{
|
||||
nMustNotMatch = 0;
|
||||
szWildCard += nMustMatch;
|
||||
szString += nMustMatch;
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Performs one MPQ search
|
||||
// TODO: Test for archives > 4GB
|
||||
static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
|
||||
{
|
||||
TMPQArchive * ha = hs->ha;
|
||||
TFileNode * pNode;
|
||||
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||
TMPQHash * pHash = ha->pHashTable + hs->dwNextIndex;
|
||||
|
||||
// Do until some file found or no more files
|
||||
while(pHash < pHashEnd)
|
||||
{
|
||||
pNode = ha->pListFile[hs->dwNextIndex++];
|
||||
|
||||
// If this entry is free, do nothing
|
||||
if(pHash->dwBlockIndex < HASH_ENTRY_FREE && (DWORD_PTR)pNode < HASH_ENTRY_FREE)
|
||||
{
|
||||
// Check the file name.
|
||||
if(CheckWildCard(pNode->szFileName, hs->szSearchMask))
|
||||
{
|
||||
TMPQBlock * pBlock = ha->pBlockTable + pHash->dwBlockIndex;
|
||||
|
||||
lpFindFileData->lcLocale = pHash->lcLocale;
|
||||
lpFindFileData->dwFileSize = pBlock->dwFSize;
|
||||
lpFindFileData->dwFileFlags = pBlock->dwFlags;
|
||||
lpFindFileData->dwBlockIndex = pHash->dwBlockIndex;
|
||||
lpFindFileData->dwCompSize = pBlock->dwCSize;
|
||||
|
||||
// Fill the file name and plain file name
|
||||
strcpy(lpFindFileData->cFileName, pNode->szFileName);
|
||||
lpFindFileData->szPlainName = strrchr(lpFindFileData->cFileName, '\\');
|
||||
if(lpFindFileData->szPlainName == NULL)
|
||||
lpFindFileData->szPlainName = lpFindFileData->cFileName;
|
||||
else
|
||||
lpFindFileData->szPlainName++;
|
||||
|
||||
// Fill the next entry
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
pHash++;
|
||||
}
|
||||
|
||||
// No more files found, return error
|
||||
return ERROR_NO_MORE_FILES;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
static void FreeMPQSearch(TMPQSearch *& hs)
|
||||
{
|
||||
if(hs != NULL)
|
||||
{
|
||||
FREEMEM(hs);
|
||||
hs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public functions
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
HANDLE WINAPI SFileFindFirstFile(HANDLE hMPQ, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const char * szListFile)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
TMPQSearch * hs = NULL; // Search object handle
|
||||
size_t nSize = 0;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Check for the valid parameters
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!IsValidMpqHandle(ha))
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(szMask == NULL || lpFindFileData == NULL)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(szListFile == NULL && !IsValidMpqHandle(ha))
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Include the listfile into the MPQ's internal listfile
|
||||
// Note that if the listfile name is NULL, do nothing because the
|
||||
// internal listfile is always included.
|
||||
if(nError == ERROR_SUCCESS && szListFile != NULL)
|
||||
nError = SFileAddListFile((HANDLE)ha, szListFile);
|
||||
|
||||
// Allocate the structure for MPQ search
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
nSize = sizeof(TMPQSearch) + strlen(szMask) + 1;
|
||||
if((hs = (TMPQSearch *)ALLOCMEM(char, nSize)) == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// Perform the first search
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
memset(hs, 0, sizeof(TMPQSearch));
|
||||
hs->ha = ha;
|
||||
hs->dwNextIndex = 0;
|
||||
strcpy(hs->szSearchMask, szMask);
|
||||
nError = DoMPQSearch(hs, lpFindFileData);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
if(nError != ERROR_SUCCESS)
|
||||
{
|
||||
FreeMPQSearch(hs);
|
||||
SetLastError(nError);
|
||||
}
|
||||
|
||||
// Return the result value
|
||||
return (HANDLE)hs;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
|
||||
{
|
||||
TMPQSearch * hs = (TMPQSearch *)hFind;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Check the parameters
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!IsValidSearchHandle(hs) || lpFindFileData == NULL)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
nError = DoMPQSearch(hs, lpFindFileData);
|
||||
|
||||
if(nError != ERROR_SUCCESS)
|
||||
{
|
||||
SetLastError(nError);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileFindClose(HANDLE hFind)
|
||||
{
|
||||
TMPQSearch * hs = (TMPQSearch *)hFind;
|
||||
|
||||
// Check the parameters
|
||||
if(!IsValidSearchHandle(hs))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FreeMPQSearch(hs);
|
||||
return TRUE;
|
||||
}
|
||||
497
src/tools/stuffextract/StormLib/SFileOpenArchive.cpp
Normal file
497
src/tools/stuffextract/StormLib/SFileOpenArchive.cpp
Normal file
@ -0,0 +1,497 @@
|
||||
/*****************************************************************************/
|
||||
/* SFileOpenArchive.cpp Copyright Ladislav Zezula 1999 */
|
||||
/* */
|
||||
/* Author : Ladislav Zezula */
|
||||
/* E-mail : ladik@zezula.net */
|
||||
/* WWW : www.zezula.net */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Archive functions of Storm.dll */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.xx 1.00 Lad The first version of SFileOpenArchive.cpp */
|
||||
/* 19.11.03 1.01 Dan Big endian handling */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Local functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
static BOOL IsAviFile(TMPQHeader * pHeader)
|
||||
{
|
||||
DWORD * AviHdr = (DWORD *)pHeader;
|
||||
|
||||
// Test for 'RIFF', 'AVI ' or 'LIST'
|
||||
return (AviHdr[0] == 'FFIR' && AviHdr[2] == ' IVA' && AviHdr[3] == 'TSIL');
|
||||
}
|
||||
|
||||
// This function gets the right positions of the hash table and the block table.
|
||||
// TODO: Test for archives > 4GB
|
||||
static int RelocateMpqTablePositions(TMPQArchive * ha)
|
||||
{
|
||||
TMPQHeader2 * pHeader = ha->pHeader;
|
||||
LARGE_INTEGER FileSize;
|
||||
LARGE_INTEGER TempSize;
|
||||
|
||||
// Get the size of the file
|
||||
FileSize.LowPart = GetFileSize(ha->hFile, (LPDWORD)&FileSize.HighPart);
|
||||
|
||||
// Set the proper hash table position
|
||||
ha->HashTablePos.HighPart = pHeader->wHashTablePosHigh;
|
||||
ha->HashTablePos.LowPart = pHeader->dwHashTablePos;
|
||||
ha->HashTablePos.QuadPart += ha->MpqPos.QuadPart;
|
||||
if(ha->HashTablePos.QuadPart > FileSize.QuadPart)
|
||||
return ERROR_BAD_FORMAT;
|
||||
|
||||
// Set the proper block table position
|
||||
ha->BlockTablePos.HighPart = pHeader->wBlockTablePosHigh;
|
||||
ha->BlockTablePos.LowPart = pHeader->dwBlockTablePos;
|
||||
ha->BlockTablePos.QuadPart += ha->MpqPos.QuadPart;
|
||||
if(ha->BlockTablePos.QuadPart > FileSize.QuadPart)
|
||||
return ERROR_BAD_FORMAT;
|
||||
|
||||
// Set the proper position of the extended block table
|
||||
if(pHeader->ExtBlockTablePos.QuadPart != 0)
|
||||
{
|
||||
ha->ExtBlockTablePos = pHeader->ExtBlockTablePos;
|
||||
ha->ExtBlockTablePos.QuadPart += ha->MpqPos.QuadPart;
|
||||
if(ha->ExtBlockTablePos.QuadPart > FileSize.QuadPart)
|
||||
return ERROR_BAD_FORMAT;
|
||||
}
|
||||
|
||||
// Size of MPQ archive is computed as the biggest of
|
||||
// (EndOfBlockTable, EndOfHashTable, EndOfExtBlockTable)
|
||||
TempSize.QuadPart = ha->HashTablePos.QuadPart + (pHeader->dwHashTableSize * sizeof(TMPQHash));
|
||||
if(TempSize.QuadPart > ha->MpqSize.QuadPart)
|
||||
ha->MpqSize = TempSize;
|
||||
TempSize.QuadPart = ha->BlockTablePos.QuadPart + (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
|
||||
if(TempSize.QuadPart > ha->MpqSize.QuadPart)
|
||||
ha->MpqSize = TempSize;
|
||||
TempSize.QuadPart = ha->ExtBlockTablePos.QuadPart + (pHeader->dwBlockTableSize * sizeof(TMPQBlockEx));
|
||||
if(TempSize.QuadPart > ha->MpqSize.QuadPart)
|
||||
ha->MpqSize = TempSize;
|
||||
|
||||
// MPQ size does not include the bytes before MPQ header
|
||||
ha->MpqSize.QuadPart -= ha->MpqPos.QuadPart;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Public functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFileGetLocale and SFileSetLocale
|
||||
// Set the locale for all neewly opened archives and files
|
||||
|
||||
LCID WINAPI SFileGetLocale()
|
||||
{
|
||||
return lcLocale;
|
||||
}
|
||||
|
||||
LCID WINAPI SFileSetLocale(LCID lcNewLocale)
|
||||
{
|
||||
lcLocale = lcNewLocale;
|
||||
return lcLocale;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFileOpenArchiveEx (not a public function !!!)
|
||||
//
|
||||
// szFileName - MPQ archive file name to open
|
||||
// dwPriority - When SFileOpenFileEx called, this contains the search priority for searched archives
|
||||
// dwFlags - If contains MPQ_OPEN_NO_LISTFILE, then the internal list file will not be used.
|
||||
// phMPQ - Pointer to store open archive handle
|
||||
|
||||
BOOL SFileOpenArchiveEx(
|
||||
const char * szMpqName,
|
||||
DWORD dwPriority,
|
||||
DWORD dwFlags,
|
||||
HANDLE * phMPQ,
|
||||
DWORD dwAccessMode)
|
||||
{
|
||||
LARGE_INTEGER TempPos;
|
||||
TMPQArchive * ha = NULL; // Archive handle
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;// Opened archive file handle
|
||||
DWORD dwMaxBlockIndex = 0; // Maximum value of block entry
|
||||
DWORD dwBlockTableSize = 0; // Block table size.
|
||||
DWORD dwTransferred; // Number of bytes read
|
||||
DWORD dwBytes = 0; // Number of bytes to read
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Check the right parameters
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(szMpqName == NULL || *szMpqName == 0 || phMPQ == NULL)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Ensure that StormBuffer is allocated
|
||||
if(nError == ERROR_SUCCESS)
|
||||
nError = PrepareStormBuffer();
|
||||
|
||||
// Open the MPQ archive file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
hFile = CreateFile(szMpqName, dwAccessMode, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Allocate the MPQhandle
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((ha = ALLOCMEM(TMPQArchive, 1)) == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// Initialize handle structure and allocate structure for MPQ header
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
memset(ha, 0, sizeof(TMPQArchive));
|
||||
strncpy(ha->szFileName, szMpqName, strlen(szMpqName));
|
||||
ha->hFile = hFile;
|
||||
ha->dwPriority = dwPriority;
|
||||
ha->pHeader = &ha->Header;
|
||||
ha->pListFile = NULL;
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// Find the offset of MPQ header within the file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
LARGE_INTEGER SearchPos = {0};
|
||||
LARGE_INTEGER MpqPos = {0};
|
||||
DWORD dwHeaderID;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Invalidate the MPQ ID and read the eventual header
|
||||
SetFilePointer(ha->hFile, MpqPos.LowPart, &MpqPos.HighPart, FILE_BEGIN);
|
||||
ReadFile(ha->hFile, ha->pHeader, sizeof(TMPQHeader2), &dwTransferred, NULL);
|
||||
dwHeaderID = BSWAP_INT32_UNSIGNED(ha->pHeader->dwID);
|
||||
|
||||
// Special check : Some MPQs are actually AVI files, only with
|
||||
// changed extension.
|
||||
if(MpqPos.QuadPart == 0 && IsAviFile(ha->pHeader))
|
||||
{
|
||||
nError = ERROR_AVI_FILE;
|
||||
break;
|
||||
}
|
||||
|
||||
// If different number of bytes read, break the loop
|
||||
if(dwTransferred != sizeof(TMPQHeader2))
|
||||
{
|
||||
nError = ERROR_BAD_FORMAT;
|
||||
break;
|
||||
}
|
||||
|
||||
// If there is the MPQ shunt signature, process it
|
||||
if(dwHeaderID == ID_MPQ_SHUNT && ha->pShunt == NULL)
|
||||
{
|
||||
// Fill the shunt header
|
||||
ha->ShuntPos = MpqPos;
|
||||
ha->pShunt = &ha->Shunt;
|
||||
memcpy(ha->pShunt, ha->pHeader, sizeof(TMPQShunt));
|
||||
BSWAP_TMPQSHUNT(ha->pShunt);
|
||||
|
||||
// Set the MPQ pos and repeat the search
|
||||
MpqPos.QuadPart = SearchPos.QuadPart + ha->pShunt->dwHeaderPos;
|
||||
continue;
|
||||
}
|
||||
|
||||
// There must be MPQ header signature
|
||||
if(dwHeaderID == ID_MPQ)
|
||||
{
|
||||
BSWAP_TMPQHEADER(ha->pHeader);
|
||||
|
||||
// Save the position where the MPQ header has been found
|
||||
ha->MpqPos = MpqPos;
|
||||
|
||||
// If valid signature has been found, break the loop
|
||||
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
|
||||
{
|
||||
// W3M Map Protectors set some garbage value into the "dwHeaderSize"
|
||||
// field of MPQ header. This value is apparently ignored by Storm.dll
|
||||
if(ha->pHeader->dwHeaderSize != sizeof(TMPQHeader) &&
|
||||
ha->pHeader->dwHeaderSize != sizeof(TMPQHeader2))
|
||||
{
|
||||
ha->dwFlags |= MPQ_FLAG_PROTECTED;
|
||||
ha->pHeader->dwHeaderSize = sizeof(TMPQHeader);
|
||||
}
|
||||
|
||||
if(ha->pHeader->dwHashTablePos < ha->pHeader->dwArchiveSize &&
|
||||
ha->pHeader->dwBlockTablePos < ha->pHeader->dwArchiveSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
nError = ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// If a MPQ shunt already has been found,
|
||||
// and no MPQ header was at potision pointed by the shunt,
|
||||
// then the archive is corrupt
|
||||
if(ha->pShunt != NULL)
|
||||
{
|
||||
nError = ERROR_BAD_FORMAT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Move to the next possible offset
|
||||
SearchPos.QuadPart += 0x200;
|
||||
MpqPos = SearchPos;
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate tables position
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Clear the fields not supported in older formats
|
||||
if(ha->pHeader->wFormatVersion < MPQ_FORMAT_VERSION_2)
|
||||
{
|
||||
ha->pHeader->ExtBlockTablePos.QuadPart = 0;
|
||||
ha->pHeader->wBlockTablePosHigh = 0;
|
||||
ha->pHeader->wHashTablePosHigh = 0;
|
||||
}
|
||||
|
||||
ha->dwBlockSize = (0x200 << ha->pHeader->wBlockSize);
|
||||
nError = RelocateMpqTablePositions(ha);
|
||||
}
|
||||
|
||||
// Allocate buffers
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
//
|
||||
// Note that the block table should be as large as the hash table
|
||||
// (For later file additions).
|
||||
//
|
||||
// I have found a MPQ which has the block table larger than
|
||||
// the hash table. We should avoid buffer overruns caused by that.
|
||||
//
|
||||
dwBlockTableSize = max(ha->pHeader->dwHashTableSize, ha->pHeader->dwBlockTableSize);
|
||||
|
||||
ha->pHashTable = ALLOCMEM(TMPQHash, ha->pHeader->dwHashTableSize);
|
||||
ha->pBlockTable = ALLOCMEM(TMPQBlock, dwBlockTableSize);
|
||||
ha->pExtBlockTable = ALLOCMEM(TMPQBlockEx, dwBlockTableSize);
|
||||
ha->pbBlockBuffer = ALLOCMEM(BYTE, ha->dwBlockSize);
|
||||
|
||||
if(!ha->pHashTable || !ha->pBlockTable || !ha->pExtBlockTable || !ha->pbBlockBuffer)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// Read the hash table into memory
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
dwBytes = ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
|
||||
SetFilePointer(ha->hFile, ha->HashTablePos.LowPart, &ha->HashTablePos.HighPart, FILE_BEGIN);
|
||||
ReadFile(ha->hFile, ha->pHashTable, dwBytes, &dwTransferred, NULL);
|
||||
|
||||
if(dwTransferred != dwBytes)
|
||||
nError = ERROR_FILE_CORRUPT;
|
||||
}
|
||||
|
||||
// Decrypt hash table and check if it is correctly decrypted
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||
TMPQHash * pHash;
|
||||
|
||||
// We have to convert the hash table from LittleEndian
|
||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)ha->pHashTable, (dwBytes / sizeof(DWORD)));
|
||||
DecryptHashTable((DWORD *)ha->pHashTable, (BYTE *)"(hash table)", (ha->pHeader->dwHashTableSize * 4));
|
||||
|
||||
// Check hash table if is correctly decrypted
|
||||
for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
|
||||
{
|
||||
// Note: Some MPQs from World of Warcraft have wPlatform set to 0x0100.
|
||||
|
||||
// If not free or deleted hash entry, check for valid values
|
||||
if(pHash->dwBlockIndex < HASH_ENTRY_DELETED)
|
||||
{
|
||||
// The block index should not be larger than size of the block table
|
||||
if(pHash->dwBlockIndex > ha->pHeader->dwBlockTableSize)
|
||||
{
|
||||
nError = ERROR_BAD_FORMAT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Remember the highest block table entry
|
||||
if(pHash->dwBlockIndex > dwMaxBlockIndex)
|
||||
dwMaxBlockIndex = pHash->dwBlockIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, read the block table
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
memset(ha->pBlockTable, 0, dwBlockTableSize * sizeof(TMPQBlock));
|
||||
|
||||
dwBytes = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
||||
SetFilePointer(ha->hFile, ha->BlockTablePos.LowPart, &ha->BlockTablePos.HighPart, FILE_BEGIN);
|
||||
ReadFile(ha->hFile, ha->pBlockTable, dwBytes, &dwTransferred, NULL);
|
||||
|
||||
// We have to convert every DWORD in ha->block from LittleEndian
|
||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)ha->pBlockTable, dwBytes / sizeof(DWORD));
|
||||
|
||||
if(dwTransferred != dwBytes)
|
||||
nError = ERROR_FILE_CORRUPT;
|
||||
}
|
||||
|
||||
// Decrypt block table.
|
||||
// Some MPQs don't have Decrypted block table, e.g. cracked Diablo version
|
||||
// We have to check if block table is really encrypted
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
TMPQBlock * pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize;
|
||||
TMPQBlock * pBlock = ha->pBlockTable;
|
||||
BOOL bBlockTableEncrypted = FALSE;
|
||||
|
||||
// Verify all blocks entries in the table
|
||||
// The loop usually stops at the first entry
|
||||
while(pBlock < pBlockEnd)
|
||||
{
|
||||
// The lower 8 bits of the MPQ flags are always zero.
|
||||
// Note that this may change in next MPQ versions
|
||||
if(pBlock->dwFlags & 0x000000FF)
|
||||
{
|
||||
bBlockTableEncrypted = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Move to the next block table entry
|
||||
pBlock++;
|
||||
}
|
||||
|
||||
if(bBlockTableEncrypted)
|
||||
{
|
||||
DecryptBlockTable((DWORD *)ha->pBlockTable,
|
||||
(BYTE *)"(block table)",
|
||||
(ha->pHeader->dwBlockTableSize * 4));
|
||||
}
|
||||
}
|
||||
|
||||
// Now, read the extended block table.
|
||||
// For V1 archives, we still will maintain the extended block table
|
||||
// (it will be filled with zeros)
|
||||
// TODO: Test with >4GB
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
memset(ha->pExtBlockTable, 0, dwBlockTableSize * sizeof(TMPQBlockEx));
|
||||
|
||||
if(ha->pHeader->ExtBlockTablePos.QuadPart != 0)
|
||||
{
|
||||
dwBytes = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx);
|
||||
SetFilePointer(ha->hFile,
|
||||
ha->ExtBlockTablePos.LowPart,
|
||||
&ha->ExtBlockTablePos.HighPart,
|
||||
FILE_BEGIN);
|
||||
ReadFile(ha->hFile, ha->pExtBlockTable, dwBytes, &dwTransferred, NULL);
|
||||
|
||||
// We have to convert every DWORD in ha->block from LittleEndian
|
||||
BSWAP_ARRAY16_UNSIGNED((USHORT *)ha->pExtBlockTable, dwBytes / sizeof(USHORT));
|
||||
|
||||
// The extended block table is not encrypted (so far)
|
||||
if(dwTransferred != dwBytes)
|
||||
nError = ERROR_FILE_CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the both block tables (If the MPQ file is not protected)
|
||||
if(nError == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_PROTECTED) == 0)
|
||||
{
|
||||
TMPQBlockEx * pBlockEx = ha->pExtBlockTable;
|
||||
TMPQBlock * pBlockEnd = ha->pBlockTable + dwMaxBlockIndex + 1;
|
||||
TMPQBlock * pBlock = ha->pBlockTable;
|
||||
|
||||
// If the MPQ file is not protected,
|
||||
// we will check if all sizes in the block table is correct.
|
||||
// Note that we will not relocate the block table (change from previous versions)
|
||||
for(; pBlock < pBlockEnd; pBlock++, pBlockEx++)
|
||||
{
|
||||
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
|
||||
{
|
||||
// Get the 64-bit file position
|
||||
TempPos.HighPart = pBlockEx->wFilePosHigh;
|
||||
TempPos.LowPart = pBlock->dwFilePos;
|
||||
|
||||
if(TempPos.QuadPart > ha->MpqSize.QuadPart || pBlock->dwCSize > ha->MpqSize.QuadPart)
|
||||
{
|
||||
nError = ERROR_BAD_FORMAT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the user didn't specified otherwise,
|
||||
// include the internal listfile to the TMPQArchive structure
|
||||
if((dwFlags & MPQ_OPEN_NO_LISTFILE) == 0)
|
||||
{
|
||||
if(nError == ERROR_SUCCESS)
|
||||
SListFileCreateListFile(ha);
|
||||
|
||||
// Add the internal listfile
|
||||
if(nError == ERROR_SUCCESS)
|
||||
SFileAddListFile((HANDLE)ha, NULL);
|
||||
}
|
||||
|
||||
// Cleanup and exit
|
||||
if(nError != ERROR_SUCCESS)
|
||||
{
|
||||
FreeMPQArchive(ha);
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hFile);
|
||||
SetLastError(nError);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pFirstOpen == NULL)
|
||||
pFirstOpen = ha;
|
||||
}
|
||||
*phMPQ = ha;
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
BOOL WINAPI SFileOpenArchive(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMPQ)
|
||||
{
|
||||
return SFileOpenArchiveEx(szMpqName, dwPriority, dwFlags, phMPQ, GENERIC_READ);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// BOOL SFileCloseArchive(HANDLE hMPQ);
|
||||
//
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileCloseArchive(HANDLE hMPQ)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
|
||||
if(!IsValidMpqHandle(ha))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(ha->dwFlags & MPQ_FLAG_CHANGED)
|
||||
{
|
||||
SListFileSaveToMpq(ha);
|
||||
SaveMPQTables(ha);
|
||||
}
|
||||
FreeMPQArchive(ha);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
403
src/tools/stuffextract/StormLib/SFileOpenFileEx.cpp
Normal file
403
src/tools/stuffextract/StormLib/SFileOpenFileEx.cpp
Normal file
@ -0,0 +1,403 @@
|
||||
/*****************************************************************************/
|
||||
/* SFileOpenFileEx.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Description : */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.99 1.00 Lad The first version of SFileOpenFileEx.cpp */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Local functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
static BOOL OpenLocalFile(const char * szFileName, HANDLE * phFile)
|
||||
{
|
||||
TMPQFile * hf = NULL;
|
||||
HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Allocate and initialize file handle
|
||||
size_t nHandleSize = sizeof(TMPQFile) + strlen(szFileName);
|
||||
if((hf = (TMPQFile *)ALLOCMEM(char, nHandleSize)) != NULL)
|
||||
{
|
||||
memset(hf, 0, nHandleSize);
|
||||
strcpy(hf->szFileName, szFileName);
|
||||
hf->hFile = hFile;
|
||||
*phFile = hf;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
*phFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
static void FreeMPQFile(TMPQFile *& hf)
|
||||
{
|
||||
if(hf != NULL)
|
||||
{
|
||||
if(hf->hFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hf->hFile);
|
||||
if(hf->pdwBlockPos != NULL)
|
||||
FREEMEM(hf->pdwBlockPos);
|
||||
if(hf->pbFileBuffer != NULL)
|
||||
FREEMEM(hf->pbFileBuffer);
|
||||
FREEMEM(hf);
|
||||
hf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Public functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFileEnumLocales enums all locale versions within MPQ.
|
||||
// Functions fills all available language identifiers on a file into the buffer
|
||||
// pointed by plcLocales. There must be enough entries to copy the localed,
|
||||
// otherwise the function returns ERROR_INSUFFICIENT_BUFFER.
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
int WINAPI SFileEnumLocales(
|
||||
HANDLE hMPQ,
|
||||
const char * szFileName,
|
||||
LCID * plcLocales,
|
||||
DWORD * pdwMaxLocales,
|
||||
DWORD dwSearchScope)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
TMPQHash * pHash = NULL;
|
||||
TMPQHash * pHashEnd = NULL;
|
||||
DWORD dwLocales = 0;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Test the parameters
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!IsValidMpqHandle(ha) || pdwMaxLocales == NULL)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
if(dwSearchScope == SFILE_OPEN_BY_INDEX && (DWORD_PTR)szFileName > ha->pHeader->dwBlockTableSize)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
if(dwSearchScope != SFILE_OPEN_BY_INDEX && *szFileName == 0)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Retrieve the hash entry for the required file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||
|
||||
if(dwSearchScope == SFILE_OPEN_BY_INDEX)
|
||||
{
|
||||
for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
|
||||
{
|
||||
if(pHash->dwBlockIndex == (DWORD_PTR)szFileName)
|
||||
break;
|
||||
}
|
||||
if(pHash == pHashEnd)
|
||||
pHash = NULL;
|
||||
}
|
||||
else
|
||||
pHash = GetHashEntry(ha, szFileName);
|
||||
}
|
||||
|
||||
// If the file was not found, sorry
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(pHash == NULL)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Count the entries which correspond to the same file name
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
TMPQHash * pSaveHash = pHash;
|
||||
DWORD dwName1 = pHash->dwName1;
|
||||
DWORD dwName2 = pHash->dwName2;
|
||||
|
||||
// For nameless access, return 1 locale always
|
||||
if(dwSearchScope == SFILE_OPEN_BY_INDEX)
|
||||
dwLocales++;
|
||||
else
|
||||
{
|
||||
while(pHash < pHashEnd && pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2)
|
||||
{
|
||||
dwLocales++;
|
||||
pHash++;
|
||||
}
|
||||
}
|
||||
|
||||
pHash = pSaveHash;
|
||||
}
|
||||
|
||||
// Test if there is enough space to copy the locales
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD dwMaxLocales = *pdwMaxLocales;
|
||||
|
||||
*pdwMaxLocales = dwLocales;
|
||||
if(dwMaxLocales < dwLocales)
|
||||
nError = ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Fill all the locales
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
for(DWORD i = 0; i < dwLocales; i++, pHash++)
|
||||
*plcLocales++ = (LCID)pHash->lcLocale;
|
||||
}
|
||||
return nError;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFileHasFile
|
||||
//
|
||||
// hMPQ - Handle of opened MPQ archive
|
||||
// szFileName - Name of file to look for
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileHasFile(HANDLE hMPQ, char * szFileName)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(ha == NULL)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
if(*szFileName == 0)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Prepare the file opening
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(GetHashEntryEx(ha, szFileName, lcLocale) == NULL)
|
||||
{
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
if(nError != ERROR_SUCCESS)
|
||||
{
|
||||
SetLastError(nError);
|
||||
}
|
||||
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFileOpenFileEx
|
||||
//
|
||||
// hMPQ - Handle of opened MPQ archive
|
||||
// szFileName - Name of file to open
|
||||
// dwSearchScope - Where to search
|
||||
// phFile - Pointer to store opened file handle
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
|
||||
{
|
||||
LARGE_INTEGER FilePos;
|
||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||
TMPQFile * hf = NULL;
|
||||
TMPQHash * pHash = NULL; // Hash table index
|
||||
TMPQBlock * pBlock = NULL; // File block
|
||||
TMPQBlockEx * pBlockEx = NULL;
|
||||
DWORD dwHashIndex = 0; // Hash table index
|
||||
DWORD dwBlockIndex = (DWORD)-1; // Found table index
|
||||
size_t nHandleSize = 0; // Memory space necessary to allocate TMPQHandle
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Due to increasing numbers of files in MPQs, I had to change the behavior
|
||||
// of opening by file index. Now, the SFILE_OPEN_BY_INDEX value of dwSearchScope
|
||||
// must be entered. This check will allow to find code places that are incompatible
|
||||
// with the new behavior.
|
||||
if(dwSearchScope != SFILE_OPEN_BY_INDEX && szFileName != NULL)
|
||||
{
|
||||
assert((DWORD_PTR)szFileName > 0x10000);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(ha == NULL && dwSearchScope == SFILE_OPEN_FROM_MPQ)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
if(phFile == NULL)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
if(dwSearchScope == SFILE_OPEN_BY_INDEX && (DWORD_PTR)szFileName > ha->pHeader->dwBlockTableSize)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
if(dwSearchScope != SFILE_OPEN_BY_INDEX && (szFileName == NULL || *szFileName == 0))
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Prepare the file opening
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// When the file is given by number, ...
|
||||
if(dwSearchScope == SFILE_OPEN_BY_INDEX)
|
||||
{
|
||||
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||
|
||||
// Set handle size to be sizeof(TMPQFile) + length of FileXXXXXXXX.xxx
|
||||
nHandleSize = sizeof(TMPQFile) + 20;
|
||||
for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
|
||||
{
|
||||
if((DWORD_PTR)szFileName == pHash->dwBlockIndex)
|
||||
{
|
||||
dwHashIndex = (DWORD)(pHash - ha->pHashTable);
|
||||
dwBlockIndex = pHash->dwBlockIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have to open a disk file
|
||||
if(dwSearchScope == SFILE_OPEN_LOCAL_FILE)
|
||||
return OpenLocalFile(szFileName, phFile);
|
||||
|
||||
nHandleSize = sizeof(TMPQFile) + strlen(szFileName);
|
||||
if((pHash = GetHashEntryEx(ha, szFileName, lcLocale)) != NULL)
|
||||
{
|
||||
dwHashIndex = (DWORD)(pHash - ha->pHashTable);
|
||||
dwBlockIndex = pHash->dwBlockIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get block index from file name and test it
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// If index was not found, or is greater than number of files, exit.
|
||||
if(dwBlockIndex == (DWORD)-1 || dwBlockIndex > ha->pHeader->dwBlockTableSize)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Get block and test if the file was not already deleted.
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Get both block tables and file position
|
||||
pBlockEx = ha->pExtBlockTable + dwBlockIndex;
|
||||
pBlock = ha->pBlockTable + dwBlockIndex;
|
||||
FilePos.HighPart = pBlockEx->wFilePosHigh;
|
||||
FilePos.LowPart = pBlock->dwFilePos;
|
||||
|
||||
if(FilePos.QuadPart > ha->MpqSize.QuadPart ||
|
||||
pBlock->dwCSize > ha->MpqSize.QuadPart)
|
||||
nError = ERROR_FILE_CORRUPT;
|
||||
if((pBlock->dwFlags & MPQ_FILE_EXISTS) == 0)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
if(pBlock->dwFlags & ~MPQ_FILE_VALID_FLAGS)
|
||||
nError = ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
// Allocate file handle
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((hf = (TMPQFile *)ALLOCMEM(char, nHandleSize)) == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// Initialize file handle
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
memset(hf, 0, nHandleSize);
|
||||
hf->hFile = INVALID_HANDLE_VALUE;
|
||||
hf->ha = ha;
|
||||
hf->pBlockEx = pBlockEx;
|
||||
hf->pBlock = pBlock;
|
||||
hf->nBlocks = (hf->pBlock->dwFSize + ha->dwBlockSize - 1) / ha->dwBlockSize;
|
||||
hf->pHash = pHash;
|
||||
|
||||
hf->MpqFilePos.HighPart = pBlockEx->wFilePosHigh;
|
||||
hf->MpqFilePos.LowPart = pBlock->dwFilePos;
|
||||
hf->MpqFilePos.QuadPart += ha->MpqPos.QuadPart;
|
||||
|
||||
hf->dwHashIndex = dwHashIndex;
|
||||
hf->dwFileIndex = dwBlockIndex;
|
||||
|
||||
// Allocate buffers for decompression.
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
||||
{
|
||||
// Allocate buffer for block positions. At the begin of file are stored
|
||||
// DWORDs holding positions of each block relative from begin of file in the archive
|
||||
// As for newer MPQs, there may be one additional entry in the block table
|
||||
// (if the MPQ_FILE_HAS_EXTRA flag is set).
|
||||
// Allocate the buffer to include this DWORD as well
|
||||
|
||||
if((hf->pdwBlockPos = ALLOCMEM(DWORD, hf->nBlocks + 2)) == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
// Decrypt file seed. Cannot be used if the file is given by index
|
||||
if(dwSearchScope != SFILE_OPEN_BY_INDEX)
|
||||
{
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_ENCRYPTED)
|
||||
{
|
||||
const char * szTemp = strrchr(szFileName, '\\');
|
||||
|
||||
strcpy(hf->szFileName, szFileName);
|
||||
if(szTemp != NULL)
|
||||
szFileName = szTemp + 1;
|
||||
hf->dwSeed1 = DecryptFileSeed((char *)szFileName);
|
||||
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED)
|
||||
{
|
||||
hf->dwSeed1 = (hf->dwSeed1 + hf->pBlock->dwFilePos) ^ hf->pBlock->dwFSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the file is encrypted and not compressed, we cannot detect the file seed
|
||||
if(SFileGetFileName(hf, hf->szFileName) == FALSE)
|
||||
nError = GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
if(nError != ERROR_SUCCESS)
|
||||
{
|
||||
FreeMPQFile(hf);
|
||||
SetLastError(nError);
|
||||
}
|
||||
|
||||
*phFile = hf;
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// BOOL SFileCloseFile(HANDLE hFile);
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileCloseFile(HANDLE hFile)
|
||||
{
|
||||
TMPQFile * hf = (TMPQFile *)hFile;
|
||||
|
||||
if(!IsValidFileHandle(hf))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set the last accessed file in the archive
|
||||
if(hf->ha != NULL)
|
||||
hf->ha->pLastFile = NULL;
|
||||
|
||||
// Free the structure
|
||||
FreeMPQFile(hf);
|
||||
return TRUE;
|
||||
}
|
||||
826
src/tools/stuffextract/StormLib/SFileReadFile.cpp
Normal file
826
src/tools/stuffextract/StormLib/SFileReadFile.cpp
Normal file
@ -0,0 +1,826 @@
|
||||
/*****************************************************************************/
|
||||
/* SFileReadFile.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Description : */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.99 1.00 Lad The first version of SFileReadFile.cpp */
|
||||
/* 24.03.99 1.00 Lad Added the SFileGetFileInfo function */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define ID_WAVE 0x46464952 // Signature of WAVes for name breaking
|
||||
#define ID_EXE 0x00005A4D // Signature of executable files
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local structures
|
||||
|
||||
struct TID2Ext
|
||||
{
|
||||
DWORD dwID;
|
||||
char * szExt;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ReadMPQBlock
|
||||
//
|
||||
// hf - MPQ File handle.
|
||||
// dwBlockPos - Position of block in the file (relative to file begin)
|
||||
// buffer - Pointer to target buffer to store blocks.
|
||||
// dwBlockSize - Number of bytes to read. Must be multiplier of block size.
|
||||
//
|
||||
// Returns number of bytes read.
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer, DWORD blockBytes)
|
||||
{
|
||||
LARGE_INTEGER FilePos;
|
||||
TMPQArchive * ha = hf->ha; // Archive handle
|
||||
BYTE * tempBuffer = NULL; // Buffer for reading compressed data from the file
|
||||
DWORD dwFilePos = dwBlockPos; // Reading position from the file
|
||||
DWORD dwToRead; // Number of bytes to read
|
||||
DWORD blockNum; // Block number (needed for decrypt)
|
||||
DWORD dwBytesRead = 0; // Total number of bytes read
|
||||
DWORD bytesRemain = 0; // Number of data bytes remaining up to the end of the file
|
||||
DWORD nBlocks; // Number of blocks to load
|
||||
DWORD i;
|
||||
|
||||
// Test parameters. Block position and block size must be block-aligned, block size nonzero
|
||||
if((dwBlockPos & (ha->dwBlockSize - 1)) || blockBytes == 0)
|
||||
return 0;
|
||||
|
||||
// Check the end of file
|
||||
if((dwBlockPos + blockBytes) > hf->pBlock->dwFSize)
|
||||
blockBytes = hf->pBlock->dwFSize - dwBlockPos;
|
||||
|
||||
bytesRemain = hf->pBlock->dwFSize - dwBlockPos;
|
||||
blockNum = dwBlockPos / ha->dwBlockSize;
|
||||
nBlocks = blockBytes / ha->dwBlockSize;
|
||||
if(blockBytes % ha->dwBlockSize)
|
||||
nBlocks++;
|
||||
|
||||
// If file has variable block positions, we have to load them
|
||||
if((hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED) && hf->bBlockPosLoaded == FALSE)
|
||||
{
|
||||
// Move file pointer to the begin of the file in the MPQ
|
||||
if(hf->MpqFilePos.QuadPart != ha->FilePointer.QuadPart)
|
||||
{
|
||||
SetFilePointer(ha->hFile, hf->MpqFilePos.LowPart, &hf->MpqFilePos.HighPart, FILE_BEGIN);
|
||||
}
|
||||
|
||||
// Read block positions from begin of file.
|
||||
dwToRead = (hf->nBlocks+1) * sizeof(DWORD);
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_HAS_EXTRA)
|
||||
dwToRead += sizeof(DWORD);
|
||||
|
||||
// Read the block pos table and convert the buffer to little endian
|
||||
ReadFile(ha->hFile, hf->pdwBlockPos, dwToRead, &dwBytesRead, NULL);
|
||||
BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, (hf->nBlocks+1));
|
||||
|
||||
//
|
||||
// If the archive if protected some way, perform additional check
|
||||
// Sometimes, the file appears not to be encrypted, but it is.
|
||||
//
|
||||
// Note: In WoW 1.10+, there's a new flag. With this flag present,
|
||||
// there's one additional entry in the block table.
|
||||
//
|
||||
|
||||
if(hf->pdwBlockPos[0] != dwBytesRead)
|
||||
hf->pBlock->dwFlags |= MPQ_FILE_ENCRYPTED;
|
||||
|
||||
// Decrypt loaded block positions if necessary
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_ENCRYPTED)
|
||||
{
|
||||
// If we don't know the file seed, try to find it.
|
||||
if(hf->dwSeed1 == 0)
|
||||
hf->dwSeed1 = DetectFileSeed(hf->pdwBlockPos, dwBytesRead);
|
||||
|
||||
// If we don't know the file seed, sorry but we cannot extract the file.
|
||||
if(hf->dwSeed1 == 0)
|
||||
return 0;
|
||||
|
||||
// Decrypt block positions
|
||||
DecryptMPQBlock(hf->pdwBlockPos, dwBytesRead, hf->dwSeed1 - 1);
|
||||
|
||||
// Check if the block positions are correctly decrypted
|
||||
// I don't know why, but sometimes it will result invalid block positions on some files
|
||||
if(hf->pdwBlockPos[0] != dwBytesRead)
|
||||
{
|
||||
// Try once again to detect file seed and decrypt the blocks
|
||||
// TODO: Test with >4GB
|
||||
SetFilePointer(ha->hFile, hf->MpqFilePos.LowPart, &hf->MpqFilePos.HighPart, FILE_BEGIN);
|
||||
ReadFile(ha->hFile, hf->pdwBlockPos, dwToRead, &dwBytesRead, NULL);
|
||||
|
||||
BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, (hf->nBlocks+1));
|
||||
hf->dwSeed1 = DetectFileSeed(hf->pdwBlockPos, dwBytesRead);
|
||||
DecryptMPQBlock(hf->pdwBlockPos, dwBytesRead, hf->dwSeed1 - 1);
|
||||
|
||||
// Check if the block positions are correctly decrypted
|
||||
if(hf->pdwBlockPos[0] != dwBytesRead)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update hf's variables
|
||||
ha->FilePointer.QuadPart = hf->MpqFilePos.QuadPart + dwBytesRead;
|
||||
hf->bBlockPosLoaded = TRUE;
|
||||
}
|
||||
|
||||
// Get file position and number of bytes to read
|
||||
dwFilePos = dwBlockPos;
|
||||
dwToRead = blockBytes;
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
||||
{
|
||||
dwFilePos = hf->pdwBlockPos[blockNum];
|
||||
dwToRead = hf->pdwBlockPos[blockNum + nBlocks] - dwFilePos;
|
||||
}
|
||||
FilePos.QuadPart = hf->MpqFilePos.QuadPart + dwFilePos;
|
||||
|
||||
// Get work buffer for store read data
|
||||
tempBuffer = buffer;
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
||||
{
|
||||
if((tempBuffer = ALLOCMEM(BYTE, dwToRead)) == NULL)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Set file pointer, if necessary
|
||||
if(ha->FilePointer.QuadPart != FilePos.QuadPart)
|
||||
{
|
||||
SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN);
|
||||
}
|
||||
|
||||
// 15018F87 : Read all requested blocks
|
||||
ReadFile(ha->hFile, tempBuffer, dwToRead, &dwBytesRead, NULL);
|
||||
ha->FilePointer.QuadPart = FilePos.QuadPart + dwBytesRead;
|
||||
|
||||
// Block processing part.
|
||||
DWORD blockStart = 0; // Index of block start in work buffer
|
||||
DWORD blockSize = min(blockBytes, ha->dwBlockSize);
|
||||
DWORD index = blockNum; // Current block index
|
||||
|
||||
dwBytesRead = 0; // Clear read byte counter
|
||||
|
||||
// Walk through all blocks
|
||||
for(i = 0; i < nBlocks; i++, index++)
|
||||
{
|
||||
BYTE * inputBuffer = tempBuffer + blockStart;
|
||||
int outLength = ha->dwBlockSize;
|
||||
|
||||
if(bytesRemain < (DWORD)outLength)
|
||||
outLength = bytesRemain;
|
||||
|
||||
// Get current block length
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
||||
blockSize = hf->pdwBlockPos[index+1] - hf->pdwBlockPos[index];
|
||||
|
||||
// If block is encrypted, we have to decrypt it.
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_ENCRYPTED)
|
||||
{
|
||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)inputBuffer, blockSize / sizeof(DWORD));
|
||||
|
||||
// If we don't know the seed, try to decode it as WAVE file
|
||||
if(hf->dwSeed1 == 0)
|
||||
hf->dwSeed1 = DetectFileSeed2((DWORD *)inputBuffer, 3, ID_WAVE, hf->pBlock->dwFSize - 8, 0x45564157);
|
||||
|
||||
// Let's try MSVC's standard EXE or header
|
||||
if(hf->dwSeed1 == 0)
|
||||
hf->dwSeed1 = DetectFileSeed2((DWORD *)inputBuffer, 2, 0x00905A4D, 0x00000003);
|
||||
|
||||
if(hf->dwSeed1 == 0)
|
||||
return 0;
|
||||
|
||||
DecryptMPQBlock((DWORD *)inputBuffer, blockSize, hf->dwSeed1 + index);
|
||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)inputBuffer, blockSize / sizeof(DWORD));
|
||||
}
|
||||
|
||||
// If the block is really compressed, decompress it.
|
||||
// WARNING : Some block may not be compressed, it can be determined only
|
||||
// by comparing uncompressed and compressed size !!!
|
||||
if(blockSize < (DWORD)outLength)
|
||||
{
|
||||
// Is the file compressed with PKWARE Data Compression Library ?
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS_PKWARE)
|
||||
Decompress_pklib((char *)buffer, &outLength, (char *)inputBuffer, (int)blockSize);
|
||||
|
||||
// Is it a file compressed by Blizzard's multiple compression ?
|
||||
// Note that Storm.dll v 1.0.9 distributed with Warcraft III
|
||||
// passes the full path name of the opened archive as the new last parameter
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS_MULTI)
|
||||
SCompDecompress((char *)buffer, &outLength, (char *)inputBuffer, (int)blockSize);
|
||||
dwBytesRead += outLength;
|
||||
buffer += outLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(buffer != inputBuffer)
|
||||
memcpy(buffer, inputBuffer, blockSize);
|
||||
|
||||
dwBytesRead += blockSize;
|
||||
buffer += blockSize;
|
||||
}
|
||||
blockStart += blockSize;
|
||||
bytesRemain -= outLength;
|
||||
}
|
||||
|
||||
// Delete input buffer, if necessary
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
||||
FREEMEM(tempBuffer);
|
||||
|
||||
return dwBytesRead;
|
||||
}
|
||||
|
||||
// When this function is called, it is already ensured that the parameters are valid
|
||||
// (e.g. the "dwToRead + dwFilePos" is not greater than the file size)
|
||||
// TODO: Test for archives > 4GB
|
||||
static DWORD WINAPI ReadMPQFileSingleUnit(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer, DWORD dwToRead)
|
||||
{
|
||||
TMPQArchive * ha = hf->ha;
|
||||
DWORD dwBytesRead = 0;
|
||||
|
||||
if(ha->FilePointer.QuadPart != hf->MpqFilePos.QuadPart)
|
||||
{
|
||||
SetFilePointer(ha->hFile, hf->MpqFilePos.LowPart, &hf->MpqFilePos.HighPart, FILE_BEGIN);
|
||||
ha->FilePointer = hf->MpqFilePos;
|
||||
}
|
||||
|
||||
// If the file is really compressed, decompress it.
|
||||
// Otherwise, read the data as-is to the caller.
|
||||
if(hf->pBlock->dwCSize < hf->pBlock->dwFSize)
|
||||
{
|
||||
if(hf->pbFileBuffer == NULL)
|
||||
{
|
||||
BYTE * inputBuffer = NULL;
|
||||
int outputBufferSize = (int)hf->pBlock->dwFSize;
|
||||
int inputBufferSize = (int)hf->pBlock->dwCSize;
|
||||
|
||||
hf->pbFileBuffer = ALLOCMEM(BYTE, outputBufferSize);
|
||||
inputBuffer = ALLOCMEM(BYTE, inputBufferSize);
|
||||
if(inputBuffer != NULL && hf->pbFileBuffer != NULL)
|
||||
{
|
||||
// Read the compressed file data
|
||||
ReadFile(ha->hFile, inputBuffer, inputBufferSize, &dwBytesRead, NULL);
|
||||
|
||||
// Is the file compressed with PKWARE Data Compression Library ?
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS_PKWARE)
|
||||
Decompress_pklib((char *)hf->pbFileBuffer, &outputBufferSize, (char *)inputBuffer, (int)inputBufferSize);
|
||||
|
||||
// Is it a file compressed by Blizzard's multiple compression ?
|
||||
// Note that Storm.dll v 1.0.9 distributed with Warcraft III
|
||||
// passes the full path name of the opened archive as the new last parameter
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS_MULTI)
|
||||
SCompDecompress((char *)hf->pbFileBuffer, &outputBufferSize, (char *)inputBuffer, (int)inputBufferSize);
|
||||
}
|
||||
|
||||
// Free the temporary buffer
|
||||
if(inputBuffer != NULL)
|
||||
FREEMEM(inputBuffer);
|
||||
}
|
||||
|
||||
// Copy the file data, if any there
|
||||
if(hf->pbFileBuffer != NULL)
|
||||
{
|
||||
memcpy(pbBuffer, hf->pbFileBuffer + dwFilePos, dwToRead);
|
||||
dwBytesRead += dwToRead;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the uncompressed file data
|
||||
ReadFile(ha->hFile, pbBuffer, dwToRead, &dwBytesRead, NULL);
|
||||
dwBytesRead = (int)dwBytesRead;
|
||||
}
|
||||
|
||||
return (DWORD)dwBytesRead;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ReadMPQFile
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
static DWORD WINAPI ReadMPQFile(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer, DWORD dwToRead)
|
||||
{
|
||||
TMPQArchive * ha = hf->ha;
|
||||
TMPQBlock * pBlock = hf->pBlock; // Pointer to file block
|
||||
DWORD dwBytesRead = 0; // Number of bytes read from the file
|
||||
DWORD dwBlockPos; // Position in the file aligned to the whole blocks
|
||||
DWORD dwLoaded;
|
||||
|
||||
// File position is greater or equal to file size ?
|
||||
if(dwFilePos >= pBlock->dwFSize)
|
||||
return dwBytesRead;
|
||||
|
||||
// If too few bytes in the file remaining, cut them
|
||||
if((pBlock->dwFSize - dwFilePos) < dwToRead)
|
||||
dwToRead = (pBlock->dwFSize - dwFilePos);
|
||||
|
||||
// If the file is stored as single unit, handle it separately
|
||||
if(pBlock->dwFlags & MPQ_FILE_SINGLE_UNIT)
|
||||
return ReadMPQFileSingleUnit(hf, dwFilePos, pbBuffer, dwToRead);
|
||||
|
||||
// Block position in the file
|
||||
dwBlockPos = dwFilePos & ~(ha->dwBlockSize - 1); // Position in the block
|
||||
|
||||
// Load the first block, if incomplete. It may be loaded in the cache buffer.
|
||||
// We have to check if this block is loaded. If not, load it.
|
||||
if((dwFilePos % ha->dwBlockSize) != 0)
|
||||
{
|
||||
// Number of bytes remaining in the buffer
|
||||
DWORD dwToCopy;
|
||||
DWORD dwLoaded = ha->dwBlockSize;
|
||||
|
||||
// Check if data are loaded in the cache
|
||||
if(hf != ha->pLastFile || dwBlockPos != ha->dwBlockPos)
|
||||
{
|
||||
// Load one MPQ block into archive buffer
|
||||
dwLoaded = ReadMPQBlocks(hf, dwBlockPos, ha->pbBlockBuffer, ha->dwBlockSize);
|
||||
if(dwLoaded == 0)
|
||||
return (DWORD)-1;
|
||||
|
||||
// Save lastly accessed file and block position for later use
|
||||
ha->pLastFile = hf;
|
||||
ha->dwBlockPos = dwBlockPos;
|
||||
ha->dwBuffPos = dwFilePos % ha->dwBlockSize;
|
||||
}
|
||||
dwToCopy = dwLoaded - ha->dwBuffPos;
|
||||
if(dwToCopy > dwToRead)
|
||||
dwToCopy = dwToRead;
|
||||
|
||||
// Copy data from block buffer into target buffer
|
||||
memcpy(pbBuffer, ha->pbBlockBuffer + ha->dwBuffPos, dwToCopy);
|
||||
|
||||
// Update pointers
|
||||
dwToRead -= dwToCopy;
|
||||
dwBytesRead += dwToCopy;
|
||||
pbBuffer += dwToCopy;
|
||||
dwBlockPos += ha->dwBlockSize;
|
||||
ha->dwBuffPos += dwToCopy;
|
||||
|
||||
// If all, return.
|
||||
if(dwToRead == 0)
|
||||
return dwBytesRead;
|
||||
}
|
||||
|
||||
// Load the whole ("middle") blocks only if there are more or equal one block
|
||||
if(dwToRead > ha->dwBlockSize)
|
||||
{
|
||||
DWORD dwBlockBytes = dwToRead & ~(ha->dwBlockSize - 1);
|
||||
|
||||
dwLoaded = ReadMPQBlocks(hf, dwBlockPos, pbBuffer, dwBlockBytes);
|
||||
if(dwLoaded == 0)
|
||||
return (DWORD)-1;
|
||||
|
||||
// Update pointers
|
||||
dwToRead -= dwLoaded;
|
||||
dwBytesRead += dwLoaded;
|
||||
pbBuffer += dwLoaded;
|
||||
dwBlockPos += dwLoaded;
|
||||
|
||||
// If all, return.
|
||||
if(dwToRead == 0)
|
||||
return dwBytesRead;
|
||||
}
|
||||
|
||||
// Load the terminating block
|
||||
if(dwToRead > 0)
|
||||
{
|
||||
DWORD dwToCopy = ha->dwBlockSize;
|
||||
|
||||
// Check if data are loaded in the cache
|
||||
if(hf != ha->pLastFile || dwBlockPos != ha->dwBlockPos)
|
||||
{
|
||||
// Load one MPQ block into archive buffer
|
||||
dwToCopy = ReadMPQBlocks(hf, dwBlockPos, ha->pbBlockBuffer, ha->dwBlockSize);
|
||||
if(dwToCopy == 0)
|
||||
return (DWORD)-1;
|
||||
|
||||
// Save lastly accessed file and block position for later use
|
||||
ha->pLastFile = hf;
|
||||
ha->dwBlockPos = dwBlockPos;
|
||||
}
|
||||
ha->dwBuffPos = 0;
|
||||
|
||||
// Check number of bytes read
|
||||
if(dwToCopy > dwToRead)
|
||||
dwToCopy = dwToRead;
|
||||
|
||||
memcpy(pbBuffer, ha->pbBlockBuffer, dwToCopy);
|
||||
dwBytesRead += dwToCopy;
|
||||
ha->dwBuffPos = dwToCopy;
|
||||
}
|
||||
|
||||
// Return what we've read
|
||||
return dwBytesRead;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFileReadFile
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileReadFile(HANDLE hFile, VOID * lpBuffer, DWORD dwToRead, DWORD * pdwRead, LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
TMPQFile * hf = (TMPQFile *)hFile;
|
||||
DWORD dwBytes = 0; // Number of bytes (for everything)
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Zero the number of bytes read
|
||||
if(pdwRead != NULL)
|
||||
*pdwRead = 0;
|
||||
|
||||
// Check valid parameters
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(hf == NULL || lpBuffer == NULL)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// If direct access to the file, use Win32 for reading
|
||||
if(nError == ERROR_SUCCESS && hf->hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD dwTransferred;
|
||||
|
||||
ReadFile(hf->hFile, lpBuffer, dwToRead, &dwTransferred, lpOverlapped);
|
||||
if(dwTransferred < dwToRead)
|
||||
{
|
||||
SetLastError(ERROR_HANDLE_EOF);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(pdwRead != NULL)
|
||||
*pdwRead = dwTransferred;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Read all the bytes available in the buffer (If any)
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(dwToRead > 0)
|
||||
{
|
||||
dwBytes = ReadMPQFile(hf, hf->dwFilePos, (BYTE *)lpBuffer, dwToRead);
|
||||
if(dwBytes == (DWORD)-1)
|
||||
{
|
||||
SetLastError(ERROR_CAN_NOT_COMPLETE);
|
||||
return FALSE;
|
||||
}
|
||||
hf->ha->pLastFile = hf;
|
||||
hf->dwFilePos += dwBytes;
|
||||
}
|
||||
if(pdwRead != NULL)
|
||||
*pdwRead = dwBytes;
|
||||
}
|
||||
|
||||
// Check number of bytes read. If not OK, return FALSE.
|
||||
if(dwBytes < dwToRead)
|
||||
{
|
||||
SetLastError(ERROR_HANDLE_EOF);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFileGetFilePos
|
||||
//
|
||||
// Returns position of archive file in the archive (relative to begin of file)
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
DWORD WINAPI SFileGetFilePos(HANDLE hFile, DWORD * pdwFilePosHigh)
|
||||
{
|
||||
TMPQFile * hf = (TMPQFile *)hFile;
|
||||
|
||||
if(pdwFilePosHigh != NULL)
|
||||
*pdwFilePosHigh = 0;
|
||||
|
||||
if(hf == NULL)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return (DWORD)-1;
|
||||
}
|
||||
|
||||
// If opened as plain file, ...
|
||||
if(hf->hFile != INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
// If opened from archive, return file size
|
||||
if(pdwFilePosHigh != NULL)
|
||||
*pdwFilePosHigh = hf->MpqFilePos.HighPart;
|
||||
return hf->MpqFilePos.LowPart;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFileGetFileSize
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh)
|
||||
{
|
||||
TMPQFile * hf = (TMPQFile *)hFile;
|
||||
|
||||
if(pdwFileSizeHigh != NULL)
|
||||
*pdwFileSizeHigh = 0;
|
||||
|
||||
if(hf == NULL)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return (DWORD)-1;
|
||||
}
|
||||
|
||||
// If opened as plain file, ...
|
||||
if(hf->hFile != INVALID_HANDLE_VALUE)
|
||||
return GetFileSize(hf->hFile, pdwFileSizeHigh);
|
||||
|
||||
// If opened from archive, return file size
|
||||
return hf->pBlock->dwFSize;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * pdwFilePosHigh, DWORD dwMethod)
|
||||
{
|
||||
TMPQArchive * ha;
|
||||
TMPQFile * hf = (TMPQFile *)hFile;
|
||||
|
||||
if(hf == NULL || (pdwFilePosHigh != NULL && *pdwFilePosHigh != 0))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return (DWORD)-1;
|
||||
}
|
||||
|
||||
// If opened as plain file, call Win32 API
|
||||
if(hf->hFile != INVALID_HANDLE_VALUE)
|
||||
return SetFilePointer(hf->hFile, lFilePos, pdwFilePosHigh, dwMethod);
|
||||
ha = hf->ha;
|
||||
|
||||
switch(dwMethod)
|
||||
{
|
||||
case FILE_BEGIN:
|
||||
// Cannot set pointer before begin of file
|
||||
if(-lFilePos > (LONG)hf->dwFilePos)
|
||||
hf->dwFilePos = 0;
|
||||
else
|
||||
hf->dwFilePos = lFilePos;
|
||||
break;
|
||||
|
||||
case FILE_CURRENT:
|
||||
// Cannot set pointer before begin of file
|
||||
if(-lFilePos > (LONG)hf->dwFilePos)
|
||||
hf->dwFilePos = 0;
|
||||
else
|
||||
hf->dwFilePos += lFilePos;
|
||||
break;
|
||||
|
||||
case FILE_END:
|
||||
// Cannot set file position before begin of file
|
||||
if(-lFilePos >= (LONG)hf->pBlock->dwFSize)
|
||||
hf->dwFilePos = 0;
|
||||
else
|
||||
hf->dwFilePos = hf->pBlock->dwFSize + lFilePos;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if(hf == ha->pLastFile && (hf->dwFilePos & ~(ha->dwBlockSize - 1)) == ha->dwBlockPos)
|
||||
ha->dwBuffPos = hf->dwFilePos & (ha->dwBlockSize - 1);
|
||||
else
|
||||
{
|
||||
ha->pLastFile = NULL;
|
||||
ha->dwBuffPos = 0;
|
||||
}
|
||||
|
||||
return hf->dwFilePos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tries to retrieve the file name
|
||||
|
||||
static TID2Ext id2ext[] =
|
||||
{
|
||||
{0x1A51504D, "mpq"}, // MPQ archive header ID ('MPQ\x1A')
|
||||
{0x46464952, "wav"}, // WAVE header 'RIFF'
|
||||
{0x324B4D53, "smk"}, // Old "Smacker Video" files 'SMK2'
|
||||
{0x694B4942, "bik"}, // Bink video files (new)
|
||||
{0x0801050A, "pcx"}, // PCX images used in Diablo I
|
||||
{0x544E4F46, "fnt"}, // Font files used in Diablo II
|
||||
{0x6D74683C, "html"}, // HTML '<htm'
|
||||
{0x4D54483C, "html"}, // HTML '<HTM
|
||||
{0x216F6F57, "tbl"}, // Table files
|
||||
{0x31504C42, "blp"}, // BLP textures
|
||||
{0x32504C42, "blp"}, // BLP textures (v2)
|
||||
{0x584C444D, "mdx"}, // MDX files
|
||||
{0x45505954, "pud"}, // Warcraft II maps
|
||||
{0x38464947, "gif"}, // GIF images 'GIF8'
|
||||
{0x3032444D, "m2"}, // WoW ??? .m2
|
||||
{0x43424457, "dbc"}, // ??? .dbc
|
||||
{0x47585053, "bls"}, // WoW pixel shaders
|
||||
{0, NULL} // Terminator
|
||||
};
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
|
||||
{
|
||||
TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle
|
||||
char * szExt = "xxx"; // Default extension
|
||||
DWORD dwFirstBytes[2]; // The first 4 bytes of the file
|
||||
DWORD dwFilePos; // Saved file position
|
||||
int nError = ERROR_SUCCESS;
|
||||
int i;
|
||||
|
||||
// Pre-zero the output buffer
|
||||
if(szFileName != NULL)
|
||||
*szFileName = 0;
|
||||
|
||||
// Check valid parameters
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(hf == NULL || szFileName == NULL)
|
||||
nError = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// If the file name is already filled, return it.
|
||||
if(nError == ERROR_SUCCESS && *hf->szFileName != 0)
|
||||
{
|
||||
if(szFileName != hf->szFileName)
|
||||
strcpy(szFileName, hf->szFileName);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(hf->dwFileIndex == (DWORD)-1)
|
||||
nError = ERROR_CAN_NOT_COMPLETE;
|
||||
}
|
||||
|
||||
// Read the first 8 bytes from the file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
dwFirstBytes[0] = dwFirstBytes[1] = 0;
|
||||
dwFilePos = SFileSetFilePointer(hf, 0, NULL, FILE_CURRENT);
|
||||
if(!SFileReadFile(hFile, &dwFirstBytes, sizeof(dwFirstBytes), NULL))
|
||||
nError = GetLastError();
|
||||
BSWAP_ARRAY32_UNSIGNED(dwFirstBytes, sizeof(dwFirstBytes) / sizeof(DWORD));
|
||||
SFileSetFilePointer(hf, dwFilePos, NULL, FILE_BEGIN);
|
||||
}
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if((dwFirstBytes[0] & 0x0000FFFF) == ID_EXE)
|
||||
szExt = "exe";
|
||||
else if(dwFirstBytes[0] == 0x00000006 && dwFirstBytes[1] == 0x00000001)
|
||||
szExt = "dc6";
|
||||
else
|
||||
{
|
||||
for(i = 0; id2ext[i].szExt != NULL; i++)
|
||||
{
|
||||
if(id2ext[i].dwID == dwFirstBytes[0])
|
||||
{
|
||||
szExt = id2ext[i].szExt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the file name
|
||||
sprintf(hf->szFileName, "File%08lu.%s", hf->dwFileIndex, szExt);
|
||||
if(szFileName != hf->szFileName)
|
||||
strcpy(szFileName, hf->szFileName);
|
||||
}
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Retrieves an information about an archive or about a file within the archive
|
||||
//
|
||||
// hMpqOrFile - Handle to an MPQ archive or to a file
|
||||
// dwInfoType - Information to obtain
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType)
|
||||
{
|
||||
TMPQArchive * ha = (TMPQArchive *)hMpqOrFile;
|
||||
TMPQFile * hf = (TMPQFile *)hMpqOrFile;
|
||||
TMPQBlock * pBlockEnd;
|
||||
TMPQBlock * pBlock;
|
||||
DWORD dwFileCount = 0;
|
||||
DWORD dwSeed;
|
||||
|
||||
switch(dwInfoType)
|
||||
{
|
||||
case SFILE_INFO_ARCHIVE_SIZE:
|
||||
if(IsValidMpqHandle(ha))
|
||||
return ha->pHeader->dwArchiveSize;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_HASH_TABLE_SIZE: // Size of the hash table
|
||||
if(IsValidMpqHandle(ha))
|
||||
return ha->pHeader->dwHashTableSize;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_BLOCK_TABLE_SIZE: // Size of the hash table
|
||||
if(IsValidMpqHandle(ha))
|
||||
return ha->pHeader->dwBlockTableSize;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_BLOCK_SIZE:
|
||||
if(IsValidMpqHandle(ha))
|
||||
return ha->dwBlockSize;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_HASH_TABLE:
|
||||
if(IsValidMpqHandle(ha))
|
||||
return (DWORD_PTR)ha->pHashTable;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_BLOCK_TABLE:
|
||||
if(IsValidMpqHandle(ha))
|
||||
return (DWORD_PTR)ha->pBlockTable;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_NUM_FILES:
|
||||
if(IsValidMpqHandle(ha))
|
||||
{
|
||||
pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize;
|
||||
for(pBlock = ha->pBlockTable; pBlock < pBlockEnd; pBlock++)
|
||||
{
|
||||
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
|
||||
dwFileCount++;
|
||||
}
|
||||
return dwFileCount;
|
||||
}
|
||||
break;
|
||||
|
||||
case SFILE_INFO_HASH_INDEX:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->dwHashIndex;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_CODENAME1:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->pHash->dwName1;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_CODENAME2:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->pHash->dwName2;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_LOCALEID:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->pHash->lcLocale;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_BLOCKINDEX:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->dwFileIndex;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_FILE_SIZE:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->pBlock->dwFSize;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_COMPRESSED_SIZE:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->pBlock->dwCSize;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_FLAGS:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->pBlock->dwFlags;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_POSITION:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->pBlock->dwFilePos;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_SEED:
|
||||
if(IsValidFileHandle(hf))
|
||||
return hf->dwSeed1;
|
||||
break;
|
||||
|
||||
case SFILE_INFO_SEED_UNFIXED:
|
||||
if(IsValidFileHandle(hf))
|
||||
{
|
||||
dwSeed = hf->dwSeed1;
|
||||
if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED)
|
||||
dwSeed = (dwSeed ^ hf->pBlock->dwFSize) - (DWORD)(hf->MpqFilePos.QuadPart - hf->ha->MpqPos.QuadPart);
|
||||
return dwSeed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Unknown parameter or invalid handle
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
561
src/tools/stuffextract/StormLib/SListFile.cpp
Normal file
561
src/tools/stuffextract/StormLib/SListFile.cpp
Normal file
@ -0,0 +1,561 @@
|
||||
/*****************************************************************************/
|
||||
/* SListFile.cpp Copyright (c) Ladislav Zezula 2004 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Description: */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 12.06.04 1.00 Lad The first version of SListFile.cpp */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
#include "StormLib.h"
|
||||
#include "SCommon.h"
|
||||
#include <assert.h>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Listfile entry structure
|
||||
|
||||
#define LISTFILE_CACHE_SIZE 0x1000 // Size of one cache element
|
||||
#define NO_MORE_CHARACTERS 256
|
||||
#define HASH_TABLE_SIZE 31 // Initial hash table size (should be a prime number)
|
||||
|
||||
// TODO: Check on x64 !!!
|
||||
#define LISTFILE_ENTRY_DELETED (DWORD_PTR)(-2)
|
||||
#define LISTFILE_ENTRY_FREE (DWORD_PTR)(-1)
|
||||
|
||||
struct TListFileCache
|
||||
{
|
||||
HANDLE hFile; // Stormlib file handle
|
||||
char * szMask; // File mask
|
||||
DWORD dwFileSize; // Total size of the cached file
|
||||
DWORD dwBuffSize; // File of the cache
|
||||
DWORD dwFilePos; // Position of the cache in the file
|
||||
BYTE * pBegin; // The begin of the listfile cache
|
||||
BYTE * pPos;
|
||||
BYTE * pEnd; // The last character in the file cache
|
||||
|
||||
BYTE Buffer[1]; // Listfile cache itself
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local functions (cache)
|
||||
|
||||
// Reloads the cache. Returns number of characters
|
||||
// that has been loaded into the cache.
|
||||
static int ReloadCache(TListFileCache * pCache)
|
||||
{
|
||||
// Check if there is enough characters in the cache
|
||||
// If not, we have to reload the next block
|
||||
if(pCache->pPos >= pCache->pEnd)
|
||||
{
|
||||
// If the cache is already at the end, do nothing more
|
||||
if((pCache->dwFilePos + pCache->dwBuffSize) >= pCache->dwFileSize)
|
||||
return 0;
|
||||
|
||||
pCache->dwFilePos += pCache->dwBuffSize;
|
||||
SFileReadFile(pCache->hFile, pCache->Buffer, pCache->dwBuffSize, &pCache->dwBuffSize, NULL);
|
||||
if(pCache->dwBuffSize == 0)
|
||||
return 0;
|
||||
|
||||
// Set the buffer pointers
|
||||
pCache->pBegin =
|
||||
pCache->pPos = &pCache->Buffer[0];
|
||||
pCache->pEnd = pCache->pBegin + pCache->dwBuffSize;
|
||||
}
|
||||
|
||||
return pCache->dwBuffSize;
|
||||
}
|
||||
|
||||
static size_t ReadLine(TListFileCache * pCache, char * szLine, int nMaxChars)
|
||||
{
|
||||
char * szLineBegin = szLine;
|
||||
char * szLineEnd = szLine + nMaxChars - 1;
|
||||
|
||||
__BeginLoading:
|
||||
|
||||
// Skip newlines, spaces, tabs and another non-printable stuff
|
||||
while(pCache->pPos < pCache->pEnd && *pCache->pPos <= 0x20)
|
||||
pCache->pPos++;
|
||||
|
||||
// Copy the remaining characters
|
||||
while(pCache->pPos < pCache->pEnd && szLine < szLineEnd)
|
||||
{
|
||||
// If we have found a newline, stop loading
|
||||
if(*pCache->pPos == 0x0D || *pCache->pPos == 0x0A)
|
||||
break;
|
||||
|
||||
*szLine++ = *pCache->pPos++;
|
||||
}
|
||||
|
||||
// If we now need to reload the cache, do it
|
||||
if(pCache->pPos == pCache->pEnd)
|
||||
{
|
||||
if(ReloadCache(pCache) > 0)
|
||||
goto __BeginLoading;
|
||||
}
|
||||
|
||||
*szLine = 0;
|
||||
return (szLine - szLineBegin);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local functions (listfile nodes)
|
||||
|
||||
// This function creates the name for the listfile.
|
||||
// the file will be created under unique name in the temporary directory
|
||||
static void GetListFileName(TMPQArchive * /* ha */, char * szListFile)
|
||||
{
|
||||
char szTemp[MAX_PATH];
|
||||
|
||||
// Create temporary file name int TEMP directory
|
||||
GetTempPath(sizeof(szTemp)-1, szTemp);
|
||||
GetTempFileName(szTemp, LISTFILE_NAME, 0, szListFile);
|
||||
}
|
||||
|
||||
// Creates new listfile. The listfile is an array of TListFileNode
|
||||
// structures. The size of the array is the same like the hash table size,
|
||||
// the ordering is the same too (listfile item index is the same like
|
||||
// the index in the MPQ hash table)
|
||||
|
||||
int SListFileCreateListFile(TMPQArchive * ha)
|
||||
{
|
||||
DWORD dwItems = ha->pHeader->dwHashTableSize;
|
||||
|
||||
// The listfile should be NULL now
|
||||
assert(ha->pListFile == NULL);
|
||||
|
||||
ha->pListFile = ALLOCMEM(TFileNode *, dwItems);
|
||||
if(ha->pListFile == NULL)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
memset(ha->pListFile, 0xFF, dwItems * sizeof(TFileNode *));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Adds a filename into the listfile. If the file name is already there,
|
||||
// does nothing.
|
||||
int SListFileAddNode(TMPQArchive * ha, const char * szFileName)
|
||||
{
|
||||
TFileNode * pNode = NULL;
|
||||
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||
TMPQHash * pHash0 = GetHashEntry(ha, szFileName);
|
||||
TMPQHash * pHash = pHash0;
|
||||
DWORD dwHashIndex = 0;
|
||||
size_t nLength; // File name lentgth
|
||||
DWORD dwName1;
|
||||
DWORD dwName2;
|
||||
|
||||
// If the file does not exist within the MPQ, do nothing
|
||||
if(pHash == NULL)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// If the listfile entry already exists, do nothing
|
||||
dwHashIndex = (DWORD)(pHash - ha->pHashTable);
|
||||
dwName1 = pHash->dwName1;
|
||||
dwName2 = pHash->dwName2;
|
||||
if((DWORD_PTR)ha->pListFile[dwHashIndex] <= LISTFILE_ENTRY_DELETED)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// Create the listfile node and insert it into the listfile table
|
||||
nLength = strlen(szFileName);
|
||||
pNode = (TFileNode *)ALLOCMEM(char, sizeof(TFileNode) + nLength);
|
||||
pNode->dwRefCount = 0;
|
||||
pNode->nLength = nLength;
|
||||
strcpy(pNode->szFileName, szFileName);
|
||||
|
||||
// Fill the nodes for all language versions
|
||||
while(pHash->dwBlockIndex < LISTFILE_ENTRY_DELETED)
|
||||
{
|
||||
if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2)
|
||||
{
|
||||
pNode->dwRefCount++;
|
||||
ha->pListFile[pHash - ha->pHashTable] = pNode;
|
||||
}
|
||||
|
||||
if(++pHash >= pHashEnd)
|
||||
pHash = ha->pHashTable;
|
||||
if(pHash == pHash0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Removes a filename from the listfile.
|
||||
// If the name is not there, does nothing
|
||||
int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName)
|
||||
{
|
||||
TFileNode * pNode = NULL;
|
||||
TMPQHash * pHash = GetHashEntry(ha, szFileName);
|
||||
size_t nHashIndex = 0;
|
||||
|
||||
if(pHash != NULL)
|
||||
{
|
||||
nHashIndex = pHash - ha->pHashTable;
|
||||
pNode = ha->pListFile[nHashIndex];
|
||||
ha->pListFile[nHashIndex] = (TFileNode *)LISTFILE_ENTRY_DELETED;
|
||||
|
||||
// If the reference count has reached zero, do nothing
|
||||
if(--pNode->dwRefCount == 0)
|
||||
FREEMEM(pNode);
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// Renames a node. We will not deal with the renaming, we'll simply
|
||||
// remove the old node and insert the new one.
|
||||
// TODO: Test for archives > 4GB
|
||||
int SListFileRenameNode(TMPQArchive * ha, const char * szOldFileName, const char * szNewFileName)
|
||||
{
|
||||
SListFileRemoveNode(ha, szOldFileName);
|
||||
return SListFileAddNode(ha, szNewFileName);
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
int SListFileFreeListFile(TMPQArchive * ha)
|
||||
{
|
||||
if(ha->pListFile != NULL)
|
||||
{
|
||||
for(DWORD i = 0; i < ha->pHeader->dwHashTableSize; i++)
|
||||
{
|
||||
TFileNode * pNode = ha->pListFile[i];
|
||||
|
||||
if((DWORD_PTR)pNode < LISTFILE_ENTRY_FREE)
|
||||
{
|
||||
if(--pNode->dwRefCount == 0)
|
||||
{
|
||||
FREEMEM(pNode);
|
||||
ha->pListFile[i] = (TFileNode *)LISTFILE_ENTRY_FREE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FREEMEM(ha->pListFile);
|
||||
ha->pListFile = NULL;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Saves the whole listfile into the MPQ.
|
||||
// TODO: Test for archives > 4GB
|
||||
int SListFileSaveToMpq(TMPQArchive * ha)
|
||||
{
|
||||
TFileNode * pNode = NULL;
|
||||
TMPQHash * pHashEnd = NULL;
|
||||
TMPQHash * pHash0 = NULL;
|
||||
TMPQHash * pHash = NULL;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
char szListFile[MAX_PATH];
|
||||
char szBuffer[MAX_PATH+4];
|
||||
DWORD dwTransferred;
|
||||
size_t nLength = 0;
|
||||
DWORD dwName1 = 0;
|
||||
DWORD dwName2 = 0;
|
||||
LCID lcSave = lcLocale;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// If no listfile, do nothing
|
||||
if(ha->pListFile == NULL)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// Create the local listfile
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
GetListFileName(ha, szListFile);
|
||||
hFile = CreateFile(szListFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
// Find the hash entry corresponding to listfile
|
||||
pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||
pHash0 = pHash = GetHashEntry(ha, 0);
|
||||
if(pHash == NULL)
|
||||
pHash0 = pHash = ha->pHashTable;
|
||||
|
||||
// Save the file
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(pHash->dwName1 != dwName1 && pHash->dwName2 != dwName2 && pHash->dwBlockIndex < LISTFILE_ENTRY_DELETED)
|
||||
{
|
||||
dwName1 = pHash->dwName1;
|
||||
dwName2 = pHash->dwName2;
|
||||
pNode = ha->pListFile[pHash - ha->pHashTable];
|
||||
|
||||
if((DWORD_PTR)pNode < LISTFILE_ENTRY_DELETED)
|
||||
{
|
||||
memcpy(szBuffer, pNode->szFileName, pNode->nLength);
|
||||
szBuffer[pNode->nLength + 0] = 0x0D;
|
||||
szBuffer[pNode->nLength + 1] = 0x0A;
|
||||
WriteFile(hFile, szBuffer, (DWORD)(pNode->nLength + 2), &dwTransferred, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if(++pHash >= pHashEnd)
|
||||
pHash = ha->pHashTable;
|
||||
if(pHash == pHash0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Write the listfile name (if not already there)
|
||||
if(GetHashEntry(ha, LISTFILE_NAME) == NULL)
|
||||
{
|
||||
nLength = strlen(LISTFILE_NAME);
|
||||
memcpy(szBuffer, LISTFILE_NAME, nLength);
|
||||
szBuffer[nLength + 0] = 0x0D;
|
||||
szBuffer[nLength + 1] = 0x0A;
|
||||
WriteFile(hFile, szBuffer, (DWORD)(nLength + 2), &dwTransferred, NULL);
|
||||
}
|
||||
|
||||
// Add the listfile into the archive.
|
||||
SFileSetLocale(LANG_NEUTRAL);
|
||||
nError = AddFileToArchive(ha, hFile, LISTFILE_NAME, MPQ_FILE_COMPRESS_PKWARE | MPQ_FILE_ENCRYPTED | MPQ_FILE_REPLACEEXISTING, 0, SFILE_TYPE_DATA, NULL);
|
||||
}
|
||||
|
||||
// Close the temporary file. This will delete it too.
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hFile);
|
||||
|
||||
lcLocale = lcSave;
|
||||
return nError;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// File functions
|
||||
|
||||
// Adds a listfile into the MPQ archive.
|
||||
// Note that the function does not remove the
|
||||
// TODO: Test for archives > 4GB
|
||||
int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile)
|
||||
{
|
||||
TListFileCache * pCache = NULL;
|
||||
TMPQArchive * ha = (TMPQArchive *)hMpq;
|
||||
HANDLE hListFile = NULL;
|
||||
char szFileName[MAX_PATH + 1];
|
||||
DWORD dwSearchScope = SFILE_OPEN_LOCAL_FILE;
|
||||
DWORD dwCacheSize = 0;
|
||||
DWORD dwFileSize = 0;
|
||||
size_t nLength = 0;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// If the szListFile is NULL, it means we have to open internal listfile
|
||||
if(szListFile == NULL)
|
||||
{
|
||||
szListFile = LISTFILE_NAME;
|
||||
dwSearchScope = SFILE_OPEN_FROM_MPQ;
|
||||
}
|
||||
|
||||
// Open the local/internal listfile
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!SFileOpenFileEx((HANDLE)ha, szListFile, dwSearchScope, &hListFile))
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
dwCacheSize =
|
||||
dwFileSize = SFileGetFileSize(hListFile, NULL);
|
||||
|
||||
// Try to allocate memory for the complete file. If it fails,
|
||||
// load the part of the file
|
||||
pCache = (TListFileCache *)ALLOCMEM(char, (sizeof(TListFileCache) + dwCacheSize));
|
||||
if(pCache == NULL)
|
||||
{
|
||||
dwCacheSize = LISTFILE_CACHE_SIZE;
|
||||
pCache = (TListFileCache *)ALLOCMEM(char, sizeof(TListFileCache) + dwCacheSize);
|
||||
}
|
||||
|
||||
if(pCache == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Initialize the file cache
|
||||
memset(pCache, 0, sizeof(TListFileCache));
|
||||
pCache->hFile = hListFile;
|
||||
pCache->dwFileSize = dwFileSize;
|
||||
pCache->dwBuffSize = dwCacheSize;
|
||||
pCache->dwFilePos = 0;
|
||||
|
||||
// Fill the cache
|
||||
SFileReadFile(hListFile, pCache->Buffer, pCache->dwBuffSize, &pCache->dwBuffSize, NULL);
|
||||
|
||||
// Initialize the pointers
|
||||
pCache->pBegin =
|
||||
pCache->pPos = &pCache->Buffer[0];
|
||||
pCache->pEnd = pCache->pBegin + pCache->dwBuffSize;
|
||||
|
||||
// Load the node tree
|
||||
while((nLength = ReadLine(pCache, szFileName, sizeof(szFileName) - 1)) > 0)
|
||||
SListFileAddNode(ha, szFileName);
|
||||
|
||||
// Add well-known names
|
||||
// Sometimes, they are not in listfile, but they exist in the archive
|
||||
SListFileAddNode(ha, LISTFILE_NAME);
|
||||
SListFileAddNode(ha, SIGNATURE_NAME);
|
||||
SListFileAddNode(ha, ATTRIBUTES_NAME);
|
||||
}
|
||||
|
||||
// Cleanup & exit
|
||||
if(pCache != NULL)
|
||||
SListFileFindClose((HANDLE)pCache);
|
||||
return nError;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Passing through the listfile
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
HANDLE SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData)
|
||||
{
|
||||
TListFileCache * pCache = NULL;
|
||||
TMPQArchive * ha = (TMPQArchive *)hMpq;
|
||||
HANDLE hListFile = NULL;
|
||||
DWORD dwSearchScope = SFILE_OPEN_LOCAL_FILE;
|
||||
DWORD dwCacheSize = 0;
|
||||
DWORD dwFileSize = 0;
|
||||
size_t nLength = 0;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Initialize the structure with zeros
|
||||
memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
|
||||
|
||||
// If the szListFile is NULL, it means we have to open internal listfile
|
||||
if(szListFile == NULL)
|
||||
{
|
||||
szListFile = LISTFILE_NAME;
|
||||
dwSearchScope = SFILE_OPEN_FROM_MPQ;
|
||||
}
|
||||
|
||||
// Open the local/internal listfile
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!SFileOpenFileEx((HANDLE)ha, szListFile, dwSearchScope, &hListFile))
|
||||
nError = GetLastError();
|
||||
}
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
dwCacheSize =
|
||||
dwFileSize = SFileGetFileSize(hListFile, NULL);
|
||||
|
||||
// Try to allocate memory for the complete file. If it fails,
|
||||
// load the part of the file
|
||||
pCache = (TListFileCache *)ALLOCMEM(char, sizeof(TListFileCache) + dwCacheSize);
|
||||
if(pCache == NULL)
|
||||
{
|
||||
dwCacheSize = LISTFILE_CACHE_SIZE;
|
||||
pCache = (TListFileCache *)ALLOCMEM(char, sizeof(TListFileCache) + dwCacheSize);
|
||||
}
|
||||
|
||||
if(pCache == NULL)
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Initialize the file cache
|
||||
memset(pCache, 0, sizeof(TListFileCache));
|
||||
pCache->hFile = hListFile;
|
||||
pCache->dwFileSize = dwFileSize;
|
||||
pCache->dwBuffSize = dwCacheSize;
|
||||
pCache->dwFilePos = 0;
|
||||
if(szMask != NULL)
|
||||
{
|
||||
pCache->szMask = ALLOCMEM(char, strlen(szMask) + 1);
|
||||
strcpy(pCache->szMask, szMask);
|
||||
}
|
||||
|
||||
// Fill the cache
|
||||
SFileReadFile(hListFile, pCache->Buffer, pCache->dwBuffSize, &pCache->dwBuffSize, NULL);
|
||||
|
||||
// Initialize the pointers
|
||||
pCache->pBegin =
|
||||
pCache->pPos = &pCache->Buffer[0];
|
||||
pCache->pEnd = pCache->pBegin + pCache->dwBuffSize;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Read the (next) line
|
||||
nLength = ReadLine(pCache, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName));
|
||||
if(nLength == 0)
|
||||
{
|
||||
nError = ERROR_NO_MORE_FILES;
|
||||
break;
|
||||
}
|
||||
|
||||
// If some mask entered, check it
|
||||
if(CheckWildCard(lpFindFileData->cFileName, pCache->szMask))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup & exit
|
||||
if(nError != ERROR_SUCCESS)
|
||||
{
|
||||
memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
|
||||
SListFileFindClose((HANDLE)pCache);
|
||||
pCache = NULL;
|
||||
|
||||
SetLastError(nError);
|
||||
}
|
||||
return (HANDLE)pCache;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
|
||||
{
|
||||
TListFileCache * pCache = (TListFileCache *)hFind;
|
||||
size_t nLength;
|
||||
BOOL bResult = FALSE;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Read the (next) line
|
||||
nLength = ReadLine(pCache, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName));
|
||||
if(nLength == 0)
|
||||
{
|
||||
nError = ERROR_NO_MORE_FILES;
|
||||
break;
|
||||
}
|
||||
|
||||
// If some mask entered, check it
|
||||
if(CheckWildCard(lpFindFileData->cFileName, pCache->szMask))
|
||||
{
|
||||
bResult = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nError != ERROR_SUCCESS)
|
||||
SetLastError(nError);
|
||||
return bResult;
|
||||
}
|
||||
|
||||
// TODO: Test for archives > 4GB
|
||||
BOOL SListFileFindClose(HANDLE hFind)
|
||||
{
|
||||
TListFileCache * pCache = (TListFileCache *)hFind;
|
||||
|
||||
if(pCache != NULL)
|
||||
{
|
||||
if(pCache->hFile != NULL)
|
||||
SFileCloseFile(pCache->hFile);
|
||||
if(pCache->szMask != NULL)
|
||||
FREEMEM(pCache->szMask);
|
||||
|
||||
FREEMEM(pCache);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
67
src/tools/stuffextract/StormLib/StormDll.h
Normal file
67
src/tools/stuffextract/StormLib/StormDll.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*****************************************************************************/
|
||||
/* Storm.h Copyright Justin Olbrantz(Quantam) 2000 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Storm Interface Library v1.0 for Windows */
|
||||
/* */
|
||||
/* Author : Justin Olbrantz(Quantam) */
|
||||
/* E-mail : omega@dragonfire.net */
|
||||
/* WWW : www.campaigncreations.com/starcraft/mpq2k/inside_mopaq/ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.00 1.00 Qua The first version of Storm.h */
|
||||
/* 11.04.03 1.00 Lad Added some functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
// We need the Windows data types for the Storm prototypes
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef __STORM_H__
|
||||
#define __STORM_H__
|
||||
|
||||
// Somethimes is necessary to change the function names so they
|
||||
// will not conflict with other MPQ tools.
|
||||
#ifdef STORM_ALTERNATE_NAMES
|
||||
#define SFILE(Name) Storm##Name
|
||||
#define SCOMP(Name) Storm##Name
|
||||
#else
|
||||
#define SFILE(Name) SFile##Name
|
||||
#define SCOMP(Name) SComp##Name
|
||||
#endif
|
||||
|
||||
|
||||
// Just in case anyone is still using C out there
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Storm file function prototypes
|
||||
BOOL WINAPI SFILE(OpenArchive)(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, HANDLE *hMPQ);
|
||||
BOOL WINAPI SFILE(CloseArchive)(HANDLE hMPQ);
|
||||
BOOL WINAPI SFILE(GetArchiveName)(HANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength);
|
||||
BOOL WINAPI SFILE(OpenFile)(LPCSTR lpFileName, HANDLE *hFile);
|
||||
BOOL WINAPI SFILE(OpenFileEx)(HANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, HANDLE *hFile);
|
||||
BOOL WINAPI SFILE(CloseFile)(HANDLE hFile);
|
||||
DWORD WINAPI SFILE(GetFileSize)(HANDLE hFile, LPDWORD lpFileSizeHigh);
|
||||
BOOL WINAPI SFILE(GetFileArchive)(HANDLE hFile, HANDLE *hMPQ);
|
||||
BOOL WINAPI SFILE(GetFileName)(HANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength);
|
||||
DWORD WINAPI SFILE(SetFilePointer)(HANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod);
|
||||
BOOL WINAPI SFILE(ReadFile)(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped);
|
||||
LCID WINAPI SFILE(SetLocale)(LCID nNewLocale);
|
||||
BOOL WINAPI SFILE(GetBasePath)(LPCSTR lpBuffer, DWORD dwBufferLength);
|
||||
BOOL WINAPI SFILE(SetBasePath)(LPCSTR lpNewBasePath);
|
||||
|
||||
// Storm (de)compression functions
|
||||
BOOL WINAPI SCOMP(Compress) (char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int uCmp, int uCmpType, int nCmpLevel);
|
||||
BOOL WINAPI SCOMP(Decompress)(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength);
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && !defined(BUILDING_STORM_CPP)
|
||||
#pragma comment(lib, "Storm.lib") // Force linking Storm.lib and thus Storm.dll
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __STORM_H__
|
||||
581
src/tools/stuffextract/StormLib/StormLib.h
Normal file
581
src/tools/stuffextract/StormLib/StormLib.h
Normal file
@ -0,0 +1,581 @@
|
||||
/*****************************************************************************/
|
||||
/* StormLib.h Copyright (c) Ladislav Zezula 1999-2005 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* StormLib library v 5.00 */
|
||||
/* */
|
||||
/* Author : Ladislav Zezula */
|
||||
/* E-mail : ladik@zezula.net */
|
||||
/* WWW : http://www.zezula.net */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.99 1.00 Lad Created */
|
||||
/* 24.03.03 2.50 Lad Version 2.50 */
|
||||
/* 02.04.03 3.00 Lad Version 3.00 with compression */
|
||||
/* 11.04.03 3.01 Lad Renamed to StormLib.h for compatibility with */
|
||||
/* original headers for Storm.dll */
|
||||
/* 10.05.03 3.02 Lad Added Pkware DCL compression */
|
||||
/* 26.05.03 4.00 Lad Completed all compressions */
|
||||
/* 18.06.03 4.01 Lad Added SFileSetFileLocale */
|
||||
/* Added SFileExtractFile */
|
||||
/* 26.07.03 4.02 Lad Implemented nameless rename and delete */
|
||||
/* 26.07.03 4.03 Lad Added support for protected MPQs */
|
||||
/* 28.08.03 4.10 Lad Fixed bugs that caused StormLib incorrectly work */
|
||||
/* with Diablo I savegames and with files having full */
|
||||
/* hash table */
|
||||
/* 08.12.03 4.11 DCH Fixed bug in reading file block larger than 0x1000 */
|
||||
/* on certain files. */
|
||||
/* Fixed bug in AddFile with MPQ_FILE_REPLACE_EXISTING */
|
||||
/* (Thanx Daniel Chiamarello, dchiamarello@madvawes.com)*/
|
||||
/* 21.12.03 4.50 Lad Completed port for Mac */
|
||||
/* Fixed bug in compacting (if fsize is mul of 0x1000) */
|
||||
/* Fixed bug in SCompCompress */
|
||||
/* 27.05.04 4.51 Lad Changed memory management from new/delete to our */
|
||||
/* own macros */
|
||||
/* 22.06.04 4.60 Lad Optimized search. Support for multiple listfiles. */
|
||||
/* 30.09.04 4.61 Lad Fixed some bugs (Aaargh !!!) */
|
||||
/* Correctly works if HashTableSize > BlockTableSize */
|
||||
/* 29.12.04 4.70 Lad Fixed compatibility problem with MPQs from WoW */
|
||||
/* 14.07.05 5.00 Lad Added the BZLIB compression support */
|
||||
/* Added suport of files stored as single unit */
|
||||
/* 17.04.06 5.01 Lad Converted to MS Visual Studio 8.0 */
|
||||
/* Fixed issue with protected Warcraft 3 protected maps */
|
||||
/* 15.05.06 5.02 Lad Fixed issue with WoW 1.10+ */
|
||||
/* 07.09.06 5.10 Lad Fixed processing files longer than 2GB */
|
||||
/* 22.11.06 6.00 Lad Support for MPQ archives V2 */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __STORMLIB_H_
|
||||
#define __STORMLIB_H_
|
||||
|
||||
#include "StormPort.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Use the apropriate library
|
||||
//
|
||||
// The library type is encoded in the library name as the following
|
||||
// StormLibXYZ.lib
|
||||
//
|
||||
// X - D for Debug version, R for Release version
|
||||
// Y - A for ANSI version, U for Unicode version (Unicode version does not exist yet)
|
||||
// Z - S for static C library, D for multithreaded DLL C-library
|
||||
//
|
||||
|
||||
#define __STORMLIB_SELF__
|
||||
|
||||
#if defined(_MSC_VER) && !defined (__STORMLIB_SELF__)
|
||||
#ifdef _DEBUG // DEBUG VERSIONS
|
||||
#ifdef _DLL
|
||||
#pragma comment(lib, "StormLibDAD.lib") // Debug Ansi Dynamic version
|
||||
#else
|
||||
#pragma comment(lib, "StormLibDAS.lib") // Debug Ansi Static version
|
||||
#endif
|
||||
#else // RELEASE VERSIONS
|
||||
#ifdef _DLL
|
||||
#pragma comment(lib, "StormLibRAD.lib") // Release Ansi Dynamic version
|
||||
#else
|
||||
#pragma comment(lib, "StormLibRAS.lib") // Release Ansi Static version
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A')
|
||||
#define ID_MPQ_SHUNT 0x1B51504D // MPQ shunt entry ('MPQ\x1B')
|
||||
|
||||
#define ERROR_AVI_FILE 10000 // No MPQ file, but AVI file.
|
||||
|
||||
// Values for SFileCreateArchiveEx
|
||||
#define HASH_TABLE_SIZE_MIN 0x00002
|
||||
#define HASH_TABLE_SIZE_MAX 0x40000
|
||||
|
||||
#define HASH_ENTRY_DELETED 0xFFFFFFFE // Block index for deleted hash entry
|
||||
#define HASH_ENTRY_FREE 0xFFFFFFFF // Block index for free hash entry
|
||||
|
||||
// Values for SFileOpenArchive
|
||||
#define SFILE_OPEN_HARD_DISK_FILE 2 // Open the archive on HDD
|
||||
#define SFILE_OPEN_CDROM_FILE 3 // Open the archive only if it is on CDROM
|
||||
|
||||
// Values for SFileOpenFile
|
||||
#define SFILE_OPEN_FROM_MPQ 0 // Open the file from the MPQ archive
|
||||
#define SFILE_OPEN_BY_INDEX 1 // The 'szFileName' parameter is actually the file index
|
||||
#define SFILE_OPEN_LOCAL_FILE (DWORD)-1 // Open the file from the MPQ archive
|
||||
|
||||
// Flags for TMPQArchive::dwFlags
|
||||
#define MPQ_FLAG_CHANGED 0x00000001 // If set, the MPQ has been changed
|
||||
#define MPQ_FLAG_PROTECTED 0x00000002 // Set on protected MPQs (like W3M maps)
|
||||
|
||||
// Flags for SFileAddFile
|
||||
#define MPQ_FILE_COMPRESS_PKWARE 0x00000100 // Compression made by PKWARE Data Compression Library
|
||||
#define MPQ_FILE_COMPRESS_MULTI 0x00000200 // Multiple compressions
|
||||
#define MPQ_FILE_COMPRESSED 0x0000FF00 // File is compressed
|
||||
#define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates whether file is encrypted
|
||||
#define MPQ_FILE_FIXSEED 0x00020000 // File decrypt seed has to be fixed
|
||||
#define MPQ_FILE_SINGLE_UNIT 0x01000000 // File is stored as a single unit, rather than split into sectors (Thx, Quantam)
|
||||
#define MPQ_FILE_DUMMY_FILE 0x02000000 // The file is only 1 byte long and its name is a hash
|
||||
#define MPQ_FILE_HAS_EXTRA 0x04000000 // The file has extra data appended after regular data.
|
||||
// Must be with compressed files only
|
||||
#define MPQ_FILE_EXISTS 0x80000000 // Set if file exists, reset when the file was deleted
|
||||
#define MPQ_FILE_REPLACEEXISTING 0x80000000 // Replace when the file exist (SFileAddFile)
|
||||
|
||||
#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_COMPRESS_PKWARE | \
|
||||
MPQ_FILE_COMPRESS_MULTI | \
|
||||
MPQ_FILE_ENCRYPTED | \
|
||||
MPQ_FILE_FIXSEED | \
|
||||
MPQ_FILE_SINGLE_UNIT | \
|
||||
MPQ_FILE_DUMMY_FILE | \
|
||||
MPQ_FILE_HAS_EXTRA | \
|
||||
MPQ_FILE_EXISTS)
|
||||
|
||||
// Compression types for multilpe compressions
|
||||
#define MPQ_COMPRESSION_HUFFMANN 0x01 // Huffmann compression (used on WAVE files only)
|
||||
#define MPQ_COMPRESSION_ZLIB 0x02 // ZLIB compression
|
||||
#define MPQ_COMPRESSION_PKWARE 0x08 // PKWARE DCL compression
|
||||
#define MPQ_COMPRESSION_BZIP2 0x10 // BZIP2 compression
|
||||
#define MPQ_COMPRESSION_WAVE_MONO 0x40 //
|
||||
#define MPQ_COMPRESSION_WAVE_STEREO 0x80 //
|
||||
|
||||
|
||||
// Constants for SFileAddWave
|
||||
#define MPQ_WAVE_QUALITY_HIGH 0 // Best quality, the worst compression
|
||||
#define MPQ_WAVE_QUALITY_MEDIUM 1 // Medium quality, medium compression
|
||||
#define MPQ_WAVE_QUALITY_LOW 2 // Low quality, the best compression
|
||||
|
||||
// Constants for SFileGetFileInfo
|
||||
#define SFILE_INFO_ARCHIVE_SIZE 1 // MPQ size (value from header)
|
||||
#define SFILE_INFO_HASH_TABLE_SIZE 2 // Size of hash table, in entries
|
||||
#define SFILE_INFO_BLOCK_TABLE_SIZE 3 // Number of entries in the block table
|
||||
#define SFILE_INFO_BLOCK_SIZE 4 // Size of file block (in bytes)
|
||||
#define SFILE_INFO_HASH_TABLE 5 // Pointer to Hash table (TMPQHash *)
|
||||
#define SFILE_INFO_BLOCK_TABLE 6 // Pointer to Block Table (TMPQBlock *)
|
||||
#define SFILE_INFO_NUM_FILES 7 // Real number of files within archive
|
||||
//------
|
||||
#define SFILE_INFO_HASH_INDEX 8 // Hash index of file in MPQ
|
||||
#define SFILE_INFO_CODENAME1 9 // The first codename of the file
|
||||
#define SFILE_INFO_CODENAME2 10 // The second codename of the file
|
||||
#define SFILE_INFO_LOCALEID 11 // Locale ID of file in MPQ
|
||||
#define SFILE_INFO_BLOCKINDEX 12 // Index to Block Table
|
||||
#define SFILE_INFO_FILE_SIZE 13 // Original file size
|
||||
#define SFILE_INFO_COMPRESSED_SIZE 14 // Compressed file size
|
||||
#define SFILE_INFO_FLAGS 15 // File flags
|
||||
#define SFILE_INFO_POSITION 16 // File position within archive
|
||||
#define SFILE_INFO_SEED 17 // File decryption seed
|
||||
#define SFILE_INFO_SEED_UNFIXED 18 // Decryption seed not fixed to file pos and size
|
||||
|
||||
// Values for compact callback
|
||||
#define CCB_CHECKING_FILES 1 // Checking archive (dwParam1 = current, dwParam2 = total)
|
||||
#define CCB_CHECKING_HASH_TABLE 2 // Checking hash table (dwParam1 = current, dwParam2 = total)
|
||||
#define CCB_COPYING_NON_MPQ_DATA 3 // Copying non-MPQ data: No params used
|
||||
#define CCB_COMPACTING_FILES 4 // Compacting archive (dwParam1 = current, dwParam2 = total)
|
||||
#define CCB_CLOSING_ARCHIVE 5 // Closing archive: No params used
|
||||
|
||||
#define LISTFILE_NAME "(listfile)" // Name of internal listfile
|
||||
#define SIGNATURE_NAME "(signature)" // Name of internal signature
|
||||
#define ATTRIBUTES_NAME "(attributes)" // Name of internal attributes file
|
||||
|
||||
#define STORMLIB_VERSION (0x0600) // Current version of StormLib
|
||||
|
||||
#define MPQ_FORMAT_VERSION_1 0 // Up to The Burning Crusade
|
||||
#define MPQ_FORMAT_VERSION_2 1 // The Burning Crusade and newer,
|
||||
|
||||
// Flags for SFileOpenArchiveEx
|
||||
#define MPQ_OPEN_NO_LISTFILE 0x00000001 // Don't add the internal listfile
|
||||
|
||||
// supports archives with size > 4 GB
|
||||
// Additional flags for SFileCreateArchiveEx
|
||||
#define MPQ_CREATE_ARCHIVE_V1 0x00000000 // Creates archive with size up to 4GB
|
||||
#define MPQ_CREATE_ARCHIVE_V2 0x00010000 // Creates archive larger than 4 GB
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Structures
|
||||
|
||||
#if (defined(WIN32) || defined(WIN64))
|
||||
#include <pshpack1.h>
|
||||
#else
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
struct TMPQFile;
|
||||
|
||||
struct TMPQShunt
|
||||
{
|
||||
// The ID_MPQ_SHUNT ('MPQ\x1B') signature
|
||||
DWORD dwID;
|
||||
|
||||
DWORD dwUnknown;
|
||||
|
||||
// Position of the MPQ header, relative to the begin of the shunt
|
||||
DWORD dwHeaderPos;
|
||||
};
|
||||
|
||||
|
||||
// MPQ file header
|
||||
struct TMPQHeader
|
||||
{
|
||||
// The ID_MPQ ('MPQ\x1A') signature
|
||||
DWORD dwID;
|
||||
|
||||
// Size of the archive header
|
||||
DWORD dwHeaderSize;
|
||||
|
||||
// Size of MPQ archive
|
||||
// This field is deprecated in the Burning Crusade MoPaQ format, and the size of the archive
|
||||
// is calculated as the size from the beginning of the archive to the end of the hash table,
|
||||
// block table, or extended block table (whichever is largest).
|
||||
DWORD dwArchiveSize;
|
||||
|
||||
// 0 = Original format
|
||||
// 1 = Extended format (The Burning Crusade and newer)
|
||||
USHORT wFormatVersion;
|
||||
|
||||
// Power of two exponent specifying the number of 512-byte disk sectors in each logical sector
|
||||
// in the archive. The size of each logical sector in the archive is 512 * 2^SectorSizeShift.
|
||||
// Bugs in the Storm library dictate that this should always be 3 (4096 byte sectors).
|
||||
USHORT wBlockSize;
|
||||
|
||||
// Offset to the beginning of the hash table, relative to the beginning of the archive.
|
||||
DWORD dwHashTablePos;
|
||||
|
||||
// Offset to the beginning of the block table, relative to the beginning of the archive.
|
||||
DWORD dwBlockTablePos;
|
||||
|
||||
// Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for
|
||||
// the original MoPaQ format, or less than 2^20 for the Burning Crusade format.
|
||||
DWORD dwHashTableSize;
|
||||
|
||||
// Number of entries in the block table
|
||||
DWORD dwBlockTableSize;
|
||||
};
|
||||
|
||||
|
||||
// Extended MPQ file header. Valid only if wFormatVersion is 1 or higher
|
||||
struct TMPQHeader2 : public TMPQHeader
|
||||
{
|
||||
// Offset to the beginning of the extended block table, relative to the beginning of the archive.
|
||||
LARGE_INTEGER ExtBlockTablePos;
|
||||
|
||||
// High 16 bits of the hash table offset for large archives.
|
||||
USHORT wHashTablePosHigh;
|
||||
|
||||
// High 16 bits of the block table offset for large archives.
|
||||
USHORT wBlockTablePosHigh;
|
||||
};
|
||||
|
||||
|
||||
// Hash entry. All files in the archive are searched by their hashes.
|
||||
struct TMPQHash
|
||||
{
|
||||
// The hash of the file path, using method A.
|
||||
DWORD dwName1;
|
||||
|
||||
// The hash of the file path, using method B.
|
||||
DWORD dwName2;
|
||||
|
||||
#ifdef PLATFORM_LITTLE_ENDIAN
|
||||
|
||||
// The language of the file. This is a Windows LANGID data type, and uses the same values.
|
||||
// 0 indicates the default language (American English), or that the file is language-neutral.
|
||||
USHORT lcLocale;
|
||||
|
||||
// The platform the file is used for. 0 indicates the default platform.
|
||||
// No other values have been observed.
|
||||
USHORT wPlatform;
|
||||
|
||||
#else
|
||||
|
||||
USHORT wPlatform;
|
||||
USHORT lcLocale;
|
||||
|
||||
#endif
|
||||
|
||||
// If the hash table entry is valid, this is the index into the block table of the file.
|
||||
// Otherwise, one of the following two values:
|
||||
// - FFFFFFFFh: Hash table entry is empty, and has always been empty.
|
||||
// Terminates searches for a given file.
|
||||
// - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file).
|
||||
// Does not terminate searches for a given file.
|
||||
DWORD dwBlockIndex;
|
||||
};
|
||||
|
||||
|
||||
// File description block contains informations about the file
|
||||
struct TMPQBlock
|
||||
{
|
||||
// Offset of the beginning of the block, relative to the beginning of the archive.
|
||||
DWORD dwFilePos;
|
||||
|
||||
// Compressed file size
|
||||
DWORD dwCSize;
|
||||
|
||||
// Only valid if the block is a file; otherwise meaningless, and should be 0.
|
||||
// If the file is compressed, this is the size of the uncompressed file data.
|
||||
DWORD dwFSize;
|
||||
|
||||
// Flags for the file. See MPQ_FILE_XXXX constants
|
||||
DWORD dwFlags;
|
||||
};
|
||||
|
||||
|
||||
// The extended block table was added to support archives larger than 4 gigabytes (2^32 bytes).
|
||||
// The table contains the upper bits of the archive offsets for each block in the block table.
|
||||
// It is simply an array of int16s, which become bits 32-47 of the archive offsets for each block,
|
||||
// with bits 48-63 being zero. Individual blocks in the archive are still limited to 4 gigabytes
|
||||
// in size. This table is only present in Burning Crusade format archives that exceed 4 gigabytes size.
|
||||
struct TMPQBlockEx
|
||||
{
|
||||
USHORT wFilePosHigh;
|
||||
};
|
||||
|
||||
|
||||
struct TFileNode
|
||||
{
|
||||
DWORD dwRefCount; // Number of references
|
||||
// There can be more files that have the same name.
|
||||
// (e.g. multiple language files). We don't want to
|
||||
// have an entry for each of them, so the entries will be referenced.
|
||||
// When a number of node references reaches zero,
|
||||
// the node will be deleted
|
||||
|
||||
size_t nLength; // File name length
|
||||
char szFileName[1]; // File name, variable length
|
||||
};
|
||||
|
||||
#if (defined(WIN32) || defined(WIN64))
|
||||
#include <poppack.h>
|
||||
#else
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
// Archive handle structure. Note that it does not agree with Storm.dll's structure.
|
||||
struct TMPQArchive
|
||||
{
|
||||
// TMPQArchive * pNext; // Next archive (used by Storm.dll only)
|
||||
// TMPQArchive * pPrev; // Previous archive (used by Storm.dll only)
|
||||
char szFileName[MAX_PATH]; // Opened archive file name
|
||||
HANDLE hFile; // File handle
|
||||
DWORD dwPriority; // Priority of the archive
|
||||
LARGE_INTEGER ShuntPos; // Position of MPQShunt (only valid if a shunt is present)
|
||||
LARGE_INTEGER MpqPos; // MPQ position in the file, relative to the begin of the file
|
||||
LARGE_INTEGER MpqSize; // Size of MPQ archive
|
||||
LARGE_INTEGER HashTablePos; // Offset of the hast table in the MPQ, relative to the begin of the file
|
||||
LARGE_INTEGER BlockTablePos; // Offset of the hast table in the MPQ, relative to the begin
|
||||
LARGE_INTEGER ExtBlockTablePos; // Offset of the extended block table, relative to the begin
|
||||
LARGE_INTEGER FilePointer; // Current position in the file (relative to begin of the file)
|
||||
|
||||
TMPQFile * pLastFile; // Recently read file
|
||||
DWORD dwBlockPos; // Position of loaded block in the file
|
||||
DWORD dwBlockSize; // Size of file block
|
||||
BYTE * pbBlockBuffer; // Buffer (cache) for file block
|
||||
DWORD dwBuffPos; // Position in block buffer
|
||||
TMPQShunt * pShunt; // MPQ shunt (NULL if not present in the file)
|
||||
TMPQHeader2 * pHeader; // MPQ file header
|
||||
TMPQHash * pHashTable; // Hash table
|
||||
TMPQBlock * pBlockTable; // Block table
|
||||
TMPQBlockEx * pExtBlockTable; // Extended block table
|
||||
|
||||
TMPQShunt Shunt; // MPQ shunt. Valid only when ID_MPQ_SHUNT has been found
|
||||
TMPQHeader2 Header; // MPQ header
|
||||
|
||||
// Non-Storm.dll members
|
||||
TFileNode ** pListFile; // File name array
|
||||
// HANDLE hListFile; // Handle to temporary listfile (when open with write access)
|
||||
DWORD dwFlags; // See MPQ_FLAG_XXXXX
|
||||
// BOOL bChanged; // TRUE if the archive was changed since open.
|
||||
// BOOL bProtected; // TRUE if the archive is protected by somehow
|
||||
};
|
||||
|
||||
|
||||
// File handle structure. Note that it does not agree with Storm.dll structures
|
||||
struct TMPQFile
|
||||
{
|
||||
HANDLE hFile; // File handle
|
||||
TMPQArchive * ha; // Archive handle
|
||||
TMPQHash * pHash; // Hash table entry
|
||||
TMPQBlockEx * pBlockEx; // Pointer to extended file block entry
|
||||
TMPQBlock * pBlock; // File block pointer
|
||||
DWORD dwSeed1; // Seed used for file decrypt
|
||||
DWORD dwFilePos; // Current file position
|
||||
LARGE_INTEGER MpqFilePos; // Position of the file data in MPQ archive
|
||||
// (relative to file begin)
|
||||
|
||||
DWORD * pdwBlockPos; // Position of each file block (only for compressed files)
|
||||
DWORD nBlocks; // Number of blocks in the file (incl. the last noncomplete one)
|
||||
BOOL bBlockPosLoaded; // TRUE if block positions loaded
|
||||
BYTE * pbFileBuffer; // Decompressed file (for single unit files, size is the uncompressed file size)
|
||||
|
||||
DWORD dwHashIndex; // Index to Hash table
|
||||
DWORD dwFileIndex; // Index to Block table
|
||||
char szFileName[1]; // File name (variable length)
|
||||
};
|
||||
|
||||
|
||||
// Used by searching in MPQ archives
|
||||
struct TMPQSearch
|
||||
{
|
||||
TMPQArchive * ha; // Handle to MPQ, where the search runs
|
||||
DWORD dwNextIndex; // The next searched hash index
|
||||
DWORD dwName1; // Lastly found Name1
|
||||
DWORD dwName2; // Lastly found Name2
|
||||
char szSearchMask[1]; // Search mask (variable length)
|
||||
};
|
||||
|
||||
|
||||
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)
|
||||
DWORD dwBlockIndex; // Block index for the file
|
||||
DWORD dwCompSize; // Compressed file size
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Memory management
|
||||
//
|
||||
// We use our own macros for allocating/freeing memory. If you want
|
||||
// to redefine them, please keep the following rules
|
||||
//
|
||||
// - The memory allocation must return NULL if not enough memory
|
||||
// (i.e not to throw exception)
|
||||
// - It is not necessary to fill the allocated block with zeros
|
||||
// - Memory freeing function must not test the pointer to NULL.
|
||||
//
|
||||
|
||||
|
||||
__inline void * DebugMalloc(char * szFile, int nLine, int nSize)
|
||||
{
|
||||
void * ptr = malloc(nSize + 100);
|
||||
char * plain;
|
||||
|
||||
plain = strrchr(szFile, '\\');
|
||||
if(plain == NULL)
|
||||
plain = strrchr(szFile, '/');
|
||||
if(plain == NULL)
|
||||
plain = szFile;
|
||||
|
||||
#if _MSC_VER > 0x1300
|
||||
sprintf_s((char *)ptr, nSize+100, "%s(%u)", plain, nLine);
|
||||
#else
|
||||
sprintf((char *)ptr, "%s(%u)", plain, nLine);
|
||||
#endif
|
||||
|
||||
return (char *)ptr + 100;
|
||||
}
|
||||
|
||||
|
||||
__inline void DebugFree(void * ptr)
|
||||
{
|
||||
free((char *)ptr - 100);
|
||||
}
|
||||
|
||||
|
||||
#ifndef ALLOCMEM
|
||||
#define ALLOCMEM(type, nitems) (type *)malloc((nitems) * sizeof(type))
|
||||
#define FREEMEM(ptr) free(ptr)
|
||||
#endif
|
||||
|
||||
//#define ALLOCMEM(type, nitems) (type *)DebugMalloc(__FILE__, __LINE__, (nitems) * sizeof(type))
|
||||
//#define FREEMEM(ptr) DebugFree(ptr)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions in StormLib - compatible with Storm.dll
|
||||
|
||||
// Typedefs for functions exported by Storm.dll
|
||||
typedef LCID (WINAPI * SFILESETLOCALE)(LCID);
|
||||
typedef BOOL (WINAPI * SFILEOPENARCHIVE)(const char *, DWORD, DWORD, HANDLE *);
|
||||
typedef BOOL (WINAPI * SFILECLOSEARCHIVE)(HANDLE);
|
||||
typedef BOOL (WINAPI * SFILEOPENFILEEX)(HANDLE, const char *, DWORD, HANDLE *);
|
||||
typedef BOOL (WINAPI * SFILECLOSEFILE)(HANDLE);
|
||||
typedef DWORD (WINAPI * SFILEGETFILESIZE)(HANDLE, DWORD *);
|
||||
typedef DWORD (WINAPI * SFILESETFILEPOINTER)(HANDLE, LONG, LONG *, DWORD);
|
||||
typedef BOOL (WINAPI * SFILEREADFILE)(HANDLE, VOID *, DWORD, DWORD *, LPOVERLAPPED);
|
||||
|
||||
// Archive opening/closing
|
||||
LCID WINAPI SFileSetLocale(LCID lcNewLocale);
|
||||
LCID WINAPI SFileGetLocale();
|
||||
BOOL WINAPI SFileOpenArchive(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMPQ);
|
||||
BOOL WINAPI SFileCloseArchive(HANDLE hMPQ);
|
||||
|
||||
// File opening/closing
|
||||
BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile);
|
||||
BOOL WINAPI SFileCloseFile(HANDLE hFile);
|
||||
|
||||
// File I/O
|
||||
DWORD WINAPI SFileGetFilePos(HANDLE hFile, DWORD * pdwFilePosHigh = NULL);
|
||||
DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh = NULL);
|
||||
DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * pdwFilePosHigh, DWORD dwMethod);
|
||||
BOOL WINAPI SFileReadFile(HANDLE hFile, VOID * lpBuffer, DWORD dwToRead, DWORD * pdwRead = NULL, LPOVERLAPPED lpOverlapped = NULL);
|
||||
|
||||
BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char * szExtracted);
|
||||
|
||||
// Adds another listfile into MPQ. The currently added listfile(s) remain,
|
||||
// so you can use this API to combining more listfiles.
|
||||
// Note that this function is internally called by SFileFindFirstFile
|
||||
int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions in StormLib - not implemented in Storm.dll
|
||||
|
||||
// Archive creating and editing
|
||||
BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposition, DWORD dwHashTableSize, HANDLE * phMPQ);
|
||||
BOOL WINAPI SFileAddFile(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags);
|
||||
BOOL WINAPI SFileAddWave(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality);
|
||||
BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope = SFILE_OPEN_BY_INDEX);
|
||||
BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szOldFileName, const char * szNewFileName);
|
||||
BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale);
|
||||
|
||||
// Retrieving info about the file
|
||||
BOOL WINAPI SFileHasFile(HANDLE hMPQ, char * szFileName);
|
||||
BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName);
|
||||
DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType);
|
||||
|
||||
// File search
|
||||
// Note that the SFileFindFirstFileEx has been removed. Use SListFileFindFirst/Next
|
||||
HANDLE WINAPI SFileFindFirstFile(HANDLE hMPQ, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const char * szListFile);
|
||||
BOOL WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData);
|
||||
BOOL WINAPI SFileFindClose(HANDLE hFind);
|
||||
|
||||
// Listfile search
|
||||
HANDLE SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData);
|
||||
BOOL SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData);
|
||||
BOOL SListFileFindClose(HANDLE hFind);
|
||||
|
||||
// Archive compacting
|
||||
typedef void (WINAPI * COMPACTCB)(void * lpUserData, DWORD dwWorkType, DWORD dwParam1, DWORD dwParam2);
|
||||
BOOL WINAPI SFileSetCompactCallback(HANDLE hMPQ, COMPACTCB CompactCB, void * lpData);
|
||||
BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile = NULL, BOOL bReserved = 0);
|
||||
|
||||
// Locale support
|
||||
int WINAPI SFileEnumLocales(HANDLE hMPQ, const char * szFileName, LCID * plcLocales, DWORD * pdwMaxLocales, DWORD dwSearchScope = SFILE_OPEN_BY_INDEX);
|
||||
|
||||
// (De)compression
|
||||
int WINAPI SCompCompress (char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int uCompressions, int nCmpType, int nCmpLevel);
|
||||
int WINAPI SCompDecompress (char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength);
|
||||
|
||||
// Sets the default data compression for files added to MPQ,
|
||||
// if MPQ_FILE_COMPRESS_MULTI has been specified in call to SFileAddFile
|
||||
int WINAPI SCompSetDataCompression(int nDataCompression);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions from Storm.dll. They use slightly different names for keeping
|
||||
// possibility to use them together with StormLib (StormXXX instead of SFileXXX)
|
||||
|
||||
#ifdef __LINK_STORM_DLL__
|
||||
#define STORM_ALTERNATE_NAMES // Force Storm.h to use alternate fnc names
|
||||
#include "StormDll.h"
|
||||
#endif // __LINK_STORM_DLL__
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GFX decode functions. See GfxDecode.cpp for details and description
|
||||
|
||||
USHORT WINAPI celGetFrameCount(BYTE * fileBuf);
|
||||
BYTE * WINAPI celGetFrameData(BYTE *fileBuf, BYTE *palette, USHORT xsize, USHORT frame, USHORT *ysize, USHORT *maxX=NULL);
|
||||
USHORT WINAPI cl2GetFrameCount(BYTE *fileBuf);
|
||||
BYTE ** WINAPI cl2GetDirData(BYTE *fileBuf, BYTE *palette, USHORT xsize, USHORT dir, USHORT *ysize);
|
||||
BYTE * WINAPI pcxGetData(BYTE *filebuf, DWORD filesize, BYTE transcol, USHORT *xsize, USHORT *ysize);
|
||||
|
||||
#endif // __STORMLIB_H_
|
||||
278
src/tools/stuffextract/StormLib/StormPort.h
Normal file
278
src/tools/stuffextract/StormLib/StormPort.h
Normal file
@ -0,0 +1,278 @@
|
||||
/*****************************************************************************/
|
||||
/* StormPort.h Copyright (c) Marko Friedemann 2001 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Portability module for the StormLib library. Contains a wrapper symbols */
|
||||
/* to make the compilation under Linux work */
|
||||
/* */
|
||||
/* Author: Marko Friedemann <marko.friedemann@bmx-chemnitz.de> */
|
||||
/* Created at: Mon Jan 29 18:26:01 CEST 2001 */
|
||||
/* Computer: whiplash.flachland-chemnitz.de */
|
||||
/* System: Linux 2.4.0 on i686 */
|
||||
/* */
|
||||
/* Author: Sam Wilkins */
|
||||
/* System: Mac OS X and port to big endian processor */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 29.01.01 1.00 Mar Created */
|
||||
/* 24.03.03 1.01 Lad Some cosmetic changes */
|
||||
/* 12.11.03 1.02 Dan Macintosh compatibility */
|
||||
/* 24.07.04 1.03 Sam Mac OS X compatibility */
|
||||
/* 22.11.06 1.04 Sam Mac OS X compatibility (for StormLib 6.0) */
|
||||
/* 31.12.06 1.05 XPinguin Full GNU/Linux compatibility */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __STORMPORT_H__
|
||||
#define __STORMPORT_H__
|
||||
|
||||
// Defines for Windows
|
||||
#if !defined(PLATFORM_DEFINED) && (defined(WIN32) || defined(WIN64))
|
||||
|
||||
// In MSVC 8.0, there are some functions declared as deprecated.
|
||||
#if _MSC_VER >= 1400
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_NON_CONFORMING_SWPRINTFS
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#define PLATFORM_LITTLE_ENDIAN 1
|
||||
|
||||
#ifdef WIN64
|
||||
#define PLATFORM_64BIT
|
||||
#else
|
||||
#define PLATFORM_32BIT
|
||||
#endif
|
||||
|
||||
#define PLATFORM_DEFINED // The platform is known now
|
||||
|
||||
#endif
|
||||
|
||||
// Defines for Mac Carbon
|
||||
#if !defined(PLATFORM_DEFINED) && defined(__APPLE__) // Mac Carbon API
|
||||
|
||||
// Macintosh using Carbon
|
||||
#include <Carbon/Carbon.h> // Mac OS X
|
||||
#define _stricmp strcasecmp // Case insensitive strcmp has a different name on this platform.
|
||||
#define _strnicmp strncasecmp
|
||||
|
||||
typedef void * LPCSTR;
|
||||
typedef unsigned long * LPDWORD;
|
||||
typedef long * PLONG;
|
||||
typedef void * LPVOID;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
#define PKEXPORT
|
||||
#define __SYS_ZLIB
|
||||
#define __SYS_BZLIB
|
||||
#define LANG_NEUTRAL 0
|
||||
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
#define PLATFORM_LITTLE_ENDIAN 0
|
||||
#else
|
||||
#define PLATFORM_LITTLE_ENDIAN 1 // Apple is now making Macs with Intel CPUs
|
||||
#endif
|
||||
#define PLATFORM_DEFINED // The platform is known now
|
||||
|
||||
#endif
|
||||
|
||||
// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin*
|
||||
// Ladik : Why the hell Linux does not use some OS-dependent #define ?
|
||||
#if !defined(PLATFORM_DEFINED)
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define PLATFORM_LITTLE_ENDIAN 1
|
||||
#define PLATFORM_DEFINED
|
||||
#define LANG_NEUTRAL 0
|
||||
|
||||
#endif /* not __powerc */
|
||||
|
||||
|
||||
#if !defined(WIN32) && !defined(WIN64)
|
||||
|
||||
// Typedefs for ANSI C
|
||||
typedef unsigned char BYTE;
|
||||
typedef short SHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short USHORT;
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
typedef unsigned long DWORD_PTR;
|
||||
typedef long LONG_PTR;
|
||||
typedef long long LONGLONG;
|
||||
#ifndef __OBJC__
|
||||
#define BOOL bool
|
||||
#endif
|
||||
typedef void * HANDLE;
|
||||
typedef void * LPOVERLAPPED; // Unsupported on Linux
|
||||
typedef char TCHAR;
|
||||
typedef unsigned long LCID;
|
||||
|
||||
typedef void * LPCSTR;
|
||||
typedef unsigned long * LPDWORD;
|
||||
typedef long * PLONG;
|
||||
typedef void * LPVOID;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
typedef struct _FILETIME
|
||||
{
|
||||
DWORD dwLowDateTime;
|
||||
DWORD dwHighDateTime;
|
||||
}
|
||||
FILETIME, *PFILETIME;
|
||||
|
||||
typedef union _LARGE_INTEGER
|
||||
{
|
||||
#if PLATFORM_LITTLE_ENDIAN
|
||||
struct
|
||||
{
|
||||
DWORD LowPart;
|
||||
LONG HighPart;
|
||||
};
|
||||
#else
|
||||
struct
|
||||
{
|
||||
LONG HighPart;
|
||||
DWORD LowPart;
|
||||
};
|
||||
#endif
|
||||
LONGLONG QuadPart;
|
||||
}
|
||||
LARGE_INTEGER, *PLARGE_INTEGER;
|
||||
|
||||
// Some Windows-specific defines
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE true
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE false
|
||||
#endif
|
||||
|
||||
#define VOID void
|
||||
#define WINAPI
|
||||
|
||||
#define FILE_BEGIN SEEK_SET
|
||||
#define FILE_CURRENT SEEK_CUR
|
||||
#define FILE_END SEEK_END
|
||||
|
||||
#define CREATE_NEW 1
|
||||
#define CREATE_ALWAYS 2
|
||||
#define OPEN_EXISTING 3
|
||||
#define OPEN_ALWAYS 4
|
||||
|
||||
#define FILE_SHARE_READ 0x00000001L
|
||||
#define GENERIC_WRITE 0x40000000
|
||||
#define GENERIC_READ 0x80000000
|
||||
|
||||
#define FILE_FLAG_DELETE_ON_CLOSE 1 // Sam: Added these two defines so it would compile.
|
||||
#define FILE_FLAG_SEQUENTIAL_SCAN 2
|
||||
|
||||
#define ERROR_SUCCESS 0
|
||||
#define ERROR_INVALID_FUNCTION 1
|
||||
#define ERROR_FILE_NOT_FOUND 2
|
||||
#define ERROR_ACCESS_DENIED 5
|
||||
#define ERROR_NOT_ENOUGH_MEMORY 8
|
||||
#define ERROR_BAD_FORMAT 11
|
||||
#define ERROR_NO_MORE_FILES 18
|
||||
#define ERROR_GEN_FAILURE 31
|
||||
#define ERROR_HANDLE_EOF 38
|
||||
#define ERROR_HANDLE_DISK_FULL 39
|
||||
#define ERROR_NOT_SUPPORTED 50
|
||||
#define ERROR_INVALID_PARAMETER 87
|
||||
#define ERROR_DISK_FULL 112
|
||||
#define ERROR_CALL_NOT_IMPLEMENTED 120
|
||||
#define ERROR_ALREADY_EXISTS 183
|
||||
#define ERROR_CAN_NOT_COMPLETE 1003
|
||||
#define ERROR_PARAMETER_QUOTA_EXCEEDED 1283
|
||||
#define ERROR_FILE_CORRUPT 1392
|
||||
#define ERROR_INSUFFICIENT_BUFFER 4999
|
||||
|
||||
#define INVALID_HANDLE_VALUE ((HANDLE) -1)
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) ((a < b) ? a : b)
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a, b) ((a > b) ? a : b)
|
||||
#endif
|
||||
|
||||
#define _stricmp strcasecmp
|
||||
#define _strnicmp strncasecmp
|
||||
|
||||
extern int globalerr;
|
||||
|
||||
void SetLastError(int err);
|
||||
int GetLastError();
|
||||
char *ErrString(int err);
|
||||
|
||||
// Emulation of functions for file I/O available in Win32
|
||||
HANDLE CreateFile(const char * lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, void * lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
||||
BOOL CloseHandle(HANDLE hObject);
|
||||
|
||||
DWORD GetFileSize(HANDLE hFile, DWORD * lpFileSizeHigh);
|
||||
DWORD SetFilePointer(HANDLE, LONG lDistanceToMove, LONG * lpDistanceToMoveHigh, DWORD dwMoveMethod);
|
||||
BOOL SetEndOfFile(HANDLE hFile);
|
||||
|
||||
BOOL ReadFile(HANDLE hFile, void * lpBuffer, DWORD nNumberOfBytesToRead, DWORD * lpNumberOfBytesRead, void * lpOverLapped);
|
||||
BOOL WriteFile(HANDLE hFile, const void * lpBuffer, DWORD nNumberOfBytesToWrite, DWORD * lpNumberOfBytesWritten, void * lpOverLapped);
|
||||
|
||||
BOOL IsBadReadPtr(const void * ptr, int size);
|
||||
DWORD GetFileAttributes(const char * szileName);
|
||||
|
||||
BOOL DeleteFile(const char * lpFileName);
|
||||
BOOL MoveFile(const char * lpFromFileName, const char * lpToFileName);
|
||||
void GetTempPath(DWORD szTempLength, char * szTemp);
|
||||
void GetTempFileName(const char * lpTempFolderPath, const char * lpFileName, DWORD something, char * szLFName);
|
||||
|
||||
#define strnicmp strncasecmp
|
||||
|
||||
#endif // !WIN32
|
||||
|
||||
#if PLATFORM_LITTLE_ENDIAN
|
||||
#define BSWAP_INT16_UNSIGNED(a) (a)
|
||||
#define BSWAP_INT16_SIGNED(a) (a)
|
||||
#define BSWAP_INT32_UNSIGNED(a) (a)
|
||||
#define BSWAP_INT32_SIGNED(a) (a)
|
||||
#define BSWAP_ARRAY16_UNSIGNED(a,b) {}
|
||||
#define BSWAP_ARRAY32_UNSIGNED(a,b) {}
|
||||
#define BSWAP_TMPQSHUNT(a) {}
|
||||
#define BSWAP_TMPQHEADER(a) {}
|
||||
#else
|
||||
extern unsigned short SwapUShort(unsigned short);
|
||||
extern unsigned long SwapULong(unsigned long);
|
||||
extern short SwapShort(unsigned short);
|
||||
extern long SwapLong(unsigned long);
|
||||
extern void ConvertUnsignedLongBuffer(unsigned long *buffer, unsigned long nbLongs);
|
||||
extern void ConvertUnsignedShortBuffer(unsigned short *buffer, unsigned long nbShorts);
|
||||
extern void ConvertTMPQShunt(void *shunt);
|
||||
extern void ConvertTMPQHeader(void *header);
|
||||
#define BSWAP_INT16_UNSIGNED(a) SwapUShort((a))
|
||||
#define BSWAP_INT32_UNSIGNED(a) SwapULong((a))
|
||||
#define BSWAP_INT16_SIGNED(a) SwapShort((a))
|
||||
#define BSWAP_INT32_SIGNED(a) SwapLong((a))
|
||||
#define BSWAP_ARRAY16_UNSIGNED(a,b) ConvertUnsignedShortBuffer((a),(b))
|
||||
#define BSWAP_ARRAY32_UNSIGNED(a,b) ConvertUnsignedLongBuffer((a),(b))
|
||||
#define BSWAP_TMPQSHUNT(a) ConvertTMPQShunt((a))
|
||||
#define BSWAP_TMPQHEADER(a) ConvertTMPQHeader((a))
|
||||
#endif
|
||||
|
||||
#endif // __STORMPORT_H__
|
||||
168
src/tools/stuffextract/StormLib/StormPortLinux.cpp
Normal file
168
src/tools/stuffextract/StormLib/StormPortLinux.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
/********************************************************************
|
||||
*
|
||||
* Description: implementation for StormLib - linux port
|
||||
* intended to be used in GLdiablo
|
||||
*
|
||||
* ----> StormLib was originally developed for Windows by
|
||||
* Ladislav Zezula (www.zezula.net), and he did
|
||||
* a _great_ job! Thanks Ladislav!
|
||||
*
|
||||
* this is currently a quick and dirty hack to get it working
|
||||
* don't expect beauty and/or miracles :)
|
||||
*
|
||||
* these are function wraps to execute Windows API calls
|
||||
* as native Macintosh file calls (open/close/read/write/...)
|
||||
*
|
||||
* continue you work: added some wrapping functions for GNU/Linux by XPinguin
|
||||
*
|
||||
* Author: Marko Friedemann <marko.friedemann@bmx-chemnitz.de>
|
||||
* Created at: Mon Jan 29 19:01:37 CEST 2001
|
||||
* Computer: whiplash.flachland-chemnitz.de
|
||||
* System: Linux 2.4.0 on i686
|
||||
*
|
||||
* Copyright (c) 2001 BMX-Chemnitz.DE All rights reserved.
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "StormPort.h"
|
||||
|
||||
int globalerr;
|
||||
|
||||
void SetLastError(int err)
|
||||
{
|
||||
globalerr = err;
|
||||
}
|
||||
|
||||
int GetLastError()
|
||||
{
|
||||
return(globalerr);
|
||||
}
|
||||
|
||||
char *ErrString(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case ERROR_INVALID_FUNCTION:
|
||||
return "function not implemented";
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
return "file not found";
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return "access denied";
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
return "not enough memory";
|
||||
case ERROR_BAD_FORMAT:
|
||||
return "bad format";
|
||||
case ERROR_NO_MORE_FILES:
|
||||
return "no more files";
|
||||
case ERROR_HANDLE_EOF:
|
||||
return "access beyound EOF";
|
||||
case ERROR_HANDLE_DISK_FULL:
|
||||
return "no space left on device";
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
return "invalid parameter";
|
||||
case ERROR_DISK_FULL:
|
||||
return "no space left on device";
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return "file exists";
|
||||
case ERROR_CAN_NOT_COMPLETE:
|
||||
return "operation cannot be completed";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE CreateFile(const char *sFileName, DWORD ulMode, DWORD ulSharing, void *pSecAttrib, DWORD ulCreation, DWORD ulFlags, HANDLE hFile)
|
||||
{
|
||||
switch (ulCreation) {
|
||||
case OPEN_EXISTING:
|
||||
return (HANDLE)open(sFileName, O_RDONLY | O_LARGEFILE);
|
||||
case OPEN_ALWAYS:
|
||||
return (HANDLE)open(sFileName, O_RDWR | O_CREAT);
|
||||
case CREATE_NEW:
|
||||
return (HANDLE)open(sFileName, O_RDWR | O_CREAT | O_TRUNC);
|
||||
default:
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CloseHandle(HANDLE hFile)
|
||||
{
|
||||
return (close((int)hFile) == 0);
|
||||
}
|
||||
|
||||
DWORD GetFileSize(HANDLE hFile, DWORD *ulOffSetHigh)
|
||||
{
|
||||
if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE))
|
||||
return 0xffffffff;
|
||||
|
||||
struct stat fileinfo;
|
||||
fstat((int)hFile, &fileinfo);
|
||||
|
||||
return fileinfo.st_size;
|
||||
}
|
||||
|
||||
DWORD SetFilePointer(HANDLE hFile, LONG lOffSetLow, LONG *pOffSetHigh, DWORD ulMethod)
|
||||
{
|
||||
return lseek64((int)hFile, (off64_t)(*pOffSetHigh) << 32 | (DWORD)lOffSetLow, ulMethod);
|
||||
}
|
||||
|
||||
BOOL SetEndOfFile(HANDLE hFile)
|
||||
{
|
||||
return (ftruncate((int)hFile, lseek((int)hFile, 0, SEEK_CUR)) == 0);
|
||||
}
|
||||
|
||||
BOOL ReadFile(HANDLE hFile, void *pBuffer, DWORD ulLen, DWORD *ulRead, void *pOverLapped)
|
||||
{
|
||||
ssize_t count;
|
||||
if ((count = read((int)hFile, pBuffer, ulLen)) == -1) {
|
||||
*ulRead = 0;
|
||||
return false;
|
||||
}
|
||||
*ulRead = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL WriteFile(HANDLE hFile, const void *pBuffer, DWORD ulLen, DWORD *ulWritten, void *pOverLapped)
|
||||
{
|
||||
ssize_t count;
|
||||
if ((count = write((int)hFile, pBuffer, ulLen)) == -1) {
|
||||
*ulWritten = 0;
|
||||
return false;
|
||||
}
|
||||
*ulWritten = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if a memory block is accessible for reading
|
||||
BOOL IsBadReadPtr(const void * ptr, int size)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Returns attributes of a file
|
||||
DWORD GetFileAttributes(const char * szFileName)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetTempPath(DWORD szTempLength, char * szTemp)
|
||||
{
|
||||
strncpy(szTemp, P_tmpdir, szTempLength);
|
||||
}
|
||||
|
||||
void GetTempFileName(const char * lpTempFolderPath, const char * lpFileName, DWORD something, char * szLFName)
|
||||
{
|
||||
strcpy(szLFName, tempnam(lpTempFolderPath, lpFileName));
|
||||
}
|
||||
|
||||
BOOL DeleteFile(const char *lpFileName)
|
||||
{
|
||||
return (BOOL)remove(lpFileName);
|
||||
}
|
||||
|
||||
BOOL MoveFile(const char *lpExistingFileName, const char *lpNewFileName)
|
||||
{
|
||||
return rename(lpExistingFileName, lpNewFileName);
|
||||
}
|
||||
|
||||
#endif
|
||||
762
src/tools/stuffextract/StormLib/StormPortMac.cpp
Normal file
762
src/tools/stuffextract/StormLib/StormPortMac.cpp
Normal file
@ -0,0 +1,762 @@
|
||||
/********************************************************************
|
||||
*
|
||||
* Description: implementation for StormLib - Macintosh port
|
||||
*
|
||||
* these are function wraps to execute Windows API calls
|
||||
* as native Macintosh file calls (open/close/read/write/...)
|
||||
* requires Mac OS X
|
||||
*
|
||||
* Derived from Marko Friedemann <marko.friedemann@bmx-chemnitz.de>
|
||||
* StormPort.cpp for Linux
|
||||
*
|
||||
* Author: Daniel Chiaramello <daniel@chiaramello.net>
|
||||
*
|
||||
* Carbonized by: Sam Wilkins <swilkins1337@gmail.com>
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#ifndef _WIN32 || _WIN64
|
||||
#include "StormPort.h"
|
||||
#include "StormLib.h"
|
||||
|
||||
// FUNCTIONS EXTRACTED FROM MOREFILE PACKAGE!!!
|
||||
// FEEL FREE TO REMOVE THEM AND TO ADD THE ORIGINAL ONES!
|
||||
|
||||
/*****************************************************************************
|
||||
* BEGIN OF MOREFILES COPY-PASTE
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef __USEPRAGMAINTERNAL
|
||||
#ifdef __MWERKS__
|
||||
#pragma internal on
|
||||
#endif
|
||||
#endif
|
||||
|
||||
union TLongAnd4Bytes
|
||||
{
|
||||
unsigned char bytes[4];
|
||||
unsigned long uvalue;
|
||||
signed long svalue;
|
||||
};
|
||||
|
||||
|
||||
static OSErr FSGetFullPath(const FSRef *ref, UInt8 *fullPath, UInt32 fullPathLength)
|
||||
{
|
||||
OSErr result;
|
||||
|
||||
result = FSRefMakePath(ref, fullPath, fullPathLength);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSErr FSLocationFromFullPath(const void *fullPath, FSRef *ref)
|
||||
{
|
||||
OSErr result;
|
||||
|
||||
result = FSPathMakeRef((UInt8 *)fullPath, ref, NULL); // Create an FSRef from the path
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static OSErr FSCreateCompat(const FSRef *parentRef, OSType creator, OSType fileType, const UniChar *fileName,
|
||||
UniCharCount nameLength, FSRef *ref)
|
||||
{
|
||||
FSCatalogInfo theCatInfo;
|
||||
OSErr theErr;
|
||||
((FileInfo *)&theCatInfo.finderInfo)->fileCreator = creator;
|
||||
((FileInfo *)&theCatInfo.finderInfo)->fileType = fileType;
|
||||
((FileInfo *)&theCatInfo.finderInfo)->finderFlags = 0;
|
||||
SetPt(&((FileInfo *)&theCatInfo.finderInfo)->location, 0, 0);
|
||||
((FileInfo *)&theCatInfo.finderInfo)->reservedField = 0;
|
||||
|
||||
theErr = FSCreateFileUnicode(parentRef, nameLength, fileName, kFSCatInfoFinderInfo, &theCatInfo, ref, NULL);
|
||||
return theErr;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static OSErr FSOpenDFCompat(FSRef *ref, char permission, short *refNum)
|
||||
{
|
||||
HFSUniStr255 forkName;
|
||||
OSErr theErr;
|
||||
Boolean isFolder, wasChanged;
|
||||
|
||||
theErr = FSResolveAliasFile(ref, TRUE, &isFolder, &wasChanged);
|
||||
if (theErr != noErr)
|
||||
return theErr;
|
||||
|
||||
FSGetDataForkName(&forkName);
|
||||
theErr = FSOpenFork(ref, forkName.length, forkName.unicode, permission, refNum);
|
||||
return theErr;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* END OF MOREFILES COPY-PASTE
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma mark -
|
||||
|
||||
int globalerr;
|
||||
|
||||
/********************************************************************
|
||||
* SwapLong
|
||||
********************************************************************/
|
||||
|
||||
unsigned long SwapULong(unsigned long data)
|
||||
{
|
||||
// Apple provided function
|
||||
uint32_t result;
|
||||
|
||||
__asm__("lwbrx %0,0,%1" : "=r" (result) : "r" (&data), "m" (data));
|
||||
return result;
|
||||
|
||||
/*
|
||||
TLongAnd4Bytes Work;
|
||||
unsigned char * value_as_4bytes = (unsigned char *)&value;
|
||||
|
||||
Work.bytes[0] = value_as_4bytes[3];
|
||||
Work.bytes[1] = value_as_4bytes[2];
|
||||
Work.bytes[2] = value_as_4bytes[1];
|
||||
Work.bytes[3] = value_as_4bytes[0];
|
||||
|
||||
return Work.uvalue;
|
||||
*/
|
||||
}
|
||||
|
||||
long SwapLong(unsigned long data)
|
||||
{
|
||||
// Apple provided function
|
||||
uint32_t result;
|
||||
|
||||
__asm__("lwbrx %0,0,%1" : "=r" (result) : "r" (&data), "m" (data));
|
||||
return (long)result;
|
||||
|
||||
/*
|
||||
TLongAnd4Bytes Work;
|
||||
unsigned char * value_as_4bytes = (unsigned char *)&value;
|
||||
|
||||
Work.bytes[0] = value_as_4bytes[3];
|
||||
Work.bytes[1] = value_as_4bytes[2];
|
||||
Work.bytes[2] = value_as_4bytes[1];
|
||||
Work.bytes[3] = value_as_4bytes[0];
|
||||
|
||||
return Work.svalue;
|
||||
*/
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* SwapShort
|
||||
********************************************************************/
|
||||
unsigned short SwapUShort(unsigned short data)
|
||||
{
|
||||
// Apple provided function
|
||||
uint16_t result;
|
||||
__asm__("lhbrx %0,0,%1" : "=r" (result) : "r" (&data), "m" (data));
|
||||
return result;
|
||||
}
|
||||
|
||||
short SwapShort(unsigned short data)
|
||||
{
|
||||
// Apple provided function
|
||||
uint16_t result;
|
||||
__asm__("lhbrx %0,0,%1" : "=r" (result) : "r" (&data), "m" (data));
|
||||
return (short)result;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* ConvertUnsignedLongBuffer
|
||||
********************************************************************/
|
||||
void ConvertUnsignedLongBuffer(unsigned long *buffer, unsigned long nbLongs)
|
||||
{
|
||||
while (nbLongs-- > 0)
|
||||
{
|
||||
*buffer = SwapLong(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* ConvertUnsignedShortBuffer
|
||||
********************************************************************/
|
||||
void ConvertUnsignedShortBuffer(unsigned short *buffer, unsigned long nbShorts)
|
||||
{
|
||||
while (nbShorts-- > 0)
|
||||
{
|
||||
*buffer = SwapShort(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* ConvertTMPQShunt
|
||||
********************************************************************/
|
||||
void ConvertTMPQShunt(void *shunt)
|
||||
{
|
||||
TMPQShunt * theShunt = (TMPQShunt *)shunt;
|
||||
|
||||
theShunt->dwID = SwapULong(theShunt->dwID);
|
||||
theShunt->dwUnknown = SwapULong(theShunt->dwUnknown);
|
||||
theShunt->dwHeaderPos = SwapULong(theShunt->dwHeaderPos);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* ConvertTMPQHeader
|
||||
********************************************************************/
|
||||
void ConvertTMPQHeader(void *header)
|
||||
{
|
||||
TMPQHeader2 * theHeader = (TMPQHeader2 *)header;
|
||||
|
||||
theHeader->dwID = SwapULong(theHeader->dwID);
|
||||
theHeader->dwHeaderSize = SwapULong(theHeader->dwHeaderSize);
|
||||
theHeader->dwArchiveSize = SwapULong(theHeader->dwArchiveSize);
|
||||
theHeader->wFormatVersion = SwapUShort(theHeader->wFormatVersion);
|
||||
theHeader->wBlockSize = SwapUShort(theHeader->wBlockSize);
|
||||
theHeader->dwHashTablePos = SwapULong(theHeader->dwHashTablePos);
|
||||
theHeader->dwBlockTablePos = SwapULong(theHeader->dwBlockTablePos);
|
||||
theHeader->dwHashTableSize = SwapULong(theHeader->dwHashTableSize);
|
||||
theHeader->dwBlockTableSize = SwapULong(theHeader->dwBlockTableSize);
|
||||
|
||||
if(theHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2)
|
||||
{
|
||||
DWORD dwTemp = theHeader->ExtBlockTablePos.LowPart;
|
||||
theHeader->ExtBlockTablePos.LowPart = theHeader->ExtBlockTablePos.HighPart;
|
||||
theHeader->ExtBlockTablePos.HighPart = dwTemp;
|
||||
theHeader->ExtBlockTablePos.LowPart = SwapULong(theHeader->ExtBlockTablePos.LowPart);
|
||||
theHeader->ExtBlockTablePos.HighPart = SwapULong(theHeader->ExtBlockTablePos.HighPart);
|
||||
theHeader->wHashTablePosHigh = SwapUShort(theHeader->wHashTablePosHigh);
|
||||
theHeader->wBlockTablePosHigh = SwapUShort(theHeader->wBlockTablePosHigh);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* ConvertTMPQHash
|
||||
********************************************************************/
|
||||
void ConvertHashTable(void *hashtable, DWORD nHashEntries)
|
||||
{
|
||||
TMPQHash * theHash = (TMPQHash *)hashtable;
|
||||
USHORT lcLocale;
|
||||
|
||||
for(DWORD i = 0; i < nHashEntries; i++, theHash++)
|
||||
{
|
||||
lcLocale = theHash->lcLocale;
|
||||
theHash->lcLocale = theHash->wPlatform;
|
||||
theHash->wPlatform = lcLocale;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/********************************************************************
|
||||
* SetLastError
|
||||
********************************************************************/
|
||||
void SetLastError(int err)
|
||||
{
|
||||
globalerr = err;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* GetLastError
|
||||
********************************************************************/
|
||||
int GetLastError()
|
||||
{
|
||||
return globalerr;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* ErrString
|
||||
********************************************************************/
|
||||
char *ErrString(int err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case ERROR_INVALID_FUNCTION:
|
||||
return "function not implemented";
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
return "file not found";
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return "access denied";
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
return "not enough memory";
|
||||
case ERROR_BAD_FORMAT:
|
||||
return "bad format";
|
||||
case ERROR_NO_MORE_FILES:
|
||||
return "no more files";
|
||||
case ERROR_HANDLE_EOF:
|
||||
return "access beyound EOF";
|
||||
case ERROR_HANDLE_DISK_FULL:
|
||||
return "no space left on device";
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
return "invalid parameter";
|
||||
case ERROR_DISK_FULL:
|
||||
return "no space left on device";
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return "file exists";
|
||||
case ERROR_CAN_NOT_COMPLETE:
|
||||
return "operation cannot be completed";
|
||||
case ERROR_INSUFFICIENT_BUFFER:
|
||||
return "insufficient buffer";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/********************************************************************
|
||||
* GetTempPath - returns a '/' or ':'-terminated path
|
||||
* szTempLength: length for path
|
||||
* szTemp: file path
|
||||
********************************************************************/
|
||||
void GetTempPath(DWORD szTempLength, char * szTemp) // I think I'll change this to use FSRefs.
|
||||
{
|
||||
FSRef theFSRef;
|
||||
OSErr theErr = FSFindFolder(kOnAppropriateDisk, kTemporaryFolderType, kCreateFolder, &theFSRef);
|
||||
if (theErr == noErr)
|
||||
{
|
||||
theErr = FSGetFullPath(&theFSRef, (UInt8 *)szTemp, MAX_PATH);
|
||||
if (theErr != noErr)
|
||||
szTemp[0] = '\0';
|
||||
}
|
||||
else
|
||||
szTemp[0] = '\0';
|
||||
strcat(szTemp, "/");
|
||||
|
||||
SetLastError(theErr);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* GetTempFileName
|
||||
* lpTempFolderPath: the temporary folder path, terminated by "/"
|
||||
* lpFileName: a file name base
|
||||
* something: unknown
|
||||
* szLFName: the final path, built from the path, the file name and a random pattern
|
||||
********************************************************************/
|
||||
void GetTempFileName(const char * lpTempFolderPath, const char * lpFileName, DWORD something, char * szLFName)
|
||||
{
|
||||
#pragma unused (something)
|
||||
char tmp[2] = "A";
|
||||
|
||||
while (true)
|
||||
{
|
||||
HANDLE fHandle;
|
||||
|
||||
strcpy(szLFName, lpTempFolderPath);
|
||||
strcat(szLFName, lpFileName);
|
||||
strcat(szLFName, tmp);
|
||||
|
||||
if ((fHandle = CreateFile(szLFName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
|
||||
// OK we found it!
|
||||
break;
|
||||
CloseHandle(fHandle);
|
||||
tmp[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* DeleteFile
|
||||
* lpFileName: file path
|
||||
********************************************************************/
|
||||
BOOL DeleteFile(const char * lpFileName)
|
||||
{
|
||||
OSErr theErr;
|
||||
FSRef theFileRef;
|
||||
|
||||
theErr = FSLocationFromFullPath(lpFileName, &theFileRef);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
theErr = FSDeleteObject(&theFileRef);
|
||||
|
||||
SetLastError(theErr);
|
||||
|
||||
return theErr == noErr;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* MoveFile
|
||||
* lpFromFileName: old file path
|
||||
* lpToFileName: new file path
|
||||
********************************************************************/
|
||||
BOOL MoveFile(const char * lpFromFileName, const char * lpToFileName)
|
||||
{
|
||||
OSErr theErr;
|
||||
FSRef fromFileRef;
|
||||
FSRef toFileRef;
|
||||
FSRef parentFolderRef;
|
||||
|
||||
// Get the path to the old file
|
||||
theErr = FSLocationFromFullPath(lpFromFileName, &fromFileRef);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the path to the new folder for the file
|
||||
char folderName[strlen(lpToFileName)];
|
||||
CFStringRef folderPathCFString = CFStringCreateWithCString(NULL, lpToFileName, kCFStringEncodingUTF8);
|
||||
CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, folderPathCFString, kCFURLPOSIXPathStyle, FALSE);
|
||||
CFURLRef folderURL = CFURLCreateCopyDeletingLastPathComponent(NULL, fileURL);
|
||||
CFURLGetFileSystemRepresentation(folderURL, TRUE, (UInt8 *)folderName, strlen(lpToFileName));
|
||||
theErr = FSLocationFromFullPath(folderName, &parentFolderRef);
|
||||
CFRelease(fileURL);
|
||||
CFRelease(folderURL);
|
||||
CFRelease(folderPathCFString);
|
||||
|
||||
// Move the old file
|
||||
theErr = FSMoveObject(&fromFileRef, &parentFolderRef, &toFileRef);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get a CFString for the new file name
|
||||
CFStringRef newFileNameCFString = CFStringCreateWithCString(NULL, lpToFileName, kCFStringEncodingUTF8);
|
||||
fileURL = CFURLCreateWithFileSystemPath(NULL, newFileNameCFString, kCFURLPOSIXPathStyle, FALSE);
|
||||
CFRelease(newFileNameCFString);
|
||||
newFileNameCFString = CFURLCopyLastPathComponent(fileURL);
|
||||
CFRelease(fileURL);
|
||||
|
||||
// Convert CFString to Unicode and rename the file
|
||||
UniChar unicodeFileName[256];
|
||||
CFStringGetCharacters(newFileNameCFString, CFRangeMake(0, CFStringGetLength(newFileNameCFString)),
|
||||
unicodeFileName);
|
||||
theErr = FSRenameUnicode(&toFileRef, CFStringGetLength(newFileNameCFString), unicodeFileName,
|
||||
kTextEncodingUnknown, NULL);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
CFRelease(newFileNameCFString);
|
||||
return false;
|
||||
}
|
||||
|
||||
CFRelease(newFileNameCFString);
|
||||
|
||||
SetLastError(theErr);
|
||||
return true;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* CreateFile
|
||||
* ulMode: GENERIC_READ | GENERIC_WRITE
|
||||
* ulSharing: FILE_SHARE_READ
|
||||
* pSecAttrib: NULL
|
||||
* ulCreation: OPEN_EXISTING, OPEN_ALWAYS, CREATE_NEW
|
||||
* ulFlags: 0
|
||||
* hFile: NULL
|
||||
********************************************************************/
|
||||
HANDLE CreateFile( const char *sFileName, /* file name */
|
||||
DWORD ulMode, /* access mode */
|
||||
DWORD ulSharing, /* share mode */
|
||||
void *pSecAttrib, /* SD */
|
||||
DWORD ulCreation, /* how to create */
|
||||
DWORD ulFlags, /* file attributes */
|
||||
HANDLE hFile ) /* handle to template file */
|
||||
{
|
||||
#pragma unused (ulSharing, pSecAttrib, ulFlags, hFile)
|
||||
|
||||
OSErr theErr;
|
||||
FSRef theFileRef;
|
||||
FSRef theParentRef;
|
||||
short fileRef;
|
||||
char permission;
|
||||
static OSType gCreator;
|
||||
static OSType gType;
|
||||
|
||||
theErr = FSLocationFromFullPath(sFileName, &theFileRef);
|
||||
if (theErr == fnfErr)
|
||||
{ // Create the FSRef for the parent directory.
|
||||
memset(&theFileRef, 0, sizeof(FSRef));
|
||||
UInt8 folderName[MAX_PATH];
|
||||
CFStringRef folderPathCFString = CFStringCreateWithCString(NULL, sFileName, kCFStringEncodingUTF8);
|
||||
CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, folderPathCFString, kCFURLPOSIXPathStyle, FALSE);
|
||||
CFURLRef folderURL = CFURLCreateCopyDeletingLastPathComponent(NULL, fileURL);
|
||||
CFURLGetFileSystemRepresentation(folderURL, TRUE, folderName, MAX_PATH);
|
||||
theErr = FSLocationFromFullPath(folderName, &theParentRef);
|
||||
CFRelease(fileURL);
|
||||
CFRelease(folderURL);
|
||||
CFRelease(folderPathCFString);
|
||||
}
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
if (ulCreation == OPEN_EXISTING || theErr != fnfErr)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (ulCreation != OPEN_EXISTING)
|
||||
{ /* We create the file */
|
||||
UniChar unicodeFileName[256];
|
||||
CFStringRef filePathCFString = CFStringCreateWithCString(NULL, sFileName, kCFStringEncodingUTF8);
|
||||
CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, filePathCFString, kCFURLPOSIXPathStyle, FALSE);
|
||||
CFStringRef fileNameCFString = CFURLCopyLastPathComponent(fileURL);
|
||||
CFStringGetCharacters(fileNameCFString, CFRangeMake(0, CFStringGetLength(fileNameCFString)),
|
||||
unicodeFileName);
|
||||
theErr = FSCreateCompat(&theParentRef, gCreator, gType, unicodeFileName,
|
||||
CFStringGetLength(fileNameCFString), &theFileRef);
|
||||
CFRelease(fileNameCFString);
|
||||
CFRelease(filePathCFString);
|
||||
CFRelease(fileURL);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ulMode == GENERIC_READ)
|
||||
permission = fsRdPerm;
|
||||
else
|
||||
{
|
||||
if (ulMode == GENERIC_WRITE)
|
||||
permission = fsWrPerm;
|
||||
else
|
||||
permission = fsRdWrPerm;
|
||||
}
|
||||
theErr = FSOpenDFCompat(&theFileRef, permission, &fileRef);
|
||||
|
||||
SetLastError(theErr);
|
||||
|
||||
if (theErr == noErr)
|
||||
return (HANDLE)(int)fileRef;
|
||||
else
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* CloseHandle
|
||||
********************************************************************/
|
||||
BOOL CloseHandle( HANDLE hFile ) /* handle to object */
|
||||
{
|
||||
OSErr theErr;
|
||||
|
||||
if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE))
|
||||
return FALSE;
|
||||
|
||||
theErr = FSCloseFork((short)(int)hFile);
|
||||
|
||||
SetLastError(theErr);
|
||||
|
||||
return theErr != noErr;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* GetFileSize
|
||||
********************************************************************/
|
||||
DWORD GetFileSize( HANDLE hFile, /* handle to file */
|
||||
DWORD *ulOffSetHigh ) /* high-order word of file size */
|
||||
{
|
||||
SInt64 fileLength;
|
||||
OSErr theErr;
|
||||
|
||||
if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE))
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return -1u;
|
||||
}
|
||||
|
||||
theErr = FSGetForkSize((short)(int)hFile, &fileLength);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return -1u;
|
||||
}
|
||||
|
||||
if (ulOffSetHigh != NULL)
|
||||
*ulOffSetHigh = fileLength >> 32;
|
||||
|
||||
SetLastError(theErr);
|
||||
|
||||
return fileLength;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* SetFilePointer
|
||||
* pOffSetHigh: NULL
|
||||
* ulMethod: FILE_BEGIN, FILE_CURRENT
|
||||
********************************************************************/
|
||||
DWORD SetFilePointer( HANDLE hFile, /* handle to file */
|
||||
LONG lOffSetLow, /* bytes to move pointer */
|
||||
LONG *pOffSetHigh, /* bytes to move pointer */
|
||||
DWORD ulMethod ) /* starting point */
|
||||
{
|
||||
OSErr theErr;
|
||||
|
||||
if (ulMethod == FILE_CURRENT)
|
||||
{
|
||||
SInt64 bytesToMove;
|
||||
|
||||
if (pOffSetHigh != NULL)
|
||||
bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow;
|
||||
else
|
||||
bytesToMove = lOffSetLow;
|
||||
|
||||
SInt64 newPos;
|
||||
|
||||
theErr = FSSetForkPosition((short)(int)hFile, fsFromMark, bytesToMove);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return -1u;
|
||||
}
|
||||
|
||||
theErr = FSGetForkPosition((short)(int)hFile, &newPos);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return -1u;
|
||||
}
|
||||
|
||||
if (pOffSetHigh != NULL)
|
||||
*pOffSetHigh = newPos >> 32;
|
||||
|
||||
SetLastError(theErr);
|
||||
return newPos;
|
||||
}
|
||||
else if (ulMethod == FILE_BEGIN)
|
||||
{
|
||||
SInt64 bytesToMove;
|
||||
|
||||
if (pOffSetHigh != NULL)
|
||||
bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow;
|
||||
else
|
||||
bytesToMove = lOffSetLow;
|
||||
|
||||
theErr = FSSetForkPosition((short)(int)hFile, fsFromStart, bytesToMove);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return -1u;
|
||||
}
|
||||
|
||||
SetLastError(theErr);
|
||||
return lOffSetLow;
|
||||
}
|
||||
else
|
||||
{
|
||||
SInt64 bytesToMove;
|
||||
|
||||
if (pOffSetHigh != NULL)
|
||||
bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow;
|
||||
else
|
||||
bytesToMove = lOffSetLow;
|
||||
|
||||
SInt64 newPos;
|
||||
|
||||
theErr = FSSetForkPosition((short)(int)hFile, fsFromLEOF, bytesToMove);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return -1u;
|
||||
}
|
||||
|
||||
theErr = FSGetForkPosition((short)(int)hFile, &newPos);
|
||||
if (theErr != noErr)
|
||||
{
|
||||
SetLastError(theErr);
|
||||
return -1u;
|
||||
}
|
||||
|
||||
if (pOffSetHigh != NULL)
|
||||
*pOffSetHigh = newPos >> 32;
|
||||
|
||||
SetLastError(theErr);
|
||||
return newPos;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* SetEndOfFile
|
||||
********************************************************************/
|
||||
BOOL SetEndOfFile( HANDLE hFile ) /* handle to file */
|
||||
{
|
||||
OSErr theErr;
|
||||
|
||||
theErr = FSSetForkSize((short)(int)hFile, fsAtMark, 0);
|
||||
|
||||
SetLastError(theErr);
|
||||
|
||||
return theErr == noErr;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* ReadFile
|
||||
* pOverLapped: NULL
|
||||
********************************************************************/
|
||||
BOOL ReadFile( HANDLE hFile, /* handle to file */
|
||||
void *pBuffer, /* data buffer */
|
||||
DWORD ulLen, /* number of bytes to read */
|
||||
DWORD *ulRead, /* number of bytes read */
|
||||
void *pOverLapped ) /* overlapped buffer */
|
||||
{
|
||||
#pragma unused (pOverLapped)
|
||||
|
||||
ByteCount nbCharsRead;
|
||||
OSErr theErr;
|
||||
|
||||
nbCharsRead = ulLen;
|
||||
theErr = FSReadFork((short)(int)hFile, fsAtMark, 0, nbCharsRead, pBuffer, &nbCharsRead);
|
||||
*ulRead = nbCharsRead;
|
||||
|
||||
SetLastError(theErr);
|
||||
|
||||
return theErr == noErr;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* WriteFile
|
||||
* pOverLapped: NULL
|
||||
********************************************************************/
|
||||
BOOL WriteFile( HANDLE hFile, /* handle to file */
|
||||
const void *pBuffer, /* data buffer */
|
||||
DWORD ulLen, /* number of bytes to write */
|
||||
DWORD *ulWritten, /* number of bytes written */
|
||||
void *pOverLapped ) /* overlapped buffer */
|
||||
{
|
||||
#pragma unused (pOverLapped)
|
||||
|
||||
ByteCount nbCharsToWrite;
|
||||
OSErr theErr;
|
||||
|
||||
nbCharsToWrite = ulLen;
|
||||
theErr = FSWriteFork((short)(int)hFile, fsAtMark, 0, nbCharsToWrite, pBuffer, &nbCharsToWrite);
|
||||
*ulWritten = nbCharsToWrite;
|
||||
|
||||
SetLastError(theErr);
|
||||
|
||||
return theErr == noErr;
|
||||
}
|
||||
|
||||
// Check if a memory block is accessible for reading. It's probably too
|
||||
// hard to check on Mac, so sorry, we'll just have to crash
|
||||
BOOL IsBadReadPtr(const void * ptr, int size)
|
||||
{
|
||||
#pragma unused (ptr, size)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Returns attributes of a file. Actually, it doesn't, it just checks if
|
||||
// the file exists, since that's all StormLib uses it for
|
||||
DWORD GetFileAttributes(const char * szFileName)
|
||||
{
|
||||
FSRef theRef;
|
||||
OSErr theErr;
|
||||
|
||||
theErr = FSLocationFromFullPath(szFileName, &theRef);
|
||||
|
||||
if (theErr != noErr)
|
||||
return -1u;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
1141
src/tools/stuffextract/StormLib/bzip2/blocksort.c
Normal file
1141
src/tools/stuffextract/StormLib/bzip2/blocksort.c
Normal file
File diff suppressed because it is too large
Load Diff
2107
src/tools/stuffextract/StormLib/bzip2/bzip2.c
Normal file
2107
src/tools/stuffextract/StormLib/bzip2/bzip2.c
Normal file
File diff suppressed because it is too large
Load Diff
546
src/tools/stuffextract/StormLib/bzip2/bzip2recover.c
Normal file
546
src/tools/stuffextract/StormLib/bzip2/bzip2recover.c
Normal file
@ -0,0 +1,546 @@
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
/*--- Block recoverer program for bzip2 ---*/
|
||||
/*--- bzip2recover.c ---*/
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*--
|
||||
This program is bzip2recover, a program to attempt data
|
||||
salvage from damaged files created by the accompanying
|
||||
bzip2-1.0.3 program.
|
||||
|
||||
Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0.3 of 15 February 2005
|
||||
--*/
|
||||
|
||||
/*--
|
||||
This program is a complete hack and should be rewritten
|
||||
properly. It isn't very complicated.
|
||||
--*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* This program records bit locations in the file to be recovered.
|
||||
That means that if 64-bit ints are not supported, we will not
|
||||
be able to recover .bz2 files over 512MB (2^32 bits) long.
|
||||
On GNU supported platforms, we take advantage of the 64-bit
|
||||
int support to circumvent this problem. Ditto MSVC.
|
||||
|
||||
This change occurred in version 1.0.2; all prior versions have
|
||||
the 512MB limitation.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
typedef unsigned long long int MaybeUInt64;
|
||||
# define MaybeUInt64_FMT "%Lu"
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int64 MaybeUInt64;
|
||||
# define MaybeUInt64_FMT "%I64u"
|
||||
#else
|
||||
typedef unsigned int MaybeUInt64;
|
||||
# define MaybeUInt64_FMT "%u"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef unsigned int UInt32;
|
||||
typedef int Int32;
|
||||
typedef unsigned char UChar;
|
||||
typedef char Char;
|
||||
typedef unsigned char Bool;
|
||||
#define True ((Bool)1)
|
||||
#define False ((Bool)0)
|
||||
|
||||
|
||||
#define BZ_MAX_FILENAME 2000
|
||||
|
||||
Char inFileName[BZ_MAX_FILENAME];
|
||||
Char outFileName[BZ_MAX_FILENAME];
|
||||
Char progName[BZ_MAX_FILENAME];
|
||||
|
||||
MaybeUInt64 bytesOut = 0;
|
||||
MaybeUInt64 bytesIn = 0;
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- Header bytes ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
#define BZ_HDR_B 0x42 /* 'B' */
|
||||
#define BZ_HDR_Z 0x5a /* 'Z' */
|
||||
#define BZ_HDR_h 0x68 /* 'h' */
|
||||
#define BZ_HDR_0 0x30 /* '0' */
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- I/O errors ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------*/
|
||||
void readError ( void )
|
||||
{
|
||||
fprintf ( stderr,
|
||||
"%s: I/O error reading `%s', possible reason follows.\n",
|
||||
progName, inFileName );
|
||||
perror ( progName );
|
||||
fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
|
||||
progName );
|
||||
exit ( 1 );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
void writeError ( void )
|
||||
{
|
||||
fprintf ( stderr,
|
||||
"%s: I/O error reading `%s', possible reason follows.\n",
|
||||
progName, inFileName );
|
||||
perror ( progName );
|
||||
fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
|
||||
progName );
|
||||
exit ( 1 );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
void mallocFail ( Int32 n )
|
||||
{
|
||||
fprintf ( stderr,
|
||||
"%s: malloc failed on request for %d bytes.\n",
|
||||
progName, n );
|
||||
fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
|
||||
progName );
|
||||
exit ( 1 );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
void tooManyBlocks ( Int32 max_handled_blocks )
|
||||
{
|
||||
fprintf ( stderr,
|
||||
"%s: `%s' appears to contain more than %d blocks\n",
|
||||
progName, inFileName, max_handled_blocks );
|
||||
fprintf ( stderr,
|
||||
"%s: and cannot be handled. To fix, increase\n",
|
||||
progName );
|
||||
fprintf ( stderr,
|
||||
"%s: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n",
|
||||
progName );
|
||||
exit ( 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- Bit stream I/O ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
typedef
|
||||
struct {
|
||||
FILE* handle;
|
||||
Int32 buffer;
|
||||
Int32 buffLive;
|
||||
Char mode;
|
||||
}
|
||||
BitStream;
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
BitStream* bsOpenReadStream ( FILE* stream )
|
||||
{
|
||||
BitStream *bs = malloc ( sizeof(BitStream) );
|
||||
if (bs == NULL) mallocFail ( sizeof(BitStream) );
|
||||
bs->handle = stream;
|
||||
bs->buffer = 0;
|
||||
bs->buffLive = 0;
|
||||
bs->mode = 'r';
|
||||
return bs;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
BitStream* bsOpenWriteStream ( FILE* stream )
|
||||
{
|
||||
BitStream *bs = malloc ( sizeof(BitStream) );
|
||||
if (bs == NULL) mallocFail ( sizeof(BitStream) );
|
||||
bs->handle = stream;
|
||||
bs->buffer = 0;
|
||||
bs->buffLive = 0;
|
||||
bs->mode = 'w';
|
||||
return bs;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
void bsPutBit ( BitStream* bs, Int32 bit )
|
||||
{
|
||||
if (bs->buffLive == 8) {
|
||||
Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
|
||||
if (retVal == EOF) writeError();
|
||||
bytesOut++;
|
||||
bs->buffLive = 1;
|
||||
bs->buffer = bit & 0x1;
|
||||
} else {
|
||||
bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) );
|
||||
bs->buffLive++;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
/*--
|
||||
Returns 0 or 1, or 2 to indicate EOF.
|
||||
--*/
|
||||
Int32 bsGetBit ( BitStream* bs )
|
||||
{
|
||||
if (bs->buffLive > 0) {
|
||||
bs->buffLive --;
|
||||
return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 );
|
||||
} else {
|
||||
Int32 retVal = getc ( bs->handle );
|
||||
if ( retVal == EOF ) {
|
||||
if (errno != 0) readError();
|
||||
return 2;
|
||||
}
|
||||
bs->buffLive = 7;
|
||||
bs->buffer = retVal;
|
||||
return ( ((bs->buffer) >> 7) & 0x1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
void bsClose ( BitStream* bs )
|
||||
{
|
||||
Int32 retVal;
|
||||
|
||||
if ( bs->mode == 'w' ) {
|
||||
while ( bs->buffLive < 8 ) {
|
||||
bs->buffLive++;
|
||||
bs->buffer <<= 1;
|
||||
};
|
||||
retVal = putc ( (UChar) (bs->buffer), bs->handle );
|
||||
if (retVal == EOF) writeError();
|
||||
bytesOut++;
|
||||
retVal = fflush ( bs->handle );
|
||||
if (retVal == EOF) writeError();
|
||||
}
|
||||
retVal = fclose ( bs->handle );
|
||||
if (retVal == EOF) {
|
||||
if (bs->mode == 'w') writeError(); else readError();
|
||||
}
|
||||
free ( bs );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
void bsPutUChar ( BitStream* bs, UChar c )
|
||||
{
|
||||
Int32 i;
|
||||
for (i = 7; i >= 0; i--)
|
||||
bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
void bsPutUInt32 ( BitStream* bs, UInt32 c )
|
||||
{
|
||||
Int32 i;
|
||||
|
||||
for (i = 31; i >= 0; i--)
|
||||
bsPutBit ( bs, (c >> i) & 0x1 );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
Bool endsInBz2 ( Char* name )
|
||||
{
|
||||
Int32 n = strlen ( name );
|
||||
if (n <= 4) return False;
|
||||
return
|
||||
(name[n-4] == '.' &&
|
||||
name[n-3] == 'b' &&
|
||||
name[n-2] == 'z' &&
|
||||
name[n-1] == '2');
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/* This logic isn't really right when it comes to Cygwin. */
|
||||
#ifdef _WIN32
|
||||
# define BZ_SPLIT_SYM '\\' /* path splitter on Windows platform */
|
||||
#else
|
||||
# define BZ_SPLIT_SYM '/' /* path splitter on Unix platform */
|
||||
#endif
|
||||
|
||||
#define BLOCK_HEADER_HI 0x00003141UL
|
||||
#define BLOCK_HEADER_LO 0x59265359UL
|
||||
|
||||
#define BLOCK_ENDMARK_HI 0x00001772UL
|
||||
#define BLOCK_ENDMARK_LO 0x45385090UL
|
||||
|
||||
/* Increase if necessary. However, a .bz2 file with > 50000 blocks
|
||||
would have an uncompressed size of at least 40GB, so the chances
|
||||
are low you'll need to up this.
|
||||
*/
|
||||
#define BZ_MAX_HANDLED_BLOCKS 50000
|
||||
|
||||
MaybeUInt64 bStart [BZ_MAX_HANDLED_BLOCKS];
|
||||
MaybeUInt64 bEnd [BZ_MAX_HANDLED_BLOCKS];
|
||||
MaybeUInt64 rbStart[BZ_MAX_HANDLED_BLOCKS];
|
||||
MaybeUInt64 rbEnd [BZ_MAX_HANDLED_BLOCKS];
|
||||
|
||||
Int32 main ( Int32 argc, Char** argv )
|
||||
{
|
||||
FILE* inFile;
|
||||
FILE* outFile;
|
||||
BitStream* bsIn, *bsWr;
|
||||
Int32 b, wrBlock, currBlock, rbCtr;
|
||||
MaybeUInt64 bitsRead;
|
||||
|
||||
UInt32 buffHi, buffLo, blockCRC;
|
||||
Char* p;
|
||||
|
||||
strcpy ( progName, argv[0] );
|
||||
inFileName[0] = outFileName[0] = 0;
|
||||
|
||||
fprintf ( stderr,
|
||||
"bzip2recover 1.0.3: extracts blocks from damaged .bz2 files.\n" );
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
|
||||
progName, progName );
|
||||
switch (sizeof(MaybeUInt64)) {
|
||||
case 8:
|
||||
fprintf(stderr,
|
||||
"\trestrictions on size of recovered file: None\n");
|
||||
break;
|
||||
case 4:
|
||||
fprintf(stderr,
|
||||
"\trestrictions on size of recovered file: 512 MB\n");
|
||||
fprintf(stderr,
|
||||
"\tto circumvent, recompile with MaybeUInt64 as an\n"
|
||||
"\tunsigned 64-bit int.\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"\tsizeof(MaybeUInt64) is not 4 or 8 -- "
|
||||
"configuration error.\n");
|
||||
break;
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strlen(argv[1]) >= BZ_MAX_FILENAME-20) {
|
||||
fprintf ( stderr,
|
||||
"%s: supplied filename is suspiciously (>= %d chars) long. Bye!\n",
|
||||
progName, (int)strlen(argv[1]) );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
strcpy ( inFileName, argv[1] );
|
||||
|
||||
inFile = fopen ( inFileName, "rb" );
|
||||
if (inFile == NULL) {
|
||||
fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bsIn = bsOpenReadStream ( inFile );
|
||||
fprintf ( stderr, "%s: searching for block boundaries ...\n", progName );
|
||||
|
||||
bitsRead = 0;
|
||||
buffHi = buffLo = 0;
|
||||
currBlock = 0;
|
||||
bStart[currBlock] = 0;
|
||||
|
||||
rbCtr = 0;
|
||||
|
||||
while (True) {
|
||||
b = bsGetBit ( bsIn );
|
||||
bitsRead++;
|
||||
if (b == 2) {
|
||||
if (bitsRead >= bStart[currBlock] &&
|
||||
(bitsRead - bStart[currBlock]) >= 40) {
|
||||
bEnd[currBlock] = bitsRead-1;
|
||||
if (currBlock > 0)
|
||||
fprintf ( stderr, " block %d runs from " MaybeUInt64_FMT
|
||||
" to " MaybeUInt64_FMT " (incomplete)\n",
|
||||
currBlock, bStart[currBlock], bEnd[currBlock] );
|
||||
} else
|
||||
currBlock--;
|
||||
break;
|
||||
}
|
||||
buffHi = (buffHi << 1) | (buffLo >> 31);
|
||||
buffLo = (buffLo << 1) | (b & 1);
|
||||
if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI
|
||||
&& buffLo == BLOCK_HEADER_LO)
|
||||
||
|
||||
( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI
|
||||
&& buffLo == BLOCK_ENDMARK_LO)
|
||||
) {
|
||||
if (bitsRead > 49) {
|
||||
bEnd[currBlock] = bitsRead-49;
|
||||
} else {
|
||||
bEnd[currBlock] = 0;
|
||||
}
|
||||
if (currBlock > 0 &&
|
||||
(bEnd[currBlock] - bStart[currBlock]) >= 130) {
|
||||
fprintf ( stderr, " block %d runs from " MaybeUInt64_FMT
|
||||
" to " MaybeUInt64_FMT "\n",
|
||||
rbCtr+1, bStart[currBlock], bEnd[currBlock] );
|
||||
rbStart[rbCtr] = bStart[currBlock];
|
||||
rbEnd[rbCtr] = bEnd[currBlock];
|
||||
rbCtr++;
|
||||
}
|
||||
if (currBlock >= BZ_MAX_HANDLED_BLOCKS)
|
||||
tooManyBlocks(BZ_MAX_HANDLED_BLOCKS);
|
||||
currBlock++;
|
||||
|
||||
bStart[currBlock] = bitsRead;
|
||||
}
|
||||
}
|
||||
|
||||
bsClose ( bsIn );
|
||||
|
||||
/*-- identified blocks run from 1 to rbCtr inclusive. --*/
|
||||
|
||||
if (rbCtr < 1) {
|
||||
fprintf ( stderr,
|
||||
"%s: sorry, I couldn't find any block boundaries.\n",
|
||||
progName );
|
||||
exit(1);
|
||||
};
|
||||
|
||||
fprintf ( stderr, "%s: splitting into blocks\n", progName );
|
||||
|
||||
inFile = fopen ( inFileName, "rb" );
|
||||
if (inFile == NULL) {
|
||||
fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName );
|
||||
exit(1);
|
||||
}
|
||||
bsIn = bsOpenReadStream ( inFile );
|
||||
|
||||
/*-- placate gcc's dataflow analyser --*/
|
||||
blockCRC = 0; bsWr = 0;
|
||||
|
||||
bitsRead = 0;
|
||||
outFile = NULL;
|
||||
wrBlock = 0;
|
||||
while (True) {
|
||||
b = bsGetBit(bsIn);
|
||||
if (b == 2) break;
|
||||
buffHi = (buffHi << 1) | (buffLo >> 31);
|
||||
buffLo = (buffLo << 1) | (b & 1);
|
||||
if (bitsRead == 47+rbStart[wrBlock])
|
||||
blockCRC = (buffHi << 16) | (buffLo >> 16);
|
||||
|
||||
if (outFile != NULL && bitsRead >= rbStart[wrBlock]
|
||||
&& bitsRead <= rbEnd[wrBlock]) {
|
||||
bsPutBit ( bsWr, b );
|
||||
}
|
||||
|
||||
bitsRead++;
|
||||
|
||||
if (bitsRead == rbEnd[wrBlock]+1) {
|
||||
if (outFile != NULL) {
|
||||
bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 );
|
||||
bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 );
|
||||
bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 );
|
||||
bsPutUInt32 ( bsWr, blockCRC );
|
||||
bsClose ( bsWr );
|
||||
}
|
||||
if (wrBlock >= rbCtr) break;
|
||||
wrBlock++;
|
||||
} else
|
||||
if (bitsRead == rbStart[wrBlock]) {
|
||||
/* Create the output file name, correctly handling leading paths.
|
||||
(31.10.2001 by Sergey E. Kusikov) */
|
||||
Char* split;
|
||||
Int32 ofs, k;
|
||||
for (k = 0; k < BZ_MAX_FILENAME; k++)
|
||||
outFileName[k] = 0;
|
||||
strcpy (outFileName, inFileName);
|
||||
split = strrchr (outFileName, BZ_SPLIT_SYM);
|
||||
if (split == NULL) {
|
||||
split = outFileName;
|
||||
} else {
|
||||
++split;
|
||||
}
|
||||
/* Now split points to the start of the basename. */
|
||||
ofs = split - outFileName;
|
||||
sprintf (split, "rec%5d", wrBlock+1);
|
||||
for (p = split; *p != 0; p++) if (*p == ' ') *p = '0';
|
||||
strcat (outFileName, inFileName + ofs);
|
||||
|
||||
if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
|
||||
|
||||
fprintf ( stderr, " writing block %d to `%s' ...\n",
|
||||
wrBlock+1, outFileName );
|
||||
|
||||
outFile = fopen ( outFileName, "wb" );
|
||||
if (outFile == NULL) {
|
||||
fprintf ( stderr, "%s: can't write `%s'\n",
|
||||
progName, outFileName );
|
||||
exit(1);
|
||||
}
|
||||
bsWr = bsOpenWriteStream ( outFile );
|
||||
bsPutUChar ( bsWr, BZ_HDR_B );
|
||||
bsPutUChar ( bsWr, BZ_HDR_Z );
|
||||
bsPutUChar ( bsWr, BZ_HDR_h );
|
||||
bsPutUChar ( bsWr, BZ_HDR_0 + 9 );
|
||||
bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 );
|
||||
bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 );
|
||||
bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 );
|
||||
}
|
||||
}
|
||||
|
||||
fprintf ( stderr, "%s: finished\n", progName );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
/*--- end bzip2recover.c ---*/
|
||||
/*-----------------------------------------------------------*/
|
||||
1617
src/tools/stuffextract/StormLib/bzip2/bzlib.c
Normal file
1617
src/tools/stuffextract/StormLib/bzip2/bzlib.c
Normal file
File diff suppressed because it is too large
Load Diff
323
src/tools/stuffextract/StormLib/bzip2/bzlib.h
Normal file
323
src/tools/stuffextract/StormLib/bzip2/bzlib.h
Normal file
@ -0,0 +1,323 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Public header file for the library. ---*/
|
||||
/*--- bzlib.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/*--
|
||||
This file is a part of bzip2 and/or libbzip2, a program and
|
||||
library for lossless, block-sorting data compression.
|
||||
|
||||
Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0 of 21 March 2000
|
||||
|
||||
This program is based on (at least) the work of:
|
||||
Mike Burrows
|
||||
David Wheeler
|
||||
Peter Fenwick
|
||||
Alistair Moffat
|
||||
Radford Neal
|
||||
Ian H. Witten
|
||||
Robert Sedgewick
|
||||
Jon L. Bentley
|
||||
|
||||
For more information on these sources, see the manual.
|
||||
--*/
|
||||
|
||||
|
||||
#ifndef _BZLIB_H
|
||||
#define _BZLIB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BZ_RUN 0
|
||||
#define BZ_FLUSH 1
|
||||
#define BZ_FINISH 2
|
||||
|
||||
#define BZ_OK 0
|
||||
#define BZ_RUN_OK 1
|
||||
#define BZ_FLUSH_OK 2
|
||||
#define BZ_FINISH_OK 3
|
||||
#define BZ_STREAM_END 4
|
||||
#define BZ_SEQUENCE_ERROR (-1)
|
||||
#define BZ_PARAM_ERROR (-2)
|
||||
#define BZ_MEM_ERROR (-3)
|
||||
#define BZ_DATA_ERROR (-4)
|
||||
#define BZ_DATA_ERROR_MAGIC (-5)
|
||||
#define BZ_IO_ERROR (-6)
|
||||
#define BZ_UNEXPECTED_EOF (-7)
|
||||
#define BZ_OUTBUFF_FULL (-8)
|
||||
#define BZ_CONFIG_ERROR (-9)
|
||||
|
||||
typedef
|
||||
struct {
|
||||
char *next_in;
|
||||
unsigned int avail_in;
|
||||
unsigned int total_in_lo32;
|
||||
unsigned int total_in_hi32;
|
||||
|
||||
char *next_out;
|
||||
unsigned int avail_out;
|
||||
unsigned int total_out_lo32;
|
||||
unsigned int total_out_hi32;
|
||||
|
||||
void *state;
|
||||
|
||||
void *(*bzalloc)(void *,int,int);
|
||||
void (*bzfree)(void *,void *);
|
||||
void *opaque;
|
||||
}
|
||||
bz_stream;
|
||||
|
||||
|
||||
#ifndef BZ_IMPORT
|
||||
#define BZ_EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
/* Need a definitition for FILE */
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# ifdef small
|
||||
/* windows.h define small to char */
|
||||
# undef small
|
||||
# endif
|
||||
# ifdef BZ_EXPORT
|
||||
# define BZ_API(func) WINAPI func
|
||||
# define BZ_EXTERN extern
|
||||
# else
|
||||
/* import windows dll dynamically */
|
||||
# define BZ_API(func) (WINAPI * func)
|
||||
# define BZ_EXTERN
|
||||
# endif
|
||||
#else
|
||||
# define BZ_API(func) func
|
||||
# define BZ_EXTERN extern
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Core (low-level) library functions --*/
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
|
||||
bz_stream* strm,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompress) (
|
||||
bz_stream* strm,
|
||||
int action
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
|
||||
bz_stream* strm
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
|
||||
bz_stream *strm,
|
||||
int verbosity,
|
||||
int small
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
|
||||
bz_stream* strm
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) (
|
||||
bz_stream *strm
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*-- High(er) level library functions --*/
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
#define BZ_MAX_UNUSED 5000
|
||||
|
||||
typedef void BZFILE;
|
||||
|
||||
BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
|
||||
int* bzerror,
|
||||
FILE* f,
|
||||
int verbosity,
|
||||
int small,
|
||||
void* unused,
|
||||
int nUnused
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
|
||||
int* bzerror,
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void** unused,
|
||||
int* nUnused
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzRead) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
|
||||
int* bzerror,
|
||||
FILE* f,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWrite) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
int abandon,
|
||||
unsigned int* nbytes_in,
|
||||
unsigned int* nbytes_out
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
int abandon,
|
||||
unsigned int* nbytes_in_lo32,
|
||||
unsigned int* nbytes_in_hi32,
|
||||
unsigned int* nbytes_out_lo32,
|
||||
unsigned int* nbytes_out_hi32
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Utility functions --*/
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
|
||||
char* dest,
|
||||
unsigned int* destLen,
|
||||
char* source,
|
||||
unsigned int sourceLen,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
|
||||
char* dest,
|
||||
unsigned int* destLen,
|
||||
char* source,
|
||||
unsigned int sourceLen,
|
||||
int small,
|
||||
int verbosity
|
||||
);
|
||||
|
||||
|
||||
/*--
|
||||
Code contributed by Yoshioka Tsuneo
|
||||
(QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp),
|
||||
to support better zlib compatibility.
|
||||
This code is not _officially_ part of libbzip2 (yet);
|
||||
I haven't tested it, documented it, or considered the
|
||||
threading-safeness of it.
|
||||
If this code breaks, please contact both Yoshioka and me.
|
||||
--*/
|
||||
|
||||
BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
|
||||
void
|
||||
);
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
|
||||
const char *path,
|
||||
const char *mode
|
||||
);
|
||||
|
||||
BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
|
||||
int fd,
|
||||
const char *mode
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzread) (
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzwrite) (
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzflush) (
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzclose) (
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
|
||||
BZFILE *b,
|
||||
int *errnum
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
537
src/tools/stuffextract/StormLib/bzip2/bzlib_private.h
Normal file
537
src/tools/stuffextract/StormLib/bzip2/bzlib_private.h
Normal file
@ -0,0 +1,537 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Private header file for the library. ---*/
|
||||
/*--- bzlib_private.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/*--
|
||||
This file is a part of bzip2 and/or libbzip2, a program and
|
||||
library for lossless, block-sorting data compression.
|
||||
|
||||
Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0 of 21 March 2000
|
||||
|
||||
This program is based on (at least) the work of:
|
||||
Mike Burrows
|
||||
David Wheeler
|
||||
Peter Fenwick
|
||||
Alistair Moffat
|
||||
Radford Neal
|
||||
Ian H. Witten
|
||||
Robert Sedgewick
|
||||
Jon L. Bentley
|
||||
|
||||
For more information on these sources, see the manual.
|
||||
--*/
|
||||
|
||||
|
||||
#ifndef _BZLIB_PRIVATE_H
|
||||
#define _BZLIB_PRIVATE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "bzlib.h"
|
||||
|
||||
|
||||
|
||||
/*-- General stuff. --*/
|
||||
|
||||
#define BZ_VERSION "1.0.3, 15-Feb-2005"
|
||||
|
||||
typedef char Char;
|
||||
typedef unsigned char Bool;
|
||||
typedef unsigned char UChar;
|
||||
typedef int Int32;
|
||||
typedef unsigned int UInt32;
|
||||
typedef short Int16;
|
||||
typedef unsigned short UInt16;
|
||||
|
||||
#define True ((Bool)1)
|
||||
#define False ((Bool)0)
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __inline__ /* */
|
||||
#endif
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
extern void BZ2_bz__AssertH__fail ( int errcode );
|
||||
#define AssertH(cond,errcode) \
|
||||
{ if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
|
||||
#if BZ_DEBUG
|
||||
#define AssertD(cond,msg) \
|
||||
{ if (!(cond)) { \
|
||||
fprintf ( stderr, \
|
||||
"\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
|
||||
exit(1); \
|
||||
}}
|
||||
#else
|
||||
#define AssertD(cond,msg) /* */
|
||||
#endif
|
||||
#define VPrintf0(zf) \
|
||||
fprintf(stderr,zf)
|
||||
#define VPrintf1(zf,za1) \
|
||||
fprintf(stderr,zf,za1)
|
||||
#define VPrintf2(zf,za1,za2) \
|
||||
fprintf(stderr,zf,za1,za2)
|
||||
#define VPrintf3(zf,za1,za2,za3) \
|
||||
fprintf(stderr,zf,za1,za2,za3)
|
||||
#define VPrintf4(zf,za1,za2,za3,za4) \
|
||||
fprintf(stderr,zf,za1,za2,za3,za4)
|
||||
#define VPrintf5(zf,za1,za2,za3,za4,za5) \
|
||||
fprintf(stderr,zf,za1,za2,za3,za4,za5)
|
||||
#else
|
||||
extern void bz_internal_error ( int errcode );
|
||||
#define AssertH(cond,errcode) \
|
||||
{ if (!(cond)) bz_internal_error ( errcode ); }
|
||||
#define AssertD(cond,msg) /* */
|
||||
#define VPrintf0(zf) /* */
|
||||
#define VPrintf1(zf,za1) /* */
|
||||
#define VPrintf2(zf,za1,za2) /* */
|
||||
#define VPrintf3(zf,za1,za2,za3) /* */
|
||||
#define VPrintf4(zf,za1,za2,za3,za4) /* */
|
||||
#define VPrintf5(zf,za1,za2,za3,za4,za5) /* */
|
||||
#endif
|
||||
|
||||
|
||||
#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
|
||||
#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp))
|
||||
|
||||
|
||||
/*-- Header bytes. --*/
|
||||
|
||||
#define BZ_HDR_B 0x42 /* 'B' */
|
||||
#define BZ_HDR_Z 0x5a /* 'Z' */
|
||||
#define BZ_HDR_h 0x68 /* 'h' */
|
||||
#define BZ_HDR_0 0x30 /* '0' */
|
||||
|
||||
/*-- Constants for the back end. --*/
|
||||
|
||||
#define BZ_MAX_ALPHA_SIZE 258
|
||||
#define BZ_MAX_CODE_LEN 23
|
||||
|
||||
#define BZ_RUNA 0
|
||||
#define BZ_RUNB 1
|
||||
|
||||
#define BZ_N_GROUPS 6
|
||||
#define BZ_G_SIZE 50
|
||||
#define BZ_N_ITERS 4
|
||||
|
||||
#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
|
||||
|
||||
|
||||
|
||||
/*-- Stuff for randomising repetitive blocks. --*/
|
||||
|
||||
extern Int32 BZ2_rNums[512];
|
||||
|
||||
#define BZ_RAND_DECLS \
|
||||
Int32 rNToGo; \
|
||||
Int32 rTPos \
|
||||
|
||||
#define BZ_RAND_INIT_MASK \
|
||||
s->rNToGo = 0; \
|
||||
s->rTPos = 0 \
|
||||
|
||||
#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
|
||||
|
||||
#define BZ_RAND_UPD_MASK \
|
||||
if (s->rNToGo == 0) { \
|
||||
s->rNToGo = BZ2_rNums[s->rTPos]; \
|
||||
s->rTPos++; \
|
||||
if (s->rTPos == 512) s->rTPos = 0; \
|
||||
} \
|
||||
s->rNToGo--;
|
||||
|
||||
|
||||
|
||||
/*-- Stuff for doing CRCs. --*/
|
||||
|
||||
extern UInt32 BZ2_crc32Table[256];
|
||||
|
||||
#define BZ_INITIALISE_CRC(crcVar) \
|
||||
{ \
|
||||
crcVar = 0xffffffffL; \
|
||||
}
|
||||
|
||||
#define BZ_FINALISE_CRC(crcVar) \
|
||||
{ \
|
||||
crcVar = ~(crcVar); \
|
||||
}
|
||||
|
||||
#define BZ_UPDATE_CRC(crcVar,cha) \
|
||||
{ \
|
||||
crcVar = (crcVar << 8) ^ \
|
||||
BZ2_crc32Table[(crcVar >> 24) ^ \
|
||||
((UChar)cha)]; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-- States and modes for compression. --*/
|
||||
|
||||
#define BZ_M_IDLE 1
|
||||
#define BZ_M_RUNNING 2
|
||||
#define BZ_M_FLUSHING 3
|
||||
#define BZ_M_FINISHING 4
|
||||
|
||||
#define BZ_S_OUTPUT 1
|
||||
#define BZ_S_INPUT 2
|
||||
|
||||
#define BZ_N_RADIX 2
|
||||
#define BZ_N_QSORT 12
|
||||
#define BZ_N_SHELL 18
|
||||
#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
|
||||
|
||||
|
||||
|
||||
|
||||
/*-- Structure holding all the compression-side stuff. --*/
|
||||
|
||||
typedef
|
||||
struct {
|
||||
/* pointer back to the struct bz_stream */
|
||||
bz_stream* strm;
|
||||
|
||||
/* mode this stream is in, and whether inputting */
|
||||
/* or outputting data */
|
||||
Int32 mode;
|
||||
Int32 state;
|
||||
|
||||
/* remembers avail_in when flush/finish requested */
|
||||
UInt32 avail_in_expect;
|
||||
|
||||
/* for doing the block sorting */
|
||||
UInt32* arr1;
|
||||
UInt32* arr2;
|
||||
UInt32* ftab;
|
||||
Int32 origPtr;
|
||||
|
||||
/* aliases for arr1 and arr2 */
|
||||
UInt32* ptr;
|
||||
UChar* block;
|
||||
UInt16* mtfv;
|
||||
UChar* zbits;
|
||||
|
||||
/* for deciding when to use the fallback sorting algorithm */
|
||||
Int32 workFactor;
|
||||
|
||||
/* run-length-encoding of the input */
|
||||
UInt32 state_in_ch;
|
||||
Int32 state_in_len;
|
||||
BZ_RAND_DECLS;
|
||||
|
||||
/* input and output limits and current posns */
|
||||
Int32 nblock;
|
||||
Int32 nblockMAX;
|
||||
Int32 numZ;
|
||||
Int32 state_out_pos;
|
||||
|
||||
/* map of bytes used in block */
|
||||
Int32 nInUse;
|
||||
Bool inUse[256];
|
||||
UChar unseqToSeq[256];
|
||||
|
||||
/* the buffer for bit stream creation */
|
||||
UInt32 bsBuff;
|
||||
Int32 bsLive;
|
||||
|
||||
/* block and combined CRCs */
|
||||
UInt32 blockCRC;
|
||||
UInt32 combinedCRC;
|
||||
|
||||
/* misc administratium */
|
||||
Int32 verbosity;
|
||||
Int32 blockNo;
|
||||
Int32 blockSize100k;
|
||||
|
||||
/* stuff for coding the MTF values */
|
||||
Int32 nMTF;
|
||||
Int32 mtfFreq [BZ_MAX_ALPHA_SIZE];
|
||||
UChar selector [BZ_MAX_SELECTORS];
|
||||
UChar selectorMtf[BZ_MAX_SELECTORS];
|
||||
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
/* second dimension: only 3 needed; 4 makes index calculations faster */
|
||||
UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4];
|
||||
|
||||
}
|
||||
EState;
|
||||
|
||||
|
||||
|
||||
/*-- externs for compression. --*/
|
||||
|
||||
extern void
|
||||
BZ2_blockSort ( EState* );
|
||||
|
||||
extern void
|
||||
BZ2_compressBlock ( EState*, Bool );
|
||||
|
||||
extern void
|
||||
BZ2_bsInitWrite ( EState* );
|
||||
|
||||
extern void
|
||||
BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
|
||||
|
||||
extern void
|
||||
BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
|
||||
|
||||
|
||||
|
||||
/*-- states for decompression. --*/
|
||||
|
||||
#define BZ_X_IDLE 1
|
||||
#define BZ_X_OUTPUT 2
|
||||
|
||||
#define BZ_X_MAGIC_1 10
|
||||
#define BZ_X_MAGIC_2 11
|
||||
#define BZ_X_MAGIC_3 12
|
||||
#define BZ_X_MAGIC_4 13
|
||||
#define BZ_X_BLKHDR_1 14
|
||||
#define BZ_X_BLKHDR_2 15
|
||||
#define BZ_X_BLKHDR_3 16
|
||||
#define BZ_X_BLKHDR_4 17
|
||||
#define BZ_X_BLKHDR_5 18
|
||||
#define BZ_X_BLKHDR_6 19
|
||||
#define BZ_X_BCRC_1 20
|
||||
#define BZ_X_BCRC_2 21
|
||||
#define BZ_X_BCRC_3 22
|
||||
#define BZ_X_BCRC_4 23
|
||||
#define BZ_X_RANDBIT 24
|
||||
#define BZ_X_ORIGPTR_1 25
|
||||
#define BZ_X_ORIGPTR_2 26
|
||||
#define BZ_X_ORIGPTR_3 27
|
||||
#define BZ_X_MAPPING_1 28
|
||||
#define BZ_X_MAPPING_2 29
|
||||
#define BZ_X_SELECTOR_1 30
|
||||
#define BZ_X_SELECTOR_2 31
|
||||
#define BZ_X_SELECTOR_3 32
|
||||
#define BZ_X_CODING_1 33
|
||||
#define BZ_X_CODING_2 34
|
||||
#define BZ_X_CODING_3 35
|
||||
#define BZ_X_MTF_1 36
|
||||
#define BZ_X_MTF_2 37
|
||||
#define BZ_X_MTF_3 38
|
||||
#define BZ_X_MTF_4 39
|
||||
#define BZ_X_MTF_5 40
|
||||
#define BZ_X_MTF_6 41
|
||||
#define BZ_X_ENDHDR_2 42
|
||||
#define BZ_X_ENDHDR_3 43
|
||||
#define BZ_X_ENDHDR_4 44
|
||||
#define BZ_X_ENDHDR_5 45
|
||||
#define BZ_X_ENDHDR_6 46
|
||||
#define BZ_X_CCRC_1 47
|
||||
#define BZ_X_CCRC_2 48
|
||||
#define BZ_X_CCRC_3 49
|
||||
#define BZ_X_CCRC_4 50
|
||||
|
||||
|
||||
|
||||
/*-- Constants for the fast MTF decoder. --*/
|
||||
|
||||
#define MTFA_SIZE 4096
|
||||
#define MTFL_SIZE 16
|
||||
|
||||
|
||||
|
||||
/*-- Structure holding all the decompression-side stuff. --*/
|
||||
|
||||
typedef
|
||||
struct {
|
||||
/* pointer back to the struct bz_stream */
|
||||
bz_stream* strm;
|
||||
|
||||
/* state indicator for this stream */
|
||||
Int32 state;
|
||||
|
||||
/* for doing the final run-length decoding */
|
||||
UChar state_out_ch;
|
||||
Int32 state_out_len;
|
||||
Bool blockRandomised;
|
||||
BZ_RAND_DECLS;
|
||||
|
||||
/* the buffer for bit stream reading */
|
||||
UInt32 bsBuff;
|
||||
Int32 bsLive;
|
||||
|
||||
/* misc administratium */
|
||||
Int32 blockSize100k;
|
||||
Bool smallDecompress;
|
||||
Int32 currBlockNo;
|
||||
Int32 verbosity;
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform */
|
||||
Int32 origPtr;
|
||||
UInt32 tPos;
|
||||
Int32 k0;
|
||||
Int32 unzftab[256];
|
||||
Int32 nblock_used;
|
||||
Int32 cftab[257];
|
||||
Int32 cftabCopy[257];
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform (FAST) */
|
||||
UInt32 *tt;
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform (SMALL) */
|
||||
UInt16 *ll16;
|
||||
UChar *ll4;
|
||||
|
||||
/* stored and calculated CRCs */
|
||||
UInt32 storedBlockCRC;
|
||||
UInt32 storedCombinedCRC;
|
||||
UInt32 calculatedBlockCRC;
|
||||
UInt32 calculatedCombinedCRC;
|
||||
|
||||
/* map of bytes used in block */
|
||||
Int32 nInUse;
|
||||
Bool inUse[256];
|
||||
Bool inUse16[16];
|
||||
UChar seqToUnseq[256];
|
||||
|
||||
/* for decoding the MTF values */
|
||||
UChar mtfa [MTFA_SIZE];
|
||||
Int32 mtfbase[256 / MTFL_SIZE];
|
||||
UChar selector [BZ_MAX_SELECTORS];
|
||||
UChar selectorMtf[BZ_MAX_SELECTORS];
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
|
||||
Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 minLens[BZ_N_GROUPS];
|
||||
|
||||
/* save area for scalars in the main decompress code */
|
||||
Int32 save_i;
|
||||
Int32 save_j;
|
||||
Int32 save_t;
|
||||
Int32 save_alphaSize;
|
||||
Int32 save_nGroups;
|
||||
Int32 save_nSelectors;
|
||||
Int32 save_EOB;
|
||||
Int32 save_groupNo;
|
||||
Int32 save_groupPos;
|
||||
Int32 save_nextSym;
|
||||
Int32 save_nblockMAX;
|
||||
Int32 save_nblock;
|
||||
Int32 save_es;
|
||||
Int32 save_N;
|
||||
Int32 save_curr;
|
||||
Int32 save_zt;
|
||||
Int32 save_zn;
|
||||
Int32 save_zvec;
|
||||
Int32 save_zj;
|
||||
Int32 save_gSel;
|
||||
Int32 save_gMinlen;
|
||||
Int32* save_gLimit;
|
||||
Int32* save_gBase;
|
||||
Int32* save_gPerm;
|
||||
|
||||
}
|
||||
DState;
|
||||
|
||||
|
||||
|
||||
/*-- Macros for decompression. --*/
|
||||
|
||||
#define BZ_GET_FAST(cccc) \
|
||||
s->tPos = s->tt[s->tPos]; \
|
||||
cccc = (UChar)(s->tPos & 0xff); \
|
||||
s->tPos >>= 8;
|
||||
|
||||
#define BZ_GET_FAST_C(cccc) \
|
||||
c_tPos = c_tt[c_tPos]; \
|
||||
cccc = (UChar)(c_tPos & 0xff); \
|
||||
c_tPos >>= 8;
|
||||
|
||||
#define SET_LL4(i,n) \
|
||||
{ if (((i) & 0x1) == 0) \
|
||||
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \
|
||||
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
|
||||
}
|
||||
|
||||
#define GET_LL4(i) \
|
||||
((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
|
||||
|
||||
#define SET_LL(i,n) \
|
||||
{ s->ll16[i] = (UInt16)(n & 0x0000ffff); \
|
||||
SET_LL4(i, n >> 16); \
|
||||
}
|
||||
|
||||
#define GET_LL(i) \
|
||||
(((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
|
||||
|
||||
#define BZ_GET_SMALL(cccc) \
|
||||
cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
|
||||
s->tPos = GET_LL(s->tPos);
|
||||
|
||||
|
||||
/*-- externs for decompression. --*/
|
||||
|
||||
extern Int32
|
||||
BZ2_indexIntoF ( Int32, Int32* );
|
||||
|
||||
extern Int32
|
||||
BZ2_decompress ( DState* );
|
||||
|
||||
extern void
|
||||
BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
|
||||
Int32, Int32, Int32 );
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
|
||||
|
||||
#ifdef BZ_NO_STDIO
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib_private.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
716
src/tools/stuffextract/StormLib/bzip2/compress.c
Normal file
716
src/tools/stuffextract/StormLib/bzip2/compress.c
Normal file
@ -0,0 +1,716 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Compression machinery (not incl block sorting) ---*/
|
||||
/*--- compress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/*--
|
||||
This file is a part of bzip2 and/or libbzip2, a program and
|
||||
library for lossless, block-sorting data compression.
|
||||
|
||||
Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0 of 21 March 2000
|
||||
|
||||
This program is based on (at least) the work of:
|
||||
Mike Burrows
|
||||
David Wheeler
|
||||
Peter Fenwick
|
||||
Alistair Moffat
|
||||
Radford Neal
|
||||
Ian H. Witten
|
||||
Robert Sedgewick
|
||||
Jon L. Bentley
|
||||
|
||||
For more information on these sources, see the manual.
|
||||
--*/
|
||||
|
||||
/*--
|
||||
CHANGES
|
||||
~~~~~~~
|
||||
0.9.0 -- original version.
|
||||
|
||||
0.9.0a/b -- no changes in this file.
|
||||
|
||||
0.9.0c
|
||||
* changed setting of nGroups in sendMTFValues() so as to
|
||||
do a bit better on small files
|
||||
--*/
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- Bit stream I/O ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_bsInitWrite ( EState* s )
|
||||
{
|
||||
s->bsLive = 0;
|
||||
s->bsBuff = 0;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsFinishWrite ( EState* s )
|
||||
{
|
||||
while (s->bsLive > 0) {
|
||||
s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
|
||||
s->numZ++;
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define bsNEEDW(nz) \
|
||||
{ \
|
||||
while (s->bsLive >= 8) { \
|
||||
s->zbits[s->numZ] \
|
||||
= (UChar)(s->bsBuff >> 24); \
|
||||
s->numZ++; \
|
||||
s->bsBuff <<= 8; \
|
||||
s->bsLive -= 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
__inline__
|
||||
void bsW ( EState* s, Int32 n, UInt32 v )
|
||||
{
|
||||
bsNEEDW ( n );
|
||||
s->bsBuff |= (v << (32 - s->bsLive - n));
|
||||
s->bsLive += n;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutUInt32 ( EState* s, UInt32 u )
|
||||
{
|
||||
bsW ( s, 8, (u >> 24) & 0xffL );
|
||||
bsW ( s, 8, (u >> 16) & 0xffL );
|
||||
bsW ( s, 8, (u >> 8) & 0xffL );
|
||||
bsW ( s, 8, u & 0xffL );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutUChar ( EState* s, UChar c )
|
||||
{
|
||||
bsW( s, 8, (UInt32)c );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- The back end proper ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void makeMaps_e ( EState* s )
|
||||
{
|
||||
Int32 i;
|
||||
s->nInUse = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (s->inUse[i]) {
|
||||
s->unseqToSeq[i] = s->nInUse;
|
||||
s->nInUse++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void generateMTFValues ( EState* s )
|
||||
{
|
||||
UChar yy[256];
|
||||
Int32 i, j;
|
||||
Int32 zPend;
|
||||
Int32 wr;
|
||||
Int32 EOB;
|
||||
|
||||
/*
|
||||
After sorting (eg, here),
|
||||
s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
|
||||
and
|
||||
((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
|
||||
holds the original block data.
|
||||
|
||||
The first thing to do is generate the MTF values,
|
||||
and put them in
|
||||
((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
|
||||
Because there are strictly fewer or equal MTF values
|
||||
than block values, ptr values in this area are overwritten
|
||||
with MTF values only when they are no longer needed.
|
||||
|
||||
The final compressed bitstream is generated into the
|
||||
area starting at
|
||||
(UChar*) (&((UChar*)s->arr2)[s->nblock])
|
||||
|
||||
These storage aliases are set up in bzCompressInit(),
|
||||
except for the last one, which is arranged in
|
||||
compressBlock().
|
||||
*/
|
||||
UInt32* ptr = s->ptr;
|
||||
UChar* block = s->block;
|
||||
UInt16* mtfv = s->mtfv;
|
||||
|
||||
makeMaps_e ( s );
|
||||
EOB = s->nInUse+1;
|
||||
|
||||
for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
|
||||
|
||||
wr = 0;
|
||||
zPend = 0;
|
||||
for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
|
||||
|
||||
for (i = 0; i < s->nblock; i++) {
|
||||
UChar ll_i;
|
||||
AssertD ( wr <= i, "generateMTFValues(1)" );
|
||||
j = ptr[i]-1; if (j < 0) j += s->nblock;
|
||||
ll_i = s->unseqToSeq[block[j]];
|
||||
AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
|
||||
|
||||
if (yy[0] == ll_i) {
|
||||
zPend++;
|
||||
} else {
|
||||
|
||||
if (zPend > 0) {
|
||||
zPend--;
|
||||
while (True) {
|
||||
if (zPend & 1) {
|
||||
mtfv[wr] = BZ_RUNB; wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
mtfv[wr] = BZ_RUNA; wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
if (zPend < 2) break;
|
||||
zPend = (zPend - 2) / 2;
|
||||
};
|
||||
zPend = 0;
|
||||
}
|
||||
{
|
||||
register UChar rtmp;
|
||||
register UChar* ryy_j;
|
||||
register UChar rll_i;
|
||||
rtmp = yy[1];
|
||||
yy[1] = yy[0];
|
||||
ryy_j = &(yy[1]);
|
||||
rll_i = ll_i;
|
||||
while ( rll_i != rtmp ) {
|
||||
register UChar rtmp2;
|
||||
ryy_j++;
|
||||
rtmp2 = rtmp;
|
||||
rtmp = *ryy_j;
|
||||
*ryy_j = rtmp2;
|
||||
};
|
||||
yy[0] = rtmp;
|
||||
j = ryy_j - &(yy[0]);
|
||||
mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (zPend > 0) {
|
||||
zPend--;
|
||||
while (True) {
|
||||
if (zPend & 1) {
|
||||
mtfv[wr] = BZ_RUNB; wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
mtfv[wr] = BZ_RUNA; wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
if (zPend < 2) break;
|
||||
zPend = (zPend - 2) / 2;
|
||||
};
|
||||
zPend = 0;
|
||||
}
|
||||
|
||||
mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
|
||||
|
||||
s->nMTF = wr;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define BZ_LESSER_ICOST 0
|
||||
#define BZ_GREATER_ICOST 15
|
||||
|
||||
static
|
||||
void sendMTFValues ( EState* s )
|
||||
{
|
||||
Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
|
||||
Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
|
||||
Int32 nGroups, nBytes;
|
||||
|
||||
/*--
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
is a global since the decoder also needs it.
|
||||
|
||||
Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
are also globals only used in this proc.
|
||||
Made global to keep stack frame size small.
|
||||
--*/
|
||||
|
||||
|
||||
UInt16 cost[BZ_N_GROUPS];
|
||||
Int32 fave[BZ_N_GROUPS];
|
||||
|
||||
UInt16* mtfv = s->mtfv;
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf3( " %d in block, %d after MTF & 1-2 coding, "
|
||||
"%d+2 syms in use\n",
|
||||
s->nblock, s->nMTF, s->nInUse );
|
||||
|
||||
alphaSize = s->nInUse+2;
|
||||
for (t = 0; t < BZ_N_GROUPS; t++)
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->len[t][v] = BZ_GREATER_ICOST;
|
||||
|
||||
/*--- Decide how many coding tables to use ---*/
|
||||
AssertH ( s->nMTF > 0, 3001 );
|
||||
if (s->nMTF < 200) nGroups = 2; else
|
||||
if (s->nMTF < 600) nGroups = 3; else
|
||||
if (s->nMTF < 1200) nGroups = 4; else
|
||||
if (s->nMTF < 2400) nGroups = 5; else
|
||||
nGroups = 6;
|
||||
|
||||
/*--- Generate an initial set of coding tables ---*/
|
||||
{
|
||||
Int32 nPart, remF, tFreq, aFreq;
|
||||
|
||||
nPart = nGroups;
|
||||
remF = s->nMTF;
|
||||
gs = 0;
|
||||
while (nPart > 0) {
|
||||
tFreq = remF / nPart;
|
||||
ge = gs-1;
|
||||
aFreq = 0;
|
||||
while (aFreq < tFreq && ge < alphaSize-1) {
|
||||
ge++;
|
||||
aFreq += s->mtfFreq[ge];
|
||||
}
|
||||
|
||||
if (ge > gs
|
||||
&& nPart != nGroups && nPart != 1
|
||||
&& ((nGroups-nPart) % 2 == 1)) {
|
||||
aFreq -= s->mtfFreq[ge];
|
||||
ge--;
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf5( " initial group %d, [%d .. %d], "
|
||||
"has %d syms (%4.1f%%)\n",
|
||||
nPart, gs, ge, aFreq,
|
||||
(100.0 * (float)aFreq) / (float)(s->nMTF) );
|
||||
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
if (v >= gs && v <= ge)
|
||||
s->len[nPart-1][v] = BZ_LESSER_ICOST; else
|
||||
s->len[nPart-1][v] = BZ_GREATER_ICOST;
|
||||
|
||||
nPart--;
|
||||
gs = ge+1;
|
||||
remF -= aFreq;
|
||||
}
|
||||
}
|
||||
|
||||
/*---
|
||||
Iterate up to BZ_N_ITERS times to improve the tables.
|
||||
---*/
|
||||
for (iter = 0; iter < BZ_N_ITERS; iter++) {
|
||||
|
||||
for (t = 0; t < nGroups; t++) fave[t] = 0;
|
||||
|
||||
for (t = 0; t < nGroups; t++)
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->rfreq[t][v] = 0;
|
||||
|
||||
/*---
|
||||
Set up an auxiliary length table which is used to fast-track
|
||||
the common case (nGroups == 6).
|
||||
---*/
|
||||
if (nGroups == 6) {
|
||||
for (v = 0; v < alphaSize; v++) {
|
||||
s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
|
||||
s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
|
||||
s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
|
||||
}
|
||||
}
|
||||
|
||||
nSelectors = 0;
|
||||
totc = 0;
|
||||
gs = 0;
|
||||
while (True) {
|
||||
|
||||
/*--- Set group start & end marks. --*/
|
||||
if (gs >= s->nMTF) break;
|
||||
ge = gs + BZ_G_SIZE - 1;
|
||||
if (ge >= s->nMTF) ge = s->nMTF-1;
|
||||
|
||||
/*--
|
||||
Calculate the cost of this group as coded
|
||||
by each of the coding tables.
|
||||
--*/
|
||||
for (t = 0; t < nGroups; t++) cost[t] = 0;
|
||||
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
register UInt32 cost01, cost23, cost45;
|
||||
register UInt16 icv;
|
||||
cost01 = cost23 = cost45 = 0;
|
||||
|
||||
# define BZ_ITER(nn) \
|
||||
icv = mtfv[gs+(nn)]; \
|
||||
cost01 += s->len_pack[icv][0]; \
|
||||
cost23 += s->len_pack[icv][1]; \
|
||||
cost45 += s->len_pack[icv][2]; \
|
||||
|
||||
BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
|
||||
BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
|
||||
BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
|
||||
BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
|
||||
BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
|
||||
BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
|
||||
BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
|
||||
BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
|
||||
BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
|
||||
BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
|
||||
|
||||
# undef BZ_ITER
|
||||
|
||||
cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
|
||||
cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
|
||||
cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++) {
|
||||
UInt16 icv = mtfv[i];
|
||||
for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
|
||||
}
|
||||
}
|
||||
|
||||
/*--
|
||||
Find the coding table which is best for this group,
|
||||
and record its identity in the selector table.
|
||||
--*/
|
||||
bc = 999999999; bt = -1;
|
||||
for (t = 0; t < nGroups; t++)
|
||||
if (cost[t] < bc) { bc = cost[t]; bt = t; };
|
||||
totc += bc;
|
||||
fave[bt]++;
|
||||
s->selector[nSelectors] = bt;
|
||||
nSelectors++;
|
||||
|
||||
/*--
|
||||
Increment the symbol frequencies for the selected table.
|
||||
--*/
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
|
||||
# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
|
||||
|
||||
BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
|
||||
BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
|
||||
BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
|
||||
BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
|
||||
BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
|
||||
BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
|
||||
BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
|
||||
BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
|
||||
BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
|
||||
BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
|
||||
|
||||
# undef BZ_ITUR
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++)
|
||||
s->rfreq[bt][ mtfv[i] ]++;
|
||||
}
|
||||
|
||||
gs = ge+1;
|
||||
}
|
||||
if (s->verbosity >= 3) {
|
||||
VPrintf2 ( " pass %d: size is %d, grp uses are ",
|
||||
iter+1, totc/8 );
|
||||
for (t = 0; t < nGroups; t++)
|
||||
VPrintf1 ( "%d ", fave[t] );
|
||||
VPrintf0 ( "\n" );
|
||||
}
|
||||
|
||||
/*--
|
||||
Recompute the tables based on the accumulated frequencies.
|
||||
--*/
|
||||
/* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
|
||||
comment in huffman.c for details. */
|
||||
for (t = 0; t < nGroups; t++)
|
||||
BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]),
|
||||
alphaSize, 17 /*20*/ );
|
||||
}
|
||||
|
||||
|
||||
AssertH( nGroups < 8, 3002 );
|
||||
AssertH( nSelectors < 32768 &&
|
||||
nSelectors <= (2 + (900000 / BZ_G_SIZE)),
|
||||
3003 );
|
||||
|
||||
|
||||
/*--- Compute MTF values for the selectors. ---*/
|
||||
{
|
||||
UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
|
||||
for (i = 0; i < nGroups; i++) pos[i] = i;
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
ll_i = s->selector[i];
|
||||
j = 0;
|
||||
tmp = pos[j];
|
||||
while ( ll_i != tmp ) {
|
||||
j++;
|
||||
tmp2 = tmp;
|
||||
tmp = pos[j];
|
||||
pos[j] = tmp2;
|
||||
};
|
||||
pos[0] = tmp;
|
||||
s->selectorMtf[i] = j;
|
||||
}
|
||||
};
|
||||
|
||||
/*--- Assign actual codes for the tables. --*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
minLen = 32;
|
||||
maxLen = 0;
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
|
||||
if (s->len[t][i] < minLen) minLen = s->len[t][i];
|
||||
}
|
||||
AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
|
||||
AssertH ( !(minLen < 1), 3005 );
|
||||
BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]),
|
||||
minLen, maxLen, alphaSize );
|
||||
}
|
||||
|
||||
/*--- Transmit the mapping table. ---*/
|
||||
{
|
||||
Bool inUse16[16];
|
||||
for (i = 0; i < 16; i++) {
|
||||
inUse16[i] = False;
|
||||
for (j = 0; j < 16; j++)
|
||||
if (s->inUse[i * 16 + j]) inUse16[i] = True;
|
||||
}
|
||||
|
||||
nBytes = s->numZ;
|
||||
for (i = 0; i < 16; i++)
|
||||
if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (inUse16[i])
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes );
|
||||
}
|
||||
|
||||
/*--- Now the selectors. ---*/
|
||||
nBytes = s->numZ;
|
||||
bsW ( s, 3, nGroups );
|
||||
bsW ( s, 15, nSelectors );
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
|
||||
bsW(s,1,0);
|
||||
}
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( "selectors %d, ", s->numZ-nBytes );
|
||||
|
||||
/*--- Now the coding tables. ---*/
|
||||
nBytes = s->numZ;
|
||||
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
Int32 curr = s->len[t][0];
|
||||
bsW ( s, 5, curr );
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
|
||||
while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
|
||||
bsW ( s, 1, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
|
||||
|
||||
/*--- And finally, the block data proper ---*/
|
||||
nBytes = s->numZ;
|
||||
selCtr = 0;
|
||||
gs = 0;
|
||||
while (True) {
|
||||
if (gs >= s->nMTF) break;
|
||||
ge = gs + BZ_G_SIZE - 1;
|
||||
if (ge >= s->nMTF) ge = s->nMTF-1;
|
||||
AssertH ( s->selector[selCtr] < nGroups, 3006 );
|
||||
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
UInt16 mtfv_i;
|
||||
UChar* s_len_sel_selCtr
|
||||
= &(s->len[s->selector[selCtr]][0]);
|
||||
Int32* s_code_sel_selCtr
|
||||
= &(s->code[s->selector[selCtr]][0]);
|
||||
|
||||
# define BZ_ITAH(nn) \
|
||||
mtfv_i = mtfv[gs+(nn)]; \
|
||||
bsW ( s, \
|
||||
s_len_sel_selCtr[mtfv_i], \
|
||||
s_code_sel_selCtr[mtfv_i] )
|
||||
|
||||
BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
|
||||
BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
|
||||
BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
|
||||
BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
|
||||
BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
|
||||
BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
|
||||
BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
|
||||
BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
|
||||
BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
|
||||
BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
|
||||
|
||||
# undef BZ_ITAH
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++) {
|
||||
bsW ( s,
|
||||
s->len [s->selector[selCtr]] [mtfv[i]],
|
||||
s->code [s->selector[selCtr]] [mtfv[i]] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gs = ge+1;
|
||||
selCtr++;
|
||||
}
|
||||
AssertH( selCtr == nSelectors, 3007 );
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( "codes %d\n", s->numZ-nBytes );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_compressBlock ( EState* s, Bool is_last_block )
|
||||
{
|
||||
if (s->nblock > 0) {
|
||||
|
||||
BZ_FINALISE_CRC ( s->blockCRC );
|
||||
s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
|
||||
s->combinedCRC ^= s->blockCRC;
|
||||
if (s->blockNo > 1) s->numZ = 0;
|
||||
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf4( " block %d: crc = 0x%08x, "
|
||||
"combined CRC = 0x%08x, size = %d\n",
|
||||
s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
|
||||
|
||||
BZ2_blockSort ( s );
|
||||
}
|
||||
|
||||
s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
|
||||
|
||||
/*-- If this is the first block, create the stream header. --*/
|
||||
if (s->blockNo == 1) {
|
||||
BZ2_bsInitWrite ( s );
|
||||
bsPutUChar ( s, BZ_HDR_B );
|
||||
bsPutUChar ( s, BZ_HDR_Z );
|
||||
bsPutUChar ( s, BZ_HDR_h );
|
||||
bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
|
||||
}
|
||||
|
||||
if (s->nblock > 0) {
|
||||
|
||||
bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
|
||||
bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
|
||||
bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
|
||||
|
||||
/*-- Now the block's CRC, so it is in a known place. --*/
|
||||
bsPutUInt32 ( s, s->blockCRC );
|
||||
|
||||
/*--
|
||||
Now a single bit indicating (non-)randomisation.
|
||||
As of version 0.9.5, we use a better sorting algorithm
|
||||
which makes randomisation unnecessary. So always set
|
||||
the randomised bit to 'no'. Of course, the decoder
|
||||
still needs to be able to handle randomised blocks
|
||||
so as to maintain backwards compatibility with
|
||||
older versions of bzip2.
|
||||
--*/
|
||||
bsW(s,1,0);
|
||||
|
||||
bsW ( s, 24, s->origPtr );
|
||||
generateMTFValues ( s );
|
||||
sendMTFValues ( s );
|
||||
}
|
||||
|
||||
|
||||
/*-- If this is the last block, add the stream trailer. --*/
|
||||
if (is_last_block) {
|
||||
|
||||
bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
|
||||
bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
|
||||
bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
|
||||
bsPutUInt32 ( s, s->combinedCRC );
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC );
|
||||
bsFinishWrite ( s );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end compress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
144
src/tools/stuffextract/StormLib/bzip2/crctable.c
Normal file
144
src/tools/stuffextract/StormLib/bzip2/crctable.c
Normal file
@ -0,0 +1,144 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Table for doing CRCs ---*/
|
||||
/*--- crctable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/*--
|
||||
This file is a part of bzip2 and/or libbzip2, a program and
|
||||
library for lossless, block-sorting data compression.
|
||||
|
||||
Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0 of 21 March 2000
|
||||
|
||||
This program is based on (at least) the work of:
|
||||
Mike Burrows
|
||||
David Wheeler
|
||||
Peter Fenwick
|
||||
Alistair Moffat
|
||||
Radford Neal
|
||||
Ian H. Witten
|
||||
Robert Sedgewick
|
||||
Jon L. Bentley
|
||||
|
||||
For more information on these sources, see the manual.
|
||||
--*/
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
/*--
|
||||
I think this is an implementation of the AUTODIN-II,
|
||||
Ethernet & FDDI 32-bit CRC standard. Vaguely derived
|
||||
from code by Rob Warnock, in Section 51 of the
|
||||
comp.compression FAQ.
|
||||
--*/
|
||||
|
||||
UInt32 BZ2_crc32Table[256] = {
|
||||
|
||||
/*-- Ugly, innit? --*/
|
||||
|
||||
0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
|
||||
0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
|
||||
0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
|
||||
0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
|
||||
0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
|
||||
0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
|
||||
0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
|
||||
0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
|
||||
0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
|
||||
0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
|
||||
0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
|
||||
0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
|
||||
0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
|
||||
0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
|
||||
0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
|
||||
0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
|
||||
0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
|
||||
0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
|
||||
0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
|
||||
0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
|
||||
0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
|
||||
0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
|
||||
0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
|
||||
0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
|
||||
0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
|
||||
0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
|
||||
0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
|
||||
0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
|
||||
0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
|
||||
0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
|
||||
0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
|
||||
0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
|
||||
0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
|
||||
0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
|
||||
0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
|
||||
0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
|
||||
0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
|
||||
0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
|
||||
0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
|
||||
0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
|
||||
0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
|
||||
0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
|
||||
0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
|
||||
0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
|
||||
0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
|
||||
0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
|
||||
0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
|
||||
0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
|
||||
0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
|
||||
0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
|
||||
0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
|
||||
0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
|
||||
0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
|
||||
0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
|
||||
0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
|
||||
0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
|
||||
0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
|
||||
0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
|
||||
0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
|
||||
0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
|
||||
0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
|
||||
0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
|
||||
0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
|
||||
0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end crctable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
666
src/tools/stuffextract/StormLib/bzip2/decompress.c
Normal file
666
src/tools/stuffextract/StormLib/bzip2/decompress.c
Normal file
@ -0,0 +1,666 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Decompression machinery ---*/
|
||||
/*--- decompress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/*--
|
||||
This file is a part of bzip2 and/or libbzip2, a program and
|
||||
library for lossless, block-sorting data compression.
|
||||
|
||||
Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0 of 21 March 2000
|
||||
|
||||
This program is based on (at least) the work of:
|
||||
Mike Burrows
|
||||
David Wheeler
|
||||
Peter Fenwick
|
||||
Alistair Moffat
|
||||
Radford Neal
|
||||
Ian H. Witten
|
||||
Robert Sedgewick
|
||||
Jon L. Bentley
|
||||
|
||||
For more information on these sources, see the manual.
|
||||
--*/
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void makeMaps_d ( DState* s )
|
||||
{
|
||||
Int32 i;
|
||||
s->nInUse = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (s->inUse[i]) {
|
||||
s->seqToUnseq[s->nInUse] = i;
|
||||
s->nInUse++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define RETURN(rrr) \
|
||||
{ retVal = rrr; goto save_state_and_return; };
|
||||
|
||||
#define GET_BITS(lll,vvv,nnn) \
|
||||
case lll: s->state = lll; \
|
||||
while (True) { \
|
||||
if (s->bsLive >= nnn) { \
|
||||
UInt32 v; \
|
||||
v = (s->bsBuff >> \
|
||||
(s->bsLive-nnn)) & ((1 << nnn)-1); \
|
||||
s->bsLive -= nnn; \
|
||||
vvv = v; \
|
||||
break; \
|
||||
} \
|
||||
if (s->strm->avail_in == 0) RETURN(BZ_OK); \
|
||||
s->bsBuff \
|
||||
= (s->bsBuff << 8) | \
|
||||
((UInt32) \
|
||||
(*((UChar*)(s->strm->next_in)))); \
|
||||
s->bsLive += 8; \
|
||||
s->strm->next_in++; \
|
||||
s->strm->avail_in--; \
|
||||
s->strm->total_in_lo32++; \
|
||||
if (s->strm->total_in_lo32 == 0) \
|
||||
s->strm->total_in_hi32++; \
|
||||
}
|
||||
|
||||
#define GET_UCHAR(lll,uuu) \
|
||||
GET_BITS(lll,uuu,8)
|
||||
|
||||
#define GET_BIT(lll,uuu) \
|
||||
GET_BITS(lll,uuu,1)
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define GET_MTF_VAL(label1,label2,lval) \
|
||||
{ \
|
||||
if (groupPos == 0) { \
|
||||
groupNo++; \
|
||||
if (groupNo >= nSelectors) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
groupPos = BZ_G_SIZE; \
|
||||
gSel = s->selector[groupNo]; \
|
||||
gMinlen = s->minLens[gSel]; \
|
||||
gLimit = &(s->limit[gSel][0]); \
|
||||
gPerm = &(s->perm[gSel][0]); \
|
||||
gBase = &(s->base[gSel][0]); \
|
||||
} \
|
||||
groupPos--; \
|
||||
zn = gMinlen; \
|
||||
GET_BITS(label1, zvec, zn); \
|
||||
while (1) { \
|
||||
if (zn > 20 /* the longest code */) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
if (zvec <= gLimit[zn]) break; \
|
||||
zn++; \
|
||||
GET_BIT(label2, zj); \
|
||||
zvec = (zvec << 1) | zj; \
|
||||
}; \
|
||||
if (zvec - gBase[zn] < 0 \
|
||||
|| zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
lval = gPerm[zvec - gBase[zn]]; \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
Int32 BZ2_decompress ( DState* s )
|
||||
{
|
||||
UChar uc;
|
||||
Int32 retVal;
|
||||
Int32 minLen, maxLen;
|
||||
bz_stream* strm = s->strm;
|
||||
|
||||
/* stuff that needs to be saved/restored */
|
||||
Int32 i;
|
||||
Int32 j;
|
||||
Int32 t;
|
||||
Int32 alphaSize;
|
||||
Int32 nGroups;
|
||||
Int32 nSelectors;
|
||||
Int32 EOB;
|
||||
Int32 groupNo;
|
||||
Int32 groupPos;
|
||||
Int32 nextSym;
|
||||
Int32 nblockMAX;
|
||||
Int32 nblock;
|
||||
Int32 es;
|
||||
Int32 N;
|
||||
Int32 curr;
|
||||
Int32 zt;
|
||||
Int32 zn;
|
||||
Int32 zvec;
|
||||
Int32 zj;
|
||||
Int32 gSel;
|
||||
Int32 gMinlen;
|
||||
Int32* gLimit;
|
||||
Int32* gBase;
|
||||
Int32* gPerm;
|
||||
|
||||
if (s->state == BZ_X_MAGIC_1) {
|
||||
/*initialise the save area*/
|
||||
s->save_i = 0;
|
||||
s->save_j = 0;
|
||||
s->save_t = 0;
|
||||
s->save_alphaSize = 0;
|
||||
s->save_nGroups = 0;
|
||||
s->save_nSelectors = 0;
|
||||
s->save_EOB = 0;
|
||||
s->save_groupNo = 0;
|
||||
s->save_groupPos = 0;
|
||||
s->save_nextSym = 0;
|
||||
s->save_nblockMAX = 0;
|
||||
s->save_nblock = 0;
|
||||
s->save_es = 0;
|
||||
s->save_N = 0;
|
||||
s->save_curr = 0;
|
||||
s->save_zt = 0;
|
||||
s->save_zn = 0;
|
||||
s->save_zvec = 0;
|
||||
s->save_zj = 0;
|
||||
s->save_gSel = 0;
|
||||
s->save_gMinlen = 0;
|
||||
s->save_gLimit = NULL;
|
||||
s->save_gBase = NULL;
|
||||
s->save_gPerm = NULL;
|
||||
}
|
||||
|
||||
/*restore from the save area*/
|
||||
i = s->save_i;
|
||||
j = s->save_j;
|
||||
t = s->save_t;
|
||||
alphaSize = s->save_alphaSize;
|
||||
nGroups = s->save_nGroups;
|
||||
nSelectors = s->save_nSelectors;
|
||||
EOB = s->save_EOB;
|
||||
groupNo = s->save_groupNo;
|
||||
groupPos = s->save_groupPos;
|
||||
nextSym = s->save_nextSym;
|
||||
nblockMAX = s->save_nblockMAX;
|
||||
nblock = s->save_nblock;
|
||||
es = s->save_es;
|
||||
N = s->save_N;
|
||||
curr = s->save_curr;
|
||||
zt = s->save_zt;
|
||||
zn = s->save_zn;
|
||||
zvec = s->save_zvec;
|
||||
zj = s->save_zj;
|
||||
gSel = s->save_gSel;
|
||||
gMinlen = s->save_gMinlen;
|
||||
gLimit = s->save_gLimit;
|
||||
gBase = s->save_gBase;
|
||||
gPerm = s->save_gPerm;
|
||||
|
||||
retVal = BZ_OK;
|
||||
|
||||
switch (s->state) {
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_1, uc);
|
||||
if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_2, uc);
|
||||
if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_3, uc)
|
||||
if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
|
||||
if (s->blockSize100k < (BZ_HDR_0 + 1) ||
|
||||
s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
s->blockSize100k -= BZ_HDR_0;
|
||||
|
||||
if (s->smallDecompress) {
|
||||
s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
|
||||
s->ll4 = BZALLOC(
|
||||
((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
|
||||
);
|
||||
if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
|
||||
} else {
|
||||
s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
|
||||
if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
|
||||
}
|
||||
|
||||
GET_UCHAR(BZ_X_BLKHDR_1, uc);
|
||||
|
||||
if (uc == 0x17) goto endhdr_2;
|
||||
if (uc != 0x31) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_2, uc);
|
||||
if (uc != 0x41) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_3, uc);
|
||||
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_4, uc);
|
||||
if (uc != 0x26) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_5, uc);
|
||||
if (uc != 0x53) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_6, uc);
|
||||
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
s->currBlockNo++;
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
|
||||
|
||||
s->storedBlockCRC = 0;
|
||||
GET_UCHAR(BZ_X_BCRC_1, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_2, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_3, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_4, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
|
||||
GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
|
||||
|
||||
s->origPtr = 0;
|
||||
GET_UCHAR(BZ_X_ORIGPTR_1, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
GET_UCHAR(BZ_X_ORIGPTR_2, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
GET_UCHAR(BZ_X_ORIGPTR_3, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
|
||||
if (s->origPtr < 0)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
if (s->origPtr > 10 + 100000*s->blockSize100k)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*--- Receive the mapping table ---*/
|
||||
for (i = 0; i < 16; i++) {
|
||||
GET_BIT(BZ_X_MAPPING_1, uc);
|
||||
if (uc == 1)
|
||||
s->inUse16[i] = True; else
|
||||
s->inUse16[i] = False;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) s->inUse[i] = False;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (s->inUse16[i])
|
||||
for (j = 0; j < 16; j++) {
|
||||
GET_BIT(BZ_X_MAPPING_2, uc);
|
||||
if (uc == 1) s->inUse[i * 16 + j] = True;
|
||||
}
|
||||
makeMaps_d ( s );
|
||||
if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
|
||||
alphaSize = s->nInUse+2;
|
||||
|
||||
/*--- Now the selectors ---*/
|
||||
GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
|
||||
if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
|
||||
GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
|
||||
if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
j = 0;
|
||||
while (True) {
|
||||
GET_BIT(BZ_X_SELECTOR_3, uc);
|
||||
if (uc == 0) break;
|
||||
j++;
|
||||
if (j >= nGroups) RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
s->selectorMtf[i] = j;
|
||||
}
|
||||
|
||||
/*--- Undo the MTF values for the selectors. ---*/
|
||||
{
|
||||
UChar pos[BZ_N_GROUPS], tmp, v;
|
||||
for (v = 0; v < nGroups; v++) pos[v] = v;
|
||||
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
v = s->selectorMtf[i];
|
||||
tmp = pos[v];
|
||||
while (v > 0) { pos[v] = pos[v-1]; v--; }
|
||||
pos[0] = tmp;
|
||||
s->selector[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Now the coding tables ---*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
GET_BITS(BZ_X_CODING_1, curr, 5);
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
while (True) {
|
||||
if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
|
||||
GET_BIT(BZ_X_CODING_2, uc);
|
||||
if (uc == 0) break;
|
||||
GET_BIT(BZ_X_CODING_3, uc);
|
||||
if (uc == 0) curr++; else curr--;
|
||||
}
|
||||
s->len[t][i] = curr;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Create the Huffman decoding tables ---*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
minLen = 32;
|
||||
maxLen = 0;
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
|
||||
if (s->len[t][i] < minLen) minLen = s->len[t][i];
|
||||
}
|
||||
BZ2_hbCreateDecodeTables (
|
||||
&(s->limit[t][0]),
|
||||
&(s->base[t][0]),
|
||||
&(s->perm[t][0]),
|
||||
&(s->len[t][0]),
|
||||
minLen, maxLen, alphaSize
|
||||
);
|
||||
s->minLens[t] = minLen;
|
||||
}
|
||||
|
||||
/*--- Now the MTF values ---*/
|
||||
|
||||
EOB = s->nInUse+1;
|
||||
nblockMAX = 100000 * s->blockSize100k;
|
||||
groupNo = -1;
|
||||
groupPos = 0;
|
||||
|
||||
for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
|
||||
|
||||
/*-- MTF init --*/
|
||||
{
|
||||
Int32 ii, jj, kk;
|
||||
kk = MTFA_SIZE-1;
|
||||
for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
|
||||
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
|
||||
s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
|
||||
kk--;
|
||||
}
|
||||
s->mtfbase[ii] = kk + 1;
|
||||
}
|
||||
}
|
||||
/*-- end MTF init --*/
|
||||
|
||||
nblock = 0;
|
||||
GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
|
||||
|
||||
while (True) {
|
||||
|
||||
if (nextSym == EOB) break;
|
||||
|
||||
if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
|
||||
|
||||
es = -1;
|
||||
N = 1;
|
||||
do {
|
||||
if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
|
||||
if (nextSym == BZ_RUNB) es = es + (1+1) * N;
|
||||
N = N * 2;
|
||||
GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
|
||||
}
|
||||
while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
|
||||
|
||||
es++;
|
||||
uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
|
||||
s->unzftab[uc] += es;
|
||||
|
||||
if (s->smallDecompress)
|
||||
while (es > 0) {
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
s->ll16[nblock] = (UInt16)uc;
|
||||
nblock++;
|
||||
es--;
|
||||
}
|
||||
else
|
||||
while (es > 0) {
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
s->tt[nblock] = (UInt32)uc;
|
||||
nblock++;
|
||||
es--;
|
||||
};
|
||||
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*-- uc = MTF ( nextSym-1 ) --*/
|
||||
{
|
||||
Int32 ii, jj, kk, pp, lno, off;
|
||||
UInt32 nn;
|
||||
nn = (UInt32)(nextSym - 1);
|
||||
|
||||
if (nn < MTFL_SIZE) {
|
||||
/* avoid general-case expense */
|
||||
pp = s->mtfbase[0];
|
||||
uc = s->mtfa[pp+nn];
|
||||
while (nn > 3) {
|
||||
Int32 z = pp+nn;
|
||||
s->mtfa[(z) ] = s->mtfa[(z)-1];
|
||||
s->mtfa[(z)-1] = s->mtfa[(z)-2];
|
||||
s->mtfa[(z)-2] = s->mtfa[(z)-3];
|
||||
s->mtfa[(z)-3] = s->mtfa[(z)-4];
|
||||
nn -= 4;
|
||||
}
|
||||
while (nn > 0) {
|
||||
s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
|
||||
};
|
||||
s->mtfa[pp] = uc;
|
||||
} else {
|
||||
/* general case */
|
||||
lno = nn / MTFL_SIZE;
|
||||
off = nn % MTFL_SIZE;
|
||||
pp = s->mtfbase[lno] + off;
|
||||
uc = s->mtfa[pp];
|
||||
while (pp > s->mtfbase[lno]) {
|
||||
s->mtfa[pp] = s->mtfa[pp-1]; pp--;
|
||||
};
|
||||
s->mtfbase[lno]++;
|
||||
while (lno > 0) {
|
||||
s->mtfbase[lno]--;
|
||||
s->mtfa[s->mtfbase[lno]]
|
||||
= s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
|
||||
lno--;
|
||||
}
|
||||
s->mtfbase[0]--;
|
||||
s->mtfa[s->mtfbase[0]] = uc;
|
||||
if (s->mtfbase[0] == 0) {
|
||||
kk = MTFA_SIZE-1;
|
||||
for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
|
||||
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
|
||||
s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
|
||||
kk--;
|
||||
}
|
||||
s->mtfbase[ii] = kk + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-- end uc = MTF ( nextSym-1 ) --*/
|
||||
|
||||
s->unzftab[s->seqToUnseq[uc]]++;
|
||||
if (s->smallDecompress)
|
||||
s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
|
||||
s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
|
||||
nblock++;
|
||||
|
||||
GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we know what nblock is, we can do a better sanity
|
||||
check on s->origPtr.
|
||||
*/
|
||||
if (s->origPtr < 0 || s->origPtr >= nblock)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*-- Set up cftab to facilitate generation of T^(-1) --*/
|
||||
s->cftab[0] = 0;
|
||||
for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
|
||||
for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
|
||||
for (i = 0; i <= 256; i++) {
|
||||
if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
|
||||
/* s->cftab[i] can legitimately be == nblock */
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
s->state_out_len = 0;
|
||||
s->state_out_ch = 0;
|
||||
BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
|
||||
s->state = BZ_X_OUTPUT;
|
||||
if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
|
||||
|
||||
if (s->smallDecompress) {
|
||||
|
||||
/*-- Make a copy of cftab, used in generation of T --*/
|
||||
for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
|
||||
|
||||
/*-- compute the T vector --*/
|
||||
for (i = 0; i < nblock; i++) {
|
||||
uc = (UChar)(s->ll16[i]);
|
||||
SET_LL(i, s->cftabCopy[uc]);
|
||||
s->cftabCopy[uc]++;
|
||||
}
|
||||
|
||||
/*-- Compute T^(-1) by pointer reversal on T --*/
|
||||
i = s->origPtr;
|
||||
j = GET_LL(i);
|
||||
do {
|
||||
Int32 tmp = GET_LL(j);
|
||||
SET_LL(j, i);
|
||||
i = j;
|
||||
j = tmp;
|
||||
}
|
||||
while (i != s->origPtr);
|
||||
|
||||
s->tPos = s->origPtr;
|
||||
s->nblock_used = 0;
|
||||
if (s->blockRandomised) {
|
||||
BZ_RAND_INIT_MASK;
|
||||
BZ_GET_SMALL(s->k0); s->nblock_used++;
|
||||
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
|
||||
} else {
|
||||
BZ_GET_SMALL(s->k0); s->nblock_used++;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*-- compute the T^(-1) vector --*/
|
||||
for (i = 0; i < nblock; i++) {
|
||||
uc = (UChar)(s->tt[i] & 0xff);
|
||||
s->tt[s->cftab[uc]] |= (i << 8);
|
||||
s->cftab[uc]++;
|
||||
}
|
||||
|
||||
s->tPos = s->tt[s->origPtr] >> 8;
|
||||
s->nblock_used = 0;
|
||||
if (s->blockRandomised) {
|
||||
BZ_RAND_INIT_MASK;
|
||||
BZ_GET_FAST(s->k0); s->nblock_used++;
|
||||
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
|
||||
} else {
|
||||
BZ_GET_FAST(s->k0); s->nblock_used++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RETURN(BZ_OK);
|
||||
|
||||
|
||||
|
||||
endhdr_2:
|
||||
|
||||
GET_UCHAR(BZ_X_ENDHDR_2, uc);
|
||||
if (uc != 0x72) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_3, uc);
|
||||
if (uc != 0x45) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_4, uc);
|
||||
if (uc != 0x38) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_5, uc);
|
||||
if (uc != 0x50) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_6, uc);
|
||||
if (uc != 0x90) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
s->storedCombinedCRC = 0;
|
||||
GET_UCHAR(BZ_X_CCRC_1, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_2, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_3, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_4, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
|
||||
s->state = BZ_X_IDLE;
|
||||
RETURN(BZ_STREAM_END);
|
||||
|
||||
default: AssertH ( False, 4001 );
|
||||
}
|
||||
|
||||
AssertH ( False, 4002 );
|
||||
|
||||
save_state_and_return:
|
||||
|
||||
s->save_i = i;
|
||||
s->save_j = j;
|
||||
s->save_t = t;
|
||||
s->save_alphaSize = alphaSize;
|
||||
s->save_nGroups = nGroups;
|
||||
s->save_nSelectors = nSelectors;
|
||||
s->save_EOB = EOB;
|
||||
s->save_groupNo = groupNo;
|
||||
s->save_groupPos = groupPos;
|
||||
s->save_nextSym = nextSym;
|
||||
s->save_nblockMAX = nblockMAX;
|
||||
s->save_nblock = nblock;
|
||||
s->save_es = es;
|
||||
s->save_N = N;
|
||||
s->save_curr = curr;
|
||||
s->save_zt = zt;
|
||||
s->save_zn = zn;
|
||||
s->save_zvec = zvec;
|
||||
s->save_zj = zj;
|
||||
s->save_gSel = gSel;
|
||||
s->save_gMinlen = gMinlen;
|
||||
s->save_gLimit = gLimit;
|
||||
s->save_gBase = gBase;
|
||||
s->save_gPerm = gPerm;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end decompress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
176
src/tools/stuffextract/StormLib/bzip2/dlltest.c
Normal file
176
src/tools/stuffextract/StormLib/bzip2/dlltest.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
minibz2
|
||||
libbz2.dll test program.
|
||||
by Yoshioka Tsuneo(QWF00133@nifty.ne.jp/tsuneo-y@is.aist-nara.ac.jp)
|
||||
This file is Public Domain.
|
||||
welcome any email to me.
|
||||
|
||||
usage: minibz2 [-d] [-{1,2,..9}] [[srcfilename] destfilename]
|
||||
*/
|
||||
|
||||
#define BZ_IMPORT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "bzlib.h"
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define BZ2_LIBNAME "libbz2-1.0.2.DLL"
|
||||
|
||||
#include <windows.h>
|
||||
static int BZ2DLLLoaded = 0;
|
||||
static HINSTANCE BZ2DLLhLib;
|
||||
int BZ2DLLLoadLibrary(void)
|
||||
{
|
||||
HINSTANCE hLib;
|
||||
|
||||
if(BZ2DLLLoaded==1){return 0;}
|
||||
hLib=LoadLibrary(BZ2_LIBNAME);
|
||||
if(hLib == NULL){
|
||||
fprintf(stderr,"Can't load %s\n",BZ2_LIBNAME);
|
||||
return -1;
|
||||
}
|
||||
BZ2_bzlibVersion=GetProcAddress(hLib,"BZ2_bzlibVersion");
|
||||
BZ2_bzopen=GetProcAddress(hLib,"BZ2_bzopen");
|
||||
BZ2_bzdopen=GetProcAddress(hLib,"BZ2_bzdopen");
|
||||
BZ2_bzread=GetProcAddress(hLib,"BZ2_bzread");
|
||||
BZ2_bzwrite=GetProcAddress(hLib,"BZ2_bzwrite");
|
||||
BZ2_bzflush=GetProcAddress(hLib,"BZ2_bzflush");
|
||||
BZ2_bzclose=GetProcAddress(hLib,"BZ2_bzclose");
|
||||
BZ2_bzerror=GetProcAddress(hLib,"BZ2_bzerror");
|
||||
|
||||
if (!BZ2_bzlibVersion || !BZ2_bzopen || !BZ2_bzdopen
|
||||
|| !BZ2_bzread || !BZ2_bzwrite || !BZ2_bzflush
|
||||
|| !BZ2_bzclose || !BZ2_bzerror) {
|
||||
fprintf(stderr,"GetProcAddress failed.\n");
|
||||
return -1;
|
||||
}
|
||||
BZ2DLLLoaded=1;
|
||||
BZ2DLLhLib=hLib;
|
||||
return 0;
|
||||
|
||||
}
|
||||
int BZ2DLLFreeLibrary(void)
|
||||
{
|
||||
if(BZ2DLLLoaded==0){return 0;}
|
||||
FreeLibrary(BZ2DLLhLib);
|
||||
BZ2DLLLoaded=0;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
puts("usage: minibz2 [-d] [-{1,2,..9}] [[srcfilename] destfilename]");
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int decompress = 0;
|
||||
int level = 9;
|
||||
char *fn_r = NULL;
|
||||
char *fn_w = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
if(BZ2DLLLoadLibrary()<0){
|
||||
fprintf(stderr,"Loading of %s failed. Giving up.\n", BZ2_LIBNAME);
|
||||
exit(1);
|
||||
}
|
||||
printf("Loading of %s succeeded. Library version is %s.\n",
|
||||
BZ2_LIBNAME, BZ2_bzlibVersion() );
|
||||
#endif
|
||||
while(++argv,--argc){
|
||||
if(**argv =='-' || **argv=='/'){
|
||||
char *p;
|
||||
|
||||
for(p=*argv+1;*p;p++){
|
||||
if(*p=='d'){
|
||||
decompress = 1;
|
||||
}else if('1'<=*p && *p<='9'){
|
||||
level = *p - '0';
|
||||
}else{
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(argc>=1){
|
||||
fn_r = *argv;
|
||||
argc--;argv++;
|
||||
}else{
|
||||
fn_r = NULL;
|
||||
}
|
||||
if(argc>=1){
|
||||
fn_w = *argv;
|
||||
argc--;argv++;
|
||||
}else{
|
||||
fn_w = NULL;
|
||||
}
|
||||
{
|
||||
int len;
|
||||
char buff[0x1000];
|
||||
char mode[10];
|
||||
|
||||
if(decompress){
|
||||
BZFILE *BZ2fp_r = NULL;
|
||||
FILE *fp_w = NULL;
|
||||
|
||||
if(fn_w){
|
||||
if((fp_w = fopen(fn_w,"wb"))==NULL){
|
||||
printf("can't open [%s]\n",fn_w);
|
||||
perror("reason:");
|
||||
exit(1);
|
||||
}
|
||||
}else{
|
||||
fp_w = stdout;
|
||||
}
|
||||
if((fn_r == NULL && (BZ2fp_r = BZ2_bzdopen(fileno(stdin),"rb"))==NULL)
|
||||
|| (fn_r != NULL && (BZ2fp_r = BZ2_bzopen(fn_r,"rb"))==NULL)){
|
||||
printf("can't bz2openstream\n");
|
||||
exit(1);
|
||||
}
|
||||
while((len=BZ2_bzread(BZ2fp_r,buff,0x1000))>0){
|
||||
fwrite(buff,1,len,fp_w);
|
||||
}
|
||||
BZ2_bzclose(BZ2fp_r);
|
||||
if(fp_w != stdout) fclose(fp_w);
|
||||
}else{
|
||||
BZFILE *BZ2fp_w = NULL;
|
||||
FILE *fp_r = NULL;
|
||||
|
||||
if(fn_r){
|
||||
if((fp_r = fopen(fn_r,"rb"))==NULL){
|
||||
printf("can't open [%s]\n",fn_r);
|
||||
perror("reason:");
|
||||
exit(1);
|
||||
}
|
||||
}else{
|
||||
fp_r = stdin;
|
||||
}
|
||||
mode[0]='w';
|
||||
mode[1] = '0' + level;
|
||||
mode[2] = '\0';
|
||||
|
||||
if((fn_w == NULL && (BZ2fp_w = BZ2_bzdopen(fileno(stdout),mode))==NULL)
|
||||
|| (fn_w !=NULL && (BZ2fp_w = BZ2_bzopen(fn_w,mode))==NULL)){
|
||||
printf("can't bz2openstream\n");
|
||||
exit(1);
|
||||
}
|
||||
while((len=fread(buff,1,0x1000,fp_r))>0){
|
||||
BZ2_bzwrite(BZ2fp_w,buff,len);
|
||||
}
|
||||
BZ2_bzclose(BZ2fp_w);
|
||||
if(fp_r!=stdin)fclose(fp_r);
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
BZ2DLLFreeLibrary();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
245
src/tools/stuffextract/StormLib/bzip2/huffman.c
Normal file
245
src/tools/stuffextract/StormLib/bzip2/huffman.c
Normal file
@ -0,0 +1,245 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Huffman coding low-level stuff ---*/
|
||||
/*--- huffman.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/*--
|
||||
This file is a part of bzip2 and/or libbzip2, a program and
|
||||
library for lossless, block-sorting data compression.
|
||||
|
||||
Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0 of 21 March 2000
|
||||
|
||||
This program is based on (at least) the work of:
|
||||
Mike Burrows
|
||||
David Wheeler
|
||||
Peter Fenwick
|
||||
Alistair Moffat
|
||||
Radford Neal
|
||||
Ian H. Witten
|
||||
Robert Sedgewick
|
||||
Jon L. Bentley
|
||||
|
||||
For more information on these sources, see the manual.
|
||||
--*/
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
|
||||
#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
|
||||
#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
|
||||
|
||||
#define ADDWEIGHTS(zw1,zw2) \
|
||||
(WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
|
||||
(1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
|
||||
|
||||
#define UPHEAP(z) \
|
||||
{ \
|
||||
Int32 zz, tmp; \
|
||||
zz = z; tmp = heap[zz]; \
|
||||
while (weight[tmp] < weight[heap[zz >> 1]]) { \
|
||||
heap[zz] = heap[zz >> 1]; \
|
||||
zz >>= 1; \
|
||||
} \
|
||||
heap[zz] = tmp; \
|
||||
}
|
||||
|
||||
#define DOWNHEAP(z) \
|
||||
{ \
|
||||
Int32 zz, yy, tmp; \
|
||||
zz = z; tmp = heap[zz]; \
|
||||
while (True) { \
|
||||
yy = zz << 1; \
|
||||
if (yy > nHeap) break; \
|
||||
if (yy < nHeap && \
|
||||
weight[heap[yy+1]] < weight[heap[yy]]) \
|
||||
yy++; \
|
||||
if (weight[tmp] < weight[heap[yy]]) break; \
|
||||
heap[zz] = heap[yy]; \
|
||||
zz = yy; \
|
||||
} \
|
||||
heap[zz] = tmp; \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbMakeCodeLengths ( UChar *len,
|
||||
Int32 *freq,
|
||||
Int32 alphaSize,
|
||||
Int32 maxLen )
|
||||
{
|
||||
/*--
|
||||
Nodes and heap entries run from 1. Entry 0
|
||||
for both the heap and nodes is a sentinel.
|
||||
--*/
|
||||
Int32 nNodes, nHeap, n1, n2, i, j, k;
|
||||
Bool tooLong;
|
||||
|
||||
Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ];
|
||||
Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
|
||||
Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ];
|
||||
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
|
||||
|
||||
while (True) {
|
||||
|
||||
nNodes = alphaSize;
|
||||
nHeap = 0;
|
||||
|
||||
heap[0] = 0;
|
||||
weight[0] = 0;
|
||||
parent[0] = -2;
|
||||
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
parent[i] = -1;
|
||||
nHeap++;
|
||||
heap[nHeap] = i;
|
||||
UPHEAP(nHeap);
|
||||
}
|
||||
|
||||
AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
|
||||
|
||||
while (nHeap > 1) {
|
||||
n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
|
||||
n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
|
||||
nNodes++;
|
||||
parent[n1] = parent[n2] = nNodes;
|
||||
weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
|
||||
parent[nNodes] = -1;
|
||||
nHeap++;
|
||||
heap[nHeap] = nNodes;
|
||||
UPHEAP(nHeap);
|
||||
}
|
||||
|
||||
AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
|
||||
|
||||
tooLong = False;
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
j = 0;
|
||||
k = i;
|
||||
while (parent[k] >= 0) { k = parent[k]; j++; }
|
||||
len[i-1] = j;
|
||||
if (j > maxLen) tooLong = True;
|
||||
}
|
||||
|
||||
if (! tooLong) break;
|
||||
|
||||
/* 17 Oct 04: keep-going condition for the following loop used
|
||||
to be 'i < alphaSize', which missed the last element,
|
||||
theoretically leading to the possibility of the compressor
|
||||
looping. However, this count-scaling step is only needed if
|
||||
one of the generated Huffman code words is longer than
|
||||
maxLen, which up to and including version 1.0.2 was 20 bits,
|
||||
which is extremely unlikely. In version 1.0.3 maxLen was
|
||||
changed to 17 bits, which has minimal effect on compression
|
||||
ratio, but does mean this scaling step is used from time to
|
||||
time, enough to verify that it works.
|
||||
|
||||
This means that bzip2-1.0.3 and later will only produce
|
||||
Huffman codes with a maximum length of 17 bits. However, in
|
||||
order to preserve backwards compatibility with bitstreams
|
||||
produced by versions pre-1.0.3, the decompressor must still
|
||||
handle lengths of up to 20. */
|
||||
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
j = weight[i] >> 8;
|
||||
j = 1 + (j / 2);
|
||||
weight[i] = j << 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbAssignCodes ( Int32 *code,
|
||||
UChar *length,
|
||||
Int32 minLen,
|
||||
Int32 maxLen,
|
||||
Int32 alphaSize )
|
||||
{
|
||||
Int32 n, vec, i;
|
||||
|
||||
vec = 0;
|
||||
for (n = minLen; n <= maxLen; n++) {
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
if (length[i] == n) { code[i] = vec; vec++; };
|
||||
vec <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbCreateDecodeTables ( Int32 *limit,
|
||||
Int32 *base,
|
||||
Int32 *perm,
|
||||
UChar *length,
|
||||
Int32 minLen,
|
||||
Int32 maxLen,
|
||||
Int32 alphaSize )
|
||||
{
|
||||
Int32 pp, i, j, vec;
|
||||
|
||||
pp = 0;
|
||||
for (i = minLen; i <= maxLen; i++)
|
||||
for (j = 0; j < alphaSize; j++)
|
||||
if (length[j] == i) { perm[pp] = j; pp++; };
|
||||
|
||||
for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
|
||||
for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
|
||||
|
||||
for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
|
||||
|
||||
for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
|
||||
vec = 0;
|
||||
|
||||
for (i = minLen; i <= maxLen; i++) {
|
||||
vec += (base[i+1] - base[i]);
|
||||
limit[i] = vec-1;
|
||||
vec <<= 1;
|
||||
}
|
||||
for (i = minLen + 1; i <= maxLen; i++)
|
||||
base[i] = ((limit[i-1] + 1) << 1) - base[i];
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end huffman.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
16
src/tools/stuffextract/StormLib/bzip2/mk251.c
Normal file
16
src/tools/stuffextract/StormLib/bzip2/mk251.c
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
/* Spew out a long sequence of the byte 251. When fed to bzip2
|
||||
versions 1.0.0 or 1.0.1, causes it to die with internal error
|
||||
1007 in blocksort.c. This assertion misses an extremely rare
|
||||
case, which is fixed in this version (1.0.2) and above.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main ()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 48500000 ; i++)
|
||||
putchar(251);
|
||||
return 0;
|
||||
}
|
||||
124
src/tools/stuffextract/StormLib/bzip2/randtable.c
Normal file
124
src/tools/stuffextract/StormLib/bzip2/randtable.c
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Table for randomising repetitive blocks ---*/
|
||||
/*--- randtable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/*--
|
||||
This file is a part of bzip2 and/or libbzip2, a program and
|
||||
library for lossless, block-sorting data compression.
|
||||
|
||||
Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0 of 21 March 2000
|
||||
|
||||
This program is based on (at least) the work of:
|
||||
Mike Burrows
|
||||
David Wheeler
|
||||
Peter Fenwick
|
||||
Alistair Moffat
|
||||
Radford Neal
|
||||
Ian H. Witten
|
||||
Robert Sedgewick
|
||||
Jon L. Bentley
|
||||
|
||||
For more information on these sources, see the manual.
|
||||
--*/
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
Int32 BZ2_rNums[512] = {
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end randtable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
39
src/tools/stuffextract/StormLib/bzip2/spewG.c
Normal file
39
src/tools/stuffextract/StormLib/bzip2/spewG.c
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
/* spew out a thoroughly gigantic file designed so that bzip2
|
||||
can compress it reasonably rapidly. This is to help test
|
||||
support for large files (> 2GB) in a reasonable amount of time.
|
||||
I suggest you use the undocumented --exponential option to
|
||||
bzip2 when compressing the resulting file; this saves a bit of
|
||||
time. Note: *don't* bother with --exponential when compressing
|
||||
Real Files; it'll just waste a lot of CPU time :-)
|
||||
(but is otherwise harmless).
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* The number of megabytes of junk to spew out (roughly) */
|
||||
#define MEGABYTES 5000
|
||||
|
||||
#define N_BUF 1000000
|
||||
char buf[N_BUF];
|
||||
|
||||
int main ( int argc, char** argv )
|
||||
{
|
||||
int ii, kk, p;
|
||||
srandom(1);
|
||||
setbuffer ( stdout, buf, N_BUF );
|
||||
for (kk = 0; kk < MEGABYTES * 515; kk+=3) {
|
||||
p = 25+random()%50;
|
||||
for (ii = 0; ii < p; ii++)
|
||||
printf ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" );
|
||||
for (ii = 0; ii < p-1; ii++)
|
||||
printf ( "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" );
|
||||
for (ii = 0; ii < p+1; ii++)
|
||||
printf ( "ccccccccccccccccccccccccccccccccccccc" );
|
||||
}
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
126
src/tools/stuffextract/StormLib/bzip2/unzcrash.c
Normal file
126
src/tools/stuffextract/StormLib/bzip2/unzcrash.c
Normal file
@ -0,0 +1,126 @@
|
||||
|
||||
/* A test program written to test robustness to decompression of
|
||||
corrupted data. Usage is
|
||||
unzcrash filename
|
||||
and the program will read the specified file, compress it (in memory),
|
||||
and then repeatedly decompress it, each time with a different bit of
|
||||
the compressed data inverted, so as to test all possible one-bit errors.
|
||||
This should not cause any invalid memory accesses. If it does,
|
||||
I want to know about it!
|
||||
|
||||
p.s. As you can see from the above description, the process is
|
||||
incredibly slow. A file of size eg 5KB will cause it to run for
|
||||
many hours.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "bzlib.h"
|
||||
|
||||
#define M_BLOCK 1000000
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
#define M_BLOCK_OUT (M_BLOCK + 1000000)
|
||||
uchar inbuf[M_BLOCK];
|
||||
uchar outbuf[M_BLOCK_OUT];
|
||||
uchar zbuf[M_BLOCK + 600 + (M_BLOCK / 100)];
|
||||
|
||||
int nIn, nOut, nZ;
|
||||
|
||||
static char *bzerrorstrings[] = {
|
||||
"OK"
|
||||
,"SEQUENCE_ERROR"
|
||||
,"PARAM_ERROR"
|
||||
,"MEM_ERROR"
|
||||
,"DATA_ERROR"
|
||||
,"DATA_ERROR_MAGIC"
|
||||
,"IO_ERROR"
|
||||
,"UNEXPECTED_EOF"
|
||||
,"OUTBUFF_FULL"
|
||||
,"???" /* for future */
|
||||
,"???" /* for future */
|
||||
,"???" /* for future */
|
||||
,"???" /* for future */
|
||||
,"???" /* for future */
|
||||
,"???" /* for future */
|
||||
};
|
||||
|
||||
void flip_bit ( int bit )
|
||||
{
|
||||
int byteno = bit / 8;
|
||||
int bitno = bit % 8;
|
||||
uchar mask = 1 << bitno;
|
||||
//fprintf ( stderr, "(byte %d bit %d mask %d)",
|
||||
// byteno, bitno, (int)mask );
|
||||
zbuf[byteno] ^= mask;
|
||||
}
|
||||
|
||||
int main ( int argc, char** argv )
|
||||
{
|
||||
FILE* f;
|
||||
int r;
|
||||
int bit;
|
||||
int i;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf ( stderr, "usage: unzcrash filename\n" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
f = fopen ( argv[1], "r" );
|
||||
if (!f) {
|
||||
fprintf ( stderr, "unzcrash: can't open %s\n", argv[1] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
nIn = fread ( inbuf, 1, M_BLOCK, f );
|
||||
fprintf ( stderr, "%d bytes read\n", nIn );
|
||||
|
||||
nZ = M_BLOCK;
|
||||
r = BZ2_bzBuffToBuffCompress (
|
||||
zbuf, &nZ, inbuf, nIn, 9, 0, 30 );
|
||||
|
||||
assert (r == BZ_OK);
|
||||
fprintf ( stderr, "%d after compression\n", nZ );
|
||||
|
||||
for (bit = 0; bit < nZ*8; bit++) {
|
||||
fprintf ( stderr, "bit %d ", bit );
|
||||
flip_bit ( bit );
|
||||
nOut = M_BLOCK_OUT;
|
||||
r = BZ2_bzBuffToBuffDecompress (
|
||||
outbuf, &nOut, zbuf, nZ, 0, 0 );
|
||||
fprintf ( stderr, " %d %s ", r, bzerrorstrings[-r] );
|
||||
|
||||
if (r != BZ_OK) {
|
||||
fprintf ( stderr, "\n" );
|
||||
} else {
|
||||
if (nOut != nIn) {
|
||||
fprintf(stderr, "nIn/nOut mismatch %d %d\n", nIn, nOut );
|
||||
return 1;
|
||||
} else {
|
||||
for (i = 0; i < nOut; i++)
|
||||
if (inbuf[i] != outbuf[i]) {
|
||||
fprintf(stderr, "mismatch at %d\n", i );
|
||||
return 1;
|
||||
}
|
||||
if (i == nOut) fprintf(stderr, "really ok!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
flip_bit ( bit );
|
||||
}
|
||||
|
||||
#if 0
|
||||
assert (nOut == nIn);
|
||||
for (i = 0; i < nOut; i++) {
|
||||
if (inbuf[i] != outbuf[i]) {
|
||||
fprintf ( stderr, "difference at %d !\n", i );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf ( stderr, "all ok\n" );
|
||||
return 0;
|
||||
}
|
||||
1453
src/tools/stuffextract/StormLib/huffman/huff.cpp
Normal file
1453
src/tools/stuffextract/StormLib/huffman/huff.cpp
Normal file
File diff suppressed because it is too large
Load Diff
142
src/tools/stuffextract/StormLib/huffman/huff.h
Normal file
142
src/tools/stuffextract/StormLib/huffman/huff.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*****************************************************************************/
|
||||
/* huffman.h Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Description : */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.xx 1.00 Lad The first version of huffman.h */
|
||||
/* 03.05.03 2.00 Lad Added compression */
|
||||
/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __HUFFMAN_H__
|
||||
#define __HUFFMAN_H__
|
||||
|
||||
#include "../StormPort.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define INSERT_ITEM 1
|
||||
#define SWITCH_ITEMS 2 // Switch the item1 and item2
|
||||
|
||||
#define PTR_NOT(ptr) (THTreeItem *)(~(DWORD_PTR)(ptr))
|
||||
#define PTR_PTR(ptr) ((THTreeItem *)(ptr))
|
||||
#define PTR_INT(ptr) (LONG_PTR)(ptr)
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Structures and classes
|
||||
|
||||
// Input stream for Huffmann decompression
|
||||
class TInputStream
|
||||
{
|
||||
public:
|
||||
|
||||
unsigned long GetBit();
|
||||
unsigned long Get7Bits();
|
||||
unsigned long Get8Bits();
|
||||
|
||||
unsigned char * pbInBuffer; // 00 - Input data
|
||||
unsigned long dwBitBuff; // 04 - Input bit buffer
|
||||
unsigned int nBits; // 08 - Number of bits remaining in 'dwValue'
|
||||
};
|
||||
|
||||
// Output stream for Huffmann compression
|
||||
class TOutputStream
|
||||
{
|
||||
public:
|
||||
|
||||
void PutBits(unsigned long dwBuff, unsigned int nPutBits);
|
||||
|
||||
unsigned char * pbOutBuffer; // 00 : Output buffer
|
||||
unsigned long dwOutSize; // 04 : Size of output buffer
|
||||
unsigned char * pbOutPos; // 08 : Current output position
|
||||
unsigned long dwBitBuff; // 0C : Bit buffer
|
||||
unsigned long nBits; // 10 : Number of bits in the bit buffer
|
||||
};
|
||||
|
||||
// Huffmann tree item (?)
|
||||
struct THTreeItem
|
||||
{
|
||||
public:
|
||||
|
||||
THTreeItem * Call1501DB70(THTreeItem * pLast);
|
||||
THTreeItem * GetPrevItem(LONG_PTR value);
|
||||
void ClearItemLinks();
|
||||
void RemoveItem();
|
||||
|
||||
THTreeItem * next; // 00 - Pointer to next THTreeItem
|
||||
THTreeItem * prev; // 04 - Pointer to prev THTreeItem (< 0 if none)
|
||||
unsigned long dcmpByte; // 08 - Index of this item in item pointer array, decompressed byte value
|
||||
unsigned long byteValue; // 0C - Some byte value
|
||||
THTreeItem * parent; // 10 - Pointer to parent THTreeItem (NULL if none)
|
||||
THTreeItem * child; // 14 - Pointer to child THTreeItem
|
||||
int addressMultiplier; // -1 if object on negative address (>0x80000000), +1 if positive
|
||||
};
|
||||
|
||||
// Structure used for quick decompress. The 'bitCount' contains number of bits
|
||||
// and byte value contains result decompressed byte value.
|
||||
// After each walk through Huffman tree are filled all entries which are
|
||||
// multiplies of number of bits loaded from input stream. These entries
|
||||
// contain number of bits and result value. At the next 7 bits is tested this
|
||||
// structure first. If corresponding entry found, decompression routine will
|
||||
// not walk through Huffman tree and directly stores output byte to output stream.
|
||||
struct TQDecompress
|
||||
{
|
||||
unsigned long offs00; // 00 - 1 if resolved
|
||||
unsigned long nBits; // 04 - Bit count
|
||||
union
|
||||
{
|
||||
unsigned long dcmpByte; // 08 - Byte value for decompress (if bitCount <= 7)
|
||||
THTreeItem * pItem; // 08 - THTreeItem (if number of bits is greater than 7
|
||||
};
|
||||
};
|
||||
|
||||
// Structure for Huffman tree (Size 0x3674 bytes). Because I'm not expert
|
||||
// for the decompression, I do not know actually if the class is really a Hufmann
|
||||
// tree. If someone knows the decompression details, please let me know
|
||||
class THuffmannTree
|
||||
{
|
||||
public:
|
||||
|
||||
THuffmannTree();
|
||||
void InitTree(bool bCompression);
|
||||
void BuildTree(unsigned int nCmpType);
|
||||
// void ModifyTree(unsigned long dwIndex);
|
||||
// void UninitTree();
|
||||
|
||||
// void Call15007010(Bit32 dwInLength, THTreeItem * item);
|
||||
THTreeItem * Call1500E740(unsigned int nValue);
|
||||
void Call1500E820(THTreeItem * pItem);
|
||||
unsigned int DoCompression(TOutputStream * os, unsigned char * pbInBuffer, int nInLength, int nCmpType);
|
||||
unsigned int DoDecompression(unsigned char * pbOutBuffer, unsigned int dwOutLength, TInputStream * is);
|
||||
|
||||
unsigned long bIsCmp0; // 0000 - 1 if compression type 0
|
||||
unsigned long offs0004; // 0004 - Some flag
|
||||
THTreeItem items0008[0x203]; // 0008 - HTree items
|
||||
|
||||
//- Sometimes used as HTree item -----------
|
||||
THTreeItem * pItem3050; // 3050 - Always NULL (?)
|
||||
THTreeItem * pItem3054; // 3054 - Pointer to Huffman tree item
|
||||
THTreeItem * pItem3058; // 3058 - Pointer to Huffman tree item (< 0 if invalid)
|
||||
|
||||
//- Sometimes used as HTree item -----------
|
||||
THTreeItem * pItem305C; // 305C - Usually NULL
|
||||
THTreeItem * pFirst; // 3060 - Pointer to top (first) Huffman tree item
|
||||
THTreeItem * pLast; // 3064 - Pointer to bottom (last) Huffman tree item (< 0 if invalid)
|
||||
unsigned long nItems; // 3068 - Number of used HTree items
|
||||
|
||||
//-------------------------------------------
|
||||
THTreeItem * items306C[0x102]; // 306C - THTreeItem pointer array
|
||||
TQDecompress qd3474[0x80]; // 3474 - Array for quick decompression
|
||||
int addressMultiplier; // -1 if object on negative address (>0x80000000), +1 if positive
|
||||
|
||||
static unsigned char Table1502A630[];// Some table
|
||||
};
|
||||
|
||||
#endif // __HUFFMAN_H__
|
||||
72
src/tools/stuffextract/StormLib/pklib/crc32_pk.c
Normal file
72
src/tools/stuffextract/StormLib/pklib/crc32_pk.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*****************************************************************************/
|
||||
/* crc32.c Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Pkware Data Compression Library Version 1.11 */
|
||||
/* Dissassembled method crc32 - cdecl version */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 09.04.03 1.00 Lad The first version of crc32.c */
|
||||
/* 02.05.03 1.00 Lad Stress test done */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "pklib.h"
|
||||
|
||||
static char CopyRight[] = "PKWARE Data Compression Library for Win32\r\n"
|
||||
"Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
|
||||
"Patent No. 5,051,745\r\n"
|
||||
"PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
|
||||
"Version 1.11\r\n";
|
||||
|
||||
static unsigned long crc_table[] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
|
||||
unsigned long PKEXPORT crc32pk(char * buffer, unsigned int * psize, unsigned long * old_crc)
|
||||
{
|
||||
unsigned int size = *psize;
|
||||
unsigned long ch;
|
||||
unsigned long crc_value = *old_crc;
|
||||
|
||||
while(size-- != 0)
|
||||
{
|
||||
ch = *buffer++ ^ (char)crc_value;
|
||||
crc_value >>= 8;
|
||||
|
||||
crc_value = crc_table[ch & 0x0FF] ^ crc_value;
|
||||
}
|
||||
return crc_value;
|
||||
}
|
||||
480
src/tools/stuffextract/StormLib/pklib/explode.c
Normal file
480
src/tools/stuffextract/StormLib/pklib/explode.c
Normal file
@ -0,0 +1,480 @@
|
||||
/*****************************************************************************/
|
||||
/* explode.c Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Implode function of PKWARE Data Compression library */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */
|
||||
/* 08.04.03 1.01 Lad Renamed to explode.c to be compatible with pklib */
|
||||
/* 02.05.03 1.01 Lad Stress test done */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pklib.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tables
|
||||
|
||||
static unsigned char DistBits[] =
|
||||
{
|
||||
0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
|
||||
};
|
||||
|
||||
static unsigned char DistCode[] =
|
||||
{
|
||||
0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
|
||||
0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
|
||||
};
|
||||
|
||||
static unsigned char ExLenBits[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
|
||||
};
|
||||
|
||||
static unsigned short LenBase[] =
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106
|
||||
};
|
||||
|
||||
static unsigned char LenBits[] =
|
||||
{
|
||||
0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
|
||||
};
|
||||
|
||||
static unsigned char LenCode[] =
|
||||
{
|
||||
0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
|
||||
};
|
||||
|
||||
static unsigned char ChBitsAsc[] =
|
||||
{
|
||||
0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
|
||||
0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
|
||||
0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
|
||||
0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
|
||||
0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
|
||||
0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
|
||||
0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
|
||||
};
|
||||
|
||||
static unsigned short ChCodeAsc[] =
|
||||
{
|
||||
0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
|
||||
0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
|
||||
0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
|
||||
0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
|
||||
0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
|
||||
0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
|
||||
0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
|
||||
0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
|
||||
0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
|
||||
0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
|
||||
0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
|
||||
0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
|
||||
0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
|
||||
0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
|
||||
0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
|
||||
0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
|
||||
0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
|
||||
0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
|
||||
0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
|
||||
0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
|
||||
0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
|
||||
0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
|
||||
0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
|
||||
0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
|
||||
0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
|
||||
0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
|
||||
0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
|
||||
0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
|
||||
0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
|
||||
0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
|
||||
0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
|
||||
0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local variables
|
||||
|
||||
static char Copyright[] = "PKWARE Data Compression Library for Win32\r\n"
|
||||
"Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
|
||||
"Patent No. 5,051,745\r\n"
|
||||
"PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
|
||||
"Version 1.11\r\n";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local functions
|
||||
|
||||
// Copies a block to another location
|
||||
static void lmemcpy(void * trg, const void * src, size_t count)
|
||||
{
|
||||
memcpy(trg, src, count);
|
||||
}
|
||||
|
||||
static void GenDecodeTabs(long count, unsigned char * bits, unsigned char * pCode, unsigned char * buffer2)
|
||||
{
|
||||
long i;
|
||||
|
||||
for(i = count-1; i >= 0; i--) // EBX - count
|
||||
{
|
||||
unsigned long idx1 = pCode[i];
|
||||
unsigned long idx2 = 1 << bits[i];
|
||||
|
||||
do
|
||||
{
|
||||
buffer2[idx1] = (unsigned char)i;
|
||||
idx1 += idx2;
|
||||
}
|
||||
while(idx1 < 0x100);
|
||||
}
|
||||
}
|
||||
|
||||
static void GenAscTabs(TDcmpStruct * pWork)
|
||||
{
|
||||
unsigned short * pChCodeAsc = &ChCodeAsc[0xFF];
|
||||
unsigned long acc, add;
|
||||
unsigned short count;
|
||||
|
||||
for(count = 0x00FF; pChCodeAsc >= ChCodeAsc; pChCodeAsc--, count--)
|
||||
{
|
||||
unsigned char * pChBitsAsc = pWork->ChBitsAsc + count;
|
||||
unsigned char bits_asc = *pChBitsAsc;
|
||||
|
||||
if(bits_asc <= 8)
|
||||
{
|
||||
add = (1 << bits_asc);
|
||||
acc = *pChCodeAsc;
|
||||
|
||||
do
|
||||
{
|
||||
pWork->offs2C34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
}
|
||||
while(acc < 0x100);
|
||||
}
|
||||
else if((acc = (*pChCodeAsc & 0xFF)) != 0)
|
||||
{
|
||||
pWork->offs2C34[acc] = 0xFF;
|
||||
|
||||
if(*pChCodeAsc & 0x3F)
|
||||
{
|
||||
bits_asc -= 4;
|
||||
*pChBitsAsc = bits_asc;
|
||||
|
||||
add = (1 << bits_asc);
|
||||
acc = *pChCodeAsc >> 4;
|
||||
do
|
||||
{
|
||||
pWork->offs2D34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
}
|
||||
while(acc < 0x100);
|
||||
}
|
||||
else
|
||||
{
|
||||
bits_asc -= 6;
|
||||
*pChBitsAsc = bits_asc;
|
||||
|
||||
add = (1 << bits_asc);
|
||||
acc = *pChCodeAsc >> 6;
|
||||
do
|
||||
{
|
||||
pWork->offs2E34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
}
|
||||
while(acc < 0x80);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bits_asc -= 8;
|
||||
*pChBitsAsc = bits_asc;
|
||||
|
||||
add = (1 << bits_asc);
|
||||
acc = *pChCodeAsc >> 8;
|
||||
do
|
||||
{
|
||||
pWork->offs2EB4[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
}
|
||||
while(acc < 0x100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Skips given number of bits in bit buffer. Result is stored in pWork->bit_buff
|
||||
// If no data in input buffer, returns true
|
||||
|
||||
static int WasteBits(TDcmpStruct * pWork, unsigned long nBits)
|
||||
{
|
||||
// If number of bits required is less than number of (bits in the buffer) ?
|
||||
if(nBits <= pWork->extra_bits)
|
||||
{
|
||||
pWork->extra_bits -= nBits;
|
||||
pWork->bit_buff >>= nBits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load input buffer if necessary
|
||||
pWork->bit_buff >>= pWork->extra_bits;
|
||||
if(pWork->in_pos == pWork->in_bytes)
|
||||
{
|
||||
pWork->in_pos = sizeof(pWork->in_buff);
|
||||
if((pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param)) == 0)
|
||||
return 1;
|
||||
pWork->in_pos = 0;
|
||||
}
|
||||
|
||||
// Update bit buffer
|
||||
pWork->bit_buff |= (pWork->in_buff[pWork->in_pos++] << 8);
|
||||
pWork->bit_buff >>= (nBits - pWork->extra_bits);
|
||||
pWork->extra_bits = (pWork->extra_bits - nBits) + 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns : 0x000 - 0x0FF : One byte from compressed file.
|
||||
// 0x100 - 0x305 : Copy previous block (0x100 = 1 byte)
|
||||
// 0x306 : Out of buffer (?)
|
||||
|
||||
static unsigned long DecodeLit(TDcmpStruct * pWork)
|
||||
{
|
||||
unsigned long nBits; // Number of bits to skip
|
||||
unsigned long value; // Position in buffers
|
||||
|
||||
// Test the current bit in byte buffer. If is not set, simply return the next byte.
|
||||
if(pWork->bit_buff & 1)
|
||||
{
|
||||
// Skip current bit in the buffer
|
||||
if(WasteBits(pWork, 1))
|
||||
return 0x306;
|
||||
|
||||
// The next bits are position in buffers
|
||||
value = pWork->position2[(pWork->bit_buff & 0xFF)];
|
||||
|
||||
// Get number of bits to skip
|
||||
if(WasteBits(pWork, pWork->LenBits[value]))
|
||||
return 0x306;
|
||||
|
||||
if((nBits = pWork->ExLenBits[value]) != 0)
|
||||
{
|
||||
unsigned long val2 = pWork->bit_buff & ((1 << nBits) - 1);
|
||||
|
||||
if(WasteBits(pWork, nBits))
|
||||
{
|
||||
if((value + val2) != 0x10E)
|
||||
return 0x306;
|
||||
}
|
||||
value = pWork->LenBase[value] + val2;
|
||||
}
|
||||
return value + 0x100; // Return number of bytes to repeat
|
||||
}
|
||||
|
||||
// Waste one bit
|
||||
if(WasteBits(pWork, 1))
|
||||
return 0x306;
|
||||
|
||||
// If the binary compression type, read 8 bits and return them as one byte.
|
||||
if(pWork->ctype == CMP_BINARY)
|
||||
{
|
||||
value = pWork->bit_buff & 0xFF;
|
||||
if(WasteBits(pWork, 8))
|
||||
return 0x306;
|
||||
return value;
|
||||
}
|
||||
|
||||
// When ASCII compression ...
|
||||
if(pWork->bit_buff & 0xFF)
|
||||
{
|
||||
value = pWork->offs2C34[pWork->bit_buff & 0xFF];
|
||||
|
||||
if(value == 0xFF)
|
||||
{
|
||||
if(pWork->bit_buff & 0x3F)
|
||||
{
|
||||
if(WasteBits(pWork, 4))
|
||||
return 0x306;
|
||||
|
||||
value = pWork->offs2D34[pWork->bit_buff & 0xFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(WasteBits(pWork, 6))
|
||||
return 0x306;
|
||||
|
||||
value = pWork->offs2E34[pWork->bit_buff & 0x7F];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(WasteBits(pWork, 8))
|
||||
return 0x306;
|
||||
|
||||
value = pWork->offs2EB4[pWork->bit_buff & 0xFF];
|
||||
}
|
||||
|
||||
return WasteBits(pWork, pWork->ChBitsAsc[value]) ? 0x306 : value;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Retrieves the number of bytes to move back
|
||||
|
||||
static unsigned long DecodeDist(TDcmpStruct * pWork, unsigned long dwLength)
|
||||
{
|
||||
unsigned long pos = pWork->position1[(pWork->bit_buff & 0xFF)];
|
||||
unsigned long nSkip = pWork->DistBits[pos]; // Number of bits to skip
|
||||
|
||||
// Skip the appropriate number of bits
|
||||
if(WasteBits(pWork, nSkip) == 1)
|
||||
return 0;
|
||||
|
||||
if(dwLength == 2)
|
||||
{
|
||||
pos = (pos << 2) | (pWork->bit_buff & 0x03);
|
||||
|
||||
if(WasteBits(pWork, 2) == 1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = (pos << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask);
|
||||
|
||||
// Skip the bits
|
||||
if(WasteBits(pWork, pWork->dsize_bits) == 1)
|
||||
return 0;
|
||||
}
|
||||
return pos+1;
|
||||
}
|
||||
|
||||
static unsigned long Expand(TDcmpStruct * pWork)
|
||||
{
|
||||
unsigned int copyBytes; // Number of bytes to copy
|
||||
unsigned long oneByte; // One byte from compressed file
|
||||
unsigned long dwResult;
|
||||
|
||||
pWork->outputPos = 0x1000; // Initialize output buffer position
|
||||
|
||||
// If end of data or error, terminate decompress
|
||||
while((dwResult = oneByte = DecodeLit(pWork)) < 0x305)
|
||||
{
|
||||
// If one byte is greater than 0x100, means "Repeat n - 0xFE bytes"
|
||||
if(oneByte >= 0x100)
|
||||
{
|
||||
unsigned char * source; // ECX
|
||||
unsigned char * target; // EDX
|
||||
unsigned long copyLength = oneByte - 0xFE;
|
||||
unsigned long moveBack;
|
||||
|
||||
// Get length of data to copy
|
||||
if((moveBack = DecodeDist(pWork, copyLength)) == 0)
|
||||
{
|
||||
dwResult = 0x306;
|
||||
break;
|
||||
}
|
||||
|
||||
// Target and source pointer
|
||||
target = &pWork->out_buff[pWork->outputPos];
|
||||
source = target - moveBack;
|
||||
pWork->outputPos += copyLength;
|
||||
|
||||
while(copyLength-- > 0)
|
||||
*target++ = *source++;
|
||||
}
|
||||
else
|
||||
pWork->out_buff[pWork->outputPos++] = (unsigned char)oneByte;
|
||||
|
||||
// If number of extracted bytes has reached 1/2 of output buffer,
|
||||
// flush output buffer.
|
||||
if(pWork->outputPos >= 0x2000)
|
||||
{
|
||||
// Copy decompressed data into user buffer
|
||||
copyBytes = 0x1000;
|
||||
pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param);
|
||||
|
||||
// If there are some data left, keep them alive
|
||||
lmemcpy(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000);
|
||||
pWork->outputPos -= 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
copyBytes = pWork->outputPos - 0x1000;
|
||||
pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param);
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Main exploding function.
|
||||
|
||||
unsigned int explode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param)
|
||||
{
|
||||
TDcmpStruct * pWork = (TDcmpStruct *)work_buf;
|
||||
|
||||
// Set the whole work buffer to zeros
|
||||
memset(pWork, 0, sizeof(TDcmpStruct));
|
||||
|
||||
// Initialize work struct and load compressed data
|
||||
pWork->read_buf = read_buf;
|
||||
pWork->write_buf = write_buf;
|
||||
pWork->param = param;
|
||||
pWork->in_pos = sizeof(pWork->in_buff);
|
||||
pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param);
|
||||
if(pWork->in_bytes <= 4)
|
||||
return CMP_BAD_DATA;
|
||||
|
||||
pWork->ctype = pWork->in_buff[0]; // Get the compression type
|
||||
pWork->dsize_bits = pWork->in_buff[1]; // Get the dictionary size
|
||||
pWork->bit_buff = pWork->in_buff[2]; // Initialize 16-bit bit buffer
|
||||
pWork->extra_bits = 0; // Extra (over 8) bits
|
||||
pWork->in_pos = 3; // Position in input buffer
|
||||
|
||||
// Test for the valid dictionary size
|
||||
if(4 > pWork->dsize_bits || pWork->dsize_bits > 6)
|
||||
return CMP_INVALID_DICTSIZE;
|
||||
|
||||
pWork->dsize_mask = 0xFFFF >> (0x10 - pWork->dsize_bits); // Shifted by 'sar' instruction
|
||||
|
||||
if(pWork->ctype != CMP_BINARY)
|
||||
{
|
||||
if(pWork->ctype != CMP_ASCII)
|
||||
return CMP_INVALID_MODE;
|
||||
|
||||
lmemcpy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc));
|
||||
GenAscTabs(pWork);
|
||||
}
|
||||
|
||||
lmemcpy(pWork->LenBits, LenBits, sizeof(pWork->LenBits));
|
||||
GenDecodeTabs(0x10, pWork->LenBits, LenCode, pWork->position2);
|
||||
lmemcpy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits));
|
||||
lmemcpy(pWork->LenBase, LenBase, sizeof(pWork->LenBase));
|
||||
lmemcpy(pWork->DistBits, DistBits, sizeof(pWork->DistBits));
|
||||
GenDecodeTabs(0x40, pWork->DistBits, DistCode, pWork->position1);
|
||||
if(Expand(pWork) != 0x306)
|
||||
return CMP_NO_ERROR;
|
||||
|
||||
return CMP_ABORT;
|
||||
}
|
||||
674
src/tools/stuffextract/StormLib/pklib/implode.c
Normal file
674
src/tools/stuffextract/StormLib/pklib/implode.c
Normal file
@ -0,0 +1,674 @@
|
||||
/*****************************************************************************/
|
||||
/* implode.c Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Implode function of PKWARE Data Compression library */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 11.04.03 1.00 Lad First version of implode.c */
|
||||
/* 02.05.03 1.00 Lad Stress test done */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pklib.h"
|
||||
|
||||
#if ((1200 < _MSC_VER) && (_MSC_VER < 1400))
|
||||
#pragma optimize("", off) // Fucking Microsoft VS.NET 2003 compiler !!!
|
||||
// (_MSC_VER=1310)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define DICT_OFFSET 0x204
|
||||
#define UNCMP_OFFSET (pWork->dsize_bytes + DICT_OFFSET)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tables
|
||||
|
||||
static unsigned char DistBits[] =
|
||||
{
|
||||
0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
|
||||
};
|
||||
|
||||
static unsigned char DistCode[] =
|
||||
{
|
||||
0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
|
||||
0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
|
||||
};
|
||||
|
||||
static unsigned char ExLenBits[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
|
||||
};
|
||||
|
||||
static unsigned char LenBits[] =
|
||||
{
|
||||
0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
|
||||
};
|
||||
|
||||
static unsigned char LenCode[] =
|
||||
{
|
||||
0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
|
||||
};
|
||||
|
||||
static unsigned char ChBitsAsc[] =
|
||||
{
|
||||
0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
|
||||
0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
|
||||
0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
|
||||
0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
|
||||
0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
|
||||
0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
|
||||
0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
|
||||
};
|
||||
|
||||
static unsigned short ChCodeAsc[] =
|
||||
{
|
||||
0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
|
||||
0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
|
||||
0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
|
||||
0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
|
||||
0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
|
||||
0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
|
||||
0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
|
||||
0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
|
||||
0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
|
||||
0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
|
||||
0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
|
||||
0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
|
||||
0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
|
||||
0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
|
||||
0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
|
||||
0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
|
||||
0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
|
||||
0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
|
||||
0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
|
||||
0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
|
||||
0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
|
||||
0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
|
||||
0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
|
||||
0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
|
||||
0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
|
||||
0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
|
||||
0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
|
||||
0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
|
||||
0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
|
||||
0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
|
||||
0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
|
||||
0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local variables
|
||||
|
||||
static char Copyright[] = "PKWARE Data Compression Library for Win32\r\n"
|
||||
"Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
|
||||
"Patent No. 5,051,745\r\n"
|
||||
"PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
|
||||
"Version 1.11\r\n";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local functions
|
||||
|
||||
// Fills memory block with a character
|
||||
static void lmemset(void * buff, int c, size_t count)
|
||||
{
|
||||
memset(buff, c, count);
|
||||
}
|
||||
|
||||
// Copies memory block to another location
|
||||
static void lmemcpy(void * trg, const void * src, size_t count)
|
||||
{
|
||||
memcpy(trg, src, count);
|
||||
}
|
||||
|
||||
static void SortBuffer(TCmpStruct * pWork, unsigned char * uncmp_data, unsigned char * work_end)
|
||||
{
|
||||
unsigned short * pin0DC8;
|
||||
unsigned char * puncmp;
|
||||
unsigned long offs1, offs2;
|
||||
unsigned long ndwords;
|
||||
unsigned int add;
|
||||
|
||||
// Fill 0x480 dwords (0x1200 bytes)
|
||||
ndwords = (unsigned long)((pWork->out_buff - (char *)pWork->offs0DC8 + 1) >> 2);
|
||||
if(ndwords <= 1)
|
||||
ndwords = 1;
|
||||
memset(pWork->offs0DC8, 0, ndwords << 2);
|
||||
|
||||
for(puncmp = uncmp_data; work_end > puncmp; puncmp++)
|
||||
pWork->offs0DC8[(puncmp[0] * 4) + (puncmp[1] * 5)]++;
|
||||
|
||||
add = 0;
|
||||
for(pin0DC8 = pWork->offs0DC8; pin0DC8 < &pWork->offs1FC8; pin0DC8++)
|
||||
{
|
||||
add += *pin0DC8;
|
||||
*pin0DC8 = (unsigned short)add;
|
||||
}
|
||||
|
||||
for(work_end--; work_end >= uncmp_data; work_end--)
|
||||
{
|
||||
offs1 = (work_end[0] * 4) + (work_end[1] * 5); // EAX
|
||||
offs2 = (unsigned long)(work_end - pWork->work_buff); // EDI
|
||||
|
||||
pWork->offs0DC8[offs1]--;
|
||||
pWork->offs49D0[pWork->offs0DC8[offs1]] = (unsigned short)offs2;
|
||||
}
|
||||
}
|
||||
|
||||
static void FlushBuf(TCmpStruct * pWork)
|
||||
{
|
||||
unsigned char save_ch1;
|
||||
unsigned char save_ch2;
|
||||
unsigned int size = 0x800;
|
||||
|
||||
pWork->write_buf(pWork->out_buff, &size, pWork->param);
|
||||
|
||||
save_ch1 = pWork->out_buff[0x800];
|
||||
save_ch2 = pWork->out_buff[pWork->out_bytes];
|
||||
pWork->out_bytes -= 0x800;
|
||||
|
||||
lmemset(pWork->out_buff, 0, 0x802);
|
||||
|
||||
if(pWork->out_bytes != 0)
|
||||
pWork->out_buff[0] = save_ch1;
|
||||
if(pWork->out_bits != 0)
|
||||
pWork->out_buff[pWork->out_bytes] = save_ch2;
|
||||
}
|
||||
|
||||
static void OutputBits(TCmpStruct * pWork, unsigned int nbits, unsigned long bit_buff)
|
||||
{
|
||||
unsigned int out_bits;
|
||||
|
||||
// If more than 8 bits to output, do recursion
|
||||
if(nbits > 8)
|
||||
{
|
||||
OutputBits(pWork, 8, bit_buff);
|
||||
bit_buff >>= 8;
|
||||
nbits -= 8;
|
||||
}
|
||||
|
||||
// Add bits to the last out byte in out_buff;
|
||||
out_bits = pWork->out_bits;
|
||||
pWork->out_buff[pWork->out_bytes] |= (unsigned char)(bit_buff << out_bits);
|
||||
pWork->out_bits += nbits;
|
||||
|
||||
// If 8 or more bits, increment number of bytes
|
||||
if(pWork->out_bits > 8)
|
||||
{
|
||||
pWork->out_bytes++;
|
||||
bit_buff >>= (8 - out_bits);
|
||||
|
||||
pWork->out_buff[pWork->out_bytes] = (unsigned char)bit_buff;
|
||||
pWork->out_bits &= 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
pWork->out_bits &= 7;
|
||||
if(pWork->out_bits == 0)
|
||||
pWork->out_bytes++;
|
||||
}
|
||||
|
||||
// If there is enough compressed bytes, flush them
|
||||
if(pWork->out_bytes >= 0x800)
|
||||
FlushBuf(pWork);
|
||||
}
|
||||
|
||||
static unsigned long FindRep(TCmpStruct * pWork, unsigned char * srcbuff)
|
||||
{
|
||||
unsigned short esp12;
|
||||
unsigned char * esp14;
|
||||
unsigned short esp18;
|
||||
unsigned char * srcbuff2;
|
||||
unsigned char esp20;
|
||||
|
||||
unsigned char * srcbuff3;
|
||||
unsigned short * pin0DC8;
|
||||
unsigned char * pin27CC;
|
||||
unsigned short * pin49D0;
|
||||
unsigned long nreps = 1; // EAX
|
||||
unsigned long ebx, esi;
|
||||
unsigned short di;
|
||||
|
||||
pin0DC8 = pWork->offs0DC8 + (srcbuff[0] * 4) + (srcbuff[1] * 5);
|
||||
esi = (unsigned long)(srcbuff - pWork->dsize_bytes - pWork->work_buff + 1);
|
||||
esp18 = *pin0DC8;
|
||||
pin49D0 = pWork->offs49D0 + esp18;
|
||||
|
||||
if(*pin49D0 < esi)
|
||||
{
|
||||
while(*pin49D0 < esi)
|
||||
{
|
||||
pin49D0++;
|
||||
esp18++;
|
||||
}
|
||||
*pin0DC8 = esp18;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
srcbuff2 = srcbuff - 1;
|
||||
pin49D0 = pWork->offs49D0 + esp18;
|
||||
pin27CC = pWork->work_buff + *pin49D0;
|
||||
if(srcbuff2 <= pin27CC)
|
||||
return 0;
|
||||
//---------------------------------------------------------------------------
|
||||
srcbuff3 = srcbuff;
|
||||
for(;;)
|
||||
{
|
||||
if(srcbuff3[nreps-1] == pin27CC[nreps-1] && *srcbuff3 == *pin27CC)
|
||||
{
|
||||
//
|
||||
// The following code does not work when compiled with MSVC.NET 2003
|
||||
// optimizing compiler. We have to switch the optimizations off to make it work
|
||||
// I found that in debug version (where the optimizations are off), the value
|
||||
// of "pin27CC" gets incremented twice (once at below, once in the "for" loop)
|
||||
//
|
||||
|
||||
pin27CC++;
|
||||
srcbuff3++;
|
||||
|
||||
for(ebx = 2; ebx < DICT_OFFSET; ebx++)
|
||||
{
|
||||
pin27CC++;
|
||||
srcbuff3++;
|
||||
if(*pin27CC != *srcbuff3)
|
||||
break;
|
||||
}
|
||||
|
||||
srcbuff3 = srcbuff;
|
||||
if(ebx >= nreps)
|
||||
{
|
||||
pWork->offs0000 = (unsigned int)(srcbuff3 - pin27CC + ebx - 1);
|
||||
if((nreps = ebx) > 10)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pin49D0++;
|
||||
esp18++;
|
||||
pin27CC = pWork->work_buff + *pin49D0;
|
||||
|
||||
if(srcbuff2 > pin27CC)
|
||||
continue;
|
||||
|
||||
return (nreps >= 2) ? nreps : 0;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
if(ebx == DICT_OFFSET)
|
||||
{
|
||||
pWork->offs0000--;
|
||||
return ebx;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
pin49D0 = pWork->offs49D0 + esp18;
|
||||
if(pWork->work_buff + pin49D0[1] >= srcbuff2)
|
||||
return nreps;
|
||||
//---------------------------------------------------------------------------
|
||||
di = 0;
|
||||
pWork->offs09BC[0] = 0xFFFF;
|
||||
pWork->offs09BC[1] = di;
|
||||
esp12 = 1;
|
||||
|
||||
do
|
||||
{
|
||||
esi = di;
|
||||
if(srcbuff[esp12] != srcbuff[esi])
|
||||
{
|
||||
di = pWork->offs09BC[esi];
|
||||
if(di != 0xFFFF)
|
||||
continue;
|
||||
}
|
||||
pWork->offs09BC[++esp12] = ++di;
|
||||
}
|
||||
while(esp12 < nreps);
|
||||
//---------------------------------------------------------------------------
|
||||
esi = nreps;
|
||||
pin27CC = pWork->work_buff + pin49D0[0] + nreps;
|
||||
esp14 = pin27CC;
|
||||
|
||||
for(;;) // 0040268B
|
||||
{
|
||||
esi = pWork->offs09BC[esi];
|
||||
if(esi == 0xFFFF)
|
||||
esi = 0;
|
||||
|
||||
pin49D0 = pWork->offs49D0 + esp18;
|
||||
do
|
||||
{
|
||||
pin49D0++;
|
||||
esp18++;
|
||||
pin27CC = pWork->work_buff + pin49D0[0];
|
||||
if(pin27CC >= srcbuff2)
|
||||
return nreps;
|
||||
}
|
||||
while(pin27CC + esi < esp14);
|
||||
//---------------------------------------------------------------------------
|
||||
esp20 = srcbuff[nreps - 2];
|
||||
if(esp20 == pin27CC[nreps - 2])
|
||||
{
|
||||
if(pin27CC + esi != esp14)
|
||||
{
|
||||
esp14 = pin27CC;
|
||||
esi = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pin49D0 = pWork->offs49D0 + esp18;
|
||||
do
|
||||
{
|
||||
pin49D0++;
|
||||
esp18++;
|
||||
pin27CC = pWork->work_buff + pin49D0[0];
|
||||
if(pin27CC >= srcbuff2)
|
||||
return nreps;
|
||||
}
|
||||
while(pin27CC[nreps - 2] != esp20 || pin27CC[0] != *srcbuff);
|
||||
|
||||
esp14 = pin27CC + 2;
|
||||
esi = 2;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
for(; esp14[0] == srcbuff[esi]; esp14++)
|
||||
{
|
||||
if(++esi >= DICT_OFFSET)
|
||||
break;
|
||||
}
|
||||
|
||||
if(esi < nreps)
|
||||
continue;
|
||||
pWork->offs0000 = (unsigned int)(srcbuff - pin27CC - 1);
|
||||
if(esi <= nreps)
|
||||
continue;
|
||||
nreps = esi;
|
||||
if(esi == DICT_OFFSET)
|
||||
return nreps;
|
||||
|
||||
do
|
||||
{
|
||||
if(srcbuff[esp12] != srcbuff[di])
|
||||
{
|
||||
di = pWork->offs09BC[di];
|
||||
if(di != 0xFFFF)
|
||||
continue;
|
||||
}
|
||||
pWork->offs09BC[++esp12] = ++di;
|
||||
}
|
||||
while(esp12 < esi);
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteCmpData(TCmpStruct * pWork)
|
||||
{
|
||||
unsigned int nreps = 0; // ESP+10 : Number of repeats
|
||||
unsigned char * uncmp_end; // ESP+14 : End of uncompressed data
|
||||
unsigned int esp18 = 0; // ESP+18 :
|
||||
unsigned int bytes_required; // ESP+1C : Number of bytes required to read
|
||||
unsigned int esp20 = 0; // ESP+20 :
|
||||
unsigned char * uncmp_begin = pWork->work_buff + UNCMP_OFFSET; // EDI
|
||||
unsigned long nreps1;
|
||||
unsigned long save_offs0000 = 0;
|
||||
|
||||
// Store the compression type and dictionary size
|
||||
pWork->out_buff[0] = (char)pWork->ctype;
|
||||
pWork->out_buff[1] = (char)pWork->dsize_bits;
|
||||
pWork->out_bytes = 2;
|
||||
|
||||
// Reset output buffer to zero
|
||||
lmemset(&pWork->out_buff[2], 0, sizeof(pWork->out_buff) - 2);
|
||||
pWork->out_bits = 0;
|
||||
|
||||
do
|
||||
{
|
||||
int total_loaded = 0;
|
||||
|
||||
for(bytes_required = 0x1000; bytes_required != 0; )
|
||||
{
|
||||
int loaded = pWork->read_buf((char *)pWork->work_buff + UNCMP_OFFSET + total_loaded,
|
||||
&bytes_required, pWork->param);
|
||||
|
||||
if(loaded == 0)
|
||||
{
|
||||
if(total_loaded == 0 && esp20 == 0)
|
||||
goto __Exit;
|
||||
esp18 = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_loaded += loaded;
|
||||
bytes_required -= loaded;
|
||||
}
|
||||
}
|
||||
|
||||
uncmp_end = pWork->work_buff + pWork->dsize_bytes + total_loaded;
|
||||
if(esp18 != 0)
|
||||
uncmp_end += DICT_OFFSET;
|
||||
|
||||
//
|
||||
// Warning: Passing "uncmp_end + 1" to the SortBuffer function may cause
|
||||
// the output to be unpredictable in Storm.dll's compression. Because Storm.dll
|
||||
// does not pass the zeroed buffer to the "implode" function, the byte after
|
||||
// uncmp_end contains random data. This causes difference within dictionary
|
||||
// created in SortBuffer function and may also cause different compressed output.
|
||||
// We always zero the data before compression, so this thing never occurs.
|
||||
// Funny is that it is actually not a bug, because if we decompress the data back,
|
||||
// we'll get the identical data with the original input.
|
||||
//
|
||||
switch(esp20)
|
||||
{
|
||||
case 0:
|
||||
SortBuffer(pWork, uncmp_begin, uncmp_end + 1);
|
||||
esp20++;
|
||||
if(pWork->dsize_bytes != 0x1000)
|
||||
esp20++;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
SortBuffer(pWork, uncmp_begin - pWork->dsize_bytes + DICT_OFFSET, uncmp_end + 1);
|
||||
esp20++;
|
||||
break;
|
||||
|
||||
default:
|
||||
SortBuffer(pWork, uncmp_begin - pWork->dsize_bytes, uncmp_end + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
while(uncmp_end > uncmp_begin)
|
||||
{
|
||||
nreps1 = FindRep(pWork, uncmp_begin);
|
||||
while(nreps1 != 0)
|
||||
{
|
||||
if(nreps1 == 2 && pWork->offs0000 >= 0x100)
|
||||
break;
|
||||
|
||||
if(esp18 != 0 && uncmp_begin + nreps1 > uncmp_end)
|
||||
goto _004022DB;
|
||||
|
||||
if(nreps1 >= 8 || uncmp_begin + 1 >= uncmp_end)
|
||||
goto _004022FF;
|
||||
|
||||
save_offs0000 = pWork->offs0000; // ebp
|
||||
nreps = nreps1;
|
||||
nreps1 = FindRep(pWork, uncmp_begin + 1);
|
||||
|
||||
if(nreps >= nreps1)
|
||||
goto _004022F9;
|
||||
|
||||
if(nreps + 1 >= nreps1 && save_offs0000 <= 0x80)
|
||||
goto _004022F9;
|
||||
|
||||
OutputBits(pWork, pWork->nChBits[*uncmp_begin], pWork->nChCodes[*uncmp_begin]);
|
||||
uncmp_begin++;
|
||||
}
|
||||
|
||||
_0040222F:
|
||||
OutputBits(pWork, pWork->nChBits[*uncmp_begin], pWork->nChCodes[*uncmp_begin]);
|
||||
uncmp_begin++;
|
||||
_00402252:;
|
||||
}
|
||||
|
||||
if(esp18 == 0)
|
||||
{
|
||||
uncmp_begin -= 0x1000;
|
||||
lmemcpy(pWork->work_buff, pWork->work_buff + 0x1000, pWork->dsize_bytes + DICT_OFFSET);
|
||||
}
|
||||
}
|
||||
while(esp18 == 0);
|
||||
|
||||
__Exit:
|
||||
OutputBits(pWork, pWork->nChBits[0x305], pWork->nChCodes[0x305]);
|
||||
if(pWork->out_bits != 0)
|
||||
pWork->out_bytes++;
|
||||
pWork->write_buf(pWork->out_buff, &pWork->out_bytes, pWork->param);
|
||||
return;
|
||||
|
||||
_004022DB:
|
||||
nreps1 = (unsigned long)(uncmp_end - uncmp_begin);
|
||||
if(nreps1 < 2)
|
||||
goto _0040222F;
|
||||
|
||||
if(nreps1 != 2 || pWork->offs0000 < 0x100)
|
||||
goto _004022FF;
|
||||
goto _0040222F;
|
||||
|
||||
_004022F9:
|
||||
nreps1 = nreps;
|
||||
pWork->offs0000 = save_offs0000;
|
||||
|
||||
_004022FF:
|
||||
OutputBits(pWork, pWork->nChBits[nreps1 + 0xFE], pWork->nChCodes[nreps1 + 0xFE]);
|
||||
|
||||
if(nreps1 == 2)
|
||||
{
|
||||
OutputBits(pWork, pWork->dist_bits[pWork->offs0000 >> 2],
|
||||
pWork->dist_codes[pWork->offs0000 >> 2]);
|
||||
OutputBits(pWork, 2, pWork->offs0000 & 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputBits(pWork, pWork->dist_bits[pWork->offs0000 >> pWork->dsize_bits],
|
||||
pWork->dist_codes[pWork->offs0000 >> pWork->dsize_bits]);
|
||||
OutputBits(pWork, pWork->dsize_bits, pWork->dsize_mask & pWork->offs0000);
|
||||
}
|
||||
uncmp_begin += nreps1;
|
||||
goto _00402252;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Main imploding function
|
||||
|
||||
unsigned int PKEXPORT implode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param,
|
||||
unsigned int *type,
|
||||
unsigned int *dsize)
|
||||
{
|
||||
TCmpStruct * pWork = (TCmpStruct *)work_buf;
|
||||
unsigned int nChCode;
|
||||
unsigned int nCount;
|
||||
unsigned int i;
|
||||
|
||||
// Initialize the work buffer. This is not in the Pklib,
|
||||
// but it seems to be a bug. Storm always pre-fills the data with zeros,
|
||||
// and always compresses one block only. So the bug will not appear.
|
||||
// But when a larger data block (size > 0x1000) is compressed,
|
||||
// it may fail.
|
||||
memset(pWork, 0, sizeof(TCmpStruct));
|
||||
|
||||
// Fill the work buffer information
|
||||
pWork->read_buf = read_buf;
|
||||
pWork->write_buf = write_buf;
|
||||
pWork->dsize_bytes = *dsize;
|
||||
pWork->ctype = *type;
|
||||
pWork->param = param;
|
||||
pWork->dsize_bits = 4;
|
||||
pWork->dsize_mask = 0x0F;
|
||||
|
||||
// Test dictionary size
|
||||
switch(*dsize)
|
||||
{
|
||||
case 0x1000 :
|
||||
pWork->dsize_bits++;
|
||||
pWork->dsize_mask |= 0x20;
|
||||
// No break here !!!
|
||||
|
||||
case 0x0800 :
|
||||
pWork->dsize_bits++;
|
||||
pWork->dsize_mask |= 0x10;
|
||||
// No break here !!!
|
||||
|
||||
case 0x0400 :
|
||||
break;
|
||||
|
||||
default:
|
||||
return CMP_INVALID_DICTSIZE;
|
||||
}
|
||||
|
||||
// Test the compression type
|
||||
switch(*type)
|
||||
{
|
||||
case CMP_BINARY: // We will compress data with binary compression type
|
||||
for(nChCode = 0, nCount = 0; nCount < 0x100; nCount++)
|
||||
{
|
||||
pWork->nChBits[nCount] = 9;
|
||||
pWork->nChCodes[nCount] = (unsigned short)nChCode;
|
||||
nChCode = (nChCode & 0x0000FFFF) + 2;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case CMP_ASCII: // We will compress data with ASCII compression type
|
||||
for(nCount = 0; nCount < 0x100; nCount++)
|
||||
{
|
||||
pWork->nChBits[nCount] = (unsigned char )(ChBitsAsc[nCount] + 1);
|
||||
pWork->nChCodes[nCount] = (unsigned short)(ChCodeAsc[nCount] * 2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return CMP_INVALID_MODE;
|
||||
}
|
||||
|
||||
for(i = 0; i < 0x10; i++)
|
||||
{
|
||||
int nCount2 = 0; // EBX
|
||||
|
||||
if((1 << ExLenBits[i]) == 0)
|
||||
continue;
|
||||
|
||||
do
|
||||
{
|
||||
pWork->nChBits[nCount] = (unsigned char)(ExLenBits[i] + LenBits[i] + 1);
|
||||
pWork->nChCodes[nCount] = (unsigned short)((nCount2 << (LenBits[i] + 1)) | ((LenCode[i] & 0xFFFF00FF) * 2) | 1);
|
||||
|
||||
nCount2++;
|
||||
nCount++;
|
||||
}
|
||||
while((1 << ExLenBits[i]) > nCount2);
|
||||
}
|
||||
|
||||
// Copy the distance codes and distance bits and perform the compression
|
||||
lmemcpy(&pWork->dist_codes, DistCode, sizeof(DistCode));
|
||||
lmemcpy(&pWork->dist_bits, DistBits, sizeof(DistBits));
|
||||
WriteCmpData(pWork);
|
||||
return CMP_NO_ERROR;
|
||||
}
|
||||
137
src/tools/stuffextract/StormLib/pklib/pklib.h
Normal file
137
src/tools/stuffextract/StormLib/pklib/pklib.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*****************************************************************************/
|
||||
/* pklib.h Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Header file for PKWARE Data Compression Library */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 31.03.03 1.00 Lad The first version of pkware.h */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __PKLIB_H__
|
||||
#define __PKLIB_H__
|
||||
|
||||
#include "../StormPort.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define CMP_BINARY 0 // Binary compression
|
||||
#define CMP_ASCII 1 // Ascii compression
|
||||
|
||||
#define CMP_NO_ERROR 0
|
||||
#define CMP_INVALID_DICTSIZE 1
|
||||
#define CMP_INVALID_MODE 2
|
||||
#define CMP_BAD_DATA 3
|
||||
#define CMP_ABORT 4
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Define calling convention
|
||||
|
||||
#ifndef PKEXPORT
|
||||
#define PKEXPORT //__cdecl // Use for normal __cdecl calling
|
||||
#endif
|
||||
//#define PKEXPORT __stdcall
|
||||
//#define PKEXPORT __fastcall
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Internal structures
|
||||
|
||||
// Compression structure
|
||||
typedef struct
|
||||
{
|
||||
unsigned int offs0000; // 0000 :
|
||||
unsigned int out_bytes; // 0004 : # bytes available in out_buff
|
||||
unsigned int out_bits; // 0008 : # of bits available in the last out byte
|
||||
unsigned int dsize_bits; // 000C : Dict size : 4=0x400, 5=0x800, 6=0x1000
|
||||
unsigned int dsize_mask; // 0010 : Dict size : 0x0F=0x400, 0x1F=0x800, 0x3F=0x1000
|
||||
unsigned int ctype; // 0014 : Compression type (Ascii or binary)
|
||||
unsigned int dsize_bytes; // 0018 : Dictionary size in bytes
|
||||
unsigned char dist_bits[0x40]; // 001C : Distance bits
|
||||
unsigned char dist_codes[0x40]; // 005C : Distance codes
|
||||
unsigned char nChBits[0x306]; // 009C :
|
||||
unsigned short nChCodes[0x306]; // 03A2 :
|
||||
unsigned short offs09AE; // 09AE :
|
||||
|
||||
void * param; // 09B0 : User parameter
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // 9B4
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param); // 9B8
|
||||
|
||||
unsigned short offs09BC[0x204]; // 09BC :
|
||||
unsigned long offs0DC4; // 0DC4 :
|
||||
unsigned short offs0DC8[0x900]; // 0DC8 :
|
||||
unsigned short offs1FC8; // 1FC8 :
|
||||
char out_buff[0x802]; // 1FCA : Output (compressed) data
|
||||
unsigned char work_buff[0x2204]; // 27CC : Work buffer
|
||||
// + DICT_OFFSET => Dictionary
|
||||
// + UNCMP_OFFSET => Uncompressed data
|
||||
unsigned short offs49D0[0x2000]; // 49D0 :
|
||||
} TCmpStruct;
|
||||
|
||||
#define CMP_BUFFER_SIZE sizeof(TCmpStruct) // Size of compression buffer
|
||||
|
||||
|
||||
// Decompression structure
|
||||
typedef struct
|
||||
{
|
||||
unsigned long offs0000; // 0000
|
||||
unsigned long ctype; // 0004 - Compression type (CMP_BINARY or CMP_ASCII)
|
||||
unsigned long outputPos; // 0008 - Position in output buffer
|
||||
unsigned long dsize_bits; // 000C - Dict size (4, 5, 6 for 0x400, 0x800, 0x1000)
|
||||
unsigned long dsize_mask; // 0010 - Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000)
|
||||
unsigned long bit_buff; // 0014 - 16-bit buffer for processing input data
|
||||
unsigned long extra_bits; // 0018 - Number of extra (above 8) bits in bit buffer
|
||||
unsigned int in_pos; // 001C - Position in in_buff
|
||||
unsigned long in_bytes; // 0020 - Number of bytes in input buffer
|
||||
void * param; // 0024 - Custom parameter
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // 0028
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param);// 002C
|
||||
unsigned char out_buff[0x2000]; // 0030 - Output circle buffer. Starting position is 0x1000
|
||||
unsigned char offs2030[0x204]; // 2030 - ???
|
||||
unsigned char in_buff[0x800]; // 2234 - Buffer for data to be decompressed
|
||||
unsigned char position1[0x100]; // 2A34 - Positions in buffers
|
||||
unsigned char position2[0x100]; // 2B34 - Positions in buffers
|
||||
unsigned char offs2C34[0x100]; // 2C34 - Buffer for
|
||||
unsigned char offs2D34[0x100]; // 2D34 - Buffer for
|
||||
unsigned char offs2E34[0x80]; // 2EB4 - Buffer for
|
||||
unsigned char offs2EB4[0x100]; // 2EB4 - Buffer for
|
||||
unsigned char ChBitsAsc[0x100]; // 2FB4 - Buffer for
|
||||
unsigned char DistBits[0x40]; // 30B4 - Numbers of bytes to skip copied block length
|
||||
unsigned char LenBits[0x10]; // 30F4 - Numbers of bits for skip copied block length
|
||||
unsigned char ExLenBits[0x10]; // 3104 - Number of valid bits for copied block
|
||||
unsigned short LenBase[0x10]; // 3114 - Buffer for
|
||||
} TDcmpStruct;
|
||||
|
||||
#define EXP_BUFFER_SIZE sizeof(TDcmpStruct) // Size of decompress buffer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public functions
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned int PKEXPORT implode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param,
|
||||
unsigned int *type,
|
||||
unsigned int *dsize);
|
||||
|
||||
|
||||
unsigned int PKEXPORT explode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param);
|
||||
|
||||
// The original name "crc32" was changed to "crc32pk" due
|
||||
// to compatibility with zlib
|
||||
unsigned long PKEXPORT crc32pk(char *buffer, unsigned int *size, unsigned long *old_crc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // End of 'extern "C"' declaration
|
||||
#endif
|
||||
|
||||
#endif // __PKLIB_H__
|
||||
356
src/tools/stuffextract/StormLib/wave/wave.cpp
Normal file
356
src/tools/stuffextract/StormLib/wave/wave.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
/*****************************************************************************/
|
||||
/* wave.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* This module contains decompression methods used by Storm.dll to decompress*/
|
||||
/* WAVe files. Thanks to Tom Amigo for releasing his sources. */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */
|
||||
/* 20.05.03 2.00 Lad Added compression */
|
||||
/* 19.11.03 2.01 Dan Big endian handling */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "wave.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Structures
|
||||
|
||||
union TByteAndWordPtr
|
||||
{
|
||||
short * pw;
|
||||
unsigned char * pb;
|
||||
};
|
||||
|
||||
union TWordAndByteArray
|
||||
{
|
||||
short w;
|
||||
unsigned char b[2];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tables necessary dor decompression
|
||||
|
||||
static long Table1503F120[] =
|
||||
{
|
||||
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006,
|
||||
0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
|
||||
0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
|
||||
0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008
|
||||
};
|
||||
|
||||
static long Table1503F1A0[] =
|
||||
{
|
||||
0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
|
||||
0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F,
|
||||
0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042,
|
||||
0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F,
|
||||
0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133,
|
||||
0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292,
|
||||
0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583,
|
||||
0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0,
|
||||
0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954,
|
||||
0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B,
|
||||
0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462,
|
||||
0x00007FFF
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// CompressWave
|
||||
|
||||
// 1500EF70
|
||||
int CompressWave(unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nChannels, int nCmpLevel)
|
||||
// ECX EDX
|
||||
{
|
||||
TWordAndByteArray Wcmp;
|
||||
TByteAndWordPtr out; // Pointer to the output buffer
|
||||
long SInt32Array1[2];
|
||||
long SInt32Array2[2];
|
||||
long SInt32Array3[2];
|
||||
long nBytesRemains = dwOutLength; // Number of bytes remaining
|
||||
long nWordsRemains; // Number of words remaining
|
||||
// unsigned char * pbSaveOutBuffer; // Copy of output buffer (actually not used)
|
||||
unsigned long dwBitBuff;
|
||||
unsigned long dwStopBit;
|
||||
unsigned long dwBit;
|
||||
unsigned long ebx;
|
||||
unsigned long esi;
|
||||
long nTableValue;
|
||||
long nOneWord;
|
||||
long var_1C;
|
||||
long var_2C;
|
||||
int nLength;
|
||||
int nIndex;
|
||||
int nValue;
|
||||
|
||||
// If less than 2 bytes remain, don't decompress anything
|
||||
// pbSaveOutBuffer = pbOutBuffer;
|
||||
out.pb = pbOutBuffer;
|
||||
if(nBytesRemains < 2)
|
||||
return 2;
|
||||
|
||||
Wcmp.b[1] = (unsigned char)(nCmpLevel - 1);
|
||||
Wcmp.b[0] = (unsigned char)0;
|
||||
|
||||
*out.pw++ = BSWAP_INT16_SIGNED(Wcmp.w);
|
||||
if((out.pb - pbOutBuffer + (nChannels * 2)) > nBytesRemains)
|
||||
return (int)(out.pb - pbOutBuffer + (nChannels * 2));
|
||||
|
||||
SInt32Array1[0] = SInt32Array1[1] = 0x2C;
|
||||
|
||||
for(int i = 0; i < nChannels; i++)
|
||||
{
|
||||
nOneWord = BSWAP_INT16_SIGNED(*pwInBuffer++);
|
||||
*out.pw++ = BSWAP_INT16_SIGNED((short)nOneWord);
|
||||
SInt32Array2[i] = nOneWord;
|
||||
}
|
||||
|
||||
// Weird. But it's there
|
||||
nLength = dwInLength;
|
||||
if(nLength < 0) // mov eax, dwInLength; cdq; sub eax, edx;
|
||||
nLength++;
|
||||
|
||||
nLength = (nLength / 2) - (int)(out.pb - pbOutBuffer);
|
||||
nLength = (nLength < 0) ? 0 : nLength;
|
||||
|
||||
nIndex = nChannels - 1; // edi
|
||||
nWordsRemains = dwInLength / 2; // eax
|
||||
|
||||
// ebx - nChannels
|
||||
// ecx - pwOutPos
|
||||
for(int chnl = nChannels; chnl < nWordsRemains; chnl++)
|
||||
{
|
||||
// 1500F030
|
||||
if((out.pb - pbOutBuffer + 2) > nBytesRemains)
|
||||
return (int)(out.pb - pbOutBuffer + 2);
|
||||
|
||||
// Switch index
|
||||
if(nChannels == 2)
|
||||
nIndex = (nIndex == 0) ? 1 : 0;
|
||||
|
||||
// Load one word from the input stream
|
||||
nOneWord = BSWAP_INT16_SIGNED(*pwInBuffer++); // ecx - nOneWord
|
||||
SInt32Array3[nIndex] = nOneWord;
|
||||
|
||||
// esi - SInt32Array2[nIndex]
|
||||
// eax - nValue
|
||||
nValue = nOneWord - SInt32Array2[nIndex];
|
||||
nValue = (nValue < 0) ? ((nValue ^ 0xFFFFFFFF) + 1) : nValue;
|
||||
|
||||
ebx = (nOneWord >= SInt32Array2[nIndex]) ? 0 : 0x40;
|
||||
|
||||
// esi - SInt32Array2[nIndex]
|
||||
// edx - Table1503F1A0[SInt32Array2[nIndex]]
|
||||
// edi - (Table1503F1A0[SInt32Array1[nIndex]] >> nCmpLevel)
|
||||
nTableValue = Table1503F1A0[SInt32Array1[nIndex]];
|
||||
dwStopBit = (unsigned long)nCmpLevel;
|
||||
|
||||
// edi - nIndex;
|
||||
if(nValue < (nTableValue >> nCmpLevel))
|
||||
{
|
||||
if(SInt32Array1[nIndex] != 0)
|
||||
SInt32Array1[nIndex]--;
|
||||
*out.pb++ = 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(nValue > nTableValue * 2)
|
||||
{
|
||||
if(SInt32Array1[nIndex] >= 0x58 || nLength == 0)
|
||||
break;
|
||||
|
||||
SInt32Array1[nIndex] += 8;
|
||||
if(SInt32Array1[nIndex] > 0x58)
|
||||
SInt32Array1[nIndex] = 0x58;
|
||||
|
||||
nTableValue = Table1503F1A0[SInt32Array1[nIndex]];
|
||||
*out.pb++ = 0x81;
|
||||
nLength--;
|
||||
}
|
||||
|
||||
var_2C = nTableValue >> Wcmp.b[1];
|
||||
dwBitBuff = 0;
|
||||
|
||||
esi = (1 << (dwStopBit - 2));
|
||||
dwStopBit = (esi <= 0x20) ? esi : 0x20;
|
||||
|
||||
for(var_1C = 0, dwBit = 1; ; dwBit <<= 1)
|
||||
{
|
||||
// esi = var_1C + nTableValue;
|
||||
if((var_1C + nTableValue) <= nValue)
|
||||
{
|
||||
var_1C += nTableValue;
|
||||
dwBitBuff |= dwBit;
|
||||
}
|
||||
if(dwBit == dwStopBit)
|
||||
break;
|
||||
|
||||
nTableValue >>= 1;
|
||||
}
|
||||
|
||||
nValue = SInt32Array2[nIndex];
|
||||
if(ebx != 0)
|
||||
{
|
||||
nValue -= (var_1C + var_2C);
|
||||
if(nValue < -32768)
|
||||
nValue = -32768;
|
||||
}
|
||||
else
|
||||
{
|
||||
nValue += (var_1C + var_2C);
|
||||
if(nValue > 32767)
|
||||
nValue = 32767;
|
||||
}
|
||||
|
||||
SInt32Array2[nIndex] = nValue;
|
||||
*out.pb++ = (unsigned char)(dwBitBuff | ebx);
|
||||
nTableValue = Table1503F120[dwBitBuff & 0x1F];
|
||||
SInt32Array1[nIndex] = SInt32Array1[nIndex] + nTableValue;
|
||||
if(SInt32Array1[nIndex] < 0)
|
||||
SInt32Array1[nIndex] = 0;
|
||||
else if(SInt32Array1[nIndex] > 0x58)
|
||||
SInt32Array1[nIndex] = 0x58;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)(out.pb - pbOutBuffer);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// DecompressWave
|
||||
|
||||
// 1500F230
|
||||
int DecompressWave(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels)
|
||||
{
|
||||
TByteAndWordPtr out; // Output buffer
|
||||
TByteAndWordPtr in;
|
||||
unsigned char * pbInBufferEnd = (pbInBuffer + dwInLength);
|
||||
long SInt32Array1[2];
|
||||
long SInt32Array2[2];
|
||||
long nOneWord;
|
||||
int dwOutLengthCopy = dwOutLength;
|
||||
int nIndex;
|
||||
|
||||
SInt32Array1[0] = SInt32Array1[1] = 0x2C;
|
||||
out.pb = pbOutBuffer;
|
||||
in.pb = pbInBuffer;
|
||||
in.pw++;
|
||||
|
||||
// Fill the Uint32Array2 array by channel values.
|
||||
for(int i = 0; i < nChannels; i++)
|
||||
{
|
||||
nOneWord = BSWAP_INT16_SIGNED(*in.pw++);
|
||||
SInt32Array2[i] = nOneWord;
|
||||
if(dwOutLengthCopy < 2)
|
||||
return (int)(out.pb - pbOutBuffer);
|
||||
|
||||
*out.pw++ = BSWAP_INT16_SIGNED((short)nOneWord);
|
||||
dwOutLengthCopy -= sizeof(short);
|
||||
}
|
||||
|
||||
// Get the initial index
|
||||
nIndex = nChannels - 1;
|
||||
|
||||
// Perform the decompression
|
||||
while(in.pb < pbInBufferEnd)
|
||||
{
|
||||
unsigned char nOneByte = *in.pb++;
|
||||
|
||||
// Switch index
|
||||
if(nChannels == 2)
|
||||
nIndex = (nIndex == 0) ? 1 : 0;
|
||||
|
||||
// 1500F2A2: Get one byte from input buffer
|
||||
if(nOneByte & 0x80)
|
||||
{
|
||||
switch(nOneByte & 0x7F)
|
||||
{
|
||||
case 0: // 1500F315
|
||||
if(SInt32Array1[nIndex] != 0)
|
||||
SInt32Array1[nIndex]--;
|
||||
|
||||
if(dwOutLengthCopy < 2)
|
||||
return (int)(out.pb - pbOutBuffer);
|
||||
|
||||
*out.pw++ = BSWAP_INT16_SIGNED((unsigned short)SInt32Array2[nIndex]);
|
||||
dwOutLength -= sizeof(unsigned short);
|
||||
break;
|
||||
|
||||
case 1: // 1500F2E8
|
||||
SInt32Array1[nIndex] += 8;
|
||||
if(SInt32Array1[nIndex] > 0x58)
|
||||
SInt32Array1[nIndex] = 0x58;
|
||||
|
||||
if(nChannels == 2)
|
||||
nIndex = (nIndex == 0) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case 2: // 1500F41E
|
||||
break;
|
||||
|
||||
default: // 1500F2C4
|
||||
SInt32Array1[nIndex] -= 8;
|
||||
if(SInt32Array1[nIndex] < 0)
|
||||
SInt32Array1[nIndex] = 0;
|
||||
|
||||
if(nChannels == 2)
|
||||
nIndex = (nIndex == 0) ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1500F349
|
||||
long temp1 = Table1503F1A0[SInt32Array1[nIndex]]; // EDI
|
||||
long temp2 = temp1 >> pbInBuffer[1]; // ESI
|
||||
long temp3 = SInt32Array2[nIndex]; // ECX
|
||||
|
||||
if(nOneByte & 0x01) // EBX = nOneByte
|
||||
temp2 += (temp1 >> 0);
|
||||
|
||||
if(nOneByte & 0x02)
|
||||
temp2 += (temp1 >> 1);
|
||||
|
||||
if(nOneByte & 0x04)
|
||||
temp2 += (temp1 >> 2);
|
||||
|
||||
if(nOneByte & 0x08)
|
||||
temp2 += (temp1 >> 3);
|
||||
|
||||
if(nOneByte & 0x10)
|
||||
temp2 += (temp1 >> 4);
|
||||
|
||||
if(nOneByte & 0x20)
|
||||
temp2 += (temp1 >> 5);
|
||||
|
||||
if(nOneByte & 0x40)
|
||||
{
|
||||
temp3 = temp3 - temp2;
|
||||
if(temp3 <= -32768)
|
||||
temp3 = -32768;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp3 = temp3 + temp2;
|
||||
if(temp3 >= 32767)
|
||||
temp3 = 32767;
|
||||
}
|
||||
|
||||
SInt32Array2[nIndex] = temp3;
|
||||
if(dwOutLength < 2)
|
||||
break;
|
||||
|
||||
// Store the output 16-bit value
|
||||
*out.pw++ = BSWAP_INT16_SIGNED((short)SInt32Array2[nIndex]);
|
||||
dwOutLength -= 2;
|
||||
|
||||
SInt32Array1[nIndex] += Table1503F120[nOneByte & 0x1F];
|
||||
|
||||
if(SInt32Array1[nIndex] < 0)
|
||||
SInt32Array1[nIndex] = 0;
|
||||
else if(SInt32Array1[nIndex] > 0x58)
|
||||
SInt32Array1[nIndex] = 0x58;
|
||||
}
|
||||
}
|
||||
return (int)(out.pb - pbOutBuffer);
|
||||
}
|
||||
22
src/tools/stuffextract/StormLib/wave/wave.h
Normal file
22
src/tools/stuffextract/StormLib/wave/wave.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*****************************************************************************/
|
||||
/* Wave.h Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Header file for WAVe unplode functions */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 31.03.03 1.00 Lad The first version of Wave.h */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __WAVE_H__
|
||||
#define __WAVE_H__
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions
|
||||
|
||||
#include "../StormPort.h"
|
||||
|
||||
int CompressWave (unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nCmpType, int nChannels);
|
||||
int DecompressWave(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels);
|
||||
|
||||
#endif // __WAVE_H__
|
||||
163
src/tools/stuffextract/StuffExtract.cpp
Normal file
163
src/tools/stuffextract/StuffExtract.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
#include <fstream>
|
||||
#define _COMMON_NO_THREADS
|
||||
#include "common.h"
|
||||
#include "MPQHelper.h"
|
||||
#include "dbcfile.h"
|
||||
#include "StuffExtract.h"
|
||||
#include "DBCFieldData.h"
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("StuffExtract [version %u]\n",SE_VERSION);
|
||||
ConvertDBC();
|
||||
|
||||
|
||||
printf("\n -- finished --\n");
|
||||
char crap[200];
|
||||
fgets(crap,sizeof(crap),stdin);
|
||||
|
||||
//while(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// be careful using this, that you supply correct format string
|
||||
std::string AutoGetDataString(DBCFile::Iterator& it, const char* format, uint32 field)
|
||||
{
|
||||
if(format[field]=='i' || format[field]=='f')
|
||||
return toString( (*it).getInt(field) );
|
||||
if(format[field]=='s')
|
||||
return (*it).getString(field);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
// output a formatted scp file
|
||||
void OutSCP(char *fn, SCPStorageMap& scp)
|
||||
{
|
||||
std::fstream f;
|
||||
f.open(fn, std::ios_base::out);
|
||||
if(f.is_open())
|
||||
{
|
||||
for(SCPStorageMap::iterator mi = scp.begin(); mi != scp.end(); mi++)
|
||||
{
|
||||
f << "[" << mi->first << "]\n";
|
||||
for(std::list<std::string>::iterator li = mi->second.begin(); li != mi->second.end(); li++)
|
||||
{
|
||||
f << *li << "\n";
|
||||
}
|
||||
f << "\n";
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("OutSCP: unable to write '%s'\n",fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ConvertDBC(void)
|
||||
{
|
||||
std::map<uint8,std::string> racemap; // needed to extract other dbc files correctly
|
||||
SCPStorageMap EmoteDataStorage,RaceDataStorage,SoundDataStorage; // will store the converted data from dbc files
|
||||
DBCFile EmotesText,EmotesTextData,EmotesTextSound,ChrRaces,SoundEntries;
|
||||
printf("Opening DBC archive...\n");
|
||||
MPQHelper mpq;
|
||||
if(!mpq.AssignArchive("Data/dbc.MPQ"))
|
||||
{
|
||||
printf("ConvertDBC: Could not open 'Data/dbc.MPQ'\n");
|
||||
return false;
|
||||
}
|
||||
printf("Opening DBC files...\n");
|
||||
EmotesText.openmem(mpq.ExtractFile("DBFilesClient\\EmotesText.dbc"));
|
||||
EmotesTextData.openmem(mpq.ExtractFile("DBFilesClient\\EmotesTextData.dbc"));
|
||||
EmotesTextSound.openmem(mpq.ExtractFile("DBFilesClient\\EmotesTextSound.dbc"));
|
||||
ChrRaces.openmem(mpq.ExtractFile("DBFilesClient\\ChrRaces.dbc"));
|
||||
SoundEntries.openmem(mpq.ExtractFile("DBFilesClient\\SoundEntries.dbc"));
|
||||
//...
|
||||
printf("DBC files opened.\n");
|
||||
//...
|
||||
printf("Reading data: races..");
|
||||
for(DBCFile::Iterator it = ChrRaces.begin(); it != ChrRaces.end(); ++it)
|
||||
{
|
||||
uint32 id = (*it).getUInt(CHRRACES_RACEID);
|
||||
racemap[id] = (*it).getString(CHRRACES_NAME_GENERAL); // for later use
|
||||
for(uint32 field=CHRRACES_RACEID; field < CHARRACES_END; field++)
|
||||
{
|
||||
if(strlen(ChrRacesFieldNames[field]))
|
||||
{
|
||||
std::string value = AutoGetDataString(it,ChrRacesFormat,field);
|
||||
RaceDataStorage[id].push_back(std::string(ChrRacesFieldNames[field]).append("=").append(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("emotes..");
|
||||
for(DBCFile::Iterator it = EmotesText.begin(); it != EmotesText.end(); ++it)
|
||||
{
|
||||
uint32 em = (*it).getUInt(EMOTESTEXT_EMOTE_ID);
|
||||
EmoteDataStorage[em].push_back(std::string("name=") + (*it).getString(EMOTESTEXT_EMOTE_STRING));
|
||||
EmoteDataStorage[em].push_back(std::string("anim=") + toString( (*it).getUInt(EMOTESTEXT_ANIM)) );
|
||||
for(uint32 field=EMOTESTEXT_EMOTE_ID; field<EMOTESTEXT_END;field++)
|
||||
{
|
||||
if((*it).getInt(field) && strlen(EmotesTextFieldNames[field]))
|
||||
{
|
||||
uint32 textid;
|
||||
std::string fname;
|
||||
for(DBCFile::Iterator ix = EmotesTextData.begin(); ix != EmotesTextData.end(); ++ix)
|
||||
{
|
||||
textid = (*ix).getUInt(EMOTESTEXTDATA_TEXTID);
|
||||
if(textid == (*it).getInt(field))
|
||||
{
|
||||
fname = EmotesTextFieldNames[field];
|
||||
EmoteDataStorage[em].push_back( fname + "=" + (*ix).getString(EMOTESTEXTDATA_STRING) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
for(DBCFile::Iterator is = EmotesTextSound.begin(); is != EmotesTextSound.end(); ++is)
|
||||
{
|
||||
if(em == (*is).getUInt(EMOTESTEXTSOUND_EMOTEID))
|
||||
{
|
||||
std::string record = "Sound";
|
||||
record += racemap[ (*is).getUInt(EMOTESTEXTSOUND_RACE) ];
|
||||
record += ((*is).getUInt(EMOTESTEXTSOUND_ISFEMALE) ? "Female" : "Male");
|
||||
record += "=";
|
||||
record += toString( (*is).getUInt(EMOTESTEXTSOUND_SOUNDID) );
|
||||
EmoteDataStorage[em].push_back(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("sound entries..");
|
||||
for(DBCFile::Iterator it = SoundEntries.begin(); it != SoundEntries.end(); ++it)
|
||||
{
|
||||
uint32 id = (*it).getUInt(SOUNDENTRY_SOUNDID);
|
||||
for(uint32 field=SOUNDENTRY_SOUNDID; field < SOUNDENTRY_END; field++)
|
||||
{
|
||||
if(strlen(SoundEntriesFieldNames[field]))
|
||||
{
|
||||
std::string value = AutoGetDataString(it,SoundEntriesFormat,field);
|
||||
if(value.size()) // only store if a file exists in that field
|
||||
SoundDataStorage[id].push_back(std::string(SoundEntriesFieldNames[field]) + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//...
|
||||
printf("DONE!\n");
|
||||
//...
|
||||
printf("Writing SCP files:\n");
|
||||
printf("emote.."); OutSCP(SCPDIR "/emote.scp",EmoteDataStorage);
|
||||
printf("race.."); OutSCP(SCPDIR "/race.scp",RaceDataStorage);
|
||||
printf("sound.."); OutSCP(SCPDIR "/sound.scp",SoundDataStorage);
|
||||
//...
|
||||
printf("DONE!\n");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
19
src/tools/stuffextract/StuffExtract.h
Normal file
19
src/tools/stuffextract/StuffExtract.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef STUFFEXTRACT_H
|
||||
#define STUFFEXTRACT_H
|
||||
|
||||
#define _COMMON_SKIP_THREADS
|
||||
#include "common.h"
|
||||
|
||||
#define SE_VERSION 1
|
||||
#define MAPS_VERSION ((uint32)0)
|
||||
#define OUTDIR "stuffextract"
|
||||
#define SCPDIR OUTDIR "/scp"
|
||||
|
||||
typedef std::map< uint32,std::list<std::string> > SCPStorageMap;
|
||||
|
||||
int main(int argc, char *argv[]);
|
||||
void OutSCP(char*, SCPStorageMap&);
|
||||
bool ConvertDBC(void);
|
||||
|
||||
|
||||
#endif
|
||||
103
src/tools/stuffextract/dbcfile.cpp
Normal file
103
src/tools/stuffextract/dbcfile.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#define _COMMON_NO_THREADS
|
||||
#include "common.h"
|
||||
#include <fstream>
|
||||
#include "dbcfile.h"
|
||||
|
||||
DBCFile::DBCFile()
|
||||
{
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
DBCFile::DBCFile(const std::string &fn)
|
||||
{
|
||||
DBCFile();
|
||||
filename = fn;
|
||||
}
|
||||
|
||||
bool DBCFile::open()
|
||||
{
|
||||
std::fstream f;
|
||||
f.open(filename.c_str(), std::ios_base::binary | std::ios_base::in);
|
||||
if(!f.is_open())
|
||||
{
|
||||
printf("DBC: %s failed to open!\n",filename.c_str());
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
char header[4];
|
||||
unsigned int na,nb,es,ss;
|
||||
|
||||
f.read(header,4); // Number of records
|
||||
if(!(header[0]=='W' && header[1]=='D' && header[2]=='B' && header[3] == 'C'))
|
||||
{
|
||||
printf("DBC: %s is no DBC file!\n",filename.c_str());
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
f.read((char*)&na,4); // Number of records
|
||||
f.read((char*)&nb,4); // Number of fields
|
||||
f.read((char*)&es,4); // Size of a record
|
||||
f.read((char*)&ss,4); // String size
|
||||
|
||||
recordSize = es;
|
||||
recordCount = na;
|
||||
fieldCount = nb;
|
||||
stringSize = ss;
|
||||
if(fieldCount*4 != recordSize)
|
||||
{
|
||||
printf("DBC: %s is corrupt!\n",filename.c_str());
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
data = new unsigned char[recordSize*recordCount+stringSize];
|
||||
stringTable = data + recordSize*recordCount;
|
||||
f.read((char*)data,recordSize*recordCount+stringSize);
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBCFile::openmem(ByteBuffer bb)
|
||||
{
|
||||
|
||||
uint32 hdr;
|
||||
bb >> hdr;
|
||||
if(memcmp(&hdr,"WDBC",4)) // check if its a valid dbc file
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bb >> recordCount >> fieldCount >> recordSize >> stringSize;
|
||||
|
||||
if(fieldCount*4 != recordSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
data = new unsigned char[recordSize*recordCount+stringSize];
|
||||
stringTable = data + recordSize*recordCount;
|
||||
memcpy(data,bb.contents()+bb.rpos(),recordSize*recordCount+stringSize);
|
||||
return true;
|
||||
}
|
||||
DBCFile::~DBCFile()
|
||||
{
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
DBCFile::Record DBCFile::getRecord(size_t id)
|
||||
{
|
||||
assert(data);
|
||||
return Record(*this, data + id*recordSize);
|
||||
}
|
||||
|
||||
DBCFile::Iterator DBCFile::begin()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, data);
|
||||
}
|
||||
DBCFile::Iterator DBCFile::end()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, stringTable);
|
||||
}
|
||||
|
||||
121
src/tools/stuffextract/dbcfile.h
Normal file
121
src/tools/stuffextract/dbcfile.h
Normal file
@ -0,0 +1,121 @@
|
||||
// thx to WoWMapView for this! (original version)
|
||||
|
||||
#ifndef DBCFILE_H
|
||||
#define DBCFILE_H
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
class DBCFile
|
||||
{
|
||||
public:
|
||||
DBCFile(const std::string &fn);
|
||||
DBCFile();
|
||||
~DBCFile();
|
||||
|
||||
// Open database. It must be openened before it can be used.
|
||||
bool open();
|
||||
bool openmem(ByteBuffer);
|
||||
|
||||
// Database exceptions
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
Exception(const std::string &message): message(message)
|
||||
{ }
|
||||
virtual ~Exception()
|
||||
{ }
|
||||
const std::string &getMessage() {return message;}
|
||||
private:
|
||||
std::string message;
|
||||
};
|
||||
class NotFound: public Exception
|
||||
{
|
||||
public:
|
||||
NotFound(): Exception("Key was not found")
|
||||
{ }
|
||||
};
|
||||
// Iteration over database
|
||||
class Iterator;
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
float getFloat(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<float*>(offset+field*4);
|
||||
}
|
||||
unsigned int getUInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<unsigned int*>(offset+field*4);
|
||||
}
|
||||
int getInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<int*>(offset+field*4);
|
||||
}
|
||||
const char *getString(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
size_t stringOffset = getUInt(field);
|
||||
assert(stringOffset < file.stringSize);
|
||||
return reinterpret_cast<char*>(file.stringTable + stringOffset);
|
||||
}
|
||||
private:
|
||||
Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {}
|
||||
unsigned char *offset;
|
||||
DBCFile &file;
|
||||
|
||||
friend class DBCFile;
|
||||
friend class DBCFile::Iterator;
|
||||
};
|
||||
/** Iterator that iterates over records
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(DBCFile &file, unsigned char *offset):
|
||||
record(file, offset) {}
|
||||
/// Advance (prefix only)
|
||||
Iterator & operator++() {
|
||||
record.offset += record.file.recordSize;
|
||||
return *this;
|
||||
}
|
||||
/// Return address of current instance
|
||||
Record const & operator*() const { return record; }
|
||||
const Record* operator->() const {
|
||||
return &record;
|
||||
}
|
||||
/// Comparison
|
||||
bool operator==(const Iterator &b) const
|
||||
{
|
||||
return record.offset == b.record.offset;
|
||||
}
|
||||
bool operator!=(const Iterator &b) const
|
||||
{
|
||||
return record.offset != b.record.offset;
|
||||
}
|
||||
private:
|
||||
Record record;
|
||||
};
|
||||
|
||||
// Get record by id
|
||||
Record getRecord(size_t id);
|
||||
/// Get begin iterator over records
|
||||
Iterator begin();
|
||||
/// Get begin iterator over records
|
||||
Iterator end();
|
||||
/// Trivial
|
||||
size_t getRecordCount() const { return recordCount;}
|
||||
size_t getFieldCount() const { return fieldCount; }
|
||||
private:
|
||||
std::string filename;
|
||||
uint32 recordSize;
|
||||
uint32 recordCount;
|
||||
uint32 fieldCount;
|
||||
uint32 stringSize;
|
||||
unsigned char *data;
|
||||
unsigned char *stringTable;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user