Merge branch 'develop' into 3DProjectiles

This commit is contained in:
Baoulettes 2022-06-20 22:32:45 +02:00 committed by GitHub
commit 14df96eacd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
489 changed files with 125389 additions and 1776 deletions

View File

@ -21,7 +21,7 @@
```bash
# Clone the repo
git clone git@github.com:HarbourMasters/ShipWright.git
git clone https://github.com/HarbourMasters/Shipwright.git
cd ShipWright
# Copy the baserom to the OTRExporter folder
cp <path to your ROM> OTRExporter

212
Jenkinsfile vendored
View File

@ -7,109 +7,119 @@ pipeline {
}
stages {
stage ('Build Windows') {
environment {
MSBUILD='C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Msbuild\\Current\\Bin\\msbuild.exe'
CONFIG='Release'
OTRPLATFORM='x64'
PLATFORM='x86'
ZIP='C:\\Program Files\\7-Zip\\7z.exe'
PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe'
CMAKE='C:\\Program Files\\CMake\\bin\\cmake.exe'
TOOLSET='v142'
}
agent {
label "SoH-Builders"
}
steps {
checkout([
$class: 'GitSCM',
branches: scm.branches,
doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
extensions: scm.extensions,
userRemoteConfigs: scm.userRemoteConfigs
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
bat """
"${env.MSBUILD}" ".\\OTRExporter\\OTRExporter.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.OTRPLATFORM};PlatformToolset=${env.TOOLSET};RestorePackagesConfig=true /restore /nodeReuse:false /m
xcopy "..\\..\\ZELOOTD.z64" "OTRExporter\\"
cd "OTRExporter"
"${env.PYTHON}" ".\\extract_assets.py"
cd "..\\"
"${env.MSBUILD}" ".\\soh\\soh.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.PLATFORM};PlatformToolset=${env.TOOLSET} /nodeReuse:false /m
cd OTRGui
mkdir build
cd build
"${env.CMAKE}" ..
"${env.CMAKE}" --build . --config Release
cd "..\\..\\"
move "soh\\Release\\soh.exe" ".\\"
move "OTRGui\\build\\assets" ".\\"
move ".\\OTRExporter\\x64\\Release\\ZAPD.exe" ".\\assets\\extractor\\"
move ".\\OTRGui\\build\\Release\\OTRGui.exe" ".\\"
rename README.md readme.txt
"${env.ZIP}" a soh.7z soh.exe OTRGui.exe assets readme.txt
"""
archiveArtifacts artifacts: 'soh.7z', followSymlinks: false, onlyIfSuccessful: true
stage('Build SoH') {
parallel {
stage ('Build Windows') {
options {
timeout(time: 20)
}
environment {
MSBUILD='C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Msbuild\\Current\\Bin\\msbuild.exe'
CONFIG='Release'
OTRPLATFORM='x64'
PLATFORM='x86'
ZIP='C:\\Program Files\\7-Zip\\7z.exe'
PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe'
CMAKE='C:\\Program Files\\CMake\\bin\\cmake.exe'
TOOLSET='v142'
}
agent {
label "SoH-Builders"
}
steps {
checkout([
$class: 'GitSCM',
branches: scm.branches,
doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
extensions: scm.extensions,
userRemoteConfigs: scm.userRemoteConfigs
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
bat """
"${env.MSBUILD}" ".\\OTRExporter\\OTRExporter.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.OTRPLATFORM};PlatformToolset=${env.TOOLSET};RestorePackagesConfig=true /restore /nodeReuse:false /m
xcopy "..\\..\\ZELOOTD.z64" "OTRExporter\\"
cd "OTRExporter"
"${env.PYTHON}" ".\\extract_assets.py"
cd "..\\"
"${env.MSBUILD}" ".\\soh\\soh.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.PLATFORM};PlatformToolset=${env.TOOLSET} /nodeReuse:false /m
cd OTRGui
mkdir build
cd build
"${env.CMAKE}" ..
"${env.CMAKE}" --build . --config Release
cd "..\\..\\"
move "soh\\Release\\soh.exe" ".\\"
move "OTRGui\\build\\assets" ".\\"
move ".\\OTRExporter\\x64\\Release\\ZAPD.exe" ".\\assets\\extractor\\"
move ".\\OTRGui\\build\\Release\\OTRGui.exe" ".\\"
rename README.md readme.txt
"${env.ZIP}" a soh.7z soh.exe OTRGui.exe assets readme.txt
"""
archiveArtifacts artifacts: 'soh.7z', followSymlinks: false, onlyIfSuccessful: true
}
}
post {
always {
step([$class: 'WsCleanup']) // Clean workspace
}
}
}
}
post {
always {
step([$class: 'WsCleanup']) // Clean workspace
}
}
}
stage ('Build Linux') {
agent {
label "SoH-Linux-Builders"
}
steps {
checkout([
$class: 'GitSCM',
branches: scm.branches,
doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
extensions: scm.extensions,
userRemoteConfigs: scm.userRemoteConfigs
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
docker build . -t soh
docker run --name sohcont -dit --rm -v $(pwd):/soh soh /bin/bash
cp ../../buildsoh.bash soh
docker exec sohcont soh/buildsoh.bash
mkdir build
mv soh/soh.elf build/
mv OTRGui/build/OTRGui build/
mv OTRGui/build/assets build/
mv ZAPDTR/ZAPD.out build/assets/extractor/
mv README.md build/readme.txt
cd build
stage ('Build Linux') {
options {
timeout(time: 20)
}
agent {
label "SoH-Linux-Builders"
}
steps {
checkout([
$class: 'GitSCM',
branches: scm.branches,
doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
extensions: scm.extensions,
userRemoteConfigs: scm.userRemoteConfigs
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
docker build . -t soh
docker run --name sohcont -dit --rm -v $(pwd):/soh soh /bin/bash
cp ../../buildsoh.bash soh
docker exec sohcont soh/buildsoh.bash
mkdir build
mv soh/soh.elf build/
mv OTRGui/build/OTRGui build/
mv OTRGui/build/assets build/
mv ZAPDTR/ZAPD.out build/assets/extractor/
mv README.md build/readme.txt
cd build
7z a soh-linux.7z soh.elf OTRGui assets readme.txt
mv soh-linux.7z ../
'''
}
sh 'sudo docker container stop sohcont'
archiveArtifacts artifacts: 'soh-linux.7z', followSymlinks: false, onlyIfSuccessful: true
}
post {
always {
step([$class: 'WsCleanup']) // Clean workspace
7z a soh-linux.7z soh.elf OTRGui assets readme.txt
mv soh-linux.7z ../
'''
}
sh 'sudo docker container stop sohcont'
archiveArtifacts artifacts: 'soh-linux.7z', followSymlinks: false, onlyIfSuccessful: true
}
post {
always {
step([$class: 'WsCleanup']) // Clean workspace
}
}
}
}
}

View File

@ -341,6 +341,7 @@ build/
ZAPDUtils/build/
ZAPD/BuildInfo.h
baserom/
baserom_ntsc/
*.vtx.inc
*.otr
*.swp

View File

@ -11,6 +11,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libultraship", "..\libultra
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZAPD", "..\ZAPDTR\ZAPD\ZAPD.vcxproj", "{B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}"
ProjectSection(ProjectDependencies) = postProject
{78424708-1F6E-4D4B-920C-FB6D26847055} = {78424708-1F6E-4D4B-920C-FB6D26847055}
{6DA9B521-65B7-41E2-8F8A-F0451CC18ED8} = {6DA9B521-65B7-41E2-8F8A-F0451CC18ED8}
{A2E01C3E-D647-45D1-9788-043DEBC1A908} = {A2E01C3E-D647-45D1-9788-043DEBC1A908}
{A6103FD3-0709-4FC7-B066-1A6E056D6306} = {A6103FD3-0709-4FC7-B066-1A6E056D6306}
@ -18,6 +19,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZAPD", "..\ZAPDTR\ZAPD\ZAPD
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZAPDUtils", "..\ZAPDTR\ZAPDUtils\ZAPDUtils.vcxproj", "{A2E01C3E-D647-45D1-9788-043DEBC1A908}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StormLib", "..\StormLib\StormLib_vs19.vcxproj", "{78424708-1F6E-4D4B-920C-FB6D26847055}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -58,6 +61,14 @@ Global
{A2E01C3E-D647-45D1-9788-043DEBC1A908}.Release|x64.Build.0 = Release|x64
{A2E01C3E-D647-45D1-9788-043DEBC1A908}.Release|x86.ActiveCfg = Release|Win32
{A2E01C3E-D647-45D1-9788-043DEBC1A908}.Release|x86.Build.0 = Release|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|x64.ActiveCfg = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|x64.Build.0 = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|x86.ActiveCfg = DebugAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|x86.Build.0 = DebugAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|x64.ActiveCfg = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|x64.Build.0 = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|x86.ActiveCfg = ReleaseAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|x86.Build.0 = ReleaseAS|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,192 @@
#include "AudioExporter.h"
#include "Main.h"
#include <Animation.h>
#include <Utils/MemoryStream.h>
#include <Globals.h>
#include <Utils/File.h>
#include "DisplayListExporter.h"
void OTRExporter_Audio::WriteSampleEntryReference(ZAudio* audio, SampleEntry* entry, std::map<uint32_t, SampleEntry*> samples, BinaryWriter* writer)
{
writer->Write((uint8_t)(entry != nullptr ? 1 : 0));
if (entry != nullptr)
{
if (audio->sampleOffsets[entry->bankId].find(entry->sampleLoopOffset) != audio->sampleOffsets[entry->bankId].end())
{
if (audio->sampleOffsets[entry->bankId][entry->sampleLoopOffset].find(entry->sampleDataOffset) != audio->sampleOffsets[entry->bankId][entry->sampleLoopOffset].end())
{
writer->Write(StringHelper::Sprintf("audio/samples/%s", audio->sampleOffsets[entry->bankId][entry->sampleLoopOffset][entry->sampleDataOffset].c_str()));
}
else
writer->Write(entry->fileName);
}
else
writer->Write(entry->fileName);
}
else
writer->Write("");
}
void OTRExporter_Audio::WriteSampleEntry(SampleEntry* entry, BinaryWriter* writer)
{
WriteHeader(nullptr, "", writer, Ship::ResourceType::AudioSample, Ship::Version::Rachael);
writer->Write(entry->codec);
writer->Write(entry->medium);
writer->Write(entry->unk_bit26);
writer->Write(entry->unk_bit25);
writer->Write((uint32_t)entry->data.size());
writer->Write((char*)entry->data.data(), entry->data.size());
writer->Write((uint32_t)(entry->loop.start));
writer->Write((uint32_t)(entry->loop.end));
writer->Write((uint32_t)(entry->loop.count));
writer->Write((uint32_t)entry->loop.states.size());
for (size_t i = 0; i < entry->loop.states.size(); i++)
writer->Write((entry->loop.states[i]));
writer->Write((uint32_t)(entry->book.order));
writer->Write((uint32_t)(entry->book.npredictors));
writer->Write((uint32_t)entry->book.books.size());
for (size_t i = 0; i < entry->book.books.size(); i++)
writer->Write((entry->book.books[i]));
}
void OTRExporter_Audio::WriteSoundFontEntry(ZAudio* audio, SoundFontEntry* entry, std::map<uint32_t, SampleEntry*> samples, BinaryWriter* writer)
{
writer->Write((uint8_t)(entry != nullptr ? 1 : 0));
if (entry != nullptr)
{
WriteSampleEntryReference(audio, entry->sampleEntry, samples, writer);
writer->Write(entry->tuning);
}
}
void OTRExporter_Audio::WriteEnvData(std::vector<AdsrEnvelope*> envelopes, BinaryWriter* writer)
{
writer->Write((uint32_t)envelopes.size());
for (auto env : envelopes)
{
writer->Write(env->delay);
writer->Write(env->arg);
}
}
void OTRExporter_Audio::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
{
ZAudio* audio = (ZAudio*)res;
WriteHeader(res, outPath, writer, Ship::ResourceType::Audio, Ship::Version::Rachael);
// Write Samples as individual files
for (auto pair : audio->samples)
{
MemoryStream* sampleStream = new MemoryStream();
BinaryWriter sampleWriter = BinaryWriter(sampleStream);
writer->Write((uint32_t)pair.first);
WriteSampleEntry(pair.second, &sampleWriter);
std::string basePath = "";
if (audio->sampleOffsets[pair.second->bankId].find(pair.second->sampleLoopOffset) != audio->sampleOffsets[pair.second->bankId].end())
{
if (audio->sampleOffsets[pair.second->bankId][pair.second->sampleLoopOffset].find(pair.second->sampleDataOffset) != audio->sampleOffsets[pair.second->bankId][pair.second->sampleLoopOffset].end())
basePath = StringHelper::Sprintf("samples/%s", audio->sampleOffsets[pair.second->bankId][pair.second->sampleLoopOffset][pair.second->sampleDataOffset].c_str());
else
basePath = StringHelper::Sprintf("samples/sample_%08X", pair.first);
}
else
basePath = StringHelper::Sprintf("samples/sample_%08X", pair.first);
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, basePath);
AddFile(fName, sampleStream->ToVector());
}
// Write the soundfont table
for (size_t i = 0; i < audio->soundFontTable.size(); i++)
{
MemoryStream* fntStream = new MemoryStream();
BinaryWriter fntWriter = BinaryWriter(fntStream);
WriteHeader(nullptr, "", &fntWriter, Ship::ResourceType::AudioSoundFont, Ship::Version::Rachael);
fntWriter.Write((uint32_t)i);
fntWriter.Write(audio->soundFontTable[i].medium);
fntWriter.Write(audio->soundFontTable[i].cachePolicy);
fntWriter.Write(audio->soundFontTable[i].data1);
fntWriter.Write(audio->soundFontTable[i].data2);
fntWriter.Write(audio->soundFontTable[i].data3);
fntWriter.Write((uint32_t)audio->soundFontTable[i].drums.size());
fntWriter.Write((uint32_t)audio->soundFontTable[i].instruments.size());
fntWriter.Write((uint32_t)audio->soundFontTable[i].soundEffects.size());
for (size_t k = 0; k < audio->soundFontTable[i].drums.size(); k++)
{
fntWriter.Write(audio->soundFontTable[i].drums[k].releaseRate);
fntWriter.Write(audio->soundFontTable[i].drums[k].pan);
fntWriter.Write(audio->soundFontTable[i].drums[k].loaded);
WriteEnvData(audio->soundFontTable[i].drums[k].env, &fntWriter);
WriteSampleEntryReference(audio, audio->soundFontTable[i].drums[k].sample, audio->samples, &fntWriter);
fntWriter.Write(audio->soundFontTable[i].drums[k].tuning);
}
for (size_t k = 0; k < audio->soundFontTable[i].instruments.size(); k++)
{
fntWriter.Write((uint8_t)audio->soundFontTable[i].instruments[k].isValidInstrument);
fntWriter.Write(audio->soundFontTable[i].instruments[k].loaded);
fntWriter.Write(audio->soundFontTable[i].instruments[k].normalRangeLo);
fntWriter.Write(audio->soundFontTable[i].instruments[k].normalRangeHi);
fntWriter.Write(audio->soundFontTable[i].instruments[k].releaseRate);
WriteEnvData(audio->soundFontTable[i].instruments[k].env, &fntWriter);
WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].lowNotesSound, audio->samples, &fntWriter);
WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].normalNotesSound, audio->samples, &fntWriter);
WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].highNotesSound, audio->samples, &fntWriter);
}
for (size_t k = 0; k < audio->soundFontTable[i].soundEffects.size(); k++)
{
WriteSoundFontEntry(audio, audio->soundFontTable[i].soundEffects[k], audio->samples, &fntWriter);
}
//std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("fonts/font_%02X", i));
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("fonts/%s", audio->soundFontNames[i].c_str()));
AddFile(fName, fntStream->ToVector());
}
// Write Sequences
for (size_t i = 0; i < audio->sequences.size(); i++)
{
auto seq = audio->sequences[i];
MemoryStream* seqStream = new MemoryStream();
BinaryWriter seqWriter = BinaryWriter(seqStream);
WriteHeader(nullptr, "", &seqWriter, Ship::ResourceType::AudioSequence, Ship::Version::Rachael);
seqWriter.Write((uint32_t)seq.size());
seqWriter.Write(seq.data(), seq.size());
seqWriter.Write((uint8_t)i);
seqWriter.Write((uint8_t)audio->sequenceTable[i].medium);
seqWriter.Write((uint8_t)audio->sequenceTable[i].cachePolicy);
seqWriter.Write((uint32_t)audio->fontIndices[i].size());
for (size_t k = 0; k < audio->fontIndices[i].size(); k++)
seqWriter.Write((uint8_t)audio->fontIndices[i][k]);
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("sequences/%s", audio->seqNames[i].c_str()));
AddFile(fName, seqStream->ToVector());
}
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "ZResource.h"
#include "ZAudio.h"
#include "Exporter.h"
#include <Utils/BinaryWriter.h>
class OTRExporter_Audio : public OTRExporter
{
public:
void WriteSampleEntry(SampleEntry* entry, BinaryWriter* writer);
void WriteSampleEntryReference(ZAudio* audio, SampleEntry* entry, std::map<uint32_t, SampleEntry*> samples, BinaryWriter* writer);
void WriteSoundFontEntry(ZAudio* audio, SoundFontEntry* entry, std::map<uint32_t, SampleEntry*> samples, BinaryWriter* writer);
void WriteEnvData(std::vector<AdsrEnvelope*> envelopes, BinaryWriter* writer);
virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
};

View File

@ -362,18 +362,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
BinaryWriter dlWriter = BinaryWriter(dlStream);
Save(dList->otherDLists[i], outPath, &dlWriter);
#ifdef _DEBUG
//if (otrArchive->HasFile(fName))
//otrArchive->RemoveFile(fName);
#endif
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, dlStream->ToVector());
else
files[fName] = dlStream->ToVector();
//otrArchive->AddFile(fName, (uintptr_t)dlStream->ToVector().data(), dlWriter.GetBaseAddress());
AddFile(fName, dlStream->ToVector());
}
}
else
@ -460,10 +449,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
Save(dList->otherDLists[i], outPath, &dlWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, dlStream->ToVector());
else
files[fName] = dlStream->ToVector();
AddFile(fName, dlStream->ToVector());
}
}
else
@ -827,10 +813,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
}
}
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, vtxStream->ToVector());
else
files[fName] = vtxStream->ToVector();
AddFile(fName, vtxStream->ToVector());
auto end = std::chrono::steady_clock::now();
size_t diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

View File

@ -1,7 +1,7 @@
#include "Exporter.h"
#include "VersionInfo.h"
void OTRExporter::WriteHeader(ZResource* res, const fs::path& outPath, BinaryWriter* writer, Ship::ResourceType resType)
void OTRExporter::WriteHeader(ZResource* res, const fs::path& outPath, BinaryWriter* writer, Ship::ResourceType resType, Ship::Version resVersion)
{
writer->Write((uint8_t)Endianess::Little); // 0x00
writer->Write((uint8_t)0); // 0x01
@ -9,7 +9,8 @@ void OTRExporter::WriteHeader(ZResource* res, const fs::path& outPath, BinaryWri
writer->Write((uint8_t)0); // 0x03
writer->Write((uint32_t)resType); // 0x04
writer->Write((uint32_t)MAJOR_VERSION); // 0x08
//writer->Write((uint32_t)MAJOR_VERSION); // 0x08
writer->Write((uint32_t)resVersion); // 0x08
writer->Write((uint64_t)0xDEADBEEFDEADBEEF); // id, 0x0C
writer->Write((uint32_t)resourceVersions[resType]); // 0x10
writer->Write((uint64_t)0); // ROM CRC, 0x14

View File

@ -4,9 +4,10 @@
//#include "OTRExporter.h"
#include <Utils/BinaryWriter.h>
#include <Resource.h>
#include "VersionInfo.h"
class OTRExporter : public ZResourceExporter
{
protected:
static void WriteHeader(ZResource* res, const fs::path& outPath, BinaryWriter* writer, Ship::ResourceType resType);
static void WriteHeader(ZResource* res, const fs::path& outPath, BinaryWriter* writer, Ship::ResourceType resType, Ship::Version resVersion = MAJOR_VERSION);
};

View File

@ -15,6 +15,7 @@
#include "TextExporter.h"
#include "BlobExporter.h"
#include "MtxExporter.h"
#include "AudioExporter.h"
#include <Globals.h>
#include <Utils/File.h>
#include <Utils/Directory.h>
@ -26,6 +27,7 @@ std::shared_ptr<Ship::Archive> otrArchive;
BinaryWriter* fileWriter;
std::chrono::steady_clock::time_point fileStart, resStart;
std::map<std::string, std::vector<char>> files;
std::mutex fileMutex;
void InitVersionInfo();
@ -45,7 +47,7 @@ static void ExporterParseFileMode(const std::string& buildMode, ZFileMode& fileM
if (File::Exists(otrFileName))
otrArchive = std::shared_ptr<Ship::Archive>(new Ship::Archive(otrFileName, true));
else
otrArchive = Ship::Archive::CreateArchive(otrFileName, 65536 / 2);
otrArchive = Ship::Archive::CreateArchive(otrFileName, 40000);
auto lst = Directory::ListFiles("Extract");
@ -62,7 +64,7 @@ static void ExporterProgramEnd()
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
{
printf("Generating OTR Archive...\n");
otrArchive = Ship::Archive::CreateArchive(otrFileName, 65536 / 2);
otrArchive = Ship::Archive::CreateArchive(otrFileName, 40000);
for (auto item : files)
{
@ -79,9 +81,9 @@ static void ExporterProgramEnd()
otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size());
}
otrArchive->AddFile("Audiobank", (uintptr_t)Globals::Instance->GetBaseromFile("Audiobank").data(), Globals::Instance->GetBaseromFile("Audiobank").size());
otrArchive->AddFile("Audioseq", (uintptr_t)Globals::Instance->GetBaseromFile("Audioseq").data(), Globals::Instance->GetBaseromFile("Audioseq").size());
otrArchive->AddFile("Audiotable", (uintptr_t)Globals::Instance->GetBaseromFile("Audiotable").data(), Globals::Instance->GetBaseromFile("Audiotable").size());
//otrArchive->AddFile("Audiobank", (uintptr_t)Globals::Instance->GetBaseromFile("Audiobank").data(), Globals::Instance->GetBaseromFile("Audiobank").size());
//otrArchive->AddFile("Audioseq", (uintptr_t)Globals::Instance->GetBaseromFile("Audioseq").data(), Globals::Instance->GetBaseromFile("Audioseq").size());
//otrArchive->AddFile("Audiotable", (uintptr_t)Globals::Instance->GetBaseromFile("Audiotable").data(), Globals::Instance->GetBaseromFile("Audiotable").size());
}
}
@ -158,7 +160,10 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer)
fName = StringHelper::Sprintf("%s/%s", oName.c_str(), rName.c_str());
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
{
std::unique_lock Lock(fileMutex);
files[fName] = strem->ToVector();
}
else
File::WriteAllBytes("Extract/" + fName, strem->ToVector());
}
@ -178,6 +183,17 @@ static void ExporterXMLEnd()
{
}
void AddFile(std::string fName, std::vector<char> data)
{
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, data);
else
{
std::unique_lock Lock(fileMutex);
files[fName] = data;
}
}
static void ImportExporters()
{
// In this example we set up a new exporter called "EXAMPLE".
@ -211,6 +227,7 @@ static void ImportExporters()
exporterSet->exporters[ZResourceType::Text] = new OTRExporter_Text();
exporterSet->exporters[ZResourceType::Blob] = new OTRExporter_Blob();
exporterSet->exporters[ZResourceType::Mtx] = new OTRExporter_MtxExporter();
exporterSet->exporters[ZResourceType::Audio] = new OTRExporter_Audio();
Globals::AddExporter("OTR", exporterSet);

View File

@ -3,4 +3,6 @@
#include <Archive.h>
extern std::shared_ptr<Ship::Archive> otrArchive;
extern std::map<std::string, std::vector<char>> files;
extern std::map<std::string, std::vector<char>> files;
void AddFile(std::string fName, std::vector<char> data);

View File

@ -46,6 +46,7 @@ INC_DIRS := $(addprefix -I, \
../../libultraship/libultraship \
../../libultraship/libultraship/Lib/spdlog/include \
../../libultraship/libultraship/Lib/Fast3D/U64 \
../../StormLib/src \
)
# create build directories

View File

@ -20,6 +20,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="ArrayExporter.h" />
<ClInclude Include="AudioExporter.h" />
<ClInclude Include="BackgroundExporter.h" />
<ClInclude Include="BlobExporter.h" />
<ClInclude Include="CollisionExporter.h" />
@ -44,6 +45,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="ArrayExporter.cpp" />
<ClCompile Include="AudioExporter.cpp" />
<ClCompile Include="BackgroundExporter.cpp" />
<ClCompile Include="BlobExporter.cpp" />
<ClCompile Include="CollisionExporter.cpp" />
@ -136,7 +138,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(ProjectDir)..\..\ZAPDTR\ZAPD;$(ProjectDir)..\..\ZAPDTR\lib\tinyxml2;$(ProjectDir)..\..\ZAPDTR\lib\libgfxd;$(ProjectDir)..\..\ZAPDTR\ZAPDUtils;$(ProjectDir)..\..\libultraship\libultraship;$(ProjectDir)..\..\libultraship\libultraship\lib\spdlog\include;$(ProjectDir)..\..\libultraship\libultraship\Lib\Fast3D\U64;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)..\..\ZAPDTR\ZAPD;$(ProjectDir)..\..\ZAPDTR\lib\tinyxml2;$(ProjectDir)..\..\ZAPDTR\lib\libgfxd;$(ProjectDir)..\..\ZAPDTR\ZAPDUtils;$(ProjectDir)..\..\libultraship\libultraship;$(ProjectDir)..\..\libultraship\libultraship\lib\spdlog\include;$(ProjectDir)..\..\libultraship\libultraship\Lib\Fast3D\U64;$(ProjectDir)..\..\StormLib\src\;$(IncludePath)</IncludePath>
<LibraryPath>$(ProjectDir)..\..\libultraship\libultraship;$(LibraryPath)</LibraryPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />
@ -144,7 +146,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(ProjectDir)..\..\ZAPDTR\ZAPD;$(ProjectDir)..\..\ZAPDTR\lib\tinyxml2;$(ProjectDir)..\..\ZAPDTR\lib\libgfxd;$(ProjectDir)..\..\ZAPDTR\ZAPDUtils;$(ProjectDir)..\..\libultraship\libultraship;$(ProjectDir)..\..\libultraship\libultraship\lib\spdlog\include;$(ProjectDir)..\..\libultraship\libultraship\Lib\Fast3D\U64;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)..\..\ZAPDTR\ZAPD;$(ProjectDir)..\..\ZAPDTR\lib\tinyxml2;$(ProjectDir)..\..\ZAPDTR\lib\libgfxd;$(ProjectDir)..\..\ZAPDTR\ZAPDUtils;$(ProjectDir)..\..\libultraship\libultraship;$(ProjectDir)..\..\libultraship\libultraship\lib\spdlog\include;$(ProjectDir)..\..\libultraship\libultraship\Lib\Fast3D\U64;$(ProjectDir)..\..\StormLib\src\;$(IncludePath)</IncludePath>
<LibraryPath>$(ProjectDir)..\..\libultraship\libultraship;$(LibraryPath)</LibraryPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />

View File

@ -81,6 +81,9 @@
<ClInclude Include="VersionInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AudioExporter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CollisionExporter.cpp">
@ -140,5 +143,8 @@
<ClCompile Include="VersionInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AudioExporter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -453,13 +453,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
OTRExporter_Cutscene cs;
cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, csStream->ToVector());
else
files[fName] = csStream->ToVector();
//std::string fName = OTRExporter_DisplayList::GetPathToRes(res, vtxDecl->varName);
//otrArchive->AddFile(fName, (uintptr_t)csStream->ToVector().data(), csWriter.GetBaseAddress());
AddFile(fName, csStream->ToVector());
}
break;
case RoomCommand::SetPathways:
@ -480,14 +474,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
OTRExporter_Path pathExp;
pathExp.Save(&cmdSetPathways->pathwayList, outPath, &pathWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + path, pathStream->ToVector());
else
files[path] = pathStream->ToVector();
//otrArchive->AddFile(path, (uintptr_t)pathStream->ToVector().data(), pathWriter.GetBaseAddress());
int bp = 0;
AddFile(path, pathStream->ToVector());
}
}
break;

View File

@ -48,7 +48,22 @@ If you still cannot get the tool to work, join our [Discord Server](https://disc
Launch the game. If the window immediately closes, or if there are visual artifacts, you may have selected the wrong rom in the OTRGui tool.
Currently, DirectX 11 and OpenGL is supported. Change the renderer by opening the `shipofharkinian.ini` configuration file in notepad and add `sdl` to `gfx backend` for OpenGL or leave blank for DirectX.
Default keyboard configuration:
| N64 | A | B | Z | Start | Analog stick | C buttons | D-Pad |
| - | - | - | - | - | - | - | - |
| Keyboard | X | C | Z | Space | WASD | Arrow keys | TFGH |
Other shortcuts:
| Keys | Action |
| - | - |
| F1 | Toggle menubar |
| F5 | Save state |
| F6 | Change state |
| F7 | Load state |
| F10 | Fullscreen (OpenGL) |
| Alt+Enter | Fullscreen (DirectX) |
Currently, DirectX 11 and OpenGL are supported. Change the renderer by opening the `shipofharkinian.ini` configuration file in notepad and add `sdl` to `gfx backend` for OpenGL or leave blank for DirectX.
## Take The Survey
Want to use cartridge readers in tandem with the OTRGui?
@ -63,8 +78,8 @@ Official Discord: https://discord.com/invite/BtBmd55HVH
Refer to the [building instructions](BUILDING.md) to compile SoH.
## Troubleshooting The Exporter
- Affirm that you have an `/assets` folder filled with XMLs in the same directory as OTRGui.exe
- Affirm that `zapd.exe` exists in the `/assets/extractor` folder
- Confirm that you have an `/assets` folder filled with XMLs in the same directory as OTRGui.exe
- Confirm that `zapd.exe` exists in the `/assets/extractor` folder
## Nightly Builds
Nightly builds of Ship of Harkinian are available [here](https://builds.shipofharkinian.com/job/SoH_Multibranch/job/develop)
@ -108,7 +123,7 @@ Nightly builds of Ship of Harkinian are available [here](https://builds.shipofha
## Video Credits
Kenix | Producer / Writer
rainbow_fash | Executive Producer
TheLegendOfXela | Editor
ReveriePass | Editor
MicTheMicrophone | Gwonam / The King
Amphibibro | Link
AceHeart | Zelda

167
StormLib/.gitignore vendored Normal file
View File

@ -0,0 +1,167 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.vspscc
.builds
*.dotCover
*.o
*.dylib
## TODO: If you have NuGet Package Restore enabled, uncomment this
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
**/project.xcworkspace
**/xcuserdata

22
StormLib/Info.plist Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>net.zezula.${PRODUCT_NAME:rfc1034Identifier}</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>8.01</string>
</dict>
</plist>

21
StormLib/LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 1999-2013 Ladislav Zezula
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

34
StormLib/PostBuild.bat Normal file
View File

@ -0,0 +1,34 @@
@echo off
rem Post-build batch for StormLib project
rem Called as PostBuild.bat $(ProjectName) $(PlatformName) $(ConfigurationName) [vs2008]
rem Example: PostBuild.bat StormLib_dll x64 Debug vs2008
rem Select build type
if "%1" == "StormLib_dll" goto PostBuild_DLL
if "%1" == "StormLib" goto PostBuild_LIB
goto:eof
:PostBuild_DLL
rem Build steps for the DLL. On 32-bit Release version, increment the build number
if not "x%2" == "xWin32" goto:eof
if not "x%3" == "xRelease" goto:eof
PostBuild.exe .\src\DllMain.rc
goto:eof
:PostBuild_LIB
rem Set target folders
if "x%2" == "xWin32" set TARGET_DIR_LEVEL2=lib32
if "x%2" == "xx64" set TARGET_DIR_LEVEL2=lib64
if "x%4" == "xvs2008" set TARGET_DIR_LEVEL3=vs2008
rem Check & create target folder structure
if not exist ..\aaa goto:eof
if not exist ..\aaa\%TARGET_DIR_LEVEL2% md ..\aaa\%TARGET_DIR_LEVEL2%
if not exist ..\aaa\%TARGET_DIR_LEVEL2%\%TARGET_DIR_LEVEL3% md ..\aaa\%TARGET_DIR_LEVEL2%\%TARGET_DIR_LEVEL3%
rem Copy include and LIB files to the target folder
copy /Y .\src\StormLib.h ..\aaa\inc >nul
copy /Y .\src\StormPort.h ..\aaa\inc >nul
copy /Y .\bin\%1\%2\%3\StormLib???.lib ..\aaa\%TARGET_DIR_LEVEL2%\%TARGET_DIR_LEVEL3% >nul

132
StormLib/Premake5.lua Normal file
View File

@ -0,0 +1,132 @@
solution 'StormLib'
location 'build'
language 'C++'
configurations { 'Debug', 'Release', }
platforms { 'x32', 'x64' }
targetdir 'bin'
objdir 'bin'
files {
'src/**.h',
'src/**.c',
'src/**.cpp',
'doc/*.txt',
}
removefiles {
'src/adpcm/*_old.*',
'src/huffman/*_old.*',
'src/huffman/huff_patch.*',
'src/pklib/crc32.c',
'src/zlib/compress.c',
}
filter 'configurations:Debug*'
flags { 'Symbols' }
defines { '_DEBUG' }
optimize 'Debug'
filter 'configurations:Release*'
defines { 'NDEBUG' }
optimize 'Full'
filter 'system:windows'
links { 'wininet', }
defines { 'WINDOWS', '_WINDOWS' }
filter { 'system:windows', 'platforms:x32' }
defines { 'WIN32', '_WIN32' }
filter { 'system:windows', 'platforms:x64' }
defines { 'WIN64', '_WIN64' }
filter 'system:linux'
defines { '_7ZIP_ST', 'BZ_STRICT_ANSI' }
removefiles {
'src/lzma/C/LzFindMt.*',
'src/lzma/C/Threads.*',
}
--------------------------------------------------------------------------------
project 'StormLib'
kind 'StaticLib'
removefiles 'src/SBaseDumpData.cpp'
configurations {
'DebugAD', -- Debug Ansi Dynamic
'DebugAS', -- Debug Ansi Static
'DebugUD', -- Debug Unicode Dynamic
'DebugUS', -- Debug Unicode Static
'ReleaseAD', -- Release Ansi Dynamic
'ReleaseAS', -- Release Ansi Static
'ReleaseUD', -- Release Unicode Dynamic'
'ReleaseUS', -- Release Unicode Static
}
configmap {
['Debug'] = 'DebugUS',
['Release'] = 'ReleaseUS',
}
filter 'configurations:*S'
flags { 'StaticRuntime' }
filter { 'configurations:*U*', 'action:vs*' }
flags { 'Unicode' }
filter { 'configurations:*U*', 'not action:vs*' }
defines { 'UNICODE', '_UNICODE' }
filter 'DebugAD'
targetsuffix 'DAD'
filter 'ReleaseAD'
targetsuffix 'RAD'
filter 'DebugAS'
targetsuffix 'DAS'
filter 'ReleaseAS'
targetsuffix 'RAS'
filter 'DebugUD'
targetsuffix 'DUD'
filter 'ReleaseUD'
targetsuffix 'RUD'
filter 'DebugUS'
targetsuffix 'DUS'
filter 'ReleaseUS'
targetsuffix 'RUS'
--------------------------------------------------------------------------------
project 'StormLib_dll'
kind 'SharedLib'
targetname 'Stormlib'
files {
'stormlib_dll/DllMain.c',
'stormlib_dll/StormLib.def',
}
removefiles 'src/SBaseDumpData.cpp'
filter { 'system:windows', 'action:gmake' }
linkoptions {
'-Xlinker --enable-stdcall-fixup',
'../stormlib_dll/StormLib.def',
}
filter 'Debug'
targetsuffix '_d'
--------------------------------------------------------------------------------
project 'StormLib_test'
kind 'ConsoleApp'
files {
'test/StormTest.cpp',
}

25
StormLib/Publish.bat Normal file
View File

@ -0,0 +1,25 @@
@echo off
rem This BAT file updates the ZIP file that is to be uploaded to web
rem Only use when both 32-bit and 64-bit are properly compiled
set STORMLIB_NAME=stormlib-9.00
echo Creating %STORMLIB_NAME%.zip ...
cd \Ladik\Appdir
zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\doc\*
zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\src\*
zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\storm_dll\*
zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\StormLib.xcodeproj\*
zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\stormlib_dll\*
zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\test\*
zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\CMakeLists.txt
zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\makefile.*
zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\Info.plist
zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\*.bat
zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\*.sln
zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\*.vcproj
zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\*.vcxproj
echo.
echo Press any key to exit ...
pause >nul

39
StormLib/README.md Normal file
View File

@ -0,0 +1,39 @@
# StormLib
This is official repository for the StomLib library, an open-source project that can work with Blizzard MPQ archives.
## Installation and basic usage
### Linux
1. Download latest release
2. Install StormLib:
```
$ cd <path-to-StormLib>
$ cmake CMakeLists.txt
$ make
$ make install
```
3. Include StormLib in your project: `#include <StormLib.h>`
4. Make sure you compile your project with `-lstorm -lz -lbz2`
### Windows (Visual Studio 2008)
1. Download the latest release of StormLib
2. Open the solution file `StormLib_vs08.sln` in Visual Studio 2008
3. Choose "Build / Batch Build" and select every build of "StormLib"
4. Choose "Rebuild"
5. The result libraries are in `.\bin\Win32` and `.\bin\x64`
### Windows (Visual Studio 2017 or 2019)
0. Make sure you have SDK 10.0.17134.0 installed
1. Download the latest release of StormLib
2. Open the solution file `StormLib_vs19.sln` in Visual Studio 2017/2019
3. Choose "Build / Batch Build" and select every build of "StormLib"
4. Choose "Rebuild"
5. The result libraries are in `.\bin\Win32` and `.\bin\x64`
### Windows (Test Project)
1. Include the main StormLib header: `#include <StormLib.h>`
2. Set the correct library directory for StormLibXYZ.lib:
* X: D = Debug, R = Release
* Y: A = ANSI build, U = Unicode build
* Z: S = Using static CRT library, D = Using Dynamic CRT library
3. Rebuild

3
StormLib/StormLib.kdev4 Normal file
View File

@ -0,0 +1,3 @@
[Project]
Manager=KDevCMakeManager
Name=StormLib

File diff suppressed because it is too large Load Diff

139
StormLib/StormLib_vs08.sln Normal file
View File

@ -0,0 +1,139 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StormLib", "StormLib_vs08.vcproj", "{78424708-1F6E-4D4B-920C-FB6D26847055}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StormLib_dll", "StormLib_vs08_dll.vcproj", "{CB385198-50B1-4CF4-883B-11F042DED6AA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StormLib_test", "StormLib_vs08_test.vcproj", "{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
DebugAD|Win32 = DebugAD|Win32
DebugAD|x64 = DebugAD|x64
DebugAS|Win32 = DebugAS|Win32
DebugAS|x64 = DebugAS|x64
DebugUD|Win32 = DebugUD|Win32
DebugUD|x64 = DebugUD|x64
DebugUS|Win32 = DebugUS|Win32
DebugUS|x64 = DebugUS|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
ReleaseAD|Win32 = ReleaseAD|Win32
ReleaseAD|x64 = ReleaseAD|x64
ReleaseAS|Win32 = ReleaseAS|Win32
ReleaseAS|x64 = ReleaseAS|x64
ReleaseUD|Win32 = ReleaseUD|Win32
ReleaseUD|x64 = ReleaseUD|x64
ReleaseUS|Win32 = ReleaseUS|Win32
ReleaseUS|x64 = ReleaseUS|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|Win32.ActiveCfg = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|x64.ActiveCfg = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|x64.Build.0 = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAD|Win32.ActiveCfg = DebugAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAD|Win32.Build.0 = DebugAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAD|x64.ActiveCfg = DebugAD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAD|x64.Build.0 = DebugAD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAS|Win32.ActiveCfg = DebugAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAS|Win32.Build.0 = DebugAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAS|x64.ActiveCfg = DebugAS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAS|x64.Build.0 = DebugAS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUD|Win32.ActiveCfg = DebugUD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUD|Win32.Build.0 = DebugUD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUD|x64.ActiveCfg = DebugUD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUD|x64.Build.0 = DebugUD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUS|Win32.ActiveCfg = DebugUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUS|Win32.Build.0 = DebugUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUS|x64.ActiveCfg = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUS|x64.Build.0 = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|Win32.ActiveCfg = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|x64.ActiveCfg = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|x64.Build.0 = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAD|Win32.ActiveCfg = ReleaseAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAD|Win32.Build.0 = ReleaseAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAD|x64.ActiveCfg = ReleaseAD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAD|x64.Build.0 = ReleaseAD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAS|Win32.ActiveCfg = ReleaseAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAS|Win32.Build.0 = ReleaseAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAS|x64.ActiveCfg = ReleaseAS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAS|x64.Build.0 = ReleaseAS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUD|Win32.ActiveCfg = ReleaseUD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUD|Win32.Build.0 = ReleaseUD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUD|x64.ActiveCfg = ReleaseUD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUD|x64.Build.0 = ReleaseUD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUS|Win32.ActiveCfg = ReleaseUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUS|Win32.Build.0 = ReleaseUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUS|x64.ActiveCfg = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUS|x64.Build.0 = ReleaseUS|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Debug|Win32.ActiveCfg = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Debug|Win32.Build.0 = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Debug|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Debug|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAD|Win32.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAD|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAD|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAS|Win32.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAS|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAS|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUD|Win32.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUD|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUD|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUS|Win32.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUS|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUS|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Release|Win32.ActiveCfg = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Release|Win32.Build.0 = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Release|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Release|x64.Build.0 = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAD|Win32.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAD|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAD|x64.Build.0 = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAS|Win32.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAS|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAS|x64.Build.0 = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUD|Win32.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUD|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUD|x64.Build.0 = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUS|Win32.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUS|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUS|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Debug|Win32.ActiveCfg = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Debug|Win32.Build.0 = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Debug|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Debug|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAD|Win32.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAD|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAD|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAS|Win32.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAS|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAS|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUD|Win32.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUD|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUD|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUS|Win32.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUS|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUS|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Release|Win32.ActiveCfg = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Release|Win32.Build.0 = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Release|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Release|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAD|Win32.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAD|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAD|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAS|Win32.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAS|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAS|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUD|Win32.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUD|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUD|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUS|Win32.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUS|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUS|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

162
StormLib/StormLib_vs19.sln Normal file
View File

@ -0,0 +1,162 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2050
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StormLib", "StormLib_vs19.vcxproj", "{78424708-1F6E-4D4B-920C-FB6D26847055}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StormLib_dll", "StormLib_vs19_dll.vcxproj", "{CB385198-50B1-4CF4-883B-11F042DED6AA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StormLib_test", "StormLib_vs19_test.vcxproj", "{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
DebugAD|Win32 = DebugAD|Win32
DebugAD|x64 = DebugAD|x64
DebugAS|Win32 = DebugAS|Win32
DebugAS|x64 = DebugAS|x64
DebugUD|Win32 = DebugUD|Win32
DebugUD|x64 = DebugUD|x64
DebugUS|Win32 = DebugUS|Win32
DebugUS|x64 = DebugUS|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
ReleaseAD|Win32 = ReleaseAD|Win32
ReleaseAD|x64 = ReleaseAD|x64
ReleaseAS|Win32 = ReleaseAS|Win32
ReleaseAS|x64 = ReleaseAS|x64
ReleaseUD|Win32 = ReleaseUD|Win32
ReleaseUD|x64 = ReleaseUD|x64
ReleaseUS|Win32 = ReleaseUS|Win32
ReleaseUS|x64 = ReleaseUS|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|Win32.ActiveCfg = DebugUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|Win32.Build.0 = DebugUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|x64.ActiveCfg = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Debug|x64.Build.0 = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAD|Win32.ActiveCfg = DebugAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAD|Win32.Build.0 = DebugAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAD|x64.ActiveCfg = DebugAD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAD|x64.Build.0 = DebugAD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAS|Win32.ActiveCfg = DebugAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAS|Win32.Build.0 = DebugAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAS|x64.ActiveCfg = DebugAS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugAS|x64.Build.0 = DebugAS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUD|Win32.ActiveCfg = DebugUD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUD|Win32.Build.0 = DebugUD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUD|x64.ActiveCfg = DebugUD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUD|x64.Build.0 = DebugUD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUS|Win32.ActiveCfg = DebugUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUS|Win32.Build.0 = DebugUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUS|x64.ActiveCfg = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.DebugUS|x64.Build.0 = DebugUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|Win32.ActiveCfg = ReleaseUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|Win32.Build.0 = ReleaseUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|x64.ActiveCfg = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.Release|x64.Build.0 = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAD|Win32.ActiveCfg = ReleaseAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAD|Win32.Build.0 = ReleaseAD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAD|x64.ActiveCfg = ReleaseAD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAD|x64.Build.0 = ReleaseAD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAS|Win32.ActiveCfg = ReleaseAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAS|Win32.Build.0 = ReleaseAS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAS|x64.ActiveCfg = ReleaseAS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseAS|x64.Build.0 = ReleaseAS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUD|Win32.ActiveCfg = ReleaseUD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUD|Win32.Build.0 = ReleaseUD|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUD|x64.ActiveCfg = ReleaseUD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUD|x64.Build.0 = ReleaseUD|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUS|Win32.ActiveCfg = ReleaseUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUS|Win32.Build.0 = ReleaseUS|Win32
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUS|x64.ActiveCfg = ReleaseUS|x64
{78424708-1F6E-4D4B-920C-FB6D26847055}.ReleaseUS|x64.Build.0 = ReleaseUS|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Debug|Win32.ActiveCfg = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Debug|Win32.Build.0 = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Debug|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Debug|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAD|Win32.ActiveCfg = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAD|Win32.Build.0 = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAD|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAD|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAS|Win32.ActiveCfg = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAS|Win32.Build.0 = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAS|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugAS|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUD|Win32.ActiveCfg = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUD|Win32.Build.0 = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUD|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUD|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUS|Win32.ActiveCfg = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUS|Win32.Build.0 = Debug|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUS|x64.ActiveCfg = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.DebugUS|x64.Build.0 = Debug|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Release|Win32.ActiveCfg = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Release|Win32.Build.0 = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Release|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.Release|x64.Build.0 = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAD|Win32.ActiveCfg = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAD|Win32.Build.0 = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAD|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAD|x64.Build.0 = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAS|Win32.ActiveCfg = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAS|Win32.Build.0 = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAS|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseAS|x64.Build.0 = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUD|Win32.ActiveCfg = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUD|Win32.Build.0 = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUD|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUD|x64.Build.0 = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUS|Win32.ActiveCfg = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUS|Win32.Build.0 = Release|Win32
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUS|x64.ActiveCfg = Release|x64
{CB385198-50B1-4CF4-883B-11F042DED6AA}.ReleaseUS|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Debug|Win32.ActiveCfg = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Debug|Win32.Build.0 = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Debug|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Debug|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAD|Win32.ActiveCfg = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAD|Win32.Build.0 = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAD|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAD|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAS|Win32.ActiveCfg = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAS|Win32.Build.0 = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAS|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugAS|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUD|Win32.ActiveCfg = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUD|Win32.Build.0 = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUD|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUD|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUS|Win32.ActiveCfg = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUS|Win32.Build.0 = Debug|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUS|x64.ActiveCfg = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.DebugUS|x64.Build.0 = Debug|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Release|Win32.ActiveCfg = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Release|Win32.Build.0 = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Release|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.Release|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAD|Win32.ActiveCfg = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAD|Win32.Build.0 = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAD|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAD|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAS|Win32.ActiveCfg = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAS|Win32.Build.0 = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAS|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseAS|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUD|Win32.ActiveCfg = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUD|Win32.Build.0 = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUD|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUD|x64.Build.0 = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUS|Win32.ActiveCfg = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUS|Win32.Build.0 = Release|Win32
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUS|x64.ActiveCfg = Release|x64
{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}.ReleaseUS|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {04583FA5-D423-4B0D-A42B-F7D44C70991C}
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,830 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Doc Files">
<UniqueIdentifier>{595d6bc1-89d0-4fb8-98f6-be35e73727c4}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{721663d8-8692-476f-b0fd-71fdadf69929}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{9cc24144-d198-4bd1-b941-b946bd61b982}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\adpcm">
<UniqueIdentifier>{be0080d3-fc04-4442-9e28-b4cc2641177d}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\bzip2">
<UniqueIdentifier>{adb84a97-8a0c-4988-9473-452326110dff}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\huffman">
<UniqueIdentifier>{87256d6a-e658-4f60-8759-6bff32a35eb2}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt">
<UniqueIdentifier>{d730d7c1-2960-49d2-ba0d-d1a91dd08964}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\hashes">
<UniqueIdentifier>{13e5ccb1-06f1-4d10-bdc1-825b51c64dbf}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\math">
<UniqueIdentifier>{73f7f025-7366-4d76-8d60-4327e00b9d18}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\misc">
<UniqueIdentifier>{be21c641-7727-4d7b-919e-c895d801db17}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk">
<UniqueIdentifier>{694a7758-f909-4b8e-aa13-4d06a8c70eff}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\asn1">
<UniqueIdentifier>{3f01cae6-5676-4f33-bb38-215341eedfc4}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\ecc">
<UniqueIdentifier>{63d75851-c430-4c76-aa08-3398523aab4a}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\pkcs1">
<UniqueIdentifier>{11175e9e-e9f1-405c-961b-933e72503cdd}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\rsa">
<UniqueIdentifier>{e30512f4-bdf8-4460-823d-475bd8f08d28}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtommath">
<UniqueIdentifier>{d2889ef6-3f12-4a9b-8624-8d061748ff03}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\lzma">
<UniqueIdentifier>{02c6dfb8-4a58-46c5-bb35-69ba6215a3a6}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\pklib">
<UniqueIdentifier>{563829a0-aaa3-4af2-88a2-8c6445d2754b}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\sparse">
<UniqueIdentifier>{e82b0d03-77ff-46dc-b5a4-5b469224222a}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\zlib">
<UniqueIdentifier>{cb92df18-9435-4db9-997a-e0e7d532cd26}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\jenkins">
<UniqueIdentifier>{2920175c-439c-4fd5-b94e-8cf1d3aaadd3}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="doc\History.txt">
<Filter>Doc Files</Filter>
</Text>
<Text Include="doc\The MoPaQ File Format 0.9.txt">
<Filter>Doc Files</Filter>
</Text>
<Text Include="doc\The MoPaQ File Format 1.0.txt">
<Filter>Doc Files</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\StormCommon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\adpcm\adpcm.h">
<Filter>Source Files\adpcm</Filter>
</ClInclude>
<ClInclude Include="src\huffman\huff.h">
<Filter>Source Files\huffman</Filter>
</ClInclude>
<ClInclude Include="src\pklib\pklib.h">
<Filter>Source Files\pklib</Filter>
</ClInclude>
<ClInclude Include="src\sparse\sparse.h">
<Filter>Source Files\sparse</Filter>
</ClInclude>
<ClInclude Include="src\jenkins\lookup.h">
<Filter>Source Files\jenkins</Filter>
</ClInclude>
<ClInclude Include="src\StormLib.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\StormPort.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\FileStream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseCommon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseFileTable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SCompression.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileAddFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileAttributes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileCompactArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileCreateArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileExtractFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileFindFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileGetFileInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileListFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileOpenArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileOpenFileEx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFilePatchArchives.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileReadFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileVerify.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\adpcm\adpcm.cpp">
<Filter>Source Files\adpcm</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\blocksort.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\bzlib.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\compress.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\crctable.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\decompress.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\huffman.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\randtable.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\huffman\huff.cpp">
<Filter>Source Files\huffman</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\hash_memory.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\md5.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\sha1.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\ltm_desc.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\multi.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\rand_prime.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\base64_decode.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_argchk.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_hash.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_prng.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_is_valid.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_libc.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_ltc_mp_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_is_valid.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_hash.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_prng.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\zeromem.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_choice.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_ex.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_flexi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_multi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_sequence.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_sequence_free.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_map.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mul2add.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mulmod.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_points.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_add_point.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_dbl_point.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_mgf1.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_oaep_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_exptmod.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_free.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_import.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_make_key.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_hash.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_simple.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_mp_invmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_mp_montgomery_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_high_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_2expt.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_abs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_add.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_add_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_addmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_and.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clamp.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clear.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clear_multi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp_mag.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cnt_lsb.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_copy.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_count_bits.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_2.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_3.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_is_modulus.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exch.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_expt_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exptmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exptmod_fast.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exteuclid.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_fread.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_fwrite.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_gcd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_get_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_grow.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_copy.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_multi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_set.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_set_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_invmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_invmod_slow.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_is_square.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_jacobi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_karatsuba_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_karatsuba_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_lcm.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_lshd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_calc_normalization.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_2.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mulmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_n_root.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_neg.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_or.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_fermat.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_is_divisible.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_is_prime.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_miller_rabin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_next_prime.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_rabin_miller_trials.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_random_ex.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_radix_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_radix_smap.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_rand.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_radix.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_signed_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_unsigned_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_rshd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_set.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_set_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_shrink.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_signed_bin_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqrmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqrt.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sub.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sub_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_submod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toom_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toom_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toradix.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toradix_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_unsigned_bin_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_xor.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_zero.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_prime_tab.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_reverse.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_add.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_exptmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_mul_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_mul_high_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_sub.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bncore.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzFind.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzFindMt.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzmaDec.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzmaEnc.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\Threads.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\pklib\explode.c">
<Filter>Source Files\pklib</Filter>
</ClCompile>
<ClCompile Include="src\pklib\implode.c">
<Filter>Source Files\pklib</Filter>
</ClCompile>
<ClCompile Include="src\sparse\sparse.cpp">
<Filter>Source Files\sparse</Filter>
</ClCompile>
<ClCompile Include="src\zlib\adler32.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\crc32.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\deflate.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inffast.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inflate.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inftrees.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\trees.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\zutil.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\jenkins\lookup3.c">
<Filter>Source Files\jenkins</Filter>
</ClCompile>
<ClCompile Include="src\zlib\compress_zlib.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\SBaseSubTypes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_ex.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_multi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_set.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_setof.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_encode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_encode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_sign_hash.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,537 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>StormLib_dll</ProjectName>
<ProjectGuid>{CB385198-50B1-4CF4-883B-11F042DED6AA}</ProjectGuid>
<RootNamespace>StormLib_dll</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.25431.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</OutDir>
<IntDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>StormLib</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</OutDir>
<IntDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>StormLib</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</OutDir>
<IntDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>StormLib</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</OutDir>
<IntDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>StormLib</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level1</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<OutputFile>$(OutDir)StormLib.dll</OutputFile>
<ModuleDefinitionFile>.\src\DllMain.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level1</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<OutputFile>$(OutDir)StormLib.dll</OutputFile>
<ModuleDefinitionFile>.\src\DllMain.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level1</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<OutputFile>$(OutDir)StormLib.dll</OutputFile>
<ModuleDefinitionFile>.\src\DllMain.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level1</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<OutputFile>$(OutDir)StormLib.dll</OutputFile>
<ModuleDefinitionFile>.\src\DllMain.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="doc\History.txt" />
<Text Include="doc\The MoPaQ File Format 0.9.txt" />
<Text Include="doc\The MoPaQ File Format 1.0.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\adpcm\adpcm.h" />
<ClInclude Include="src\huffman\huff.h" />
<ClInclude Include="src\jenkins\lookup.h" />
<ClInclude Include="src\pklib\pklib.h" />
<ClInclude Include="src\sparse\sparse.h" />
<ClInclude Include="src\StormCommon.h" />
<ClInclude Include="src\StormLib.h" />
<ClInclude Include="src\StormPort.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\adpcm\adpcm.cpp" />
<ClCompile Include="src\bzip2\blocksort.c" />
<ClCompile Include="src\bzip2\bzlib.c" />
<ClCompile Include="src\bzip2\compress.c" />
<ClCompile Include="src\bzip2\crctable.c" />
<ClCompile Include="src\bzip2\decompress.c" />
<ClCompile Include="src\bzip2\huffman.c" />
<ClCompile Include="src\bzip2\randtable.c" />
<ClCompile Include="src\FileStream.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\huffman\huff.cpp" />
<ClCompile Include="src\jenkins\lookup3.c" />
<ClCompile Include="src\libtomcrypt\src\hashes\hash_memory.c" />
<ClCompile Include="src\libtomcrypt\src\hashes\md5.c" />
<ClCompile Include="src\libtomcrypt\src\hashes\sha1.c" />
<ClCompile Include="src\libtomcrypt\src\math\ltm_desc.c" />
<ClCompile Include="src\libtomcrypt\src\math\multi.c" />
<ClCompile Include="src\libtomcrypt\src\math\rand_prime.c" />
<ClCompile Include="src\libtomcrypt\src\misc\base64_decode.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_argchk.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_hash.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_prng.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_descriptor.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_is_valid.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_libc.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_ltc_mp_descriptor.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_descriptor.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_is_valid.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_hash.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_prng.c" />
<ClCompile Include="src\libtomcrypt\src\misc\zeromem.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_bit_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_boolean.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_choice.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_ia5_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_object_identifier.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_octet_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_printable_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_ex.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_flexi.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_multi.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_short_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utctime.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utf8_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_bit_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_boolean.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_ia5_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_object_identifier.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_octet_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_printable_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_ex.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_multi.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_set.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_setof.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_short_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utctime.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utf8_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_bit_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_boolean.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_ia5_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_object_identifier.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_octet_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_printable_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_sequence.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_short_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utctime.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utf8_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_sequence_free.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_map.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mul2add.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mulmod.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_points.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_add_point.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_dbl_point.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_mgf1.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_oaep_decode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_decode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_encode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_decode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_encode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_exptmod.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_free.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_import.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_make_key.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_sign_hash.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_hash.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_simple.c" />
<ClCompile Include="src\libtommath\bncore.c" />
<ClCompile Include="src\libtommath\bn_fast_mp_invmod.c" />
<ClCompile Include="src\libtommath\bn_fast_mp_montgomery_reduce.c" />
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_digs.c" />
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_high_digs.c" />
<ClCompile Include="src\libtommath\bn_fast_s_mp_sqr.c" />
<ClCompile Include="src\libtommath\bn_mp_2expt.c" />
<ClCompile Include="src\libtommath\bn_mp_abs.c" />
<ClCompile Include="src\libtommath\bn_mp_add.c" />
<ClCompile Include="src\libtommath\bn_mp_addmod.c" />
<ClCompile Include="src\libtommath\bn_mp_add_d.c" />
<ClCompile Include="src\libtommath\bn_mp_and.c" />
<ClCompile Include="src\libtommath\bn_mp_clamp.c" />
<ClCompile Include="src\libtommath\bn_mp_clear.c" />
<ClCompile Include="src\libtommath\bn_mp_clear_multi.c" />
<ClCompile Include="src\libtommath\bn_mp_cmp.c" />
<ClCompile Include="src\libtommath\bn_mp_cmp_d.c" />
<ClCompile Include="src\libtommath\bn_mp_cmp_mag.c" />
<ClCompile Include="src\libtommath\bn_mp_cnt_lsb.c" />
<ClCompile Include="src\libtommath\bn_mp_copy.c" />
<ClCompile Include="src\libtommath\bn_mp_count_bits.c" />
<ClCompile Include="src\libtommath\bn_mp_div.c" />
<ClCompile Include="src\libtommath\bn_mp_div_2.c" />
<ClCompile Include="src\libtommath\bn_mp_div_2d.c" />
<ClCompile Include="src\libtommath\bn_mp_div_3.c" />
<ClCompile Include="src\libtommath\bn_mp_div_d.c" />
<ClCompile Include="src\libtommath\bn_mp_dr_is_modulus.c" />
<ClCompile Include="src\libtommath\bn_mp_dr_reduce.c" />
<ClCompile Include="src\libtommath\bn_mp_dr_setup.c" />
<ClCompile Include="src\libtommath\bn_mp_exch.c" />
<ClCompile Include="src\libtommath\bn_mp_exptmod.c" />
<ClCompile Include="src\libtommath\bn_mp_exptmod_fast.c" />
<ClCompile Include="src\libtommath\bn_mp_expt_d.c" />
<ClCompile Include="src\libtommath\bn_mp_exteuclid.c" />
<ClCompile Include="src\libtommath\bn_mp_fread.c" />
<ClCompile Include="src\libtommath\bn_mp_fwrite.c" />
<ClCompile Include="src\libtommath\bn_mp_gcd.c" />
<ClCompile Include="src\libtommath\bn_mp_get_int.c" />
<ClCompile Include="src\libtommath\bn_mp_grow.c" />
<ClCompile Include="src\libtommath\bn_mp_init.c" />
<ClCompile Include="src\libtommath\bn_mp_init_copy.c" />
<ClCompile Include="src\libtommath\bn_mp_init_multi.c" />
<ClCompile Include="src\libtommath\bn_mp_init_set.c" />
<ClCompile Include="src\libtommath\bn_mp_init_set_int.c" />
<ClCompile Include="src\libtommath\bn_mp_init_size.c" />
<ClCompile Include="src\libtommath\bn_mp_invmod.c" />
<ClCompile Include="src\libtommath\bn_mp_invmod_slow.c" />
<ClCompile Include="src\libtommath\bn_mp_is_square.c" />
<ClCompile Include="src\libtommath\bn_mp_jacobi.c" />
<ClCompile Include="src\libtommath\bn_mp_karatsuba_mul.c" />
<ClCompile Include="src\libtommath\bn_mp_karatsuba_sqr.c" />
<ClCompile Include="src\libtommath\bn_mp_lcm.c" />
<ClCompile Include="src\libtommath\bn_mp_lshd.c" />
<ClCompile Include="src\libtommath\bn_mp_mod.c" />
<ClCompile Include="src\libtommath\bn_mp_mod_2d.c" />
<ClCompile Include="src\libtommath\bn_mp_mod_d.c" />
<ClCompile Include="src\libtommath\bn_mp_montgomery_calc_normalization.c" />
<ClCompile Include="src\libtommath\bn_mp_montgomery_reduce.c" />
<ClCompile Include="src\libtommath\bn_mp_montgomery_setup.c" />
<ClCompile Include="src\libtommath\bn_mp_mul.c" />
<ClCompile Include="src\libtommath\bn_mp_mulmod.c" />
<ClCompile Include="src\libtommath\bn_mp_mul_2.c" />
<ClCompile Include="src\libtommath\bn_mp_mul_2d.c" />
<ClCompile Include="src\libtommath\bn_mp_mul_d.c" />
<ClCompile Include="src\libtommath\bn_mp_neg.c" />
<ClCompile Include="src\libtommath\bn_mp_n_root.c" />
<ClCompile Include="src\libtommath\bn_mp_or.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_fermat.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_is_divisible.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_is_prime.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_miller_rabin.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_next_prime.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_rabin_miller_trials.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_random_ex.c" />
<ClCompile Include="src\libtommath\bn_mp_radix_size.c" />
<ClCompile Include="src\libtommath\bn_mp_radix_smap.c" />
<ClCompile Include="src\libtommath\bn_mp_rand.c" />
<ClCompile Include="src\libtommath\bn_mp_read_radix.c" />
<ClCompile Include="src\libtommath\bn_mp_read_signed_bin.c" />
<ClCompile Include="src\libtommath\bn_mp_read_unsigned_bin.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_2k.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_l.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup_l.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k_l.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_setup.c" />
<ClCompile Include="src\libtommath\bn_mp_rshd.c" />
<ClCompile Include="src\libtommath\bn_mp_set.c" />
<ClCompile Include="src\libtommath\bn_mp_set_int.c" />
<ClCompile Include="src\libtommath\bn_mp_shrink.c" />
<ClCompile Include="src\libtommath\bn_mp_signed_bin_size.c" />
<ClCompile Include="src\libtommath\bn_mp_sqr.c" />
<ClCompile Include="src\libtommath\bn_mp_sqrmod.c" />
<ClCompile Include="src\libtommath\bn_mp_sqrt.c" />
<ClCompile Include="src\libtommath\bn_mp_sub.c" />
<ClCompile Include="src\libtommath\bn_mp_submod.c" />
<ClCompile Include="src\libtommath\bn_mp_sub_d.c" />
<ClCompile Include="src\libtommath\bn_mp_toom_mul.c" />
<ClCompile Include="src\libtommath\bn_mp_toom_sqr.c" />
<ClCompile Include="src\libtommath\bn_mp_toradix.c" />
<ClCompile Include="src\libtommath\bn_mp_toradix_n.c" />
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin.c" />
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin_n.c" />
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin.c" />
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin_n.c" />
<ClCompile Include="src\libtommath\bn_mp_unsigned_bin_size.c" />
<ClCompile Include="src\libtommath\bn_mp_xor.c" />
<ClCompile Include="src\libtommath\bn_mp_zero.c" />
<ClCompile Include="src\libtommath\bn_prime_tab.c" />
<ClCompile Include="src\libtommath\bn_reverse.c" />
<ClCompile Include="src\libtommath\bn_s_mp_add.c" />
<ClCompile Include="src\libtommath\bn_s_mp_exptmod.c" />
<ClCompile Include="src\libtommath\bn_s_mp_mul_digs.c" />
<ClCompile Include="src\libtommath\bn_s_mp_mul_high_digs.c" />
<ClCompile Include="src\libtommath\bn_s_mp_sqr.c" />
<ClCompile Include="src\libtommath\bn_s_mp_sub.c" />
<ClCompile Include="src\lzma\C\LzFind.c" />
<ClCompile Include="src\lzma\C\LzFindMt.c" />
<ClCompile Include="src\lzma\C\LzmaDec.c" />
<ClCompile Include="src\lzma\C\LzmaEnc.c" />
<ClCompile Include="src\lzma\C\Threads.c" />
<ClCompile Include="src\pklib\explode.c" />
<ClCompile Include="src\pklib\implode.c" />
<ClCompile Include="src\SBaseCommon.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SBaseFileTable.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SBaseSubTypes.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SCompression.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileAddFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileAttributes.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileCompactArchive.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileCreateArchive.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileExtractFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileFindFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileGetFileInfo.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileListFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileOpenArchive.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileOpenFileEx.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFilePatchArchives.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileReadFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileVerify.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\sparse\sparse.cpp" />
<ClCompile Include="src\zlib\adler32.c" />
<ClCompile Include="src\zlib\compress_zlib.c" />
<ClCompile Include="src\zlib\crc32.c" />
<ClCompile Include="src\zlib\deflate.c" />
<ClCompile Include="src\zlib\inffast.c" />
<ClCompile Include="src\zlib\inflate.c" />
<ClCompile Include="src\zlib\inftrees.c" />
<ClCompile Include="src\zlib\trees.c" />
<ClCompile Include="src\zlib\zutil.c" />
<ClCompile Include="src\DllMain.c">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="src\DllMain.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,838 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Doc Files">
<UniqueIdentifier>{b352ea2c-4169-4b60-85bc-82eadd5a9d2e}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{9171b211-949a-4dc1-a028-edf0a2ed4605}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{712a20a0-c7a8-4e56-947b-2cf030bbb287}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\adpcm">
<UniqueIdentifier>{83502600-f49c-43b1-afe6-038d3560a859}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\bzip2">
<UniqueIdentifier>{ea8b08a3-5c21-48e0-b75f-78eaa2adbc22}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\huffman">
<UniqueIdentifier>{593ac5e7-fe06-42b8-8025-e3bd725f95d8}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt">
<UniqueIdentifier>{9887a885-78fa-4164-80b9-9db6b0c11f86}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\hashes">
<UniqueIdentifier>{7db62947-d38d-48e9-8b52-4cad226394a6}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\math">
<UniqueIdentifier>{b435fecf-9a65-4f2e-8d64-7dfc70de3137}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\misc">
<UniqueIdentifier>{d8ad7878-9e42-427a-b5b6-ae51d92b92cf}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk">
<UniqueIdentifier>{07806629-c061-49ed-8212-0585d25fae23}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\asn1">
<UniqueIdentifier>{ca554d9f-b602-452a-971e-86b537ee2ad1}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\ecc">
<UniqueIdentifier>{46e1697c-e6c2-4a8c-b4d2-0142311bb48b}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\pkcs1">
<UniqueIdentifier>{99279e07-2e33-44c9-8f37-0b810ee4ba25}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\rsa">
<UniqueIdentifier>{04fbcfe0-3023-4fa0-8e36-26ab024a4abf}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtommath">
<UniqueIdentifier>{4720c7a0-f4aa-4737-978c-9efe8b429906}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\lzma">
<UniqueIdentifier>{856c9964-4d85-40e9-8cbd-f4c672c07780}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\pklib">
<UniqueIdentifier>{7ad3c876-768a-45bc-85b1-38cd492814ea}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\sparse">
<UniqueIdentifier>{22e86a97-80e9-45a0-ac8e-70d7ea848f35}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\zlib">
<UniqueIdentifier>{7b2ea923-8454-4073-bb9c-85de0f66caa1}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\jenkins">
<UniqueIdentifier>{5404ec38-706a-47f8-97b7-941c2574ddf2}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="doc\History.txt">
<Filter>Doc Files</Filter>
</Text>
<Text Include="doc\The MoPaQ File Format 0.9.txt">
<Filter>Doc Files</Filter>
</Text>
<Text Include="doc\The MoPaQ File Format 1.0.txt">
<Filter>Doc Files</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\StormCommon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\StormLib.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\StormPort.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\adpcm\adpcm.h">
<Filter>Source Files\adpcm</Filter>
</ClInclude>
<ClInclude Include="src\huffman\huff.h">
<Filter>Source Files\huffman</Filter>
</ClInclude>
<ClInclude Include="src\pklib\pklib.h">
<Filter>Source Files\pklib</Filter>
</ClInclude>
<ClInclude Include="src\sparse\sparse.h">
<Filter>Source Files\sparse</Filter>
</ClInclude>
<ClInclude Include="src\jenkins\lookup.h">
<Filter>Source Files\jenkins</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\FileStream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseCommon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseFileTable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseSubTypes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SCompression.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileAddFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileAttributes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileCompactArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileCreateArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileExtractFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileFindFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileGetFileInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileListFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileOpenArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileOpenFileEx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFilePatchArchives.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileReadFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileVerify.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\adpcm\adpcm.cpp">
<Filter>Source Files\adpcm</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\blocksort.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\bzlib.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\compress.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\crctable.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\decompress.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\huffman.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\randtable.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\huffman\huff.cpp">
<Filter>Source Files\huffman</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\hash_memory.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\md5.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\sha1.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\ltm_desc.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\multi.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\rand_prime.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\base64_decode.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_argchk.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_hash.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_prng.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_is_valid.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_libc.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_ltc_mp_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_is_valid.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_hash.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_prng.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\zeromem.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_choice.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_ex.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_flexi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_multi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_ex.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_multi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_set.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_setof.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_sequence.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_sequence_free.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_map.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mul2add.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mulmod.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_points.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_add_point.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_dbl_point.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_mgf1.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_oaep_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_encode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_encode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_exptmod.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_free.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_import.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_make_key.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_sign_hash.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_hash.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_simple.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_mp_invmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_mp_montgomery_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_high_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_2expt.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_abs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_add.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_add_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_addmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_and.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clamp.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clear.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clear_multi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp_mag.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cnt_lsb.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_copy.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_count_bits.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_2.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_3.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_is_modulus.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exch.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_expt_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exptmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exptmod_fast.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exteuclid.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_fread.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_fwrite.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_gcd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_get_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_grow.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_copy.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_multi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_set.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_set_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_invmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_invmod_slow.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_is_square.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_jacobi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_karatsuba_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_karatsuba_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_lcm.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_lshd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_calc_normalization.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_2.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mulmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_n_root.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_neg.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_or.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_fermat.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_is_divisible.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_is_prime.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_miller_rabin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_next_prime.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_rabin_miller_trials.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_random_ex.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_radix_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_radix_smap.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_rand.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_radix.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_signed_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_unsigned_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_rshd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_set.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_set_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_shrink.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_signed_bin_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqrmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqrt.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sub.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sub_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_submod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toom_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toom_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toradix.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toradix_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_unsigned_bin_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_xor.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_zero.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_prime_tab.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_reverse.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_add.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_exptmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_mul_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_mul_high_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_sub.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bncore.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzFind.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzFindMt.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzmaDec.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzmaEnc.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\Threads.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\pklib\explode.c">
<Filter>Source Files\pklib</Filter>
</ClCompile>
<ClCompile Include="src\pklib\implode.c">
<Filter>Source Files\pklib</Filter>
</ClCompile>
<ClCompile Include="src\sparse\sparse.cpp">
<Filter>Source Files\sparse</Filter>
</ClCompile>
<ClCompile Include="src\zlib\adler32.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\compress_zlib.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\crc32.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\deflate.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inffast.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inflate.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inftrees.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\trees.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\zutil.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\jenkins\lookup3.c">
<Filter>Source Files\jenkins</Filter>
</ClCompile>
<ClCompile Include="src\DllMain.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="src\DllMain.rc">
<Filter>Source Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,549 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>StormLib_test</ProjectName>
<ProjectGuid>{AA561A7B-26EA-49AF-90E8-C53C1FA2965D}</ProjectGuid>
<RootNamespace>StormLib_test</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.25431.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</OutDir>
<IntDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</OutDir>
<IntDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</OutDir>
<IntDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</OutDir>
<IntDir>./bin/$(ProjectName)/$(Platform)/$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;__STORMLIB_TEST__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level1</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<CompileAs>Default</CompileAs>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;__STORMLIB_TEST__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level1</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;__STORMLIB_TEST__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level1</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;__STORMLIB_TEST__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level1</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="doc\History.txt" />
<Text Include="doc\The MoPaQ File Format 0.9.txt" />
<Text Include="doc\The MoPaQ File Format 1.0.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\adpcm\adpcm.h" />
<ClInclude Include="src\FileStream.h" />
<ClInclude Include="src\huffman\huff.h" />
<ClInclude Include="src\jenkins\lookup.h" />
<ClInclude Include="src\pklib\pklib.h" />
<ClInclude Include="src\sparse\sparse.h" />
<ClInclude Include="src\StormCommon.h" />
<ClInclude Include="src\StormLib.h" />
<ClInclude Include="src\StormPort.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\adpcm\adpcm.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\bzip2\blocksort.c" />
<ClCompile Include="src\bzip2\bzlib.c" />
<ClCompile Include="src\bzip2\compress.c" />
<ClCompile Include="src\bzip2\crctable.c" />
<ClCompile Include="src\bzip2\decompress.c" />
<ClCompile Include="src\bzip2\huffman.c" />
<ClCompile Include="src\bzip2\randtable.c" />
<ClCompile Include="src\FileStream.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\huffman\huff.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\jenkins\lookup3.c">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level1</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level1</WarningLevel>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\hash_memory.c" />
<ClCompile Include="src\libtomcrypt\src\hashes\md5.c" />
<ClCompile Include="src\libtomcrypt\src\hashes\sha1.c" />
<ClCompile Include="src\libtomcrypt\src\math\ltm_desc.c" />
<ClCompile Include="src\libtomcrypt\src\math\multi.c" />
<ClCompile Include="src\libtomcrypt\src\math\rand_prime.c" />
<ClCompile Include="src\libtomcrypt\src\misc\base64_decode.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_argchk.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_hash.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_prng.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_descriptor.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_is_valid.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_libc.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_ltc_mp_descriptor.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_descriptor.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_is_valid.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_hash.c" />
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_prng.c" />
<ClCompile Include="src\libtomcrypt\src\misc\zeromem.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_bit_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_boolean.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_choice.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_ia5_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_object_identifier.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_octet_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_printable_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_ex.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_flexi.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_multi.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_short_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utctime.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utf8_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_bit_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_boolean.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_ia5_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_object_identifier.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_octet_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_printable_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_ex.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_multi.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_set.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_setof.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_short_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utctime.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utf8_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_bit_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_boolean.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_ia5_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_object_identifier.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_octet_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_printable_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_sequence.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_short_integer.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utctime.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utf8_string.c" />
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_sequence_free.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_map.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mul2add.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mulmod.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_points.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_add_point.c" />
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_dbl_point.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_mgf1.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_oaep_decode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_decode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_encode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_decode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_encode.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_exptmod.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_free.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_import.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_make_key.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_sign_hash.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_hash.c" />
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_simple.c" />
<ClCompile Include="src\libtommath\bncore.c" />
<ClCompile Include="src\libtommath\bn_fast_mp_invmod.c" />
<ClCompile Include="src\libtommath\bn_fast_mp_montgomery_reduce.c" />
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_digs.c" />
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_high_digs.c" />
<ClCompile Include="src\libtommath\bn_fast_s_mp_sqr.c" />
<ClCompile Include="src\libtommath\bn_mp_2expt.c" />
<ClCompile Include="src\libtommath\bn_mp_abs.c" />
<ClCompile Include="src\libtommath\bn_mp_add.c" />
<ClCompile Include="src\libtommath\bn_mp_addmod.c" />
<ClCompile Include="src\libtommath\bn_mp_add_d.c" />
<ClCompile Include="src\libtommath\bn_mp_and.c" />
<ClCompile Include="src\libtommath\bn_mp_clamp.c" />
<ClCompile Include="src\libtommath\bn_mp_clear.c" />
<ClCompile Include="src\libtommath\bn_mp_clear_multi.c" />
<ClCompile Include="src\libtommath\bn_mp_cmp.c" />
<ClCompile Include="src\libtommath\bn_mp_cmp_d.c" />
<ClCompile Include="src\libtommath\bn_mp_cmp_mag.c" />
<ClCompile Include="src\libtommath\bn_mp_cnt_lsb.c" />
<ClCompile Include="src\libtommath\bn_mp_copy.c" />
<ClCompile Include="src\libtommath\bn_mp_count_bits.c" />
<ClCompile Include="src\libtommath\bn_mp_div.c" />
<ClCompile Include="src\libtommath\bn_mp_div_2.c" />
<ClCompile Include="src\libtommath\bn_mp_div_2d.c" />
<ClCompile Include="src\libtommath\bn_mp_div_3.c" />
<ClCompile Include="src\libtommath\bn_mp_div_d.c" />
<ClCompile Include="src\libtommath\bn_mp_dr_is_modulus.c" />
<ClCompile Include="src\libtommath\bn_mp_dr_reduce.c" />
<ClCompile Include="src\libtommath\bn_mp_dr_setup.c" />
<ClCompile Include="src\libtommath\bn_mp_exch.c" />
<ClCompile Include="src\libtommath\bn_mp_exptmod.c" />
<ClCompile Include="src\libtommath\bn_mp_exptmod_fast.c" />
<ClCompile Include="src\libtommath\bn_mp_expt_d.c" />
<ClCompile Include="src\libtommath\bn_mp_exteuclid.c" />
<ClCompile Include="src\libtommath\bn_mp_fread.c" />
<ClCompile Include="src\libtommath\bn_mp_fwrite.c" />
<ClCompile Include="src\libtommath\bn_mp_gcd.c" />
<ClCompile Include="src\libtommath\bn_mp_get_int.c" />
<ClCompile Include="src\libtommath\bn_mp_grow.c" />
<ClCompile Include="src\libtommath\bn_mp_init.c" />
<ClCompile Include="src\libtommath\bn_mp_init_copy.c" />
<ClCompile Include="src\libtommath\bn_mp_init_multi.c" />
<ClCompile Include="src\libtommath\bn_mp_init_set.c" />
<ClCompile Include="src\libtommath\bn_mp_init_set_int.c" />
<ClCompile Include="src\libtommath\bn_mp_init_size.c" />
<ClCompile Include="src\libtommath\bn_mp_invmod.c" />
<ClCompile Include="src\libtommath\bn_mp_invmod_slow.c" />
<ClCompile Include="src\libtommath\bn_mp_is_square.c" />
<ClCompile Include="src\libtommath\bn_mp_jacobi.c" />
<ClCompile Include="src\libtommath\bn_mp_karatsuba_mul.c" />
<ClCompile Include="src\libtommath\bn_mp_karatsuba_sqr.c" />
<ClCompile Include="src\libtommath\bn_mp_lcm.c" />
<ClCompile Include="src\libtommath\bn_mp_lshd.c" />
<ClCompile Include="src\libtommath\bn_mp_mod.c" />
<ClCompile Include="src\libtommath\bn_mp_mod_2d.c" />
<ClCompile Include="src\libtommath\bn_mp_mod_d.c" />
<ClCompile Include="src\libtommath\bn_mp_montgomery_calc_normalization.c" />
<ClCompile Include="src\libtommath\bn_mp_montgomery_reduce.c" />
<ClCompile Include="src\libtommath\bn_mp_montgomery_setup.c" />
<ClCompile Include="src\libtommath\bn_mp_mul.c" />
<ClCompile Include="src\libtommath\bn_mp_mulmod.c" />
<ClCompile Include="src\libtommath\bn_mp_mul_2.c" />
<ClCompile Include="src\libtommath\bn_mp_mul_2d.c" />
<ClCompile Include="src\libtommath\bn_mp_mul_d.c" />
<ClCompile Include="src\libtommath\bn_mp_neg.c" />
<ClCompile Include="src\libtommath\bn_mp_n_root.c" />
<ClCompile Include="src\libtommath\bn_mp_or.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_fermat.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_is_divisible.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_is_prime.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_miller_rabin.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_next_prime.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_rabin_miller_trials.c" />
<ClCompile Include="src\libtommath\bn_mp_prime_random_ex.c" />
<ClCompile Include="src\libtommath\bn_mp_radix_size.c" />
<ClCompile Include="src\libtommath\bn_mp_radix_smap.c" />
<ClCompile Include="src\libtommath\bn_mp_rand.c" />
<ClCompile Include="src\libtommath\bn_mp_read_radix.c" />
<ClCompile Include="src\libtommath\bn_mp_read_signed_bin.c" />
<ClCompile Include="src\libtommath\bn_mp_read_unsigned_bin.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_2k.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_l.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup_l.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k_l.c" />
<ClCompile Include="src\libtommath\bn_mp_reduce_setup.c" />
<ClCompile Include="src\libtommath\bn_mp_rshd.c" />
<ClCompile Include="src\libtommath\bn_mp_set.c" />
<ClCompile Include="src\libtommath\bn_mp_set_int.c" />
<ClCompile Include="src\libtommath\bn_mp_shrink.c" />
<ClCompile Include="src\libtommath\bn_mp_signed_bin_size.c" />
<ClCompile Include="src\libtommath\bn_mp_sqr.c" />
<ClCompile Include="src\libtommath\bn_mp_sqrmod.c" />
<ClCompile Include="src\libtommath\bn_mp_sqrt.c" />
<ClCompile Include="src\libtommath\bn_mp_sub.c" />
<ClCompile Include="src\libtommath\bn_mp_submod.c" />
<ClCompile Include="src\libtommath\bn_mp_sub_d.c" />
<ClCompile Include="src\libtommath\bn_mp_toom_mul.c" />
<ClCompile Include="src\libtommath\bn_mp_toom_sqr.c" />
<ClCompile Include="src\libtommath\bn_mp_toradix.c" />
<ClCompile Include="src\libtommath\bn_mp_toradix_n.c" />
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin.c" />
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin_n.c" />
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin.c" />
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin_n.c" />
<ClCompile Include="src\libtommath\bn_mp_unsigned_bin_size.c" />
<ClCompile Include="src\libtommath\bn_mp_xor.c" />
<ClCompile Include="src\libtommath\bn_mp_zero.c" />
<ClCompile Include="src\libtommath\bn_prime_tab.c" />
<ClCompile Include="src\libtommath\bn_reverse.c" />
<ClCompile Include="src\libtommath\bn_s_mp_add.c" />
<ClCompile Include="src\libtommath\bn_s_mp_exptmod.c" />
<ClCompile Include="src\libtommath\bn_s_mp_mul_digs.c" />
<ClCompile Include="src\libtommath\bn_s_mp_mul_high_digs.c" />
<ClCompile Include="src\libtommath\bn_s_mp_sqr.c" />
<ClCompile Include="src\libtommath\bn_s_mp_sub.c" />
<ClCompile Include="src\lzma\C\LzFind.c" />
<ClCompile Include="src\lzma\C\LzFindMt.c" />
<ClCompile Include="src\lzma\C\LzmaDec.c" />
<ClCompile Include="src\lzma\C\LzmaEnc.c" />
<ClCompile Include="src\lzma\C\Threads.c" />
<ClCompile Include="src\pklib\explode.c" />
<ClCompile Include="src\pklib\implode.c" />
<ClCompile Include="src\SBaseCommon.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SBaseDumpData.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SBaseFileTable.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SBaseSubTypes.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SCompression.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileAddFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileAttributes.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileCompactArchive.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileCreateArchive.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileExtractFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileFindFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileGetFileInfo.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileListFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileOpenArchive.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileOpenFileEx.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFilePatchArchives.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileReadFile.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\SFileVerify.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="src\sparse\sparse.cpp" />
<ClCompile Include="src\zlib\adler32.c" />
<ClCompile Include="src\zlib\compress_zlib.c" />
<ClCompile Include="src\zlib\crc32.c" />
<ClCompile Include="src\zlib\deflate.c" />
<ClCompile Include="src\zlib\inffast.c" />
<ClCompile Include="src\zlib\inflate.c" />
<ClCompile Include="src\zlib\inftrees.c" />
<ClCompile Include="src\zlib\trees.c" />
<ClCompile Include="src\zlib\zutil.c" />
<ClCompile Include="test\StormTest.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level4</WarningLevel>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

View File

@ -0,0 +1,839 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Doc Files">
<UniqueIdentifier>{1dbbb48c-9db9-4fdb-a903-223ed233cc21}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{ab878eef-1074-4594-bac5-272c05774bd8}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{640f063a-5028-4ba1-9007-96d98a634561}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\adpcm">
<UniqueIdentifier>{6e8cfdab-fca3-4737-8905-6154bc657e15}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\bzip2">
<UniqueIdentifier>{a810fdb6-0d21-4279-8e39-b2de644170c0}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\huffman">
<UniqueIdentifier>{7861b4fb-1471-4573-92ea-08c06dc14b93}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt">
<UniqueIdentifier>{8ba6c5c7-3ad0-44e6-8829-5020fce13d49}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\hashes">
<UniqueIdentifier>{92cb0c1d-86f0-4735-9e4e-b07df664c359}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\math">
<UniqueIdentifier>{f7fb3d55-94af-4a6e-be7b-76cb909e7325}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\misc">
<UniqueIdentifier>{337159fe-94a7-45a8-a91b-fa8b9d06b2ae}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk">
<UniqueIdentifier>{359bb3d3-71d5-47e7-967a-1fada7882e4d}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\asn1">
<UniqueIdentifier>{775dbb7e-ef06-4660-9d84-50ff2557ef54}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\ecc">
<UniqueIdentifier>{2e5d39cc-482c-4775-8830-79f8314e72e4}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\pkcs1">
<UniqueIdentifier>{1e0ef267-228e-4c59-8d88-e3b33aeaff49}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtomcrypt\pk\rsa">
<UniqueIdentifier>{98330deb-0b92-4f02-8016-8a33dc5f5d29}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\libtommath">
<UniqueIdentifier>{fa78c716-784a-43a0-a548-db413431973b}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\lzma">
<UniqueIdentifier>{5308566b-d3fd-4561-a7fb-982a63662793}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\pklib">
<UniqueIdentifier>{d5371a5f-1630-4e79-9e7e-1ef654a2ddec}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\sparse">
<UniqueIdentifier>{c2971fba-aff1-42ab-9f4f-71707edabf77}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\zlib">
<UniqueIdentifier>{4f4fe3d6-6f2b-4c83-9cf9-f1d108ecd854}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\jenkins">
<UniqueIdentifier>{5aaea51e-4b7c-4a35-b35c-96c2fc7750f1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="doc\History.txt">
<Filter>Doc Files</Filter>
</Text>
<Text Include="doc\The MoPaQ File Format 0.9.txt">
<Filter>Doc Files</Filter>
</Text>
<Text Include="doc\The MoPaQ File Format 1.0.txt">
<Filter>Doc Files</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\FileStream.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\StormCommon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\StormLib.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\StormPort.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\adpcm\adpcm.h">
<Filter>Source Files\adpcm</Filter>
</ClInclude>
<ClInclude Include="src\huffman\huff.h">
<Filter>Source Files\huffman</Filter>
</ClInclude>
<ClInclude Include="src\pklib\pklib.h">
<Filter>Source Files\pklib</Filter>
</ClInclude>
<ClInclude Include="src\sparse\sparse.h">
<Filter>Source Files\sparse</Filter>
</ClInclude>
<ClInclude Include="src\jenkins\lookup.h">
<Filter>Source Files\jenkins</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\FileStream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseCommon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseDumpData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseFileTable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SBaseSubTypes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SCompression.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileAddFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileAttributes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileCompactArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileCreateArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileExtractFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileFindFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileGetFileInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileListFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileOpenArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileOpenFileEx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFilePatchArchives.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileReadFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SFileVerify.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="test\StormTest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\adpcm\adpcm.cpp">
<Filter>Source Files\adpcm</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\blocksort.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\bzlib.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\compress.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\crctable.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\decompress.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\huffman.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\bzip2\randtable.c">
<Filter>Source Files\bzip2</Filter>
</ClCompile>
<ClCompile Include="src\huffman\huff.cpp">
<Filter>Source Files\huffman</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\hash_memory.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\md5.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\hashes\sha1.c">
<Filter>Source Files\libtomcrypt\hashes</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\ltm_desc.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\multi.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\math\rand_prime.c">
<Filter>Source Files\libtomcrypt\math</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\base64_decode.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_argchk.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_hash.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_find_prng.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_hash_is_valid.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_libc.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_ltc_mp_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_descriptor.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_prng_is_valid.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_hash.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\crypt_register_prng.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\misc\zeromem.c">
<Filter>Source Files\libtomcrypt\misc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_choice.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_ex.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_flexi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_sequence_multi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_decode_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_ex.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_sequence_multi.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_set.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_setof.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_encode_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_bit_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_boolean.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_ia5_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_object_identifier.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_octet_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_printable_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_sequence.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_short_integer.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utctime.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_length_utf8_string.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\asn1\der_sequence_free.c">
<Filter>Source Files\libtomcrypt\pk\asn1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_map.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mul2add.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_mulmod.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_points.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_add_point.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\ecc\ltc_ecc_projective_dbl_point.c">
<Filter>Source Files\libtomcrypt\pk\ecc</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_mgf1.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_oaep_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_pss_encode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_decode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\pkcs1\pkcs_1_v1_5_encode.c">
<Filter>Source Files\libtomcrypt\pk\pkcs1</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_exptmod.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_free.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_import.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_make_key.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_sign_hash.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_hash.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtomcrypt\src\pk\rsa\rsa_verify_simple.c">
<Filter>Source Files\libtomcrypt\pk\rsa</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_mp_invmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_mp_montgomery_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_mul_high_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_fast_s_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_2expt.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_abs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_add.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_add_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_addmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_and.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clamp.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clear.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_clear_multi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cmp_mag.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_cnt_lsb.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_copy.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_count_bits.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_2.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_3.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_div_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_is_modulus.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_dr_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exch.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_expt_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exptmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exptmod_fast.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_exteuclid.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_fread.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_fwrite.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_gcd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_get_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_grow.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_copy.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_multi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_set.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_set_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_init_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_invmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_invmod_slow.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_is_square.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_jacobi.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_karatsuba_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_karatsuba_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_lcm.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_lshd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mod_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_calc_normalization.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_montgomery_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_2.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_2d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mul_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_mulmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_n_root.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_neg.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_or.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_fermat.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_is_divisible.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_is_prime.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_miller_rabin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_next_prime.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_rabin_miller_trials.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_prime_random_ex.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_radix_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_radix_smap.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_rand.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_radix.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_signed_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_read_unsigned_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_2k_setup_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_is_2k_l.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_reduce_setup.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_rshd.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_set.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_set_int.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_shrink.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_signed_bin_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqrmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sqrt.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sub.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_sub_d.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_submod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_signed_bin_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_to_unsigned_bin_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toom_mul.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toom_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toradix.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_toradix_n.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_unsigned_bin_size.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_xor.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_mp_zero.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_prime_tab.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_reverse.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_add.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_exptmod.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_mul_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_mul_high_digs.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_sqr.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bn_s_mp_sub.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\libtommath\bncore.c">
<Filter>Source Files\libtommath</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzFind.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzFindMt.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzmaDec.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\LzmaEnc.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\lzma\C\Threads.c">
<Filter>Source Files\lzma</Filter>
</ClCompile>
<ClCompile Include="src\pklib\explode.c">
<Filter>Source Files\pklib</Filter>
</ClCompile>
<ClCompile Include="src\pklib\implode.c">
<Filter>Source Files\pklib</Filter>
</ClCompile>
<ClCompile Include="src\sparse\sparse.cpp">
<Filter>Source Files\sparse</Filter>
</ClCompile>
<ClCompile Include="src\zlib\adler32.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\compress_zlib.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\crc32.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\deflate.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inffast.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inflate.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\inftrees.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\trees.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\zlib\zutil.c">
<Filter>Source Files\zlib</Filter>
</ClCompile>
<ClCompile Include="src\jenkins\lookup3.c">
<Filter>Source Files\jenkins</Filter>
</ClCompile>
</ItemGroup>
</Project>

78
StormLib/doc/History.txt Normal file
View File

@ -0,0 +1,78 @@
StormLib history
================
Version 9.11
- Fixed bug in processing HET table.
Version 9.10
- Support for weak-signing
- Anti-protector: New Spazzler
Version 9.00
- Support for streaming (master-mirror)
- Support for multi-file MPQs used by some WoW versions
- Opening maps protected by Spazzler protector
- Opening maps protected by BOBA protector
Version 8.02
- Support for UNICODE encoding for on-disk files
- Optimized file deleting
Version 8.01
- SFileFindFirstFile and SFileFindNextFile no longer find files that have
patch file in the oldest MPQ in the patch chain
- Write support for MPQs version 4
Version 8.00
- Updated support for protected maps from Warcraft III
Version 7.11
- Support for MPQs v 3.0 (WOW-Cataclysm BETA)
- StormLib now deals properly with files that have MPQ_SECTOR_CHECKSUM missing,
but have sector checksum entry present in the sector offset table
Version 7.10
- Support for partial MPQs ("interface.MPQ.part")
- The only operation that is externally allowed to do with internal files
("(listfile)", "(attributes)" and "(signature)") is reading. Attempt to modify any of the file
fails and GetLastError returns ERROR_INTERNAL_FILE
- Fixed memory leak that has occured when writing more than one sector to the file at once
Version 7.01
- Support for adding files from memory
- Fixed improper validation of handles to MPQ file and MPQ archive
- Fixed bug where StormLib didn't save CRC32 of the file when added to archive
Version 7.00
- Properly deals with MPQs protected by w3xMaster
- Major rewrite
- Fixed support for (attributes)
- Added file verification
- Added MPQ signature verification
Version 6.22
- Properly deals with MPQs protected by w3xMaster
Version 6.21
- SFileRenameFile now properly re-crypts the file if necessary.
- SFileFindFirstFile correctly deals with deleted files
Version 6.20
- Fixed lots of bugs when processing files with same names but different locales
- Fixed bugs when repeately extracts the same file with MPQ_FILE_SINGLE_UNIT flag
- Added SFileFlushArchive
- Fixed issue opening AVI files renamed to MPQ using SFileCreateArchiveEx

View File

@ -0,0 +1,318 @@
THE MOPAQ ARCHIVE FORMAT
v0.9 (Thursday, June 30, 2005)
by Justin Olbrantz(Quantam)
Distribution and reproduction of this specification are allowed without limitation, as long as it is not altered. Quoting
in other works is freely allowed, as long as the source and author of the quote is stated.
TABLE OF CONTENTS
1. Introduction to the MoPaQ Format
2. The MoPaQ Format
2.1 General Archive Layout
2.2 Archive Header
2.3 Block Table
2.4 Hash Table
2.5 File Data
2.6 Listfile
2.7 Extended Attributes
2.8 Weak (Old) Digital Signature
2.9 Strong (New) Digital Signature
3. Algorithm Source Code
3.1 Encryption/Decryption
3.2 Hashing
3.3 Conversion of FILETIME and time_t
1. INTRODUCTION TO THE MOPAQ FORMAT
The MoPaQ (or MPQ) format is an archive file format designed by Mike O'Brien (hence the name Mike O'brien PaCK) at Blizzard
Entertainment. The format has been used in all Blizzard games since (and including) Diablo. It is heavily optimized to be
a read-only game archive format, and excels at this role.
The Blizzard MoPaQ-reading functions are contained in the Storm module, which my be either statically or dynamically linked.
The Blizzard MoPaQ-writing functions are contained in the MPQAPI module, which is always statically linked.
2. THE MOPAQ FORMAT
All numbers in the MoPaQ format are in little endian. Data types are listed either as int (integer, the number of bits specified),
byte (8 bits), and char (bytes which contain ASCII characters). All sizes and offsets are in bytes, unless specified otherwise.
Structure members are listed in the following general form:
offset from the beginning of the structure: data type(array size) member name : member description
2.1 GENERAL ARCHIVE LAYOUT
- Archive Header
- File Data
- File Data - Special Files
- Hash Table
- Block Table
- Strong Digital signature
This is the usual archive format, and is not absolutely essential. Some archives have been observed placing the hash table
and file table after the archive header, and before the file data.
2.2 ARCHIVE HEADER
00h: char(4) Magic : Indicates that the file is a MoPaQ archive. Must be ASCII "MPQ" 1Ah.
04h: int32 HeaderSize : Size of the archive header. Should be 32.
08h: int32 ArchiveSize : Size of the whole archive, including the header. Does not include the strong digital signature, if present.
This size is used, among other things, for determining the region to hash in computing the digital signature.
0Ch: int16 Unknown : Unknown
0Eh: int8 SectorSizeShift : 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 the archive is 512 * 2^SectorSizeShift. Bugs in the Storm library dictate
that this should always be 3 (4096 byte sectors).
10h: int32 HashTableOffset : Offset to the beginning of the hash table, relative to the beginning of the archive.
14h: int32 BlockTableOffset : Offset to the beginning of the block table, relative to the beginning of the archive.
18h: int32 HashTableEntries : Number of entries in the hash table. Must be a power of two, and must be less than 2^16.
1Ch: int32 BlockTableEntries : Number of entries in the block table.
The archive header is the first structure in the archive, at archive offset 0, but the archive does not need to be at offset
0 of the containing file. The offset of the archive in the file is referred to here as ArchiveOffset. If the archive is not
at the beginning of the file, it must begin at a disk sector boundary (512 bytes). Early versions of Storm require that the
archive be at the end of the containing file (ArchiveOffset + ArchiveSize = file size), but this is not required in newer
versions (due to the strong digital signature not being considered a part of the archive).
2.3 BLOCK TABLE
The block table contains entries for each region in the archive. Regions may be either files or empty space, which may be
overwritten by new files (typically this space is from deleted file data). The block table is encrypted, using the hash
of "(block table)" as the key. Each entry is structured as follows:
00h: int32 BlockOffset : Offset of the beginning of the block, relative to the beginning of the archive. Meaningless if the block size is 0.
04h: int32 BlockSize : Size of the block in the archive.
08h: int32 FileSize : Size of the file data stored in the block. 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.
0Ch: int32 Flags : Bit mask of the flags for the block. The following values are conclusively identified:
80000000h: Block is a file, and follows the file data format; otherwise, block is free space, and may be overwritten. If the block is not a file, all other flags should be cleared.
01000000h: File is stored as a single unit, rather than split into sectors.
00020000h: The file's encryption key is adjusted by the block offset and file size (explained in detail in the File Data section). File must be encrypted.
00010000h: File is encrypted.
00000200h: File is compressed. Mutually exclusive to file imploded.
00000100h: File is imploded. Mutually exclusive to file compressed.
2.4 HASH TABLE
Instead of storing file names, for quick access MoPaQs use a fixed, power of two-size hash table of files in the archive. A file is uniquely identified by its file path, its language, and its platform. The home entry for a file in the hash table is computed as a hash of the file path. In the event of a collision (the home entry is occupied by another file), progressive overflow is used, and the file is placed in the next available hash table entry. Searches for a desired file in the hash table proceed from the home entry for the file until either the file is found, the entire hash table is searched, or an empty hash table entry (FileBlockIndex of FFFFFFFFh) is encountered. The hash table is encrypted using the hash of "(hash table)" as the key. Each entry is structured as follows:
00h: int32 FilePathHashA : The hash of the file path, using method A.
04h: int32 FilePathHashB : The hash of the file path, using method B.
08h: int16 Language : 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.
0Ah: int8 Platform : The platform the file is used for. 0 indicates the default platform. No other values have been observed.
0Ch: int32 FileBlockIndex : 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 (in other words, the file was deleted). Does not terminate searches for a given file.
2.5 FILE DATA
00h: int32(SectorsInFile + 1) SectorOffsetTable : Offsets to the start of each sector's data, relative to the beginning of the file data. Not present if this information is calculatable (see details below).
immediately following SectorOffsetTable: SectorData : Data of each sector in the file, packed end to end (see details below).
Normally, file data is split up into sectors, for simple streaming. All sectors, save for the last, will contain as many bytes of file data as specified in the archive header's SectorSizeShift; the last sector may be smaller than this, depending on the size of the file data. This sector size is the size of the raw file data; if the file is compressed, the compressed sector will be smaller or the same size as the uncompressed sector size. Individual sectors in a compressed file may be stored uncompressed; this occurs if and only if the sector could not be compressed by the algorithm used (if the compressed sector size was greater than or equal to the size of the raw data), and is indicated by the sector's compressed size in SectorOffsetTable being equal to the uncompressed size of the sector (which may be calculated from the FileSize).
If the sector is compressed (but not imploded), a bit mask byte of the compression algorithm(s) used to compress the sector is appended to the beginning of the compressed sector data. This additional byte counts towards the total size of the sector; if the size of the sector (including this byte) exceeds or matches the uncompressed size of the sector data, the sector will be stored uncompressed, and this byte omitted. Multiple compression algorithms may be used on the same sector; in this case, successive compression occurs in the order the algorithms are listed below, and decompression occurs in the opposite order. For implimentations of all of these algorithms, see StormLib.
40h: IMA ADPCM mono
80h: IMA ADPCM stereo
01h: Huffman encoded
02h: Deflated (see ZLib)
08h: Imploded (see PKWare Data Compression Library)
10h: BZip2 compressed (see BZip2)
If the file is stored as a single unit (indicated in the file's Flags), there is effectively only a single sector, which
contains the entire file.
If the file is encrypted, each sector (after compression and appendage of the compression type byte, if applicable)
is encrypted with the file's key. The base key for a file is determined by a hash of the file name stripped of the
directory (i.e. the key for a file named "directory\file" would be computed as the hash of "file"). If this key is
adjusted, as indicated in the file's Flags, the final key is calculated as ((base key + BlockOffset - ArchiveOffset)
XOR FileSize) (StormLib - an open-source implementation of the MoPaQ reading and writing functions,
by Ladislav Zezula - incorrectly uses an AND in place of the XOR). Each sector is encrypted using the key + the
0-based index of the sector in the file. The SectorOffsetTable, if present, is encrypted using the key - 1.
The SectorOffsetTable is omitted when the sizes and offsets of all sectors in the file are calculatable from the FileSize.
This can happen in several circumstances. If the file is not compressed/imploded, then the size and offset of all sectors
is known, based on the archive's SectorSizeShift. If the file is stored as a single unit compressed/imploded, then the
SectorOffsetTable is omitted, as the single file "sector" corresponds to BlockSize and FileSize, as mentioned previously.
Note that the SectorOffsetTable will always be present if the file is compressed/imploded and the file is not stored as
a single unit, even if there is only a single sector in the file (the size of the file is less than or equal to the
archive's sector size).
2.6 LISTFILE
The listfile is a very simple extension to the MoPaQ format that contains the file paths of (most) files in the archive.
The languages and platforms of the files are not stored in the listfile. The listfile is contained in the file "(listfile)",
and is simply a non-Unix-style text file with one file path on each line, lines terminated with the bytes 0Dh 0Ah. The file
"(listfile)" may not be listed in the listfile.
2.7 EXTENDED ATTRIBUTES
The extended attributes are optional file attributes for files in the block table. These attributes were added at times after
the MoPaQ format was already finalized, and it is not necessary for every archive to have all (or any) of the extended attributes.
If an archive contains a given attribute, there will be an instance of that attribute for every block in the block table, although
the attribute will be meaningless if the block is not a file. The order of the attributes for blocks correspond to the order of the
blocks in the block table, and are of the same number. The attributes are stored in parallel arrays in the "(attributes)" file,
in the archive. The attributes corresponding to this file need not be valid (and logically cannot be). Unlike all the other
structures in the MoPaQ format, entries in the extended attributes are NOT guaranteed to be aligned. Also note that in some
archives, malicious zeroing of the attributes has been observed, perhaps with the intent of breaking archive viewers. This
file is structured as follows:
00h: int32 Version : Specifies the extended attributes format version. For now, must be 100.
04h: int32 AttributesPresent : Bit mask of the extended attributes present in the archive:
00000001h: File CRC32s.
00000002h: File timestamps.
00000004h: File MD5s.
08h: int32(BlockTableEntries) CRC32s : CRC32s of the (uncompressed) file data for each block in the archive. Omitted if the
archive does not have CRC32s. immediately after CRC32s: FILETIME(BlockTableEntries) Timestamps : Timestamps for each block
in the archive. The format is that of the Windows FILETIME structure. Omitted if the archive does not have timestamps.
immediately after Timestamps: MD5(BlockTableEntries) MD5s : MD5s of the (uncompressed) file data for each block in the archive.
Omitted if the archive does not have MD5s.
2.8 WEAK DIGITAL SIGNATURE
The weak digital signature is a digital signature using Microsoft CryptoAPI. It is an implimentation of the RSASSA-PKCS1-v1_5
digital signature protocol, using the MD5 hashing algorithm and a 512-bit (weak) RSA key (for more information about this
protocol, see the RSA Labs PKCS1 specification). The public key and exponent are stored in a resource in Storm. The signature
is stored uncompressed, unencrypted in the file "(signature)" in the archive. The archive is hashed from the beginning of the
archive (ArchiveOffset in the containing file) to the end of the archive (the length indicated by ArchiveSize); the signature
file is added to the archive before signing, and the space occupied by the file is considered to be all binary 0s during
signing/verification. This file is structured as follows:
00h: int32 Unknown : Must be 0.
04h: int32 Unknown : must be 0.
08h: int512 Signature : The digital signature. Like all other numbers in the MoPaQ format, this is stored in little-endian order.
2.9 STRONG DIGITAL SIGNATURE
The strong digital signature uses a simple proprietary implementation of RSA signing, using the SHA-1 hashing algorithm and
a 2048-bit (strong) RSA key. The default public key and exponent are stored in Storm, but other keys may be used as well.
The strong digital signature is stored immediately after the archive, in the containing file; the entire archive (ArchiveSize
bytes, starting at ArchiveOffset in the containing file) is hashed as a single block. The signature has the following format:
00h: char(4) Magic : Indicates the presence of a digital signature. Must be "NGIS" ("SIGN" backwards).
04h: int2048 Signature : The digital signature, stored in little-endian format.
When the Signature field is decrypted with the public key and exponent, and the result stored in little-endian order, it is structured as follows:
00h: byte Padding : Must be 0Bh.
01h: byte(235) Padding : Must be BBh.
ECh: byte(20) SHA-1 : SHA-1 hash of the archive, in standard SHA-1 format.
3. ALGORITHM SOURCE CODE
3.1 ENCRYPTION/DECRYPTION
I believe this was derived at some point from code in StormLib. Assumes the long type to be 32 bits, and the machine to be little endian order.
unsigned long dwCryptTable[0x500];
void InitializeCryptTable()
{
unsigned long seed = 0x00100001;
unsigned long index1 = 0;
unsigned long index2 = 0;
int i;
for (index1 = 0; index1 < 0x100; index1++)
{
for (index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
{
unsigned long temp1, temp2;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp1 = (seed & 0xFFFF) << 0x10;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp2 = (seed & 0xFFFF);
dwCryptTable[index2] = (temp1 | temp2);
}
}
}
void EncryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
{
unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
unsigned long seed = 0xEEEEEEEE;
unsigned long ch;
assert(lpbyBuffer);
dwLength /= sizeof(unsigned long);
while(dwLength-- > 0)
{
seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
ch = *lpdwBuffer ^ (dwKey + seed);
dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
seed = *lpdwBuffer + seed + (seed << 5) + 3;
*lpdwBuffer++ = ch;
}
}
void DecryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
{
unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
unsigned long seed = 0xEEEEEEEE;
unsigned long ch;
assert(lpbyBuffer);
dwLength /= sizeof(unsigned long);
while(dwLength-- > 0)
{
seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
ch = *lpdwBuffer ^ (dwKey + seed);
dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
seed = ch + seed + (seed << 5) + 3;
*lpdwBuffer++ = ch;
}
}
3.2 HASHING
Based on code from StormLib.
// Different types of hashes to make with HashString
#define MPQ_HASH_TABLE_OFFSET 0
#define MPQ_HASH_NAME_A 1
#define MPQ_HASH_NAME_B 2
#define MPQ_HASH_FILE_KEY 3
unsigned long HashString(const char *lpszString, unsigned long dwHashType)
{
unsigned long seed1 = 0x7FED7FED;
unsigned long seed2 = 0xEEEEEEEE;
int ch;
while (*lpszString != 0)
{
ch = toupper(*lpszString++);
seed1 = dwCryptTable[(dwHashType * 0xFF) + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
3.3 CONVERSION OF FILETIME AND time_t
#define EPOCH_OFFSET 116444736000000000ULL // Number of 100 ns units between 01/01/1601 and 01/01/1970
bool GetTimeFromFileTime(FILETIME &fileTime, time_t &time)
{
// The FILETIME represents a 64-bit integer: the number of 100 ns units since January 1, 1601
unsigned long long nTime = ((unsigned long long)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
if (nTime < EPOCH_OFFSET)
return false;
nTime -= EPOCH_OFFSET; // Convert the time base from 01/01/1601 to 01/01/1970
nTime /= 10000000ULL; // Convert 100 ns to sec
time = (time_t)nTime;
// Test for overflow (FILETIME is 64 bits, time_t is 32 bits)
if ((nTime - (unsigned long long)time) > 0)
return false;
return true;
}
void GetFileTimeFromTime(time_t &time, FILETIME &fileTime)
{
unsigned long long nTime = (unsigned long long)time;
nTime *= 10000000ULL;
nTime += EPOCH_OFFSET;
fileTime.dwLowDateTime = (DWORD)nTime;
fileTime.dwHighDateTime = (DWORD)(nTime >> 32);
}

View File

@ -0,0 +1,433 @@
THE MOPAQ ARCHIVE FORMAT
v1.0 (Friday, September 1, 2006)
by Justin Olbrantz(Quantam)
Distribution and reproduction of this specification are allowed without limitation, as long as it is not altered. Quotation in other works is freely allowed, as long as the source and author of the quote are stated.
TABLE OF CONTENTS
1. Introduction to the MoPaQ Format
2. The MoPaQ Format
2.1 General Archive Layout
2.2 Archive Header
2.3 Block Table
2.4 Extended Block Table
2.5 Hash Table
2.6 File Data
2.7 Listfile
2.8 Extended Attributes
2.9 Weak (Old) Digital Signature
2.10 Strong (New) Digital Signature
3. Algorithm Source Code
3.1 Encryption/Decryption
3.2 Hashing and File Key Computation
3.3 Finding Files
3.4 Deleting Files
3.5 Conversion of FILETIME and time_t
3.6 Forming a 64-bit Large Archive Offset from 32-bit and 16-bit Components
4. Revision History
1. INTRODUCTION TO THE MOPAQ FORMAT
The MoPaQ (or MPQ) format is an archive file format designed by Mike O'Brien (hence the name Mike O'brien PaCK) at Blizzard Entertainment. The format has been used in all Blizzard games since (and including) Diablo. It is heavily optimized to be a read-only game archive format, and excels at this role.
The Blizzard MoPaQ-reading functions are contained in the Storm module, which my be either statically or dynamically linked. The Blizzard MoPaQ-writing functions are contained in the MPQAPI module, which is always statically linked.
StormLib - mentioned several times in this specification - is an open-source MoPaQ reading and writing library written by Ladislav Zezula (no affiliation with Blizzard Entertainment). While it's a bit dated, and does not support all of the newer MoPaQ features, it contains source code to the more exotic compression methods used by MoPaQ, such as the PKWare implode algorithm, MoPaQ's huffman compression algorithm, and the IMA ADPCM compression used by MoPaQ.
2. THE MOPAQ FORMAT
All numbers in the MoPaQ format are in little endian byte order; signed numbers use the two's complement system. Data types are listed either as int (integer, the number of bits specified), byte (8 bits), or char (bytes which contain ASCII characters). All sizes and offsets are in bytes, unless specified otherwise. Structure members are listed in the following general form:
offset from the beginning of the structure: data type(array size) member name : member description
2.1 GENERAL ARCHIVE LAYOUT
- Archive Header
- File Data
- File Data - Special Files
- Hash Table
- Block Table
- Extended Block Table
- Strong Digital signature
This is the usual archive format, but it is not mandatory. Some archives have been observed placing the hash table and file table after the archive header, and before the file data.
2.2 ARCHIVE HEADER
00h: char(4) Magic : Indicates that the file is a MoPaQ archive. Must be ASCII "MPQ" 1Ah.
04h: int32 HeaderSize : Size of the archive header.
08h: int32 ArchiveSize : Size of the whole archive, including the header. Does not include the strong digital signature, if present. This size is used, among other things, for determining the region to hash in computing the digital signature. 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).
0Ch: int16 FormatVersion : MoPaQ format version. MPQAPI will not open archives where this is negative. Known versions:
0000h: Original format. HeaderSize should be 20h, and large archives are not supported.
0001h: Burning Crusade format. Header size should be 2Ch, and large archives are supported.
0Eh: int8 SectorSizeShift : 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).
10h: int32 HashTableOffset : Offset to the beginning of the hash table, relative to the beginning of the archive.
14h: int32 BlockTableOffset : Offset to the beginning of the block table, relative to the beginning of the archive.
18h: int32 HashTableEntries : 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.
1Ch: int32 BlockTableEntries : Number of entries in the block table.
Fields only present in the Burning Crusade format and later:
20h: int64 ExtendedBlockTableOffset : Offset to the beginning of the extended block table, relative to the beginning of the archive.
28h: int16 HashTableOffsetHigh : High 16 bits of the hash table offset for large archives.
2Ah: int16 BlockTableOffsetHigh : High 16 bits of the block table offset for large archives.
The archive header is the first structure in the archive, at archive offset 0; however, the archive does not need to be at offset 0 of the containing file. The offset of the archive in the file is referred to here as ArchiveOffset. If the archive is not at the beginning of the file, it must begin at a disk sector boundary (512 bytes). Early versions of Storm require that the archive be at the end of the containing file (ArchiveOffset + ArchiveSize = file size), but this is not required in newer versions (due to the strong digital signature not being considered a part of the archive).
2.3 BLOCK TABLE
The block table contains entries for each region in the archive. Regions may be either files, empty space, which may be overwritten by new files (typically this space is from deleted file data), or unused block table entries. Empty space entries should have BlockOffset and BlockSize nonzero, and FileSize and Flags zero; unused block table entries should have BlockSize, FileSize, and Flags zero. The block table is encrypted, using the hash of "(block table)" as the key. Each entry is structured as follows:
00h: int32 BlockOffset : Offset of the beginning of the block, relative to the beginning of the archive.
04h: int32 BlockSize : Size of the block in the archive.
08h: int32 FileSize : Size of the file data stored in the block. 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.
0Ch: int32 Flags : Bit mask of the flags for the block. The following values are conclusively identified:
80000000h: Block is a file, and follows the file data format; otherwise, block is free space or unused. If the block is not a file, all other flags should be cleared, and FileSize should be 0.
01000000h: File is stored as a single unit, rather than split into sectors.
00020000h: The file's encryption key is adjusted by the block offset and file size (explained in detail in the File Data section). File must be encrypted.
00010000h: File is encrypted.
00000200h: File is compressed. File cannot be imploded.
00000100h: File is imploded. File cannot be compressed.
2.4 EXTENDED BLOCK TABLE
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.
As of the Burning Crusade Friends and Family beta, this table is not encrypted.
2.5 HASH TABLE
Instead of storing file names, for quick access MoPaQs use a fixed, power of two-size hash table of files in the archive. A file is uniquely identified by its file path, its language, and its platform. The home entry for a file in the hash table is computed as a hash of the file path. In the event of a collision (the home entry is occupied by another file), progressive overflow is used, and the file is placed in the next available hash table entry. Searches for a desired file in the hash table proceed from the home entry for the file until either the file is found, the entire hash table is searched, or an empty hash table entry (FileBlockIndex of FFFFFFFFh) is encountered. The hash table is encrypted using the hash of "(hash table)" as the key. Each entry is structured as follows:
00h: int32 FilePathHashA : The hash of the file path, using method A.
04h: int32 FilePathHashB : The hash of the file path, using method B.
08h: int16 Language : 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.
0Ah: int8 Platform : The platform the file is used for. 0 indicates the default platform. No other values have been observed.
0Ch: int32 FileBlockIndex : 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 (in other words, the file was deleted). Does not terminate searches for a given file.
2.6 FILE DATA
The data for each file is composed of the following structure:
00h: int32(SectorsInFile + 1) SectorOffsetTable : Offsets to the start of each sector, relative to the beginning of the file data. The last entry contains the file size, making it possible to easily calculate the size of any given sector. This table is not present if this information can be calculated (see details below).
immediately following SectorOffsetTable: SECTOR Sectors(SectorsInFile) : Data of each sector in the file, packed end to end (see details below).
Normally, file data is split up into sectors, for simple streaming. All sectors, save for the last, will contain as many bytes of file data as specified in the archive header's SectorSizeShift; the last sector may contain less than this, depending on the size of the entire file's data. If the file is compressed or imploded, the sector will be smaller or the same size as the file data it contains. Individual sectors in a compressed or imploded file may be stored uncompressed; this occurs if and only if the file data the sector contains could not be compressed by the algorithm(s) used (if the compressed sector size was greater than or equal to the size of the file data), and is indicated by the sector's size in SectorOffsetTable being equal to the size of the file data in the sector (which may be calculated from the FileSize).
The format of each sector depends on the kind of sector it is. Uncompressed sectors are simply the the raw file data contained in the sector. Imploded sectors are the raw compressed data following compression with the implode algorithm (these sectors can only be in imploded files). Compressed sectors (only found in compressed - not imploded - files) are compressed with one or more compression algorithms, and have the following structure:
00h: byte CompressionMask : Mask of the compression types applied to this sector. If multiple compression types are used, they are applied in the order listed below, and decompression is performed in the opposite order. This byte counts towards the total sector size, meaning that the sector will be stored uncompressed if the data cannot be compressed by at least two bytes; as well, this byte is encrypted with the sector data, if applicable. The following compression types are defined (for implementations of these algorithms, see StormLib):
40h: IMA ADPCM mono
80h: IMA ADPCM stereo
01h: Huffman encoded
02h: Deflated (see ZLib)
08h: Imploded (see PKWare Data Compression Library)
10h: BZip2 compressed (see BZip2)
01h: byte(SectorSize - 1) SectorData : The compressed data for the sector.
If the file is stored as a single unit (indicated in the file's Flags), there is effectively only a single sector, which contains the entire file data.
If the file is encrypted, each sector (after compression/implosion, if applicable) is encrypted with the file's key. The base key for a file is determined by a hash of the file name stripped of the directory (i.e. the key for a file named "directory\file" would be computed as the hash of "file"). If this key is adjusted, as indicated in the file's Flags, the final key is calculated as ((base key + BlockOffset - ArchiveOffset) XOR FileSize) (StormLib incorrectly uses an AND in place of the XOR). Each sector is encrypted using the key + the 0-based index of the sector in the file. The SectorOffsetTable, if present, is encrypted using the key - 1.
The SectorOffsetTable is omitted when the sizes and offsets of all sectors in the file are calculatable from the FileSize. This can happen in several circumstances. If the file is not compressed/imploded, then the size and offset of all sectors is known, based on the archive's SectorSizeShift. If the file is stored as a single unit compressed/imploded, then the SectorOffsetTable is omitted, as the single file "sector" corresponds to BlockSize and FileSize, as mentioned previously. However, the SectorOffsetTable will be present if the file is compressed/imploded and the file is not stored as a single unit, even if there is only a single sector in the file (the size of the file is less than or equal to the archive's sector size).
2.7 LISTFILE
The listfile is a very simple extension to the MoPaQ format that contains the file paths of (most) files in the archive. The languages and platforms of the files are not stored in the listfile. The listfile is contained in the file "(listfile)" (default language and platform), and is simply a text file with file paths separated by ';', 0Dh, 0Ah, or some combination of these. The file "(listfile)" may not be listed in the listfile.
2.8 EXTENDED ATTRIBUTES
The extended attributes are optional file attributes for files in the block table. These attributes were added at times after the MoPaQ format was already finalized, and it is not necessary for every archive to have all (or any) of the extended attributes. If an archive contains a given attribute, there will be an instance of that attribute for every block in the block table, although the attribute will be meaningless if the block is not a file. The order of the attributes for blocks correspond to the order of the blocks in the block table, and are of the same number. The attributes are stored in parallel arrays in the "(attributes)" file (default language and platform), in the archive. The attributes corresponding to this file need not be valid (and logically cannot be). Unlike all the other structures in the MoPaQ format, entries in the extended attributes are NOT guaranteed to be aligned. Also note that in some archives, malicious zeroing of the attributes has been observed, perhaps with the intent of breaking archive viewers. This file is structured as follows:
00h: int32 Version : Specifies the extended attributes format version. For now, must be 100.
04h: int32 AttributesPresent : Bit mask of the extended attributes present in the archive:
00000001h: File CRC32s.
00000002h: File timestamps.
00000004h: File MD5s.
08h: int32(BlockTableEntries) CRC32s : CRC32s of the (uncompressed) file data for each block in the archive. Omitted if the archive does not have CRC32s.
immediately after CRC32s: FILETIME(BlockTableEntries) Timestamps : Timestamps for each block in the archive. The format is that of the Windows FILETIME structure. Omitted if the archive does not have timestamps.
immediately after Timestamps: MD5(BlockTableEntries) MD5s : MD5s of the (uncompressed) file data for each block in the archive. Omitted if the archive does not have MD5s.
2.9 WEAK DIGITAL SIGNATURE
The weak digital signature is a digital signature using Microsoft CryptoAPI. It is an implimentation
of the RSASSA-PKCS1-v1_5 digital signature protocol, using the MD5 hashing algorithm and a 512-bit (weak)
RSA key (for more information about this protocol, see the RSA Labs PKCS1 specification). The public key
and exponent are stored in a resource in Storm, the private key is stored in a separate file, whose filename
is passed to MPQAPI (the private key is not stored in MPQAPI). The signature is stored uncompressed,
unencrypted in the file "(signature)" (default language and platform) in the archive. The archive
is hashed from the beginning of the archive (ArchiveOffset in the containing file) to the end of
the archive (the length indicated by ArchiveSize, or calculated in the Burning Crusade MoPaQ format);
the signature file is added to the archive before signing, and the space occupied by the file is considered
to be all binary 0s during signing/verification. This file is structured as follows:
00h: int32 Unknown : Must be 0.
04h: int32 Unknown : Must be 0.
08h: int512 Signature : The digital signature. Like all other numbers in the MoPaQ format, this is stored
in little-endian order. The structure of this, when decrypted, follows the RSASSA-PKCS1-v1_5 specification;
this format is rather icky to work with (I wrote a program to verify this signature using nothing but an MD5
function and huge integer functions; it wasn't pleasant), and best left to an encryption library such as Cryto++.
2.10 STRONG DIGITAL SIGNATURE
The strong digital signature uses a simple proprietary implementation of RSA signing, using the SHA-1 hashing algorithm and a 2048-bit (strong) RSA key. The default public key and exponent are stored in Storm, but other keys may be used as well. The strong digital signature is stored immediately after the archive, in the containing file; the entire archive (ArchiveSize bytes, starting at ArchiveOffset in the containing file) is hashed as a single block. The signature has the following format:
00h: char(4) Magic : Indicates the presence of a digital signature. Must be "NGIS" ("SIGN" backwards).
04h: int2048 Signature : The digital signature, stored in little-endian format.
When the Signature field is decrypted with the public key and exponent, and the resulting large integer is stored in little-endian order, it is structured as follows:
00h: byte Padding : Must be 0Bh.
01h: byte(235) Padding : Must be BBh.
ECh: byte(20) SHA-1 : SHA-1 hash of the archive, in standard SHA-1 byte order.
3. ALGORITHM SOURCE CODE
All of the sample code here assumes little endian machine byte order, that the short type is 16 bits, that the long type is 32 bits, and that the long long type is 64 bits. Adjustments must be made if these assumptions are not correct on a given platform. All code not credited otherwise was written by myself in the writing of this specification.
3.1 ENCRYPTION/DECRYPTION
Based on code from StormLib.
unsigned long dwCryptTable[0x500];
// The encryption and hashing functions use a number table in their procedures. This table must be initialized before the functions are called the first time.
void InitializeCryptTable()
{
unsigned long seed = 0x00100001;
unsigned long index1 = 0;
unsigned long index2 = 0;
int i;
for (index1 = 0; index1 < 0x100; index1++)
{
for (index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
{
unsigned long temp1, temp2;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp1 = (seed & 0xFFFF) << 0x10;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp2 = (seed & 0xFFFF);
dwCryptTable[index2] = (temp1 | temp2);
}
}
}
void EncryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
{
assert(lpbyBuffer);
unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
unsigned long seed = 0xEEEEEEEE;
unsigned long ch;
dwLength /= sizeof(unsigned long);
while(dwLength-- > 0)
{
seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
ch = *lpdwBuffer ^ (dwKey + seed);
dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
seed = *lpdwBuffer + seed + (seed << 5) + 3;
*lpdwBuffer++ = ch;
}
}
void DecryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
{
assert(lpbyBuffer);
unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
unsigned long seed = 0xEEEEEEEEL;
unsigned long ch;
dwLength /= sizeof(unsigned long);
while(dwLength-- > 0)
{
seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
ch = *lpdwBuffer ^ (dwKey + seed);
dwKey = ((~dwKey << 0x15) + 0x11111111L) | (dwKey >> 0x0B);
seed = ch + seed + (seed << 5) + 3;
*lpdwBuffer++ = ch;
}
}
3.2 HASHING AND FILE KEY COMPUTATION
These functions may have been derived from StormLib code at some point in the very distant past. It was so long ago that I don't remember for certain.
// Different types of hashes to make with HashString
#define MPQ_HASH_TABLE_OFFSET 0
#define MPQ_HASH_NAME_A 1
#define MPQ_HASH_NAME_B 2
#define MPQ_HASH_FILE_KEY 3
// Based on code from StormLib.
unsigned long HashString(const char *lpszString, unsigned long dwHashType)
{
assert(lpszString);
assert(dwHashType <= MPQ_HASH_FILE_KEY);
unsigned long seed1 = 0x7FED7FEDL;
unsigned long seed2 = 0xEEEEEEEEL;
int ch;
while (*lpszString != 0)
{
ch = toupper(*lpszString++);
seed1 = dwCryptTable[(dwHashType * 0x100) + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
#define BLOCK_OFFSET_ADJUSTED_KEY 0x00020000L
unsigned long ComputeFileKey(const char *lpszFilePath, const BlockTableEntry &blockEntry, unsigned long nArchiveOffset)
{
assert(lpszFilePath);
// Find the file name part of the path
const char *lpszFileName = strrchr(lpszFilePath, '\\');
if (lpszFileName)
lpszFileName++; // Skip the \
else
lpszFileName = lpszFilePath;
// Hash the name to get the base key
unsigned long nFileKey = HashString(lpszFileName, MPQ_HASH_FILE_KEY);
// Offset-adjust the key if necessary
if (blockEntry.Flags & BLOCK_OFFSET_ADJUSTED_KEY)
nFileKey = (nFileKey + blockEntry.BlockOffset) ^ blockEntry.FileSize;
return nFileKey;
}
3.3 FINDING FILES
#define MPQ_HASH_ENTRY_EMPTY 0xFFFFFFFFL
#define MPQ_HASH_ENTRY_DELETED 0xFFFFFFFEL
bool FindFileInHashTable(const HashTableEntry *lpHashTable, unsigned long nHashTableSize, const char *lpszFilePath, unsigned short nLang, unsigned char nPlatform, unsigned long &iFileHashEntry)
{
assert(lpHashTable);
assert(nHashTableSize);
assert(lpszFilePath);
// Find the home entry in the hash table for the file
unsigned long iInitEntry = HashString(lpszFilePath, MPQ_HASH_TABLE_OFFSET) & (nHashTableSize - 1);
// Is there anything there at all?
if (lpHashTable[iInitEntry].FileBlockIndex == MPQ_HASH_ENTRY_EMPTY)
return false;
// Compute the hashes to compare the hash table entry against
unsigned long nNameHashA = HashString(lpszFilePath, MPQ_HASH_NAME_A),
nNameHashB = HashString(lpszFilePath, MPQ_HASH_NAME_B),
iCurEntry = iInitEntry;
// Check each entry in the hash table till a termination point is reached
do
{
if (lpHashTable[iCurEntry].FileBlockIndex != MPQ_HASH_ENTRY_DELETED)
{
if (lpHashTable[iCurEntry].FilePathHashA == nNameHashA
&& lpHashTable[iCurEntry].FilePathHashB == nNameHashB
&& lpHashTable[iCurEntry].Language == nLang
&& lpHashTable[iCurEntry].Platform == nPlatform)
{
iFileHashEntry = iCurEntry;
return true;
}
}
iCurEntry = (iCurEntry + 1) & (nHashTableSize - 1);
} while (iCurEntry != iInitEntry && lpHashTable[iCurEntry].FileBlockIndex != MPQ_HASH_ENTRY_EMPTY);
return false;
}
3.4 DELETING FILES
bool DeleteFile(HashTableEntry *lpHashTable, unsigned long nHashTableSize, BlockTableEntry *lpBlockTable, const char *lpszFilePath, unsigned short nLang, unsigned char nPlatform)
{
assert(lpHashTable);
assert(nHashTableSize);
assert(lpBlockTable);
// Find the file in the hash table
unsigned long iFileHashEntry;
if (!FindFileInHashTable(lpHashTable, nHashTableSize, lpszFilePath, nLang, nPlatform, iFileHashEntry))
return false;
// Get the block table index before we nuke the hash table entry
unsigned long iFileBlockEntry = lpHashTable[iFileHashEntry].FileBlockIndex;
// Delete the file's entry in the hash table
memset(&lpHashTable[iFileHashEntry], 0xFF, sizeof(HashTableEntry));
// If the next entry is empty, mark this one as empty; otherwise, mark this as deleted.
if (lpHashTable[(iFileHashEntry + 1) & (nHashTableSize - 1)].FileBlockIndex == MPQ_HASH_ENTRY_EMPTY)
lpHashTable[iFileHashEntry].FileBlockIndex = MPQ_HASH_ENTRY_EMPTY;
else
lpHashTable[iFileHashEntry].FileBlockIndex = MPQ_HASH_ENTRY_DELETED;
// If the block occupies space, mark the block as free space; otherwise, clear the block table entry.
if (lpBlockTable[iFileBlockEntry].BlockSize > 0)
{
lpBlockTable[iFileBlockEntry].FileSize = 0;
lpBlockTable[iFileBlockEntry].Flags = 0;
}
else
memset(&lpBlockTable[iFileBlockEntry], 0, sizeof(BlockTableEntry);
return true;
}
3.5 CONVERSION OF FILETIME AND time_t
This code assumes that the base ("zero") date for time_t is 01/01/1970. This is true on Windows, Unix System V systems, and Mac OS X. It is unknown whether this is true on all other platforms. You'll need to research this yourself, if you plan on porting it somewhere else.
#define EPOCH_OFFSET 116444736000000000ULL // Number of 100 ns units between 01/01/1601 and 01/01/1970
bool GetTimeFromFileTime(const FILETIME &fileTime, time_t &time)
{
// The FILETIME represents a 64-bit integer: the number of 100 ns units since January 1, 1601
unsigned long long nTime = ((unsigned long long)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
if (nTime < EPOCH_OFFSET)
return false;
nTime -= EPOCH_OFFSET; // Convert the time base from 01/01/1601 to 01/01/1970
nTime /= 10000000ULL; // Convert 100 ns to sec
time = (time_t)nTime;
// Test for overflow (FILETIME is 64 bits, time_t is 32 bits)
if ((nTime - (unsigned long long)time) > 0)
return false;
return true;
}
void GetFileTimeFromTime(const time_t &time, FILETIME &fileTime)
{
unsigned long long nTime = (unsigned long long)time;
nTime *= 10000000ULL;
nTime += EPOCH_OFFSET;
fileTime.dwLowDateTime = (DWORD)nTime;
fileTime.dwHighDateTime = (DWORD)(nTime >> 32);
}
3.6 FORMING A 64-BIT LARGE ARCHIVE OFFSET FROM 32-BIT AND 16-BIT COMPONENTS
unsigned long long MakeLargeArchiveOffset(unsigned long nOffsetLow, unsigned short nOffsetHigh)
{
return ((unsigned long long)nOffsetHigh << 32) + (unsigned long long)nOffsetLow;
}
4. REVISION HISTORY
1.0
- Updated to include most of the changes found in the Burning Crusade Friends and Family beta
0.91.
- Updated several structure member descriptions
- Listed the full set of characters that can separate list file entries
- Noted that (attributes), (listfile), and (signature) use the default language and platform codes
- Redid part of the file data specs to clarify the format of sectors
- Enhanced descriptions of the different kinds of block table entries
- Added ComputeFileKey, FindFileInHashTable, and DeleteFile source

View File

@ -0,0 +1 @@
UCMXF6EJY352EFH4XFRXCFH2XC9MQRZK

View File

@ -0,0 +1 @@
MMKVHY48RP7WXP4GHYBQ7SL9J9UNPHBP

View File

@ -0,0 +1 @@
8MXLWHQ7VGGLTZ9MQZQSFDCLJYET3CPP

View File

@ -0,0 +1 @@
EJ2R5TM6XFE2GUNG5QDGHKQ9UAKPWZSZ

View File

@ -0,0 +1 @@
PBGFBE42Z6LNK65UGJQ3WZVMCLP4HQQT

View File

@ -0,0 +1 @@
X7SEJJS9TSGCW5P28EBSC47AJPEY8VU2

View File

@ -0,0 +1 @@
5KVBQA8VYE6XRY3DLGC5ZDE4XS4P7YA2

View File

@ -0,0 +1 @@
478JD2K56EVNVVY4XX8TDWYT5B8KB254

View File

@ -0,0 +1 @@
8TS4VNFQRZTN6YWHE9CHVDH9NVWD474A

View File

@ -0,0 +1 @@
LJ52Z32DF4LZ4ZJJXVKK3AZQA6GABLJB

View File

@ -0,0 +1 @@
K6BDHY2ECUE2545YKNLBJPVYWHE7XYAG

View File

@ -0,0 +1 @@
6VWCQTN8V3ZZMRUCZXV8A8CGUX2TAA8H

View File

@ -0,0 +1 @@
S48B6CDTN5XEQAKQDJNDLJBJ73FDFM3U

View File

@ -0,0 +1 @@
Y45MD3CAK4KXSSXHYD9VY64Z8EKJ4XFX

View File

@ -0,0 +1 @@
G8MN8UDG6NA2ANGY6A3DNY82HRGF29ZH

View File

@ -0,0 +1 @@
3DH5RE5NVM5GTFD85LXGWT6FK859ETR5

View File

@ -0,0 +1 @@
8WLKUAXE94PFQU4Y249PAZ24N4R4XKTQ

View File

@ -0,0 +1 @@
A34DXX3VHGGXSQBRFE5UFFDXMF9G4G54

View File

@ -0,0 +1 @@
ZG7J9K938HJEFWPQUA768MA2PFER6EAJ

View File

@ -0,0 +1 @@
NE7CUNNNTVAPXV7E3G2BSVBWGVMW8BL2

View File

@ -0,0 +1 @@
3V9E2FTMBM9QQWK7U6MAMWAZWQDB838F

View File

@ -0,0 +1 @@
2NSFB8MELULJ83U6YHA3UP6K4MQD48L6

View File

@ -0,0 +1 @@
QA2TZ9EWZ4CUU8BMB5WXCTY65F9CSW4E

View File

@ -0,0 +1 @@
VHB378W64BAT9SH7D68VV9NLQDK9YEGT

View File

@ -0,0 +1 @@
U3NFQJV4M6GC7KBN9XQJ3BRDN3PLD9NE

60
StormLib/make-msvc.bat Normal file
View File

@ -0,0 +1,60 @@
:: Build file for Visual Studio 2008 and 2017
@echo off
:: Save the values of INCLUDE, LIB and PATH
set SAVE_INCLUDE=%INCLUDE%
set SAVE_LIB=%LIB%
set SAVE_PATH=%PATH%
set LIB_NAME=StormLib
:: Determine where the program files are, both for 64-bit and 32-bit Windows
if exist "%ProgramFiles%" set PROGRAM_FILES_DIR=%ProgramFiles%
if exist "%ProgramFiles(x86)%" set PROGRAM_FILES_DIR=%ProgramFiles(x86)%
:: Determine the installed version of Visual Studio (Prioritize Enterprise over Professional)
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" set VCVARS_2008=%PROGRAM_FILES_DIR%\Microsoft Visual Studio 9.0\VC\vcvarsall.bat
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_2017=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_2017=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_2017=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_2019=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_2019=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_2019=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat
::Build all libraries using Visual Studio 2008 and 2017
call :BuildLibs "%VCVARS_2008%" x86 %LIB_NAME%_vs08.sln
call :BuildLibs "%VCVARS_2008%" x64 %LIB_NAME%_vs08.sln
call :BuildLibs "%VCVARS_2019%" x86 %LIB_NAME%_vs19.sln
call :BuildLibs "%VCVARS_2019%" x64 %LIB_NAME%_vs19.sln
goto:eof
::-----------------------------------------------------------------------------
:: Build all 8 configurations of the library
::
:: Parameters:
::
:: %1 Full path to the VCVARS.BAT file
:: %2 Target build platform (x86 or x64)
:: %3 Plain name of the /sln solution file
::
:BuildLibs
::set VSCMD_DEBUG=1
call %1 %2
if "%2" == "x86" set SLN_TRG=Win32
if "%2" == "x64" set SLN_TRG=x64
devenv.com %3 /project "%LIB_NAME%" /rebuild "DebugAD|%SLN_TRG%"
devenv.com %3 /project "%LIB_NAME%" /rebuild "DebugAS|%SLN_TRG%"
devenv.com %3 /project "%LIB_NAME%" /rebuild "DebugUD|%SLN_TRG%"
devenv.com %3 /project "%LIB_NAME%" /rebuild "DebugUS|%SLN_TRG%"
devenv.com %3 /project "%LIB_NAME%" /rebuild "ReleaseAD|%SLN_TRG%"
devenv.com %3 /project "%LIB_NAME%" /rebuild "ReleaseAS|%SLN_TRG%"
devenv.com %3 /project "%LIB_NAME%" /rebuild "ReleaseUD|%SLN_TRG%"
devenv.com %3 /project "%LIB_NAME%" /rebuild "ReleaseUS|%SLN_TRG%"
:: Restore environment variables to the old level
set INCLUDE=%SAVE_INCLUDE%
set LIB=%SAVE_LIB%
set PATH=%SAVE_PATH%
set VSINSTALLDIR=
set VCINSTALLDIR=
set DevEnvDir=

46
StormLib/make.bat Normal file
View File

@ -0,0 +1,46 @@
@echo off
if not "x%WDKDIR%" == "x" goto SELECT_LIB
echo The WDKDIR environment variable is not set
echo Set this variable to your WDK directory (without ending backslash)
echo Example: set WDKDIR C:\WinDDK\6001
pause
goto:eof
:SELECT_LIB
set PROJECT_DIR=%~dp0
set LIBRARY_NAME=StormLibWDK
:PREPARE_SOURCES
echo Preparing sources ...
copy .\src\wdk\sources-cpp.cpp . >nul
copy .\src\wdk\sources-wdk-* . >nul
echo.
:BUILD_LIB_32
echo Building %LIBRARY_NAME%.lib (32-bit) ...
set DDKBUILDENV=
call %WDKDIR%\bin\setenv.bat %WDKDIR%\ fre w2k
cd %PROJECT_DIR%
build.exe -czgw
del buildfre_w2k_x86.log
echo.
:BUILD_LIB_64
echo Building %LIBRARY_NAME%.lib (64-bit) ...
set DDKBUILDENV=
call %WDKDIR%\bin\setenv.bat %WDKDIR%\ fre x64 WLH
cd %PROJECT_DIR%
build.exe -czgw
del buildfre_wlh_amd64.log
echo.
:COPY_LIBS
copy /Y .\objfre_wlh_amd64\amd64\%LIBRARY_NAME%.lib ..\aaa\lib64\%LIBRARY_NAME%.lib >nul
copy /Y .\objfre_w2k_x86\i386\%LIBRARY_NAME%.lib ..\aaa\lib32\%LIBRARY_NAME%.lib >nul
copy /Y .\src\StormPort.h ..\aaa\inc >nul
copy /Y .\src\StormLib.h ..\aaa\inc >nul
:CLEANUP
if exist sources-cpp.cpp del sources-cpp.cpp
if exist sources-wdk-* del sources-wdk-*
if exist build.bat del build.bat

14
StormLib/sources Normal file
View File

@ -0,0 +1,14 @@
TARGETNAME=StormLibWDK
TARGETTYPE=LIBRARY
USE_MSVCRT=1
C_DEFINES=$(C_DEFINES) -DUNICODE -D_UNICODE -DWDK_BUILD
SOURCES=sources-cpp.cpp \
sources-wdk-bzip2.c \
sources-wdk-ltc.c \
sources-wdk-lzma.c \
sources-wdk-misc.c \
sources-wdk-tomcrypt.c \
sources-wdk-tommath.c \
sources-wdk-zlib.c

24
StormLib/src/DllMain.c Normal file
View File

@ -0,0 +1,24 @@
/*****************************************************************************/
/* DllMain.c Copyright (c) Ladislav Zezula 2006 */
/*---------------------------------------------------------------------------*/
/* Description: DllMain for the StormLib.dll library */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 23.11.06 1.00 Lad The first version of DllMain.c */
/*****************************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//-----------------------------------------------------------------------------
// DllMain
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(hInst);
UNREFERENCED_PARAMETER(dwReason);
UNREFERENCED_PARAMETER(lpReserved);
return TRUE;
}

79
StormLib/src/DllMain.def Normal file
View File

@ -0,0 +1,79 @@
;
; Export file for Windows
; Copyright (c) 2007-2010 Ladislav Zezula
; ladik@zezula.net
;
LIBRARY StormLib.dll
EXPORTS
SFileSetLocale
SFileGetLocale
SFileOpenArchive
SFileCreateArchive
SFileCreateArchive2
SFileFlushArchive
SFileCloseArchive
SFileAddListFile
SFileSetCompactCallback
SFileCompactArchive
SFileGetMaxFileCount
SFileSetMaxFileCount
SFileGetAttributes
SFileSetAttributes
SFileUpdateFileAttributes
SFileOpenPatchArchive
SFileIsPatchedArchive
SFileOpenFileEx
SFileGetFileSize
SFileSetFilePointer
SFileReadFile
SFileCloseFile
SFileHasFile
SFileGetFileName
SFileGetFileInfo
SFileExtractFile
SFileVerifyFile
SFileVerifyRawData
SFileVerifyArchive
SFileFindFirstFile
SFileFindNextFile
SFileFindClose
SListFileFindFirstFile
SListFileFindNextFile
SListFileFindClose
SFileEnumLocales
SFileCreateFile
SFileWriteFile
SFileFinishFile
SFileAddFileEx
SFileAddFile
SFileAddWave
SFileRemoveFile
SFileRenameFile
SFileSetFileLocale
SFileSetDataCompression
SFileSetAddFileCallback
SCompImplode
SCompExplode
SCompCompress
SCompDecompress
GetLastError=Kernel32.GetLastError
SetLastError=Kernel32.SetLastError

114
StormLib/src/DllMain.rc Normal file
View File

@ -0,0 +1,114 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Neutral resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
#ifdef _WIN32
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#pragma code_page(1250)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 9,22,0,3
PRODUCTVERSION 9,22,0,3
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x0L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040504b0"
BEGIN
VALUE "Comments", "http://www.zezula.net/mpq.html"
VALUE "FileDescription", "StormLib library for reading Blizzard MPQ archives"
VALUE "FileVersion", "9, 22, 0, 3\0"
VALUE "InternalName", "StormLib"
VALUE "LegalCopyright", "Copyright (c) 2014 - 2020 Ladislav Zezula"
VALUE "OriginalFilename", "StormLib.dll"
VALUE "ProductName", "StormLib"
VALUE "ProductVersion", "9, 22, 0, 3\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x405, 1200
END
END
#endif // Neutral resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Czech resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY)
#ifdef _WIN32
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
#pragma code_page(1250)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
#endif // APSTUDIO_INVOKED
#endif // Czech resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

2923
StormLib/src/FileStream.cpp Normal file

File diff suppressed because it is too large Load Diff

217
StormLib/src/FileStream.h Normal file
View File

@ -0,0 +1,217 @@
/*****************************************************************************/
/* FileStream.h Copyright (c) Ladislav Zezula 2012 */
/*---------------------------------------------------------------------------*/
/* Description: Definitions for FileStream object */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 14.04.12 1.00 Lad The first version of FileStream.h */
/*****************************************************************************/
#ifndef __FILESTREAM_H__
#define __FILESTREAM_H__
//-----------------------------------------------------------------------------
// Function prototypes
typedef void (*STREAM_INIT)(
struct TFileStream * pStream // Pointer to an unopened stream
);
typedef bool (*STREAM_CREATE)(
struct TFileStream * pStream // Pointer to an unopened stream
);
typedef bool (*STREAM_OPEN)(
struct TFileStream * pStream, // Pointer to an unopened stream
const TCHAR * szFileName, // Pointer to file name to be open
DWORD dwStreamFlags // Stream flags
);
typedef bool (*STREAM_READ)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
void * pvBuffer, // Pointer to data to be read
DWORD dwBytesToRead // Number of bytes to read from the file
);
typedef bool (*STREAM_WRITE)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it writes to the current position
const void * pvBuffer, // Pointer to data to be written
DWORD dwBytesToWrite // Number of bytes to read from the file
);
typedef bool (*STREAM_RESIZE)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG FileSize // New size for the file, in bytes
);
typedef bool (*STREAM_GETSIZE)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG * pFileSize // Receives the file size, in bytes
);
typedef bool (*STREAM_GETPOS)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG * pByteOffset // Pointer to store current file position
);
typedef void (*STREAM_CLOSE)(
struct TFileStream * pStream // Pointer to an open stream
);
typedef bool (*BLOCK_READ)(
struct TFileStream * pStream, // Pointer to a block-oriented stream
ULONGLONG StartOffset, // Byte offset of start of the block array
ULONGLONG EndOffset, // End offset (either end of the block or end of the file)
LPBYTE BlockBuffer, // Pointer to block-aligned buffer
DWORD BytesNeeded, // Number of bytes that are really needed
bool bAvailable // true if the block is available
);
typedef bool (*BLOCK_CHECK)(
struct TFileStream * pStream, // Pointer to a block-oriented stream
ULONGLONG BlockOffset // Offset of the file to check
);
typedef void (*BLOCK_SAVEMAP)(
struct TFileStream * pStream // Pointer to a block-oriented stream
);
//-----------------------------------------------------------------------------
// Local structures - partial file structure and bitmap footer
#define ID_FILE_BITMAP_FOOTER 0x33767470 // Signature of the file bitmap footer ('ptv3')
#define DEFAULT_BLOCK_SIZE 0x00004000 // Default size of the stream block
#define DEFAULT_BUILD_NUMBER 10958 // Build number for newly created partial MPQs
typedef struct _PART_FILE_HEADER
{
DWORD PartialVersion; // Always set to 2
char GameBuildNumber[0x20]; // Minimum build number of the game that can use this MPQ
DWORD Flags; // Flags (details unknown)
DWORD FileSizeLo; // Low 32 bits of the contained file size
DWORD FileSizeHi; // High 32 bits of the contained file size
DWORD BlockSize; // Size of one file block, in bytes
} PART_FILE_HEADER, *PPART_FILE_HEADER;
// Structure describing the block-to-file map entry
typedef struct _PART_FILE_MAP_ENTRY
{
DWORD Flags; // 3 = the block is present in the file
DWORD BlockOffsLo; // Low 32 bits of the block position in the file
DWORD BlockOffsHi; // High 32 bits of the block position in the file
DWORD LargeValueLo; // 64-bit value, meaning is unknown
DWORD LargeValueHi;
} PART_FILE_MAP_ENTRY, *PPART_FILE_MAP_ENTRY;
typedef struct _FILE_BITMAP_FOOTER
{
DWORD Signature; // 'ptv3' (ID_FILE_BITMAP_FOOTER)
DWORD Version; // Unknown, seems to always have value of 3 (version?)
DWORD BuildNumber; // Game build number for that MPQ
DWORD MapOffsetLo; // Low 32-bits of the offset of the bit map
DWORD MapOffsetHi; // High 32-bits of the offset of the bit map
DWORD BlockSize; // Size of one block (usually 0x4000 bytes)
} FILE_BITMAP_FOOTER, *PFILE_BITMAP_FOOTER;
//-----------------------------------------------------------------------------
// Structure for file stream
union TBaseProviderData
{
struct
{
ULONGLONG FileSize; // Size of the file
ULONGLONG FilePos; // Current file position
ULONGLONG FileTime; // Last write time
HANDLE hFile; // File handle
} File;
struct
{
ULONGLONG FileSize; // Size of the file
ULONGLONG FilePos; // Current file position
ULONGLONG FileTime; // Last write time
LPBYTE pbFile; // Pointer to mapped view
} Map;
struct
{
ULONGLONG FileSize; // Size of the file
ULONGLONG FilePos; // Current file position
ULONGLONG FileTime; // Last write time
HANDLE hInternet; // Internet handle
HANDLE hConnect; // Connection to the internet server
} Http;
};
struct TFileStream
{
// Stream provider functions
STREAM_READ StreamRead; // Pointer to stream read function for this archive. Do not use directly.
STREAM_WRITE StreamWrite; // Pointer to stream write function for this archive. Do not use directly.
STREAM_RESIZE StreamResize; // Pointer to function changing file size
STREAM_GETSIZE StreamGetSize; // Pointer to function returning file size
STREAM_GETPOS StreamGetPos; // Pointer to function that returns current file position
STREAM_CLOSE StreamClose; // Pointer to function closing the stream
// Block-oriented functions
BLOCK_READ BlockRead; // Pointer to function reading one or more blocks
BLOCK_CHECK BlockCheck; // Pointer to function checking whether the block is present
// Base provider functions
STREAM_CREATE BaseCreate; // Pointer to base create function
STREAM_OPEN BaseOpen; // Pointer to base open function
STREAM_READ BaseRead; // Read from the stream
STREAM_WRITE BaseWrite; // Write to the stream
STREAM_RESIZE BaseResize; // Pointer to function changing file size
STREAM_GETSIZE BaseGetSize; // Pointer to function returning file size
STREAM_GETPOS BaseGetPos; // Pointer to function that returns current file position
STREAM_CLOSE BaseClose; // Pointer to function closing the stream
// Base provider data (file size, file position)
TBaseProviderData Base;
// Stream provider data
TFileStream * pMaster; // Master stream (e.g. MPQ on a web server)
TCHAR * szFileName; // File name (self-relative pointer)
ULONGLONG StreamSize; // Stream size (can be less than file size)
ULONGLONG StreamPos; // Stream position
DWORD BuildNumber; // Game build number
DWORD dwFlags; // Stream flags
// Followed by stream provider data, with variable length
};
//-----------------------------------------------------------------------------
// Structures for block-oriented stream
struct TBlockStream : public TFileStream
{
SFILE_DOWNLOAD_CALLBACK pfnCallback; // Callback for downloading
void * FileBitmap; // Array of bits for file blocks
void * UserData; // User data to be passed to the download callback
DWORD BitmapSize; // Size of the file bitmap (in bytes)
DWORD BlockSize; // Size of one block, in bytes
DWORD BlockCount; // Number of data blocks in the file
DWORD IsComplete; // If nonzero, no blocks are missing
DWORD IsModified; // nonzero if the bitmap has been modified
};
//-----------------------------------------------------------------------------
// Structure for encrypted stream
#define MPQE_CHUNK_SIZE 0x40 // Size of one chunk to be decrypted
struct TEncryptedStream : public TBlockStream
{
BYTE Key[MPQE_CHUNK_SIZE]; // File key
};
#endif // __FILESTREAM_H__

2045
StormLib/src/SBaseCommon.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
/*****************************************************************************/
/* SBaseDumpData.cpp Copyright (c) Ladislav Zezula 2011 */
/*---------------------------------------------------------------------------*/
/* Description : */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 26.01.11 1.00 Lad The first version of SBaseDumpData.cpp */
/*****************************************************************************/
#define __STORMLIB_SELF__
#include "StormLib.h"
#include "StormCommon.h"
#ifdef __STORMLIB_DUMP_DATA__
void DumpMpqHeader(TMPQHeader * pHeader)
{
printf("== MPQ Header =================================\n");
printf("DWORD dwID = %08X\n", pHeader->dwID);
printf("DWORD dwHeaderSize = %08X\n", pHeader->dwHeaderSize);
printf("DWORD dwArchiveSize = %08X\n", pHeader->dwArchiveSize);
printf("USHORT wFormatVersion = %04X\n", pHeader->wFormatVersion);
printf("USHORT wSectorSize = %04X\n", pHeader->wSectorSize);
printf("DWORD dwHashTablePos = %08X\n", pHeader->dwHashTablePos);
printf("DWORD dwBlockTablePos = %08X\n", pHeader->dwBlockTablePos);
printf("DWORD dwHashTableSize = %08X\n", pHeader->dwHashTableSize);
printf("DWORD dwBlockTableSize = %08X\n", pHeader->dwBlockTableSize);
printf("ULONGLONG HiBlockTablePos64 = %016llX\n", pHeader->HiBlockTablePos64);
printf("USHORT wHashTablePosHi = %04X\n", pHeader->wHashTablePosHi);
printf("USHORT wBlockTablePosHi = %04X\n", pHeader->wBlockTablePosHi);
printf("ULONGLONG ArchiveSize64 = %016llX\n", pHeader->ArchiveSize64);
printf("ULONGLONG BetTablePos64 = %016llX\n", pHeader->BetTablePos64);
printf("ULONGLONG HetTablePos64 = %016llX\n", pHeader->HetTablePos64);
printf("ULONGLONG HashTableSize64 = %016llX\n", pHeader->HashTableSize64);
printf("ULONGLONG BlockTableSize64 = %016llX\n", pHeader->BlockTableSize64);
printf("ULONGLONG HiBlockTableSize64 = %016llX\n", pHeader->HiBlockTableSize64);
printf("ULONGLONG HetTableSize64 = %016llX\n", pHeader->HetTableSize64);
printf("ULONGLONG BetTableSize64 = %016llX\n", pHeader->BetTableSize64);
printf("DWORD dwRawChunkSize = %08X\n", pHeader->dwRawChunkSize);
printf("-----------------------------------------------\n\n");
}
void DumpHashTable(TMPQHash * pHashTable, DWORD dwHashTableSize)
{
DWORD i;
if(pHashTable == NULL || dwHashTableSize == 0)
return;
printf("== Hash Table =================================\n");
for(i = 0; i < dwHashTableSize; i++)
{
printf("[%08x] %08X %08X %04X %02X %08X\n", i,
pHashTable[i].dwName1,
pHashTable[i].dwName2,
pHashTable[i].lcLocale,
pHashTable[i].Platform,
pHashTable[i].dwBlockIndex);
}
printf("-----------------------------------------------\n\n");
}
void DumpHetAndBetTable(TMPQHetTable * pHetTable, TMPQBetTable * pBetTable)
{
DWORD i;
if(pHetTable == NULL || pBetTable == NULL)
return;
printf("== HET Header =================================\n");
printf("ULONGLONG AndMask64 = %016llX\n", pHetTable->AndMask64);
printf("ULONGLONG OrMask64 = %016llX\n", pHetTable->OrMask64);
printf("DWORD dwEntryCount = %08X\n", pHetTable->dwEntryCount);
printf("DWORD dwTotalCount = %08X\n", pHetTable->dwTotalCount);
printf("DWORD dwNameHashBitSize = %08X\n", pHetTable->dwNameHashBitSize);
printf("DWORD dwIndexSizeTotal = %08X\n", pHetTable->dwIndexSizeTotal);
printf("DWORD dwIndexSizeExtra = %08X\n", pHetTable->dwIndexSizeExtra);
printf("DWORD dwIndexSize = %08X\n", pHetTable->dwIndexSize);
printf("-----------------------------------------------\n\n");
printf("== BET Header =================================\n");
printf("DWORD dwTableEntrySize = %08X\n", pBetTable->dwTableEntrySize);
printf("DWORD dwBitIndex_FilePos = %08X\n", pBetTable->dwBitIndex_FilePos);
printf("DWORD dwBitIndex_FileSize = %08X\n", pBetTable->dwBitIndex_FileSize);
printf("DWORD dwBitIndex_CmpSize = %08X\n", pBetTable->dwBitIndex_CmpSize);
printf("DWORD dwBitIndex_FlagIndex = %08X\n", pBetTable->dwBitIndex_FlagIndex);
printf("DWORD dwBitIndex_Unknown = %08X\n", pBetTable->dwBitIndex_Unknown);
printf("DWORD dwBitCount_FilePos = %08X\n", pBetTable->dwBitCount_FilePos);
printf("DWORD dwBitCount_FileSize = %08X\n", pBetTable->dwBitCount_FileSize);
printf("DWORD dwBitCount_CmpSize = %08X\n", pBetTable->dwBitCount_CmpSize);
printf("DWORD dwBitCount_FlagIndex = %08X\n", pBetTable->dwBitCount_FlagIndex);
printf("DWORD dwBitCount_Unknown = %08X\n", pBetTable->dwBitCount_Unknown);
printf("DWORD dwBitTotal_NameHash2 = %08X\n", pBetTable->dwBitTotal_NameHash2);
printf("DWORD dwBitExtra_NameHash2 = %08X\n", pBetTable->dwBitExtra_NameHash2);
printf("DWORD dwBitCount_NameHash2 = %08X\n", pBetTable->dwBitCount_NameHash2);
printf("DWORD dwEntryCount = %08X\n", pBetTable->dwEntryCount);
printf("DWORD dwFlagCount = %08X\n", pBetTable->dwFlagCount);
printf("-----------------------------------------------\n\n");
printf("== HET & Bet Table ======================================================================\n\n");
printf("HetIdx HetHash BetIdx BetHash ByteOffset FileSize CmpSize FlgIdx Flags \n");
printf("------ ------- ------ ---------------- ---------------- -------- -------- ------ --------\n");
for(i = 0; i < pHetTable->dwTotalCount; i++)
{
ULONGLONG ByteOffset = 0;
ULONGLONG BetHash = 0;
DWORD dwFileSize = 0;
DWORD dwCmpSize = 0;
DWORD dwFlagIndex = 0;
DWORD dwFlags = 0;
DWORD dwBetIndex = 0;
GetMPQBits(pHetTable->pBetIndexes, i * pHetTable->dwIndexSizeTotal,
pHetTable->dwIndexSize,
&dwBetIndex, 4);
if(dwBetIndex < pHetTable->dwTotalCount)
{
DWORD dwEntryIndex = pBetTable->dwTableEntrySize * dwBetIndex;
GetMPQBits(pBetTable->pNameHashes, dwBetIndex * pBetTable->dwBitTotal_NameHash2,
pBetTable->dwBitCount_NameHash2,
&BetHash, 8);
GetMPQBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FilePos,
pBetTable->dwBitCount_FilePos,
&ByteOffset, 8);
GetMPQBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FileSize,
pBetTable->dwBitCount_FileSize,
&dwFileSize, 4);
GetMPQBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_CmpSize,
pBetTable->dwBitCount_CmpSize,
&dwCmpSize, 4);
GetMPQBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FlagIndex,
pBetTable->dwBitCount_FlagIndex,
&dwFlagIndex, 4);
dwFlags = pBetTable->pFileFlags[dwFlagIndex];
}
printf(" %04X %02lX %04X %016llX %016llX %08X %08X %04X %08X\n", i,
pHetTable->pNameHashes[i],
dwBetIndex,
BetHash,
ByteOffset,
dwFileSize,
dwCmpSize,
dwFlagIndex,
dwFlags);
}
printf("-----------------------------------------------------------------------------------------\n");
}
void DumpFileTable(TFileEntry * pFileTable, DWORD dwFileTableSize)
{
DWORD i;
if(pFileTable == NULL || dwFileTableSize == 0)
return;
printf("== File Table =================================\n");
for(i = 0; i < dwFileTableSize; i++, pFileTable++)
{
printf("[%04u] %08X-%08X %08X-%08X %08X-%08X 0x%08X 0x%08X 0x%08X %s\n", i,
(DWORD)(pFileTable->FileNameHash >> 0x20),
(DWORD)(pFileTable->FileNameHash & 0xFFFFFFFF),
(DWORD)(pFileTable->ByteOffset >> 0x20),
(DWORD)(pFileTable->ByteOffset & 0xFFFFFFFF),
(DWORD)(pFileTable->FileTime >> 0x20),
(DWORD)(pFileTable->FileTime & 0xFFFFFFFF),
pFileTable->dwFileSize,
pFileTable->dwCmpSize,
pFileTable->dwFlags,
pFileTable->szFileName != NULL ? pFileTable->szFileName : "");
}
printf("-----------------------------------------------\n\n");
}
#endif // __STORMLIB_DUMP_DATA__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,618 @@
/*****************************************************************************/
/* SBaseSubTypes.cpp Copyright (c) Ladislav Zezula 2013 */
/*---------------------------------------------------------------------------*/
/* Conversion routines for archive formats that are similar to MPQ format */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 02.11.11 1.00 Lad The first version of SBaseSubTypes.cpp */
/*****************************************************************************/
#define __STORMLIB_SELF__
#include "StormLib.h"
#include "StormCommon.h"
/*****************************************************************************/
/* */
/* Support for SQP file format (War of the Immortals) */
/* */
/*****************************************************************************/
typedef struct _TSQPHeader
{
// The ID_MPQ ('MPQ\x1A') signature
DWORD dwID;
// Size of the archive header
DWORD dwHeaderSize;
// 32-bit size of MPQ archive
DWORD dwArchiveSize;
// 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;
// Must be zero for SQP files
USHORT wFormatVersion;
// Power of two exponent specifying the number of 512-byte disk sectors in each file sector
// in the archive. The size of each file sector in the archive is 512 * 2 ^ wSectorSize.
USHORT wSectorSize;
} TSQPHeader;
typedef struct _TSQPHash
{
// Most likely the lcLocale+wPlatform.
DWORD dwAlwaysZero;
// 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;
// The hash of the file path, using method A.
DWORD dwName1;
// The hash of the file path, using method B.
DWORD dwName2;
} TSQPHash;
typedef struct _TSQPBlock
{
// Offset of the beginning of the file, relative to the beginning of the archive.
DWORD dwFilePos;
// Flags for the file. See MPQ_FILE_XXXX constants
DWORD dwFlags;
// Compressed file size
DWORD dwCSize;
// Uncompressed file size
DWORD dwFSize;
} TSQPBlock;
//-----------------------------------------------------------------------------
// Functions - SQP file format
// This function converts SQP file header into MPQ file header
DWORD ConvertSqpHeaderToFormat4(
TMPQArchive * ha,
ULONGLONG FileSize,
DWORD dwFlags)
{
TSQPHeader * pSqpHeader = (TSQPHeader *)ha->HeaderData;
TMPQHeader Header;
// SQP files from War of the Immortal use MPQ file format with slightly
// modified structure. These fields have different position:
//
// Offset TMPQHeader TSQPHeader
// ------ ---------- -----------
// 000C wFormatVersion dwHashTablePos (lo)
// 000E wSectorSize dwHashTablePos (hi)
// 001C dwBlockTableSize (lo) wBlockSize
// 001E dwHashTableSize (hi) wFormatVersion
// Can't open the archive with certain flags
if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1)
return ERROR_FILE_CORRUPT;
// The file must not be greater than 4 GB
if((FileSize >> 0x20) != 0)
return ERROR_FILE_CORRUPT;
// Translate the SQP header into a MPQ header
memset(&Header, 0, sizeof(TMPQHeader));
Header.dwID = BSWAP_INT32_UNSIGNED(pSqpHeader->dwID);
Header.dwHeaderSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHeaderSize);
Header.dwArchiveSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwArchiveSize);
Header.dwHashTablePos = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHashTablePos);
Header.dwBlockTablePos = BSWAP_INT32_UNSIGNED(pSqpHeader->dwBlockTablePos);
Header.dwHashTableSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHashTableSize);
Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwBlockTableSize);
Header.wFormatVersion = BSWAP_INT16_UNSIGNED(pSqpHeader->wFormatVersion);
Header.wSectorSize = BSWAP_INT16_UNSIGNED(pSqpHeader->wSectorSize);
// Verify the SQP header
if(Header.dwID == g_dwMpqSignature && Header.dwHeaderSize == sizeof(TSQPHeader) && Header.dwArchiveSize == FileSize)
{
// Check for fixed values of version and sector size
if(Header.wFormatVersion == MPQ_FORMAT_VERSION_1 && Header.wSectorSize == 3)
{
// Initialize the fields of 3.0 header
Header.ArchiveSize64 = Header.dwArchiveSize;
Header.HashTableSize64 = Header.dwHashTableSize * sizeof(TMPQHash);
Header.BlockTableSize64 = Header.dwBlockTableSize * sizeof(TMPQBlock);
// Copy the converted MPQ header back
memcpy(ha->HeaderData, &Header, sizeof(TMPQHeader));
// Mark this file as SQP file
ha->pfnHashString = HashStringSlash;
ha->dwFlags |= MPQ_FLAG_READ_ONLY;
ha->dwSubType = MPQ_SUBTYPE_SQP;
return ERROR_SUCCESS;
}
}
return ERROR_FILE_CORRUPT;
}
void * LoadSqpTable(TMPQArchive * ha, DWORD dwByteOffset, DWORD cbTableSize, DWORD dwKey)
{
ULONGLONG ByteOffset;
LPBYTE pbSqpTable;
// Allocate buffer for the table
pbSqpTable = STORM_ALLOC(BYTE, cbTableSize);
if(pbSqpTable != NULL)
{
// Load the table
ByteOffset = ha->MpqPos + dwByteOffset;
if(FileStream_Read(ha->pStream, &ByteOffset, pbSqpTable, cbTableSize))
{
// Decrypt the SQP table
DecryptMpqBlock(pbSqpTable, cbTableSize, dwKey);
return pbSqpTable;
}
// Free the table
STORM_FREE(pbSqpTable);
}
return NULL;
}
TMPQHash * LoadSqpHashTable(TMPQArchive * ha)
{
TMPQHeader * pHeader = ha->pHeader;
TSQPHash * pSqpHashTable;
TSQPHash * pSqpHashEnd;
TSQPHash * pSqpHash;
TMPQHash * pMpqHash;
DWORD dwErrCode = ERROR_SUCCESS;
// Load the hash table
pSqpHashTable = (TSQPHash *)LoadSqpTable(ha, pHeader->dwHashTablePos, pHeader->dwHashTableSize * sizeof(TSQPHash), MPQ_KEY_HASH_TABLE);
if(pSqpHashTable != NULL)
{
// Parse the entire hash table and convert it to MPQ hash table
pSqpHashEnd = pSqpHashTable + pHeader->dwHashTableSize;
pMpqHash = (TMPQHash *)pSqpHashTable;
for(pSqpHash = pSqpHashTable; pSqpHash < pSqpHashEnd; pSqpHash++, pMpqHash++)
{
// Ignore free entries
if(pSqpHash->dwBlockIndex != HASH_ENTRY_FREE)
{
// Check block index against the size of the block table
if(pHeader->dwBlockTableSize <= MPQ_BLOCK_INDEX(pSqpHash) && pSqpHash->dwBlockIndex < HASH_ENTRY_DELETED)
dwErrCode = ERROR_FILE_CORRUPT;
// We do not support nonzero locale and platform ID
if(pSqpHash->dwAlwaysZero != 0 && pSqpHash->dwAlwaysZero != HASH_ENTRY_FREE)
dwErrCode = ERROR_FILE_CORRUPT;
// Store the file name hash
pMpqHash->dwName1 = pSqpHash->dwName1;
pMpqHash->dwName2 = pSqpHash->dwName2;
// Store the rest. Note that this must be done last,
// because block index corresponds to pMpqHash->dwName2
pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(pSqpHash);
pMpqHash->Platform = 0;
pMpqHash->lcLocale = 0;
}
}
// If an error occured, we need to free the hash table
if(dwErrCode != ERROR_SUCCESS)
{
STORM_FREE(pSqpHashTable);
pSqpHashTable = NULL;
}
}
// Return the converted hash table (or NULL on failure)
return (TMPQHash *)pSqpHashTable;
}
// Loads the SQP Block table and converts it to a MPQ block table
TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha)
{
TMPQHeader * pHeader = ha->pHeader;
TSQPBlock * pSqpBlockTable;
TSQPBlock * pSqpBlockEnd;
TSQPBlock * pSqpBlock;
TMPQBlock * pMpqBlock;
DWORD dwFlags;
DWORD dwErrCode = ERROR_SUCCESS;
// Load the hash table
pSqpBlockTable = (TSQPBlock *)LoadSqpTable(ha, pHeader->dwBlockTablePos, pHeader->dwBlockTableSize * sizeof(TSQPBlock), MPQ_KEY_BLOCK_TABLE);
if(pSqpBlockTable != NULL)
{
// Parse the entire hash table and convert it to MPQ hash table
pSqpBlockEnd = pSqpBlockTable + pHeader->dwBlockTableSize;
pMpqBlock = (TMPQBlock *)pSqpBlockTable;
for(pSqpBlock = pSqpBlockTable; pSqpBlock < pSqpBlockEnd; pSqpBlock++, pMpqBlock++)
{
// Check for valid flags
if(pSqpBlock->dwFlags & ~MPQ_FILE_VALID_FLAGS)
dwErrCode = ERROR_FILE_CORRUPT;
// Convert SQP block table entry to MPQ block table entry
dwFlags = pSqpBlock->dwFlags;
pMpqBlock->dwCSize = pSqpBlock->dwCSize;
pMpqBlock->dwFSize = pSqpBlock->dwFSize;
pMpqBlock->dwFlags = dwFlags;
}
// If an error occured, we need to free the hash table
if(dwErrCode != ERROR_SUCCESS)
{
STORM_FREE(pSqpBlockTable);
pSqpBlockTable = NULL;
}
}
// Return the converted hash table (or NULL on failure)
return (TMPQBlock *)pSqpBlockTable;
}
/*****************************************************************************/
/* */
/* Support for MPK file format (Longwu Online) */
/* */
/*****************************************************************************/
#define MPK_FILE_UNKNOWN_0001 0x00000001 // Seems to be always present
#define MPK_FILE_UNKNOWN_0010 0x00000010 // Seems to be always present
#define MPK_FILE_COMPRESSED 0x00000100 // Indicates a compressed file
#define MPK_FILE_UNKNOWN_2000 0x00002000 // Seems to be always present
#define MPK_FILE_EXISTS 0x01000000 // Seems to be always present
typedef struct _TMPKHeader
{
// The ID_MPK ('MPK\x1A') signature
DWORD dwID;
// Contains '2000'
DWORD dwVersion;
// 32-bit size of the archive
DWORD dwArchiveSize;
// Size of the archive header
DWORD dwHeaderSize;
DWORD dwHashTablePos;
DWORD dwHashTableSize;
DWORD dwBlockTablePos;
DWORD dwBlockTableSize;
DWORD dwUnknownPos;
DWORD dwUnknownSize;
} TMPKHeader;
typedef struct _TMPKHash
{
// The hash of the file path, using method A.
DWORD dwName1;
// The hash of the file path, using method B.
DWORD dwName2;
// The hash of the file path, using method C.
DWORD dwName3;
// 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;
} TMPKHash;
typedef struct _TMPKBlock
{
DWORD dwFlags; // 0x1121 - Compressed , 0x1120 - Not compressed
DWORD dwFilePos; // Offset of the beginning of the file, relative to the beginning of the archive.
DWORD dwFSize; // Uncompressed file size
DWORD dwCSize; // Compressed file size
DWORD dwUnknown; // 0x86364E6D
} TMPKBlock;
//-----------------------------------------------------------------------------
// Local variables - MPK file format
static const unsigned char MpkDecryptionKey[512] =
{
0x60, 0x20, 0x29, 0xE1, 0x01, 0xCE, 0xAA, 0xFE, 0xA3, 0xAB, 0x8E, 0x30, 0xAF, 0x02, 0xD1, 0x7D,
0x41, 0x24, 0x06, 0xBD, 0xAE, 0xBE, 0x43, 0xC3, 0xBA, 0xB7, 0x08, 0x13, 0x51, 0xCF, 0xF8, 0xF7,
0x25, 0x42, 0xA5, 0x4A, 0xDA, 0x0F, 0x52, 0x1C, 0x90, 0x3B, 0x63, 0x49, 0x36, 0xF6, 0xDD, 0x1B,
0xEA, 0x58, 0xD4, 0x40, 0x70, 0x61, 0x55, 0x09, 0xCD, 0x0B, 0xA2, 0x4B, 0x68, 0x2C, 0x8A, 0xF1,
0x3C, 0x3A, 0x65, 0xBB, 0xA1, 0xA8, 0x23, 0x97, 0xFD, 0x15, 0x00, 0x94, 0x88, 0x33, 0x59, 0xE9,
0xFB, 0x69, 0x21, 0xEF, 0x85, 0x5B, 0x57, 0x6C, 0xFA, 0xB5, 0xEE, 0xB8, 0x71, 0xDC, 0xB1, 0x38,
0x0C, 0x0A, 0x5C, 0x56, 0xC9, 0xB4, 0x84, 0x17, 0x1E, 0xE5, 0xD3, 0x5A, 0xCC, 0xFC, 0x11, 0x86,
0x7F, 0x45, 0x4F, 0x54, 0xC8, 0x8D, 0x73, 0x89, 0x79, 0x5D, 0xB3, 0xBF, 0xB9, 0xE3, 0x93, 0xE4,
0x6F, 0x35, 0x2D, 0x46, 0xF2, 0x76, 0xC5, 0x7E, 0xE2, 0xA4, 0xE6, 0xD9, 0x6E, 0x48, 0x34, 0x2B,
0xC6, 0x5F, 0xBC, 0xA0, 0x6D, 0x0D, 0x47, 0x6B, 0x95, 0x96, 0x92, 0x91, 0xB2, 0x27, 0xEB, 0x9E,
0xEC, 0x8F, 0xDF, 0x9C, 0x74, 0x99, 0x64, 0xF5, 0xFF, 0x28, 0xB6, 0x37, 0xF3, 0x7C, 0x81, 0x03,
0x44, 0x62, 0x1F, 0xDB, 0x04, 0x7B, 0xB0, 0x9B, 0x31, 0xA7, 0xDE, 0x78, 0x9F, 0xAD, 0x0E, 0x3F,
0x3E, 0x4D, 0xC7, 0xD7, 0x39, 0x19, 0x5E, 0xC2, 0xD0, 0xAC, 0xE8, 0x1A, 0x87, 0x8B, 0x07, 0x05,
0x22, 0xED, 0x72, 0x2E, 0x1D, 0xC1, 0xA9, 0xD6, 0xE0, 0x83, 0xD5, 0xD8, 0xCB, 0x80, 0xF0, 0x66,
0x7A, 0x9D, 0x50, 0xF9, 0x10, 0x4E, 0x16, 0x14, 0x77, 0x75, 0x6A, 0x67, 0xD2, 0xC0, 0xA6, 0xC4,
0x53, 0x8C, 0x32, 0xCA, 0x82, 0x2A, 0x18, 0x9A, 0xF4, 0x4C, 0x3D, 0x26, 0x12, 0xE7, 0x98, 0x2F,
0x4A, 0x04, 0x0D, 0xAF, 0xB4, 0xCF, 0x12, 0xCE, 0x1A, 0x37, 0x61, 0x39, 0x60, 0x95, 0xBE, 0x25,
0xE4, 0x6E, 0xFC, 0x1B, 0xE7, 0x49, 0xE6, 0x67, 0xF6, 0xC5, 0xCB, 0x2F, 0x27, 0xD4, 0x68, 0xB2,
0x01, 0x52, 0xD0, 0x46, 0x11, 0x20, 0xFB, 0x9D, 0xA9, 0x02, 0xF5, 0x8F, 0x3D, 0x82, 0xD3, 0xFF,
0x0B, 0xB8, 0xF2, 0x4D, 0x8E, 0x81, 0x2C, 0xAB, 0x5F, 0xC4, 0x41, 0x29, 0x40, 0xFA, 0xC0, 0xBF,
0x33, 0x10, 0x21, 0x16, 0xB0, 0x71, 0x83, 0x96, 0x8D, 0x2B, 0x23, 0x3B, 0xF9, 0xC1, 0xE5, 0x72,
0xE2, 0x1C, 0x26, 0xF0, 0x73, 0x36, 0x63, 0x56, 0x31, 0x4E, 0x6B, 0x55, 0x62, 0x79, 0xC6, 0x91,
0x00, 0x35, 0xB1, 0x2A, 0xA6, 0x42, 0xDF, 0xEB, 0x3C, 0x51, 0xEA, 0x97, 0x57, 0x94, 0x8C, 0x80,
0x34, 0x5C, 0xD2, 0x76, 0xA4, 0xE9, 0x85, 0xE8, 0xBB, 0x78, 0xE0, 0xB5, 0xAD, 0x0F, 0x87, 0x70,
0xDD, 0xAE, 0xF4, 0xD9, 0x66, 0x54, 0x6F, 0xCC, 0x4C, 0x77, 0x3E, 0xCD, 0xF1, 0x75, 0x0A, 0xA1,
0x28, 0x9B, 0x9A, 0x7E, 0x4B, 0x98, 0x99, 0x47, 0xFE, 0xA5, 0xF7, 0xB7, 0xA3, 0xE1, 0x9F, 0xBC,
0x93, 0x44, 0x3A, 0x08, 0x89, 0x22, 0xEE, 0xB9, 0x45, 0xD6, 0x06, 0x09, 0xC9, 0xBD, 0x14, 0x0C,
0xB6, 0x5E, 0x9C, 0x7A, 0x65, 0x59, 0xAA, 0x19, 0x5B, 0x7C, 0x18, 0x43, 0x92, 0x13, 0x15, 0x7B,
0xED, 0xD5, 0xC7, 0x17, 0xEF, 0x86, 0x90, 0xC2, 0x74, 0x64, 0xF3, 0xDC, 0x6C, 0x38, 0x05, 0x1D,
0xC8, 0x0E, 0xEC, 0x6A, 0x32, 0xDA, 0xD7, 0xC3, 0xDB, 0x8B, 0x24, 0xB3, 0x5D, 0x2E, 0xBA, 0xA2,
0xD8, 0x03, 0x88, 0x7D, 0x7F, 0x69, 0x8A, 0xFD, 0xCA, 0x4F, 0x30, 0x9E, 0xA0, 0xD1, 0x5A, 0x53,
0xDE, 0x3F, 0x84, 0xAC, 0xF8, 0xA7, 0x2D, 0x1F, 0x1E, 0xE3, 0x58, 0x50, 0x6D, 0x48, 0x07, 0xA8
};
//-----------------------------------------------------------------------------
// Functions - MPK file format
// This function converts MPK file header into MPQ file header
DWORD ConvertMpkHeaderToFormat4(
TMPQArchive * ha,
ULONGLONG FileSize,
DWORD dwFlags)
{
TMPKHeader * pMpkHeader = (TMPKHeader *)ha->HeaderData;
TMPQHeader Header;
// Can't open the archive with certain flags
if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1)
return ERROR_FILE_CORRUPT;
// Translate the MPK header into a MPQ header
// Note: Hash table size and block table size are in bytes, not in entries
memset(&Header, 0, sizeof(TMPQHeader));
Header.dwID = BSWAP_INT32_UNSIGNED(pMpkHeader->dwID);
Header.dwArchiveSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwArchiveSize);
Header.dwHeaderSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHeaderSize);
Header.dwHashTablePos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHashTablePos);
Header.dwHashTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHashTableSize) / sizeof(TMPKHash);
Header.dwBlockTablePos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTablePos);
Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTableSize) / sizeof(TMPKBlock);
// Header.dwUnknownPos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwUnknownPos);
// Header.dwUnknownSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwUnknownSize);
assert(Header.dwHeaderSize == sizeof(TMPKHeader));
// Verify the MPK header
if(Header.dwID == ID_MPK && Header.dwHeaderSize == sizeof(TMPKHeader) && Header.dwArchiveSize == (DWORD)FileSize)
{
// The header ID must be ID_MPQ
Header.dwID = g_dwMpqSignature;
Header.wFormatVersion = MPQ_FORMAT_VERSION_1;
Header.wSectorSize = 3;
// Initialize the fields of 3.0 header
Header.ArchiveSize64 = Header.dwArchiveSize;
Header.HashTableSize64 = Header.dwHashTableSize * sizeof(TMPQHash);
Header.BlockTableSize64 = Header.dwBlockTableSize * sizeof(TMPQBlock);
// Copy the converted MPQ header back
memcpy(ha->HeaderData, &Header, sizeof(TMPQHeader));
// Mark this file as MPK file
ha->pfnHashString = HashStringLower;
ha->dwFlags |= MPQ_FLAG_READ_ONLY;
ha->dwSubType = MPQ_SUBTYPE_MPK;
return ERROR_SUCCESS;
}
return ERROR_FILE_CORRUPT;
}
// Attempts to search a free hash entry in the hash table being converted.
// The created hash table must always be of nonzero size,
// should have no duplicated items and no deleted entries
TMPQHash * FindFreeHashEntry(TMPQHash * pHashTable, DWORD dwHashTableSize, DWORD dwStartIndex)
{
TMPQHash * pHash;
DWORD dwIndex;
// Set the initial index
dwStartIndex = dwIndex = (dwStartIndex & (dwHashTableSize - 1));
assert(dwHashTableSize != 0);
// Search the hash table and return the found entries in the following priority:
for(;;)
{
// We are not expecting to find matching entry in the hash table being built
// We are not expecting to find deleted entry either
pHash = pHashTable + dwIndex;
// If we found a free entry, we need to stop searching
if(pHash->dwBlockIndex == HASH_ENTRY_FREE)
return pHash;
// Move to the next hash entry.
// If we reached the starting entry, it's failure.
dwIndex = (dwIndex + 1) & (dwHashTableSize - 1);
if(dwIndex == dwStartIndex)
break;
}
// We haven't found anything
assert(false);
return NULL;
}
void DecryptMpkTable(void * pvMpkTable, size_t cbSize)
{
LPBYTE pbMpkTable = (LPBYTE)pvMpkTable;
for(size_t i = 0; i < cbSize; i++)
pbMpkTable[i] = MpkDecryptionKey[pbMpkTable[i]];
}
void * LoadMpkTable(TMPQArchive * ha, DWORD dwByteOffset, DWORD cbTableSize)
{
ULONGLONG ByteOffset;
LPBYTE pbMpkTable = NULL;
// Allocate space for the table
pbMpkTable = STORM_ALLOC(BYTE, cbTableSize);
if(pbMpkTable != NULL)
{
// Load and the MPK hash table
ByteOffset = ha->MpqPos + dwByteOffset;
if(FileStream_Read(ha->pStream, &ByteOffset, pbMpkTable, cbTableSize))
{
// Decrypt the table
DecryptMpkTable(pbMpkTable, cbTableSize);
return pbMpkTable;
}
// Free the MPK table
STORM_FREE(pbMpkTable);
pbMpkTable = NULL;
}
// Return the table
return pbMpkTable;
}
TMPQHash * LoadMpkHashTable(TMPQArchive * ha)
{
TMPQHeader * pHeader = ha->pHeader;
TMPQHash * pHashTable = NULL;
TMPKHash * pMpkHash;
TMPQHash * pHash = NULL;
DWORD dwHashTableSize = pHeader->dwHashTableSize;
// MPKs use different hash table searching.
// Instead of using MPQ_HASH_TABLE_INDEX hash as index,
// they store the value directly in the hash table.
// Also for faster searching, the hash table is sorted ascending by the value
// Load and decrypt the MPK hash table.
pMpkHash = (TMPKHash *)LoadMpkTable(ha, pHeader->dwHashTablePos, pHeader->dwHashTableSize * sizeof(TMPKHash));
if(pMpkHash != NULL)
{
// Calculate the hash table size as if it was real MPQ hash table
pHeader->dwHashTableSize = GetNearestPowerOfTwo(pHeader->dwHashTableSize);
pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash);
// Now allocate table that will serve like a true MPQ hash table,
// so we translate the MPK hash table to MPQ hash table
pHashTable = STORM_ALLOC(TMPQHash, pHeader->dwHashTableSize);
if(pHashTable != NULL)
{
// Set the entire hash table to free
memset(pHashTable, 0xFF, (size_t)pHeader->HashTableSize64);
// Copy the MPK hash table into MPQ hash table
for(DWORD i = 0; i < dwHashTableSize; i++)
{
// Finds the free hash entry in the hash table
// We don't expect any errors here, because we are putting files to empty hash table
pHash = FindFreeHashEntry(pHashTable, pHeader->dwHashTableSize, pMpkHash[i].dwName1);
assert(pHash->dwBlockIndex == HASH_ENTRY_FREE);
// Copy the MPK hash entry to the hash table
pHash->dwBlockIndex = pMpkHash[i].dwBlockIndex;
pHash->Platform = 0;
pHash->lcLocale = 0;
pHash->dwName1 = pMpkHash[i].dwName2;
pHash->dwName2 = pMpkHash[i].dwName3;
}
}
// Free the temporary hash table
STORM_FREE(pMpkHash);
}
return pHashTable;
}
static DWORD ConvertMpkFlagsToMpqFlags(DWORD dwMpkFlags)
{
DWORD dwMpqFlags = MPQ_FILE_EXISTS;
// Check for flags that are always present
assert((dwMpkFlags & MPK_FILE_UNKNOWN_0001) != 0);
assert((dwMpkFlags & MPK_FILE_UNKNOWN_0010) != 0);
assert((dwMpkFlags & MPK_FILE_UNKNOWN_2000) != 0);
assert((dwMpkFlags & MPK_FILE_EXISTS) != 0);
// Append the compressed flag
dwMpqFlags |= (dwMpkFlags & MPK_FILE_COMPRESSED) ? MPQ_FILE_COMPRESS : 0;
// All files in the MPQ seem to be single unit files
dwMpqFlags |= MPQ_FILE_ENCRYPTED | MPQ_FILE_SINGLE_UNIT;
return dwMpqFlags;
}
TMPQBlock * LoadMpkBlockTable(TMPQArchive * ha)
{
TMPQHeader * pHeader = ha->pHeader;
TMPKBlock * pMpkBlockTable;
TMPKBlock * pMpkBlockEnd;
TMPQBlock * pBlockTable = NULL;
TMPKBlock * pMpkBlock;
TMPQBlock * pMpqBlock;
// Load and decrypt the MPK block table
pMpkBlockTable = pMpkBlock = (TMPKBlock *)LoadMpkTable(ha, pHeader->dwBlockTablePos, pHeader->dwBlockTableSize * sizeof(TMPKBlock));
if(pMpkBlockTable != NULL)
{
// Allocate buffer for MPQ-like block table
pBlockTable = pMpqBlock = STORM_ALLOC(TMPQBlock, pHeader->dwBlockTableSize);
if(pBlockTable != NULL)
{
// Convert the MPK block table to MPQ block table
pMpkBlockEnd = pMpkBlockTable + pHeader->dwBlockTableSize;
while(pMpkBlock < pMpkBlockEnd)
{
// Translate the MPK block table entry to MPQ block table entry
pMpqBlock->dwFilePos = pMpkBlock->dwFilePos;
pMpqBlock->dwCSize = pMpkBlock->dwCSize;
pMpqBlock->dwFSize = pMpkBlock->dwFSize;
pMpqBlock->dwFlags = ConvertMpkFlagsToMpqFlags(pMpkBlock->dwFlags);
// Move both
pMpkBlock++;
pMpqBlock++;
}
}
// Free the MPK block table
STORM_FREE(pMpkBlockTable);
}
return pBlockTable;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,570 @@
/*****************************************************************************/
/* SAttrFile.cpp Copyright (c) Ladislav Zezula 2007 */
/*---------------------------------------------------------------------------*/
/* Description: */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 12.06.04 1.00 Lad The first version of SAttrFile.cpp */
/*****************************************************************************/
#define __STORMLIB_SELF__
#include "StormLib.h"
#include "StormCommon.h"
//-----------------------------------------------------------------------------
// Local structures
typedef struct _MPQ_ATTRIBUTES_HEADER
{
DWORD dwVersion; // Version of the (attributes) file. Must be 100 (0x64)
DWORD dwFlags; // See MPQ_ATTRIBUTE_XXXX
// Followed by an array of CRC32
// Followed by an array of file times
// Followed by an array of MD5
// Followed by an array of patch bits
// Note: The MD5 in (attributes), if present, is a hash of the entire file.
// In case the file is an incremental patch, it contains MD5 of the file
// after being patched.
} MPQ_ATTRIBUTES_HEADER, *PMPQ_ATTRIBUTES_HEADER;
//-----------------------------------------------------------------------------
// Local functions
static DWORD GetSizeOfAttributesFile(DWORD dwAttrFlags, DWORD dwBlockTableSize)
{
DWORD cbAttrFile = sizeof(MPQ_ATTRIBUTES_HEADER);
// Calculate size of the (attributes) file
if(dwAttrFlags & MPQ_ATTRIBUTE_CRC32)
cbAttrFile += dwBlockTableSize * sizeof(DWORD);
if(dwAttrFlags & MPQ_ATTRIBUTE_FILETIME)
cbAttrFile += dwBlockTableSize * sizeof(ULONGLONG);
if(dwAttrFlags & MPQ_ATTRIBUTE_MD5)
cbAttrFile += dwBlockTableSize * MD5_DIGEST_SIZE;
// The bit array has been created without the last bit belonging to (attributes)
// When the number of files is a multiplier of 8 plus one, then the size of (attributes)
// if 1 byte less than expected.
// Example: wow-update-13164.MPQ: BlockTableSize = 0x62E1, but there's only 0xC5C bytes
if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
cbAttrFile += (dwBlockTableSize + 6) / 8;
return cbAttrFile;
}
static DWORD CheckSizeOfAttributesFile(DWORD cbAttrFile, DWORD dwAttrFlags, DWORD dwBlockTableSize)
{
DWORD cbHeaderSize = sizeof(MPQ_ATTRIBUTES_HEADER);
DWORD cbChecksumSize1 = 0;
DWORD cbChecksumSize2 = 0;
DWORD cbFileTimeSize1 = 0;
DWORD cbFileTimeSize2 = 0;
DWORD cbFileHashSize1 = 0;
DWORD cbFileHashSize2 = 0;
DWORD cbPatchBitSize1 = 0;
DWORD cbPatchBitSize2 = 0;
DWORD cbPatchBitSize3 = 0;
//
// Various variants with the patch bit
//
// interface.MPQ.part from WoW build 10958 has
// the MPQ_ATTRIBUTE_PATCH_BIT set, but there's an array of DWORDs instead.
// The array is filled with zeros, so we don't know what it should contain
//
// Zenith.SC2MAP has the MPQ_ATTRIBUTE_PATCH_BIT set, but the bit array is missing
//
// Elimination Tournament 2.w3x's (attributes) have one entry less
//
// There may be two variants: Either the (attributes) file has full
// number of entries, or has one entry less
//
// Get the expected size of CRC32 array
if(dwAttrFlags & MPQ_ATTRIBUTE_CRC32)
{
cbChecksumSize1 += dwBlockTableSize * sizeof(DWORD);
cbChecksumSize2 += cbChecksumSize1 - sizeof(DWORD);
}
// Get the expected size of FILETIME array
if(dwAttrFlags & MPQ_ATTRIBUTE_FILETIME)
{
cbFileTimeSize1 += dwBlockTableSize * sizeof(ULONGLONG);
cbFileTimeSize2 += cbFileTimeSize1 - sizeof(ULONGLONG);
}
// Get the expected size of MD5 array
if(dwAttrFlags & MPQ_ATTRIBUTE_MD5)
{
cbFileHashSize1 += dwBlockTableSize * MD5_DIGEST_SIZE;
cbFileHashSize2 += cbFileHashSize1 - MD5_DIGEST_SIZE;
}
// Get the expected size of patch bit array
if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
{
cbPatchBitSize1 =
cbPatchBitSize2 = ((dwBlockTableSize + 6) / 8);
cbPatchBitSize3 = dwBlockTableSize * sizeof(DWORD);
}
// Check if the (attributes) file entry count is equal to our file table size
if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1 + cbPatchBitSize1))
return dwBlockTableSize;
// Check if the (attributes) file entry count is equal to our file table size minus one
if(cbAttrFile == (cbHeaderSize + cbChecksumSize2 + cbFileTimeSize2 + cbFileHashSize2 + cbPatchBitSize2))
return dwBlockTableSize - 1;
// Zenith.SC2MAP has the MPQ_ATTRIBUTE_PATCH_BIT set, but the bit array is missing
if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1))
return dwBlockTableSize;
// interface.MPQ.part (WoW build 10958) has the MPQ_ATTRIBUTE_PATCH_BIT set
// but there's an array of DWORDs (filled with zeros) instead of array of bits
if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1 + cbPatchBitSize3))
return dwBlockTableSize;
#ifdef __STORMLIB_TEST__
// Invalid size of the (attributes) file
// Note that many MPQs, especially Warcraft III maps have the size of (attributes) invalid.
// We only perform this check if this is the STORMLIB testprogram itself
// assert(false);
#endif
return 0;
}
static DWORD LoadAttributesFile(TMPQArchive * ha, LPBYTE pbAttrFile, DWORD cbAttrFile)
{
LPBYTE pbAttrFileEnd = pbAttrFile + cbAttrFile;
LPBYTE pbAttrPtr = pbAttrFile;
DWORD dwAttributesEntries = 0;
DWORD i;
// Load and verify the header
if((pbAttrPtr + sizeof(MPQ_ATTRIBUTES_HEADER)) <= pbAttrFileEnd)
{
PMPQ_ATTRIBUTES_HEADER pAttrHeader = (PMPQ_ATTRIBUTES_HEADER)pbAttrPtr;
// Verify the header version
BSWAP_ARRAY32_UNSIGNED(pAttrHeader, sizeof(MPQ_ATTRIBUTES_HEADER));
if(pAttrHeader->dwVersion != MPQ_ATTRIBUTES_V1)
return ERROR_BAD_FORMAT;
// Verify the flags
if(pAttrHeader->dwFlags & ~MPQ_ATTRIBUTE_ALL)
return ERROR_BAD_FORMAT;
// Verify whether file size of (attributes) is expected
dwAttributesEntries = CheckSizeOfAttributesFile(cbAttrFile, pAttrHeader->dwFlags, ha->pHeader->dwBlockTableSize);
if(dwAttributesEntries == 0)
return ERROR_BAD_FORMAT;
ha->dwAttrFlags = pAttrHeader->dwFlags;
pbAttrPtr = (LPBYTE)(pAttrHeader + 1);
}
// Load the CRC32 (if present)
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_CRC32)
{
LPDWORD ArrayCRC32 = (LPDWORD)pbAttrPtr;
DWORD cbArraySize = dwAttributesEntries * sizeof(DWORD);
// Verify if there's enough data
if((pbAttrPtr + cbArraySize) > pbAttrFileEnd)
return ERROR_FILE_CORRUPT;
BSWAP_ARRAY32_UNSIGNED(ArrayCRC32, cbCRC32Size);
for(i = 0; i < dwAttributesEntries; i++)
ha->pFileTable[i].dwCrc32 = ArrayCRC32[i];
pbAttrPtr += cbArraySize;
}
// Load the FILETIME (if present)
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_FILETIME)
{
ULONGLONG * ArrayFileTime = (ULONGLONG *)pbAttrPtr;
DWORD cbArraySize = dwAttributesEntries * sizeof(ULONGLONG);
// Verify if there's enough data
if((pbAttrPtr + cbArraySize) > pbAttrFileEnd)
return ERROR_FILE_CORRUPT;
BSWAP_ARRAY64_UNSIGNED(ArrayFileTime, cbFileTimeSize);
for(i = 0; i < dwAttributesEntries; i++)
ha->pFileTable[i].FileTime = ArrayFileTime[i];
pbAttrPtr += cbArraySize;
}
// Load the MD5 (if present)
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_MD5)
{
LPBYTE ArrayMd5 = pbAttrPtr;
DWORD cbArraySize = dwAttributesEntries * MD5_DIGEST_SIZE;
// Verify if there's enough data
if((pbAttrPtr + cbArraySize) > pbAttrFileEnd)
return ERROR_FILE_CORRUPT;
for(i = 0; i < dwAttributesEntries; i++)
{
memcpy(ha->pFileTable[i].md5, ArrayMd5, MD5_DIGEST_SIZE);
ArrayMd5 += MD5_DIGEST_SIZE;
}
pbAttrPtr += cbArraySize;
}
// Read the patch bit for each file (if present)
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
{
LPBYTE pbBitArray = pbAttrPtr;
DWORD cbArraySize = (dwAttributesEntries + 7) / 8;
DWORD dwByteIndex = 0;
DWORD dwBitMask = 0x80;
// Verify if there's enough data
if((pbAttrPtr + cbArraySize) == pbAttrFileEnd)
{
for(i = 0; i < dwAttributesEntries; i++)
{
ha->pFileTable[i].dwFlags |= (pbBitArray[dwByteIndex] & dwBitMask) ? MPQ_FILE_PATCH_FILE : 0;
dwByteIndex += (dwBitMask & 0x01);
dwBitMask = (dwBitMask << 0x07) | (dwBitMask >> 0x01);
}
}
}
return ERROR_SUCCESS;
}
static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
{
PMPQ_ATTRIBUTES_HEADER pAttrHeader;
TFileEntry * pFileTableEnd = ha->pFileTable + ha->pHeader->dwBlockTableSize;
TFileEntry * pFileEntry;
LPBYTE pbAttrFile;
LPBYTE pbAttrPtr;
size_t cbAttrFile;
// Check if we need patch bits in the (attributes) file
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
{
if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
{
ha->dwAttrFlags |= MPQ_ATTRIBUTE_PATCH_BIT;
break;
}
}
// Allocate the buffer for holding the entire (attributes)
// Allocate 1 byte more (See GetSizeOfAttributesFile for more info)
cbAttrFile = GetSizeOfAttributesFile(ha->dwAttrFlags, ha->pHeader->dwBlockTableSize);
pbAttrFile = pbAttrPtr = STORM_ALLOC(BYTE, cbAttrFile + 1);
if(pbAttrFile != NULL)
{
// Make sure it's all zeroed
memset(pbAttrFile, 0, cbAttrFile + 1);
// Write the header of the (attributes) file
pAttrHeader = (PMPQ_ATTRIBUTES_HEADER)pbAttrPtr;
pAttrHeader->dwVersion = BSWAP_INT32_UNSIGNED(100);
pAttrHeader->dwFlags = BSWAP_INT32_UNSIGNED((ha->dwAttrFlags & MPQ_ATTRIBUTE_ALL));
pbAttrPtr = (LPBYTE)(pAttrHeader + 1);
// Write the array of CRC32, if present
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_CRC32)
{
LPDWORD pArrayCRC32 = (LPDWORD)pbAttrPtr;
// Copy from file table
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
*pArrayCRC32++ = BSWAP_INT32_UNSIGNED(pFileEntry->dwCrc32);
// Update pointer
pbAttrPtr = (LPBYTE)pArrayCRC32;
}
// Write the array of file time
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_FILETIME)
{
ULONGLONG * pArrayFileTime = (ULONGLONG *)pbAttrPtr;
// Copy from file table
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
*pArrayFileTime++ = BSWAP_INT64_UNSIGNED(pFileEntry->FileTime);
// Update pointer
pbAttrPtr = (LPBYTE)pArrayFileTime;
}
// Write the array of MD5s
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_MD5)
{
LPBYTE pbArrayMD5 = pbAttrPtr;
// Copy from file table
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
{
memcpy(pbArrayMD5, pFileEntry->md5, MD5_DIGEST_SIZE);
pbArrayMD5 += MD5_DIGEST_SIZE;
}
// Update pointer
pbAttrPtr = pbArrayMD5;
}
// Write the array of patch bits
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
{
LPBYTE pbBitArray = pbAttrPtr;
DWORD dwByteIndex = 0;
BYTE dwBitMask = 0x80;
// Copy from file table
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
{
// Set the bit, if needed
if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
pbBitArray[dwByteIndex] |= dwBitMask;
// Update bit index and bit mask
dwByteIndex += (dwBitMask & 0x01);
dwBitMask = (dwBitMask << 0x07) | (dwBitMask >> 0x01);
}
// Move past the bit array
pbAttrPtr += (ha->pHeader->dwBlockTableSize + 6) / 8;
}
// Now we expect that current position matches the estimated size
// Note that if there is 1 extra bit above the byte size,
// the table is actually 1 byte shorter in Blizzard MPQs. See GetSizeOfAttributesFile
assert((size_t)(pbAttrPtr - pbAttrFile) == cbAttrFile);
}
// Give away the attributes file
if(pcbAttrFile != NULL)
*pcbAttrFile = (DWORD)cbAttrFile;
return pbAttrFile;
}
//-----------------------------------------------------------------------------
// Public functions (internal use by StormLib)
DWORD SAttrLoadAttributes(TMPQArchive * ha)
{
HANDLE hFile = NULL;
LPBYTE pbAttrFile;
DWORD dwBytesRead;
DWORD cbAttrFile = 0;
DWORD dwErrCode = ERROR_FILE_CORRUPT;
// File table must be initialized
assert(ha->pFileTable != NULL);
assert((ha->dwFlags & MPQ_FLAG_BLOCK_TABLE_CUT) == 0);
// Don't load the attributes file from malformed Warcraft III maps
if(ha->dwFlags & MPQ_FLAG_MALFORMED)
return ERROR_FILE_CORRUPT;
// Attempt to open the "(attributes)" file.
if(SFileOpenFileEx((HANDLE)ha, ATTRIBUTES_NAME, SFILE_OPEN_ANY_LOCALE, &hFile))
{
// Retrieve and check size of the (attributes) file
cbAttrFile = SFileGetFileSize(hFile, NULL);
// Integer overflow check
if((cbAttrFile + 1) > cbAttrFile)
{
// Size of the (attributes) might be 1 byte less than expected
// See GetSizeOfAttributesFile for more info
pbAttrFile = STORM_ALLOC(BYTE, cbAttrFile + 1);
if(pbAttrFile != NULL)
{
// Set the last byte to 0 in case the size should be 1 byte greater
pbAttrFile[cbAttrFile] = 0;
// Load the entire file to memory
SFileReadFile(hFile, pbAttrFile, cbAttrFile, &dwBytesRead, NULL);
if(dwBytesRead == cbAttrFile)
dwErrCode = LoadAttributesFile(ha, pbAttrFile, cbAttrFile);
// Free the buffer
STORM_FREE(pbAttrFile);
}
}
// Close the attributes file
SFileCloseFile(hFile);
}
return dwErrCode;
}
// Saves the (attributes) to the MPQ
DWORD SAttrFileSaveToMpq(TMPQArchive * ha)
{
TMPQFile * hf = NULL;
LPBYTE pbAttrFile;
DWORD cbAttrFile = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Only save the attributes if we should do so
if(ha->dwFileFlags2 != 0)
{
// At this point, we expect to have at least one reserved entry in the file table
assert(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_NEW);
assert(ha->dwReservedFiles > 0);
// Create the raw data that is to be written to (attributes)
// Note: Blizzard MPQs have entries for (listfile) and (attributes),
// but they are filled empty
pbAttrFile = CreateAttributesFile(ha, &cbAttrFile);
if(pbAttrFile != NULL)
{
// Determine the real flags for (attributes)
if(ha->dwFileFlags2 == MPQ_FILE_DEFAULT_INTERNAL)
ha->dwFileFlags2 = GetDefaultSpecialFileFlags(cbAttrFile, ha->pHeader->wFormatVersion);
// Create the attributes file in the MPQ
dwErrCode = SFileAddFile_Init(ha, ATTRIBUTES_NAME,
0,
cbAttrFile,
LANG_NEUTRAL,
ha->dwFileFlags2 | MPQ_FILE_REPLACEEXISTING,
&hf);
// Write the attributes file raw data to it
if(dwErrCode == ERROR_SUCCESS)
{
// Write the content of the attributes file to the MPQ
dwErrCode = SFileAddFile_Write(hf, pbAttrFile, cbAttrFile, MPQ_COMPRESSION_ZLIB);
SFileAddFile_Finish(hf);
}
// Clear the number of reserved files
ha->dwFlags &= ~(MPQ_FLAG_ATTRIBUTES_NEW | MPQ_FLAG_ATTRIBUTES_NONE);
ha->dwReservedFiles--;
// Free the attributes buffer
STORM_FREE(pbAttrFile);
}
else
{
// If the (attributes) file would be empty, its OK
dwErrCode = (cbAttrFile == 0) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;
}
}
return dwErrCode;
}
//-----------------------------------------------------------------------------
// Public functions
DWORD WINAPI SFileGetAttributes(HANDLE hMpq)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
// Verify the parameters
if(!IsValidMpqHandle(hMpq))
{
SetLastError(ERROR_INVALID_PARAMETER);
return SFILE_INVALID_ATTRIBUTES;
}
return ha->dwAttrFlags;
}
bool WINAPI SFileSetAttributes(HANDLE hMpq, DWORD dwFlags)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
// Verify the parameters
if(!IsValidMpqHandle(hMpq))
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Not allowed when the archive is read-only
if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
{
SetLastError(ERROR_ACCESS_DENIED);
return false;
}
// Set the attributes
InvalidateInternalFiles(ha);
ha->dwAttrFlags = (dwFlags & MPQ_ATTRIBUTE_ALL);
return true;
}
bool WINAPI SFileUpdateFileAttributes(HANDLE hMpq, const char * szFileName)
{
hash_state md5_state;
TMPQArchive * ha = (TMPQArchive *)hMpq;
TMPQFile * hf;
BYTE Buffer[0x1000];
HANDLE hFile = NULL;
DWORD dwTotalBytes = 0;
DWORD dwBytesRead;
DWORD dwCrc32;
// Verify the parameters
if(!IsValidMpqHandle(ha))
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Not allowed when the archive is read-only
if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
{
SetLastError(ERROR_ACCESS_DENIED);
return false;
}
// Attempt to open the file
if(!SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_BASE_FILE, &hFile))
return false;
// Get the file size
hf = (TMPQFile *)hFile;
dwTotalBytes = hf->pFileEntry->dwFileSize;
// Initialize the CRC32 and MD5 contexts
md5_init(&md5_state);
dwCrc32 = crc32(0, Z_NULL, 0);
// Go through entire file and calculate both CRC32 and MD5
while(dwTotalBytes != 0)
{
// Read data from file
SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL);
if(dwBytesRead == 0)
break;
// Update CRC32 and MD5
dwCrc32 = crc32(dwCrc32, Buffer, dwBytesRead);
md5_process(&md5_state, Buffer, dwBytesRead);
// Decrement the total size
dwTotalBytes -= dwBytesRead;
}
// Update both CRC32 and MD5
hf->pFileEntry->dwCrc32 = dwCrc32;
md5_done(&md5_state, hf->pFileEntry->md5);
// Remember that we need to save the MPQ tables
InvalidateInternalFiles(ha);
SFileCloseFile(hFile);
return true;
}

View File

@ -0,0 +1,654 @@
/*****************************************************************************/
/* 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 */
/* 21.04.13 1.02 Dea Compact callback now part of TMPQArchive */
/*****************************************************************************/
#define __STORMLIB_SELF__
#include "StormLib.h"
#include "StormCommon.h"
/*****************************************************************************/
/* Local functions */
/*****************************************************************************/
static DWORD CheckIfAllFilesKnown(TMPQArchive * ha)
{
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
TFileEntry * pFileEntry;
DWORD dwBlockIndex = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Verify the file table
if(dwErrCode == ERROR_SUCCESS)
{
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++, dwBlockIndex++)
{
// If there is an existing entry in the file table, check its name
if(pFileEntry->dwFlags & MPQ_FILE_EXISTS)
{
// The name must be valid and must not be a pseudo-name
if(pFileEntry->szFileName == NULL || IsPseudoFileName(pFileEntry->szFileName, NULL))
{
dwErrCode = ERROR_UNKNOWN_FILE_NAMES;
break;
}
}
}
}
return dwErrCode;
}
static DWORD CheckIfAllKeysKnown(TMPQArchive * ha, const TCHAR * szListFile, LPDWORD pFileKeys)
{
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
TFileEntry * pFileEntry;
DWORD dwBlockIndex = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Add the listfile to the MPQ
if(szListFile != NULL)
{
// Notify the user
if(ha->pfnCompactCB != NULL)
ha->pfnCompactCB(ha->pvCompactUserData, CCB_CHECKING_FILES, ha->CompactBytesProcessed, ha->CompactTotalBytes);
dwErrCode = SFileAddListFile((HANDLE)ha, szListFile);
}
// Verify the file table
if(dwErrCode == ERROR_SUCCESS)
{
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++, dwBlockIndex++)
{
// If the file exists and it's encrypted
if(pFileEntry->dwFlags & MPQ_FILE_EXISTS)
{
// If we know the name, we decrypt the file key from the file name
if(pFileEntry->szFileName != NULL && !IsPseudoFileName(pFileEntry->szFileName, NULL))
{
// Give the key to the caller
pFileKeys[dwBlockIndex] = DecryptFileKey(pFileEntry->szFileName,
pFileEntry->ByteOffset,
pFileEntry->dwFileSize,
pFileEntry->dwFlags);
continue;
}
// We don't know the encryption key of this file,
// thus we cannot compact the file
dwErrCode = ERROR_UNKNOWN_FILE_NAMES;
break;
}
}
}
return dwErrCode;
}
static DWORD CopyNonMpqData(
TMPQArchive * ha,
TFileStream * pSrcStream,
TFileStream * pTrgStream,
ULONGLONG & ByteOffset,
ULONGLONG & ByteCount)
{
ULONGLONG DataSize = ByteCount;
DWORD dwToRead;
char DataBuffer[0x1000];
DWORD dwErrCode = ERROR_SUCCESS;
// Copy the data
while(DataSize > 0)
{
// Get the proper size of data
dwToRead = sizeof(DataBuffer);
if(DataSize < dwToRead)
dwToRead = (DWORD)DataSize;
// Read from the source stream
if(!FileStream_Read(pSrcStream, &ByteOffset, DataBuffer, dwToRead))
{
dwErrCode = GetLastError();
break;
}
// Write to the target stream
if(!FileStream_Write(pTrgStream, NULL, DataBuffer, dwToRead))
{
dwErrCode = GetLastError();
break;
}
// Update the progress
if(ha->pfnCompactCB != NULL)
{
ha->CompactBytesProcessed += dwToRead;
ha->pfnCompactCB(ha->pvCompactUserData, CCB_COPYING_NON_MPQ_DATA, ha->CompactBytesProcessed, ha->CompactTotalBytes);
}
// Decrement the number of data to be copied
ByteOffset += dwToRead;
DataSize -= dwToRead;
}
return dwErrCode;
}
// Copies all file sectors into another archive.
static DWORD CopyMpqFileSectors(
TMPQArchive * ha,
TMPQFile * hf,
TFileStream * pNewStream,
ULONGLONG MpqFilePos) // MPQ file position in the new archive
{
TFileEntry * pFileEntry = hf->pFileEntry;
ULONGLONG RawFilePos; // Used for calculating sector offset in the old MPQ archive
DWORD dwBytesToCopy = pFileEntry->dwCmpSize;
DWORD dwPatchSize = 0; // Size of patch header
DWORD dwFileKey1 = 0; // File key used for decryption
DWORD dwFileKey2 = 0; // File key used for encryption
DWORD dwCmpSize = 0; // Compressed file size, including patch header
DWORD dwErrCode = ERROR_SUCCESS;
// Resolve decryption keys. Note that the file key given
// in the TMPQFile structure also includes the key adjustment
if(dwErrCode == ERROR_SUCCESS && (pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED))
{
dwFileKey2 = dwFileKey1 = hf->dwFileKey;
if(pFileEntry->dwFlags & MPQ_FILE_FIX_KEY)
{
dwFileKey2 = (dwFileKey1 ^ pFileEntry->dwFileSize) - (DWORD)pFileEntry->ByteOffset;
dwFileKey2 = (dwFileKey2 + (DWORD)MpqFilePos) ^ pFileEntry->dwFileSize;
}
}
// If we have to save patch header, do it
if(dwErrCode == ERROR_SUCCESS && hf->pPatchInfo != NULL)
{
BSWAP_ARRAY32_UNSIGNED(hf->pPatchInfo, sizeof(DWORD) * 3);
if(!FileStream_Write(pNewStream, NULL, hf->pPatchInfo, hf->pPatchInfo->dwLength))
dwErrCode = GetLastError();
// Save the size of the patch info
dwPatchSize = hf->pPatchInfo->dwLength;
}
// If we have to save sector offset table, do it.
if(dwErrCode == ERROR_SUCCESS && hf->SectorOffsets != NULL)
{
DWORD * SectorOffsetsCopy = STORM_ALLOC(DWORD, hf->SectorOffsets[0] / sizeof(DWORD));
DWORD dwSectorOffsLen = hf->SectorOffsets[0];
assert((pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) == 0);
assert(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK);
if(SectorOffsetsCopy == NULL)
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
// Encrypt the secondary sector offset table and write it to the target file
if(dwErrCode == ERROR_SUCCESS)
{
memcpy(SectorOffsetsCopy, hf->SectorOffsets, dwSectorOffsLen);
if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
EncryptMpqBlock(SectorOffsetsCopy, dwSectorOffsLen, dwFileKey2 - 1);
BSWAP_ARRAY32_UNSIGNED(SectorOffsetsCopy, dwSectorOffsLen);
if(!FileStream_Write(pNewStream, NULL, SectorOffsetsCopy, dwSectorOffsLen))
dwErrCode = GetLastError();
dwBytesToCopy -= dwSectorOffsLen;
dwCmpSize += dwSectorOffsLen;
}
// Update compact progress
if(ha->pfnCompactCB != NULL)
{
ha->CompactBytesProcessed += dwSectorOffsLen;
ha->pfnCompactCB(ha->pvCompactUserData, CCB_COMPACTING_FILES, ha->CompactBytesProcessed, ha->CompactTotalBytes);
}
STORM_FREE(SectorOffsetsCopy);
}
// Now we have to copy all file sectors. We do it without
// recompression, because recompression is not necessary in this case
if(dwErrCode == ERROR_SUCCESS)
{
for(DWORD dwSector = 0; dwSector < hf->dwSectorCount; dwSector++)
{
DWORD dwRawDataInSector = hf->dwSectorSize;
DWORD dwRawByteOffset = dwSector * hf->dwSectorSize;
// Fix the raw data length if the file is compressed
if(hf->SectorOffsets != NULL)
{
dwRawDataInSector = hf->SectorOffsets[dwSector+1] - hf->SectorOffsets[dwSector];
dwRawByteOffset = hf->SectorOffsets[dwSector];
}
// Last sector: If there is not enough bytes remaining in the file, cut the raw size
if(dwRawDataInSector > dwBytesToCopy)
dwRawDataInSector = dwBytesToCopy;
// Calculate the raw file offset of the file sector
RawFilePos = CalculateRawSectorOffset(hf, dwRawByteOffset);
// Read the file sector
if(!FileStream_Read(ha->pStream, &RawFilePos, hf->pbFileSector, dwRawDataInSector))
{
dwErrCode = GetLastError();
break;
}
// If necessary, re-encrypt the sector
// Note: Recompression is not necessary here. Unlike encryption,
// the compression does not depend on the position of the file in MPQ.
if((pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) && dwFileKey1 != dwFileKey2)
{
BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector);
DecryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwFileKey1 + dwSector);
EncryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwFileKey2 + dwSector);
BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector);
}
// Now write the sector back to the file
if(!FileStream_Write(pNewStream, NULL, hf->pbFileSector, dwRawDataInSector))
{
dwErrCode = GetLastError();
break;
}
// Update compact progress
if(ha->pfnCompactCB != NULL)
{
ha->CompactBytesProcessed += dwRawDataInSector;
ha->pfnCompactCB(ha->pvCompactUserData, CCB_COMPACTING_FILES, ha->CompactBytesProcessed, ha->CompactTotalBytes);
}
// Adjust byte counts
dwBytesToCopy -= dwRawDataInSector;
dwCmpSize += dwRawDataInSector;
}
}
// Copy the sector CRCs, if any
// Sector CRCs are always compressed (not imploded) and unencrypted
if(dwErrCode == ERROR_SUCCESS && hf->SectorOffsets != NULL && hf->SectorChksums != NULL)
{
DWORD dwCrcLength;
dwCrcLength = hf->SectorOffsets[hf->dwSectorCount + 1] - hf->SectorOffsets[hf->dwSectorCount];
if(dwCrcLength != 0)
{
if(!FileStream_Read(ha->pStream, NULL, hf->SectorChksums, dwCrcLength))
dwErrCode = GetLastError();
if(!FileStream_Write(pNewStream, NULL, hf->SectorChksums, dwCrcLength))
dwErrCode = GetLastError();
// Update compact progress
if(ha->pfnCompactCB != NULL)
{
ha->CompactBytesProcessed += dwCrcLength;
ha->pfnCompactCB(ha->pvCompactUserData, CCB_COMPACTING_FILES, ha->CompactBytesProcessed, ha->CompactTotalBytes);
}
// Size of the CRC block is also included in the compressed file size
dwBytesToCopy -= dwCrcLength;
dwCmpSize += dwCrcLength;
}
}
// There might be extra data beyond sector checksum table
// Sometimes, these data are even part of sector offset table
// Examples:
// 2012 - WoW\15354\locale-enGB.MPQ:DBFilesClient\SpellLevels.dbc
// 2012 - WoW\15354\locale-enGB.MPQ:Interface\AddOns\Blizzard_AuctionUI\Blizzard_AuctionUI.xml
if(dwErrCode == ERROR_SUCCESS && dwBytesToCopy != 0)
{
LPBYTE pbExtraData;
// Allocate space for the extra data
pbExtraData = STORM_ALLOC(BYTE, dwBytesToCopy);
if(pbExtraData != NULL)
{
if(!FileStream_Read(ha->pStream, NULL, pbExtraData, dwBytesToCopy))
dwErrCode = GetLastError();
if(!FileStream_Write(pNewStream, NULL, pbExtraData, dwBytesToCopy))
dwErrCode = GetLastError();
// Include these extra data in the compressed size
dwCmpSize += dwBytesToCopy;
STORM_FREE(pbExtraData);
}
else
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
// Write the MD5's of the raw file data, if needed
if(dwErrCode == ERROR_SUCCESS && ha->pHeader->dwRawChunkSize != 0)
{
dwErrCode = WriteMpqDataMD5(pNewStream,
ha->MpqPos + MpqFilePos,
pFileEntry->dwCmpSize,
ha->pHeader->dwRawChunkSize);
}
// Verify the number of bytes written
if(dwErrCode == 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 (an unknown archive version, MPQ malformation, ...)
//
// Note: Diablo savegames have very weird layout, and the file "hero"
// seems to have improper compressed size. Instead of real compressed size,
// the "dwCmpSize" member of the block table entry contains
// uncompressed size of file data + size of the sector table.
// If we compact the archive, Diablo will refuse to load the game
//
// Note: Some patch files in WOW patches don't count the patch header
// into compressed size
//
if(!(dwCmpSize <= pFileEntry->dwCmpSize && pFileEntry->dwCmpSize <= dwCmpSize + dwPatchSize))
{
dwErrCode = ERROR_FILE_CORRUPT;
assert(false);
}
}
return dwErrCode;
}
static DWORD CopyMpqFiles(TMPQArchive * ha, LPDWORD pFileKeys, TFileStream * pNewStream)
{
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
TFileEntry * pFileEntry;
TMPQFile * hf = NULL;
ULONGLONG MpqFilePos;
DWORD dwErrCode = ERROR_SUCCESS;
// Walk through all files and write them to the destination MPQ archive
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
{
// Copy all the file sectors
// Only do that when the file has nonzero size
if((pFileEntry->dwFlags & MPQ_FILE_EXISTS))
{
// Query the position where the destination file will be
FileStream_GetPos(pNewStream, &MpqFilePos);
MpqFilePos = MpqFilePos - ha->MpqPos;
// Perform file copy ONLY if the file has nonzero size
if(pFileEntry->dwFileSize != 0)
{
// Allocate structure for the MPQ file
hf = CreateFileHandle(ha, pFileEntry);
if(hf == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Set the file decryption key
hf->dwFileKey = pFileKeys[pFileEntry - ha->pFileTable];
// If the file is a patch file, load the patch header
if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
{
dwErrCode = AllocatePatchInfo(hf, true);
if(dwErrCode != ERROR_SUCCESS)
break;
}
// Allocate buffers for file sector and sector offset table
dwErrCode = AllocateSectorBuffer(hf);
if(dwErrCode != ERROR_SUCCESS)
break;
// Also allocate sector offset table and sector checksum table
dwErrCode = AllocateSectorOffsets(hf, true);
if(dwErrCode != ERROR_SUCCESS)
break;
// Also load sector checksums, if any
if(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC)
{
dwErrCode = AllocateSectorChecksums(hf, false);
if(dwErrCode != ERROR_SUCCESS)
break;
}
// Copy all file sectors
dwErrCode = CopyMpqFileSectors(ha, hf, pNewStream, MpqFilePos);
if(dwErrCode != ERROR_SUCCESS)
break;
// Free buffers. This also sets "hf" to NULL.
FreeFileHandle(hf);
}
// Note: DO NOT update the compressed size in the file entry, no matter how bad it is.
pFileEntry->ByteOffset = MpqFilePos;
}
}
// Cleanup and exit
if(hf != NULL)
FreeFileHandle(hf);
return dwErrCode;
}
/*****************************************************************************/
/* Public functions */
/*****************************************************************************/
//-----------------------------------------------------------------------------
// Changing hash table size
DWORD WINAPI SFileGetMaxFileCount(HANDLE hMpq)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
return ha->dwMaxFileCount;
}
bool WINAPI SFileSetMaxFileCount(HANDLE hMpq, DWORD dwMaxFileCount)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
DWORD dwNewHashTableSize = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Test the valid parameters
if(!IsValidMpqHandle(hMpq))
dwErrCode = ERROR_INVALID_HANDLE;
if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
dwErrCode = ERROR_ACCESS_DENIED;
if(dwMaxFileCount < ha->dwFileTableSize)
dwErrCode = ERROR_DISK_FULL;
// ALL file names must be known in order to be able to rebuild hash table
if(dwErrCode == ERROR_SUCCESS && ha->pHashTable != NULL)
{
dwErrCode = CheckIfAllFilesKnown(ha);
if(dwErrCode == ERROR_SUCCESS)
{
// Calculate the hash table size for the new file limit
dwNewHashTableSize = GetNearestPowerOfTwo(dwMaxFileCount);
// Rebuild both file tables
dwErrCode = RebuildFileTable(ha, dwNewHashTableSize);
}
}
// We always have to rebuild the (attributes) file due to file table change
if(dwErrCode == ERROR_SUCCESS)
{
// Invalidate (listfile) and (attributes)
InvalidateInternalFiles(ha);
// Rebuild the HET table, if we have any
if(ha->pHetTable != NULL)
dwErrCode = RebuildHetTable(ha);
}
// Return the error
if(dwErrCode != ERROR_SUCCESS)
SetLastError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}
//-----------------------------------------------------------------------------
// Archive compacting
bool WINAPI SFileSetCompactCallback(HANDLE hMpq, SFILE_COMPACT_CALLBACK pfnCompactCB, void * pvUserData)
{
TMPQArchive * ha = (TMPQArchive *) hMpq;
if (!IsValidMpqHandle(hMpq))
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
ha->pfnCompactCB = pfnCompactCB;
ha->pvCompactUserData = pvUserData;
return true;
}
bool WINAPI SFileCompactArchive(HANDLE hMpq, const TCHAR * szListFile, bool /* bReserved */)
{
TFileStream * pTempStream = NULL;
TMPQArchive * ha = (TMPQArchive *)hMpq;
ULONGLONG ByteOffset;
ULONGLONG ByteCount;
LPDWORD pFileKeys = NULL;
TCHAR szTempFile[MAX_PATH+1] = _T("");
DWORD dwErrCode = ERROR_SUCCESS;
// Test the valid parameters
if(!IsValidMpqHandle(hMpq))
dwErrCode = ERROR_INVALID_HANDLE;
if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
dwErrCode = ERROR_ACCESS_DENIED;
// If the MPQ is changed at this moment, we have to flush the archive
if(dwErrCode == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_CHANGED))
{
SFileFlushArchive(hMpq);
}
// Create the table with file keys
if(dwErrCode == ERROR_SUCCESS)
{
if((pFileKeys = STORM_ALLOC(DWORD, ha->dwFileTableSize)) != NULL)
memset(pFileKeys, 0, sizeof(DWORD) * ha->dwFileTableSize);
else
dwErrCode = 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(dwErrCode == ERROR_SUCCESS)
{
// Initialize the progress variables for compact callback
FileStream_GetSize(ha->pStream, &(ha->CompactTotalBytes));
ha->CompactBytesProcessed = 0;
dwErrCode = CheckIfAllKeysKnown(ha, szListFile, pFileKeys);
}
// Get the temporary file name and create it
if(dwErrCode == ERROR_SUCCESS)
{
// Create temporary file name. Prevent buffer overflow
StringCopy(szTempFile, _countof(szTempFile), FileStream_GetFileName(ha->pStream));
StringCat(szTempFile, _countof(szTempFile), _T(".tmp"));
// Create temporary file
pTempStream = FileStream_CreateFile(szTempFile, STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE);
if(pTempStream == NULL)
dwErrCode = GetLastError();
}
// Write the data before MPQ user data (if any)
if(dwErrCode == ERROR_SUCCESS && ha->UserDataPos != 0)
{
// Inform the application about the progress
if(ha->pfnCompactCB != NULL)
ha->pfnCompactCB(ha->pvCompactUserData, CCB_COPYING_NON_MPQ_DATA, ha->CompactBytesProcessed, ha->CompactTotalBytes);
ByteOffset = 0;
ByteCount = ha->UserDataPos;
dwErrCode = CopyNonMpqData(ha, ha->pStream, pTempStream, ByteOffset, ByteCount);
}
// Write the MPQ user data (if any)
if(dwErrCode == ERROR_SUCCESS && ha->MpqPos > ha->UserDataPos)
{
// At this point, we assume that the user data size is equal
// to pUserData->dwHeaderOffs.
// If this assumption doesn't work, then we have an unknown version of MPQ
ByteOffset = ha->UserDataPos;
ByteCount = ha->MpqPos - ha->UserDataPos;
assert(ha->pUserData != NULL);
assert(ha->pUserData->dwHeaderOffs == ByteCount);
dwErrCode = CopyNonMpqData(ha, ha->pStream, pTempStream, ByteOffset, ByteCount);
}
// Write the MPQ header
if(dwErrCode == ERROR_SUCCESS)
{
TMPQHeader SaveMpqHeader;
// Write the MPQ header to the file
memcpy(&SaveMpqHeader, ha->pHeader, ha->pHeader->dwHeaderSize);
BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_1);
BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_2);
BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_3);
BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_4);
if(!FileStream_Write(pTempStream, NULL, &SaveMpqHeader, ha->pHeader->dwHeaderSize))
dwErrCode = GetLastError();
// Update the progress
ha->CompactBytesProcessed += ha->pHeader->dwHeaderSize;
}
// Now copy all files
if(dwErrCode == ERROR_SUCCESS)
dwErrCode = CopyMpqFiles(ha, pFileKeys, pTempStream);
// If succeeded, switch the streams
if(dwErrCode == ERROR_SUCCESS)
{
ha->dwFlags |= MPQ_FLAG_CHANGED;
if(FileStream_Replace(ha->pStream, pTempStream))
pTempStream = NULL;
else
dwErrCode = ERROR_CAN_NOT_COMPLETE;
}
// Final user notification
if(dwErrCode == ERROR_SUCCESS && ha->pfnCompactCB != NULL)
{
ha->CompactBytesProcessed += (ha->pHeader->dwHashTableSize * sizeof(TMPQHash));
ha->CompactBytesProcessed += (ha->dwFileTableSize * sizeof(TMPQBlock));
ha->pfnCompactCB(ha->pvCompactUserData, CCB_CLOSING_ARCHIVE, ha->CompactBytesProcessed, ha->CompactTotalBytes);
}
// Cleanup and return
if(pTempStream != NULL)
FileStream_Close(pTempStream);
if(pFileKeys != NULL)
STORM_FREE(pFileKeys);
if(dwErrCode != ERROR_SUCCESS)
SetLastError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}

View File

@ -0,0 +1,276 @@
/*****************************************************************************/
/* SFileCreateArchive.cpp Copyright (c) Ladislav Zezula 2003 */
/*---------------------------------------------------------------------------*/
/* MPQ Editing functions */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 24.03.03 1.00 Lad Splitted from SFileOpenArchive.cpp */
/* 08.06.10 1.00 Lad Renamed to SFileCreateArchive.cpp */
/*****************************************************************************/
#define __STORMLIB_SELF__
#include "StormLib.h"
#include "StormCommon.h"
//-----------------------------------------------------------------------------
// Local variables
static const DWORD MpqHeaderSizes[] =
{
MPQ_HEADER_SIZE_V1,
MPQ_HEADER_SIZE_V2,
MPQ_HEADER_SIZE_V3,
MPQ_HEADER_SIZE_V4
};
//-----------------------------------------------------------------------------
// Local functions
static USHORT GetSectorSizeShift(DWORD dwSectorSize)
{
USHORT wSectorSizeShift = 0;
while(dwSectorSize > 0x200)
{
dwSectorSize >>= 1;
wSectorSizeShift++;
}
return wSectorSizeShift;
}
static DWORD WriteNakedMPQHeader(TMPQArchive * ha)
{
TMPQHeader * pHeader = ha->pHeader;
TMPQHeader Header;
DWORD dwBytesToWrite = pHeader->dwHeaderSize;
DWORD dwErrCode = ERROR_SUCCESS;
// Prepare the naked MPQ header
memset(&Header, 0, sizeof(TMPQHeader));
Header.dwID = pHeader->dwID;
Header.dwHeaderSize = pHeader->dwHeaderSize;
Header.dwArchiveSize = pHeader->dwHeaderSize;
Header.wFormatVersion = pHeader->wFormatVersion;
Header.wSectorSize = pHeader->wSectorSize;
// Write it to the file
BSWAP_TMPQHEADER(&Header, MPQ_FORMAT_VERSION_1);
BSWAP_TMPQHEADER(&Header, MPQ_FORMAT_VERSION_2);
BSWAP_TMPQHEADER(&Header, MPQ_FORMAT_VERSION_3);
BSWAP_TMPQHEADER(&Header, MPQ_FORMAT_VERSION_4);
if(!FileStream_Write(ha->pStream, &ha->MpqPos, &Header, dwBytesToWrite))
dwErrCode = GetLastError();
return dwErrCode;
}
//-----------------------------------------------------------------------------
// Creates a new MPQ archive.
bool WINAPI SFileCreateArchive(const TCHAR * szMpqName, DWORD dwCreateFlags, DWORD dwMaxFileCount, HANDLE * phMpq)
{
SFILE_CREATE_MPQ CreateInfo;
// Fill the create structure
memset(&CreateInfo, 0, sizeof(SFILE_CREATE_MPQ));
CreateInfo.cbSize = sizeof(SFILE_CREATE_MPQ);
CreateInfo.dwMpqVersion = (dwCreateFlags & MPQ_CREATE_ARCHIVE_VMASK) >> FLAGS_TO_FORMAT_SHIFT;
CreateInfo.dwStreamFlags = STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE;
CreateInfo.dwFileFlags1 = (dwCreateFlags & MPQ_CREATE_LISTFILE) ? MPQ_FILE_DEFAULT_INTERNAL : 0;
CreateInfo.dwFileFlags2 = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? MPQ_FILE_DEFAULT_INTERNAL : 0;
CreateInfo.dwFileFlags3 = (dwCreateFlags & MPQ_CREATE_SIGNATURE) ? MPQ_FILE_DEFAULT_INTERNAL : 0;
CreateInfo.dwAttrFlags = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? (MPQ_ATTRIBUTE_CRC32 | MPQ_ATTRIBUTE_FILETIME | MPQ_ATTRIBUTE_MD5) : 0;
CreateInfo.dwSectorSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_3) ? 0x4000 : 0x1000;
CreateInfo.dwRawChunkSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_4) ? 0x4000 : 0;
CreateInfo.dwMaxFileCount = dwMaxFileCount;
// Set the proper attribute parts
if((CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_3) && (dwCreateFlags & MPQ_CREATE_ATTRIBUTES))
CreateInfo.dwAttrFlags |= MPQ_ATTRIBUTE_PATCH_BIT;
// Backward compatibility: SFileCreateArchive always used to add (listfile)
// We would break loads of applications if we change that
CreateInfo.dwFileFlags1 = MPQ_FILE_DEFAULT_INTERNAL;
// Let the main function create the archive
return SFileCreateArchive2(szMpqName, &CreateInfo, phMpq);
}
bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCreateInfo, HANDLE * phMpq)
{
TFileStream * pStream = NULL; // File stream
TMPQArchive * ha = NULL; // MPQ archive handle
TMPQHeader * pHeader;
ULONGLONG MpqPos = 0; // Position of MPQ header in the file
HANDLE hMpq = NULL;
DWORD dwBlockTableSize = 0; // Initial block table size
DWORD dwHashTableSize = 0;
DWORD dwReservedFiles = 0; // Number of reserved file entries
DWORD dwMpqFlags = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Check the parameters, if they are valid
if(szMpqName == NULL || *szMpqName == 0 || pCreateInfo == NULL || phMpq == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Verify if all variables in SFILE_CREATE_MPQ are correct
if((pCreateInfo->cbSize == 0 || pCreateInfo->cbSize > sizeof(SFILE_CREATE_MPQ)) ||
(pCreateInfo->dwMpqVersion > MPQ_FORMAT_VERSION_4) ||
(pCreateInfo->pvUserData != NULL || pCreateInfo->cbUserData != 0) ||
(pCreateInfo->dwAttrFlags & ~MPQ_ATTRIBUTE_ALL) ||
(pCreateInfo->dwSectorSize & (pCreateInfo->dwSectorSize - 1)) ||
(pCreateInfo->dwRawChunkSize & (pCreateInfo->dwRawChunkSize - 1)))
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// One time initialization of MPQ cryptography
InitializeMpqCryptography();
// We verify if the file already exists and if it's a MPQ archive.
// If yes, we won't allow to overwrite it.
if(SFileOpenArchive(szMpqName, 0, STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE | MPQ_OPEN_NO_ATTRIBUTES | MPQ_OPEN_NO_LISTFILE, &hMpq))
{
SFileCloseArchive(hMpq);
SetLastError(ERROR_ALREADY_EXISTS);
return false;
}
//
// At this point, we have to create the archive.
// - If the file exists, convert it to MPQ archive.
// - If the file doesn't exist, create new empty file
//
pStream = FileStream_OpenFile(szMpqName, pCreateInfo->dwStreamFlags);
if(pStream == NULL)
{
pStream = FileStream_CreateFile(szMpqName, pCreateInfo->dwStreamFlags);
if(pStream == NULL)
return false;
}
// Increment the maximum amount of files to have space for (listfile)
if(pCreateInfo->dwMaxFileCount && pCreateInfo->dwFileFlags1)
{
dwMpqFlags |= MPQ_FLAG_LISTFILE_NEW;
dwReservedFiles++;
}
// Increment the maximum amount of files to have space for (attributes)
if(pCreateInfo->dwMaxFileCount && pCreateInfo->dwFileFlags2 && pCreateInfo->dwAttrFlags)
{
dwMpqFlags |= MPQ_FLAG_ATTRIBUTES_NEW;
dwReservedFiles++;
}
// Increment the maximum amount of files to have space for (signature)
if(pCreateInfo->dwMaxFileCount && pCreateInfo->dwFileFlags3)
{
dwMpqFlags |= MPQ_FLAG_SIGNATURE_NEW;
dwReservedFiles++;
}
// If file count is not zero, initialize the hash table size
dwHashTableSize = GetNearestPowerOfTwo(pCreateInfo->dwMaxFileCount + dwReservedFiles);
// Retrieve the file size and round it up to 0x200 bytes
FileStream_GetSize(pStream, &MpqPos);
MpqPos = (MpqPos + 0x1FF) & (ULONGLONG)0xFFFFFFFFFFFFFE00ULL;
if(!FileStream_SetSize(pStream, MpqPos))
dwErrCode = GetLastError();
#ifdef _DEBUG
// Debug code, used for testing StormLib
// dwBlockTableSize = dwHashTableSize * 2;
#endif
// Create the archive handle
if(dwErrCode == ERROR_SUCCESS)
{
if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL)
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
// Fill the MPQ archive handle structure
if(dwErrCode == ERROR_SUCCESS)
{
memset(ha, 0, sizeof(TMPQArchive));
ha->pfnHashString = HashStringSlash;
ha->pStream = pStream;
ha->dwSectorSize = pCreateInfo->dwSectorSize;
ha->UserDataPos = MpqPos;
ha->MpqPos = MpqPos;
ha->pHeader = pHeader = (TMPQHeader *)ha->HeaderData;
ha->dwMaxFileCount = dwHashTableSize;
ha->dwFileTableSize = 0;
ha->dwReservedFiles = dwReservedFiles;
ha->dwFileFlags1 = pCreateInfo->dwFileFlags1;
ha->dwFileFlags2 = pCreateInfo->dwFileFlags2;
ha->dwFileFlags3 = pCreateInfo->dwFileFlags3 ? MPQ_FILE_EXISTS : 0;
ha->dwAttrFlags = pCreateInfo->dwAttrFlags;
ha->dwFlags = dwMpqFlags | MPQ_FLAG_CHANGED;
ha->useFreeSpaceOptimization = true;
ha->lastFreeSpaceEntry = nullptr;
pStream = NULL;
// Fill the MPQ header
memset(pHeader, 0, sizeof(ha->HeaderData));
pHeader->dwID = g_dwMpqSignature;
pHeader->dwHeaderSize = MpqHeaderSizes[pCreateInfo->dwMpqVersion];
pHeader->dwArchiveSize = pHeader->dwHeaderSize + dwHashTableSize * sizeof(TMPQHash);
pHeader->wFormatVersion = (USHORT)pCreateInfo->dwMpqVersion;
pHeader->wSectorSize = GetSectorSizeShift(ha->dwSectorSize);
pHeader->dwHashTablePos = pHeader->dwHeaderSize;
pHeader->dwHashTableSize = dwHashTableSize;
pHeader->dwBlockTablePos = pHeader->dwHashTablePos + dwHashTableSize * sizeof(TMPQHash);
pHeader->dwBlockTableSize = dwBlockTableSize;
// For MPQs version 4 and higher, we set the size of raw data block
// for calculating MD5
if(pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_4)
pHeader->dwRawChunkSize = pCreateInfo->dwRawChunkSize;
// Write the naked MPQ header
dwErrCode = WriteNakedMPQHeader(ha);
}
// Create initial HET table, if the caller required an MPQ format 3.0 or newer
if(dwErrCode == ERROR_SUCCESS && pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_3 && pCreateInfo->dwMaxFileCount != 0)
{
ha->pHetTable = CreateHetTable(ha->dwFileTableSize, 0, 0x40, NULL);
if(ha->pHetTable == NULL)
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
// Create initial hash table
if(dwErrCode == ERROR_SUCCESS && dwHashTableSize != 0)
{
dwErrCode = CreateHashTable(ha, dwHashTableSize);
}
// Create initial file table
if(dwErrCode == ERROR_SUCCESS && ha->dwMaxFileCount != 0)
{
dwErrCode = CreateFileTable(ha, ha->dwMaxFileCount);
}
// Cleanup : If an error, delete all buffers and return
if(dwErrCode != ERROR_SUCCESS)
{
FileStream_Close(pStream);
FreeArchiveHandle(ha);
SetLastError(dwErrCode);
ha = NULL;
}
// Return the values
*phMpq = (HANDLE)ha;
return (dwErrCode == ERROR_SUCCESS);
}

View File

@ -0,0 +1,64 @@
/*****************************************************************************/
/* 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 "StormCommon.h"
bool WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const TCHAR * szExtracted, DWORD dwSearchScope)
{
TFileStream * pLocalFile = NULL;
HANDLE hMpqFile = NULL;
DWORD dwErrCode = ERROR_SUCCESS;
// Open the MPQ file
if(dwErrCode == ERROR_SUCCESS)
{
if(!SFileOpenFileEx(hMpq, szToExtract, dwSearchScope, &hMpqFile))
dwErrCode = GetLastError();
}
// Create the local file
if(dwErrCode == ERROR_SUCCESS)
{
pLocalFile = FileStream_CreateFile(szExtracted, 0);
if(pLocalFile == NULL)
dwErrCode = GetLastError();
}
// Copy the file's content
while(dwErrCode == ERROR_SUCCESS)
{
char szBuffer[0x1000];
DWORD dwTransferred = 0;
// dwTransferred is only set to nonzero if something has been read.
// dwErrCode can be ERROR_SUCCESS or ERROR_HANDLE_EOF
if(!SFileReadFile(hMpqFile, szBuffer, sizeof(szBuffer), &dwTransferred, NULL))
dwErrCode = GetLastError();
if(dwErrCode == ERROR_HANDLE_EOF)
dwErrCode = ERROR_SUCCESS;
if(dwTransferred == 0)
break;
// If something has been actually read, write it
if(!FileStream_Write(pLocalFile, NULL, szBuffer, dwTransferred))
dwErrCode = GetLastError();
}
// Close the files
if(hMpqFile != NULL)
SFileCloseFile(hMpqFile);
if(pLocalFile != NULL)
FileStream_Close(pLocalFile);
if(dwErrCode != ERROR_SUCCESS)
SetLastError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}

View File

@ -0,0 +1,483 @@
/*****************************************************************************/
/* 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 "StormCommon.h"
//-----------------------------------------------------------------------------
// Private structure used for file search (search handle)
// Used by searching in MPQ archives
struct TMPQSearch
{
TMPQArchive * ha; // Handle to MPQ, where the search runs
TFileEntry ** pSearchTable; // Table for files that have been already found
DWORD dwSearchTableItems; // Number of items in the search table
DWORD dwNextIndex; // Next file index to be checked
DWORD dwFlagMask; // For checking flag mask
char szSearchMask[1]; // Search mask (variable length)
};
//-----------------------------------------------------------------------------
// Local functions
static TMPQSearch * IsValidSearchHandle(HANDLE hFind)
{
TMPQSearch * hs = (TMPQSearch *)hFind;
if(hs != NULL && IsValidMpqHandle(hs->ha))
return hs;
return NULL;
}
bool SFileCheckWildCard(const char * szString, const char * szWildCard)
{
const char * szWildCardPtr;
for(;;)
{
// If there is '?' in the wildcard, we skip one char
while(szWildCard[0] == '?')
{
if(szString[0] == 0)
return false;
szWildCard++;
szString++;
}
// Handle '*'
szWildCardPtr = szWildCard;
if(szWildCardPtr[0] != 0)
{
if(szWildCardPtr[0] == '*')
{
while(szWildCardPtr[0] == '*')
szWildCardPtr++;
if(szWildCardPtr[0] == 0)
return true;
if(AsciiToUpperTable[szWildCardPtr[0]] == AsciiToUpperTable[szString[0]])
{
if(SFileCheckWildCard(szString, szWildCardPtr))
return true;
}
}
else
{
if(AsciiToUpperTable[szWildCardPtr[0]] != AsciiToUpperTable[szString[0]])
return false;
szWildCard = szWildCardPtr + 1;
}
if(szString[0] == 0)
return false;
szString++;
}
else
{
return (szString[0] == 0) ? true : false;
}
}
}
static DWORD GetSearchTableItems(TMPQArchive * ha)
{
DWORD dwMergeItems = 0;
// Loop over all patches
while(ha != NULL)
{
// Append the number of files
dwMergeItems += (ha->pHetTable != NULL) ? ha->pHetTable->dwEntryCount
: ha->pHeader->dwBlockTableSize;
// Move to the patched archive
ha = ha->haPatch;
}
// Return the double size of number of items
return (dwMergeItems | 1);
}
static bool FileWasFoundBefore(
TMPQArchive * ha,
TMPQSearch * hs,
TFileEntry * pFileEntry)
{
TFileEntry * pEntry;
char * szRealFileName = pFileEntry->szFileName;
DWORD dwStartIndex;
DWORD dwNameHash;
DWORD dwIndex;
if(hs->pSearchTable != NULL && szRealFileName != NULL)
{
// If we are in patch MPQ, we check if patch prefix matches
// and then trim the patch prefix
if(ha->pPatchPrefix != NULL)
{
// If the patch prefix doesn't fit, we pretend that the file
// was there before and it will be skipped
if(_strnicmp(szRealFileName, ha->pPatchPrefix->szPatchPrefix, ha->pPatchPrefix->nLength))
return true;
szRealFileName += ha->pPatchPrefix->nLength;
}
// Calculate the hash to the table
dwNameHash = ha->pfnHashString(szRealFileName, MPQ_HASH_NAME_A);
dwStartIndex = dwIndex = (dwNameHash % hs->dwSearchTableItems);
// The file might have been found before
// only if this is not the first MPQ being searched
if(ha->haBase != NULL)
{
// Enumerate all entries in the search table
for(;;)
{
// Get the file entry at that position
pEntry = hs->pSearchTable[dwIndex];
if(pEntry == NULL)
break;
if(pEntry->szFileName != NULL)
{
// Does the name match?
if(!_stricmp(pEntry->szFileName, szRealFileName))
return true;
}
// Move to the next entry
dwIndex = (dwIndex + 1) % hs->dwSearchTableItems;
if(dwIndex == dwStartIndex)
break;
}
}
// Put the entry to the table for later use
hs->pSearchTable[dwIndex] = pFileEntry;
}
return false;
}
static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry)
{
TFileEntry * pPatchEntry = pFileEntry;
TFileEntry * pTempEntry;
char szFileName[MAX_PATH+1];
// Can't find patch entry for a file that doesn't have name
if(pFileEntry->szFileName != NULL && pFileEntry->szFileName[0] != 0)
{
// Go while there are patches
while(ha->haPatch != NULL)
{
// Move to the patch archive
ha = ha->haPatch;
szFileName[0] = 0;
// Prepare the prefix for the file name
if(ha->pPatchPrefix && ha->pPatchPrefix->nLength)
StringCopy(szFileName, _countof(szFileName), ha->pPatchPrefix->szPatchPrefix);
StringCat(szFileName, _countof(szFileName), pFileEntry->szFileName);
// Try to find the file there
pTempEntry = GetFileEntryExact(ha, szFileName, 0, NULL);
if(pTempEntry != NULL)
pPatchEntry = pTempEntry;
}
}
// Return the found patch entry
return pPatchEntry;
}
static bool DoMPQSearch_FileEntry(
TMPQSearch * hs,
SFILE_FIND_DATA * lpFindFileData,
TMPQArchive * ha,
TMPQHash * pHashEntry,
TFileEntry * pFileEntry)
{
TFileEntry * pPatchEntry;
HANDLE hFile = NULL;
const char * szFileName;
size_t nPrefixLength = (ha->pPatchPrefix != NULL) ? ha->pPatchPrefix->nLength : 0;
DWORD dwBlockIndex;
char szNameBuff[MAX_PATH];
// Is it a file but not a patch file?
if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS)
{
// Ignore fake files which are not compressed but have size higher than the archive
if ((pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) == 0 && (pFileEntry->dwFileSize > ha->FileSize))
return false;
// Now we have to check if this file was not enumerated before
if(!FileWasFoundBefore(ha, hs, pFileEntry))
{
// if(pFileEntry != NULL && !_stricmp(pFileEntry->szFileName, "TriggerLibs\\NativeLib.galaxy"))
// DebugBreak();
// Find a patch to this file
// Note: This either succeeds or returns pFileEntry
pPatchEntry = FindPatchEntry(ha, pFileEntry);
// Prepare the block index
dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
if(dwBlockIndex == 569)
szNameBuff[0] = 'F';
// Get the file name. If it's not known, we will create pseudo-name
szFileName = pFileEntry->szFileName;
if(szFileName == NULL)
{
// Open the file by its pseudo-name.
StringCreatePseudoFileName(szNameBuff, _countof(szNameBuff), dwBlockIndex, "xxx");
if(SFileOpenFileEx((HANDLE)hs->ha, szNameBuff, SFILE_OPEN_BASE_FILE, &hFile))
{
SFileGetFileName(hFile, szNameBuff);
szFileName = szNameBuff;
SFileCloseFile(hFile);
}
}
// If the file name is still NULL, we cannot include the file to search results
if(szFileName != NULL)
{
// Check the file name against the wildcard
if(SFileCheckWildCard(szFileName + nPrefixLength, hs->szSearchMask))
{
// Fill the found entry. hash entry and block index are taken from the base MPQ
lpFindFileData->dwHashIndex = HASH_ENTRY_FREE;
lpFindFileData->dwBlockIndex = dwBlockIndex;
lpFindFileData->dwFileSize = pPatchEntry->dwFileSize;
lpFindFileData->dwFileFlags = pPatchEntry->dwFlags;
lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize;
lpFindFileData->lcLocale = 0; // pPatchEntry->lcLocale;
// Fill the filetime
lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32);
lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime);
// Fill-in the entries from hash table entry, if given
if(pHashEntry != NULL)
{
lpFindFileData->dwHashIndex = (DWORD)(pHashEntry - ha->pHashTable);
lpFindFileData->lcLocale = pHashEntry->lcLocale;
}
// Fill the file name and plain file name
StringCopy(lpFindFileData->cFileName, _countof(lpFindFileData->cFileName), szFileName + nPrefixLength);
lpFindFileData->szPlainName = (char *)GetPlainFileName(lpFindFileData->cFileName);
return true;
}
}
}
}
// Either not a valid item or was found before
return false;
}
static DWORD DoMPQSearch_HashTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha)
{
TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
TMPQHash * pHash;
// Parse the file table
for(pHash = ha->pHashTable + hs->dwNextIndex; pHash < pHashTableEnd; pHash++)
{
// Increment the next index for subsequent search
hs->dwNextIndex++;
// Does this hash table entry point to a proper block table entry?
if(IsValidHashEntry(ha, pHash))
{
// Check if this file entry should be included in the search result
if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, pHash, ha->pFileTable + MPQ_BLOCK_INDEX(pHash)))
return ERROR_SUCCESS;
}
}
// No more files
return ERROR_NO_MORE_FILES;
}
static DWORD DoMPQSearch_FileTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha)
{
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
TFileEntry * pFileEntry;
// Parse the file table
for(pFileEntry = ha->pFileTable + hs->dwNextIndex; pFileEntry < pFileTableEnd; pFileEntry++)
{
// Increment the next index for subsequent search
hs->dwNextIndex++;
// Check if this file entry should be included in the search result
if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, NULL, pFileEntry))
return ERROR_SUCCESS;
}
// No more files
return ERROR_NO_MORE_FILES;
}
// Performs one MPQ search
static DWORD DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
{
TMPQArchive * ha = hs->ha;
DWORD dwErrCode;
// Start searching with base MPQ
while(ha != NULL)
{
// If the archive has hash table, we need to use hash table
// in order to catch hash table index and file locale.
// Note: If multiple hash table entries, point to the same block entry,
// we need, to report them all
dwErrCode = (ha->pHashTable != NULL) ? DoMPQSearch_HashTable(hs, lpFindFileData, ha)
: DoMPQSearch_FileTable(hs, lpFindFileData, ha);
if(dwErrCode == ERROR_SUCCESS)
return dwErrCode;
// If there is no more patches in the chain, stop it.
// This also keeps hs->ha non-NULL, which is required
// for freeing the handle later
if(ha->haPatch == NULL)
break;
// Move to the next patch in the patch chain
hs->ha = ha = ha->haPatch;
hs->dwNextIndex = 0;
}
// No more files found, return error
return ERROR_NO_MORE_FILES;
}
static void FreeMPQSearch(TMPQSearch *& hs)
{
if(hs != NULL)
{
if(hs->pSearchTable != NULL)
STORM_FREE(hs->pSearchTable);
STORM_FREE(hs);
hs = NULL;
}
}
//-----------------------------------------------------------------------------
// Public functions
HANDLE WINAPI SFileFindFirstFile(HANDLE hMpq, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const TCHAR * szListFile)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
TMPQSearch * hs = NULL;
size_t nSize = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Check for the valid parameters
if(!IsValidMpqHandle(hMpq))
dwErrCode = ERROR_INVALID_HANDLE;
if(szMask == NULL || lpFindFileData == NULL)
dwErrCode = 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(dwErrCode == ERROR_SUCCESS && szListFile != NULL && *szListFile != 0)
dwErrCode = SFileAddListFile((HANDLE)ha, szListFile);
// Allocate the structure for MPQ search
if(dwErrCode == ERROR_SUCCESS)
{
nSize = sizeof(TMPQSearch) + strlen(szMask) + 1;
if((hs = (TMPQSearch *)STORM_ALLOC(char, nSize)) == NULL)
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
// Perform the first search
if(dwErrCode == ERROR_SUCCESS)
{
memset(hs, 0, sizeof(TMPQSearch));
strcpy(hs->szSearchMask, szMask);
hs->dwFlagMask = MPQ_FILE_EXISTS;
hs->ha = ha;
// If the archive is patched archive, we have to create a merge table
// to prevent files being repeated
if(ha->haPatch != NULL)
{
hs->dwSearchTableItems = GetSearchTableItems(ha);
hs->pSearchTable = STORM_ALLOC(TFileEntry *, hs->dwSearchTableItems);
hs->dwFlagMask = MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE;
if(hs->pSearchTable != NULL)
memset(hs->pSearchTable, 0, hs->dwSearchTableItems * sizeof(TFileEntry *));
else
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
}
// Perform first item searching
if(dwErrCode == ERROR_SUCCESS)
{
dwErrCode = DoMPQSearch(hs, lpFindFileData);
}
// Cleanup
if(dwErrCode != ERROR_SUCCESS)
{
FreeMPQSearch(hs);
SetLastError(dwErrCode);
}
// Return the result value
return (HANDLE)hs;
}
bool WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
{
TMPQSearch * hs = IsValidSearchHandle(hFind);
DWORD dwErrCode = ERROR_SUCCESS;
// Check the parameters
if(hs == NULL)
dwErrCode = ERROR_INVALID_HANDLE;
if(lpFindFileData == NULL)
dwErrCode = ERROR_INVALID_PARAMETER;
if(dwErrCode == ERROR_SUCCESS)
dwErrCode = DoMPQSearch(hs, lpFindFileData);
if(dwErrCode != ERROR_SUCCESS)
SetLastError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}
bool WINAPI SFileFindClose(HANDLE hFind)
{
TMPQSearch * hs = IsValidSearchHandle(hFind);
// Check the parameters
if(hs == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
FreeMPQSearch(hs);
return true;
}

View File

@ -0,0 +1,607 @@
/*****************************************************************************/
/* SFileGetFileInfo.cpp Copyright (c) Ladislav Zezula 2013 */
/*---------------------------------------------------------------------------*/
/* Description: */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 30.11.13 1.00 Lad The first version of SFileGetFileInfo.cpp */
/*****************************************************************************/
#define __STORMLIB_SELF__
#include "StormLib.h"
#include "StormCommon.h"
//-----------------------------------------------------------------------------
// Local functions
static DWORD GetMpqFileCount(TMPQArchive * ha)
{
TFileEntry * pFileTableEnd;
TFileEntry * pFileEntry;
DWORD dwFileCount = 0;
// Go through all open MPQs, including patches
while(ha != NULL)
{
// Only count files that are not patch files
pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
{
// If the file is patch file and this is not primary archive, skip it
// BUGBUG: This errorneously counts non-patch files that are in both
// base MPQ and in patches, and increases the number of files by cca 50%
if((pFileEntry->dwFlags & (MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE)) == MPQ_FILE_EXISTS)
dwFileCount++;
}
// Move to the next patch archive
ha = ha->haPatch;
}
return dwFileCount;
}
static bool GetInfo_ReturdwErrCode(DWORD dwErrCode)
{
SetLastError(dwErrCode);
return false;
}
static bool GetInfo_BufferCheck(void * pvFileInfo, DWORD cbFileInfo, DWORD cbData, LPDWORD pcbLengthNeeded)
{
// Give the length needed to store the info
if(pcbLengthNeeded != NULL)
pcbLengthNeeded[0] = cbData;
// Check for sufficient buffer
if(cbData > cbFileInfo)
return GetInfo_ReturdwErrCode(ERROR_INSUFFICIENT_BUFFER);
// If the buffer size is sufficient, check for valid user buffer
if(pvFileInfo == NULL)
return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER);
// Buffers and sizes are OK, we are ready to proceed file copying
return true;
}
static bool GetInfo(void * pvFileInfo, DWORD cbFileInfo, const void * pvData, DWORD cbData, LPDWORD pcbLengthNeeded)
{
// Verify buffer pointer and buffer size
if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded))
return false;
// Copy the data to the caller-supplied buffer
memcpy(pvFileInfo, pvData, cbData);
return true;
}
static bool GetInfo_Allocated(void * pvFileInfo, DWORD cbFileInfo, void * pvData, DWORD cbData, LPDWORD pcbLengthNeeded)
{
bool bResult;
// Verify buffer pointer and buffer size
if((bResult = GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) != false)
memcpy(pvFileInfo, pvData, cbData);
// Copy the data to the user buffer
STORM_FREE(pvData);
return bResult;
}
static bool GetInfo_TablePointer(void * pvFileInfo, DWORD cbFileInfo, void * pvTablePointer, SFileInfoClass InfoClass, LPDWORD pcbLengthNeeded)
{
// Verify buffer pointer and buffer size
if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, sizeof(void *), pcbLengthNeeded))
{
SFileFreeFileInfo(pvTablePointer, InfoClass);
return false;
}
// The user buffer receives pointer to the table.
// When done, the caller needs to call SFileFreeFileInfo on it
*(void **)pvFileInfo = pvTablePointer;
return true;
}
static bool GetInfo_ReadFromFile(void * pvFileInfo, DWORD cbFileInfo, TFileStream * pStream, ULONGLONG ByteOffset, DWORD cbData, LPDWORD pcbLengthNeeded)
{
// Verify buffer pointer and buffer size
if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded))
return false;
return FileStream_Read(pStream, &ByteOffset, pvFileInfo, cbData);
}
static bool GetInfo_FileEntry(void * pvFileInfo, DWORD cbFileInfo, TFileEntry * pFileEntry, LPDWORD pcbLengthNeeded)
{
LPBYTE pbFileInfo = (LPBYTE)pvFileInfo;
DWORD cbSrcFileInfo = sizeof(TFileEntry);
DWORD cbFileName = 1;
// The file name belongs to the file entry
if(pFileEntry->szFileName)
cbFileName = (DWORD)strlen(pFileEntry->szFileName) + 1;
cbSrcFileInfo += cbFileName;
// Verify buffer pointer and buffer size
if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbSrcFileInfo, pcbLengthNeeded))
return false;
// Copy the file entry
memcpy(pbFileInfo, pFileEntry, sizeof(TFileEntry));
pbFileInfo += sizeof(TFileEntry);
pbFileInfo[0] = 0;
// Copy the file name
if(pFileEntry->szFileName)
memcpy(pbFileInfo, pFileEntry->szFileName, cbFileName);
return true;
}
static bool GetInfo_PatchChain(TMPQFile * hf, void * pvFileInfo, DWORD cbFileInfo, LPDWORD pcbLengthNeeded)
{
TMPQFile * hfTemp;
LPCTSTR szPatchName;
LPTSTR szFileInfo = (LPTSTR)pvFileInfo;
size_t cchCharsNeeded = 1;
size_t nLength;
// Patch chain is only supported on MPQ files. Local files are not supported.
if(hf->pStream != NULL)
return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER);
// Calculate the necessary length of the multi-string
for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch)
cchCharsNeeded += _tcslen(FileStream_GetFileName(hfTemp->ha->pStream)) + 1;
// Verify whether the caller gave us valid buffer with enough size
if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, (DWORD)(cchCharsNeeded * sizeof(TCHAR)), pcbLengthNeeded))
return false;
// Copy each patch name
for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch)
{
// Get the file name and its length
szPatchName = FileStream_GetFileName(hfTemp->ha->pStream);
nLength = _tcslen(szPatchName) + 1;
// Copy the file name
memcpy(szFileInfo, szPatchName, nLength * sizeof(TCHAR));
szFileInfo += nLength;
}
// Make it multi-string
szFileInfo[0] = 0;
return true;
}
//-----------------------------------------------------------------------------
// Retrieves an information about an archive or about a file within the archive
//
// hMpqOrFile - Handle to an MPQ archive or to a file
// InfoClass - Information to obtain
// pvFileInfo - Pointer to buffer to store the information
// cbFileInfo - Size of the buffer pointed by pvFileInfo
// pcbLengthNeeded - Receives number of bytes necessary to store the information
bool WINAPI SFileGetFileInfo(
HANDLE hMpqOrFile,
SFileInfoClass InfoClass,
void * pvFileInfo,
DWORD cbFileInfo,
LPDWORD pcbLengthNeeded)
{
MPQ_SIGNATURE_INFO SignatureInfo;
const TCHAR * szSrcFileInfo;
TMPQArchive * ha = NULL;
TFileEntry * pFileEntry = NULL;
TMPQHeader * pHeader = NULL;
ULONGLONG Int64Value = 0;
TMPQFile * hf = NULL;
void * pvSrcFileInfo = NULL;
DWORD cbSrcFileInfo = 0;
DWORD dwInt32Value = 0;
// Validate archive/file handle
if((int)InfoClass <= (int)SFileMpqFlags)
{
if((ha = IsValidMpqHandle(hMpqOrFile)) == NULL)
return GetInfo_ReturdwErrCode(ERROR_INVALID_HANDLE);
pHeader = ha->pHeader;
}
else
{
if((hf = IsValidFileHandle(hMpqOrFile)) == NULL)
return GetInfo_ReturdwErrCode(ERROR_INVALID_HANDLE);
pFileEntry = hf->pFileEntry;
}
// Return info-class-specific data
switch(InfoClass)
{
case SFileMpqFileName:
szSrcFileInfo = FileStream_GetFileName(ha->pStream);
cbSrcFileInfo = (DWORD)((_tcslen(szSrcFileInfo) + 1) * sizeof(TCHAR));
return GetInfo(pvFileInfo, cbFileInfo, szSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded);
case SFileMpqStreamBitmap:
return FileStream_GetBitmap(ha->pStream, pvFileInfo, cbFileInfo, pcbLengthNeeded);
case SFileMpqUserDataOffset:
return GetInfo(pvFileInfo, cbFileInfo, &ha->UserDataPos, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqUserDataHeader:
if(ha->pUserData == NULL)
return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER);
return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->UserDataPos, sizeof(TMPQUserData), pcbLengthNeeded);
case SFileMpqUserData:
if(ha->pUserData == NULL)
return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER);
return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->UserDataPos + sizeof(TMPQUserData), ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData), pcbLengthNeeded);
case SFileMpqHeaderOffset:
return GetInfo(pvFileInfo, cbFileInfo, &ha->MpqPos, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqHeaderSize:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwHeaderSize, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqHeader:
return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->MpqPos, pHeader->dwHeaderSize, pcbLengthNeeded);
case SFileMpqHetTableOffset:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HetTablePos64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqHetTableSize:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HetTableSize64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqHetHeader:
pvSrcFileInfo = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE);
if(pvSrcFileInfo == NULL)
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, sizeof(TMPQHetHeader), pcbLengthNeeded);
case SFileMpqHetTable:
if((pvSrcFileInfo = LoadHetTable(ha)) == NULL)
return GetInfo_ReturdwErrCode(ERROR_NOT_ENOUGH_MEMORY);
return GetInfo_TablePointer(pvFileInfo, cbFileInfo, pvSrcFileInfo, InfoClass, pcbLengthNeeded);
case SFileMpqBetTableOffset:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BetTablePos64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqBetTableSize:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BetTableSize64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqBetHeader:
// Retrieve the table and its size
pvSrcFileInfo = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE);
if(pvSrcFileInfo == NULL)
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
cbSrcFileInfo = sizeof(TMPQBetHeader) + ((TMPQBetHeader *)pvSrcFileInfo)->dwFlagCount * sizeof(DWORD);
// It is allowed for the caller to only require BET header
if(cbFileInfo == sizeof(TMPQBetHeader))
cbSrcFileInfo = sizeof(TMPQBetHeader);
return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded);
case SFileMpqBetTable:
if((pvSrcFileInfo = LoadBetTable(ha)) == NULL)
return GetInfo_ReturdwErrCode(ERROR_NOT_ENOUGH_MEMORY);
return GetInfo_TablePointer(pvFileInfo, cbFileInfo, pvSrcFileInfo, InfoClass, pcbLengthNeeded);
case SFileMpqHashTableOffset:
Int64Value = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
return GetInfo(pvFileInfo, cbFileInfo, &Int64Value, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqHashTableSize64:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HashTableSize64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqHashTableSize:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwHashTableSize, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqHashTable:
cbSrcFileInfo = pHeader->dwHashTableSize * sizeof(TMPQHash);
return GetInfo(pvFileInfo, cbFileInfo, ha->pHashTable, cbSrcFileInfo, pcbLengthNeeded);
case SFileMpqBlockTableOffset:
Int64Value = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
return GetInfo(pvFileInfo, cbFileInfo, &Int64Value, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqBlockTableSize64:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BlockTableSize64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqBlockTableSize:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwBlockTableSize, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqBlockTable:
if(MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos) >= ha->FileSize)
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
cbSrcFileInfo = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
pvSrcFileInfo = LoadBlockTable(ha, true);
return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded);
case SFileMpqHiBlockTableOffset:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HiBlockTablePos64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqHiBlockTableSize64:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HiBlockTableSize64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqHiBlockTable:
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
case SFileMpqSignatures:
if(!QueryMpqSignatureInfo(ha, &SignatureInfo))
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
return GetInfo(pvFileInfo, cbFileInfo, &SignatureInfo.SignatureTypes, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqStrongSignatureOffset:
if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0)
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
return GetInfo(pvFileInfo, cbFileInfo, &SignatureInfo.EndMpqData, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqStrongSignatureSize:
if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0)
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
dwInt32Value = MPQ_STRONG_SIGNATURE_SIZE + 4;
return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqStrongSignature:
if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0)
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
return GetInfo(pvFileInfo, cbFileInfo, SignatureInfo.Signature, MPQ_STRONG_SIGNATURE_SIZE + 4, pcbLengthNeeded);
case SFileMpqArchiveSize64:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->ArchiveSize64, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileMpqArchiveSize:
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwArchiveSize, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqMaxFileCount:
return GetInfo(pvFileInfo, cbFileInfo, &ha->dwMaxFileCount, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqFileTableSize:
return GetInfo(pvFileInfo, cbFileInfo, &ha->dwFileTableSize, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqSectorSize:
return GetInfo(pvFileInfo, cbFileInfo, &ha->dwSectorSize, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqNumberOfFiles:
dwInt32Value = GetMpqFileCount(ha);
return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqRawChunkSize:
if(pHeader->dwRawChunkSize == 0)
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwRawChunkSize, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqStreamFlags:
FileStream_GetFlags(ha->pStream, &dwInt32Value);
return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded);
case SFileMpqFlags:
return GetInfo(pvFileInfo, cbFileInfo, &ha->dwFlags, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoPatchChain:
return GetInfo_PatchChain(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded);
case SFileInfoFileEntry:
if(pFileEntry == NULL)
return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND);
return GetInfo_FileEntry(pvFileInfo, cbFileInfo, pFileEntry, pcbLengthNeeded);
case SFileInfoHashEntry:
return GetInfo(pvFileInfo, cbFileInfo, hf->pHashEntry, sizeof(TMPQHash), pcbLengthNeeded);
case SFileInfoHashIndex:
return GetInfo(pvFileInfo, cbFileInfo, &hf->dwHashIndex, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoNameHash1:
return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName1, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoNameHash2:
return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName2, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoNameHash3:
return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->FileNameHash, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileInfoLocale:
dwInt32Value = hf->pHashEntry->lcLocale;
return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoFileIndex:
dwInt32Value = (DWORD)(pFileEntry - hf->ha->pFileTable);
return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoByteOffset:
return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->ByteOffset, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileInfoFileTime:
return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->FileTime, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileInfoFileSize:
return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwFileSize, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoCompressedSize:
return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwCmpSize, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoFlags:
return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwFlags, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoEncryptionKey:
return GetInfo(pvFileInfo, cbFileInfo, &hf->dwFileKey, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoEncryptionKeyRaw:
dwInt32Value = hf->dwFileKey;
if(pFileEntry->dwFlags & MPQ_FILE_FIX_KEY)
dwInt32Value = (dwInt32Value ^ pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos;
return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoCRC32:
return GetInfo(pvFileInfo, cbFileInfo, &hf->pFileEntry->dwCrc32, sizeof(DWORD), pcbLengthNeeded);
}
// Invalid info class
return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER);
}
bool WINAPI SFileFreeFileInfo(void * pvFileInfo, SFileInfoClass InfoClass)
{
switch(InfoClass)
{
case SFileMpqHetTable:
FreeHetTable((TMPQHetTable *)pvFileInfo);
return true;
case SFileMpqBetTable:
FreeBetTable((TMPQBetTable *)pvFileInfo);
return true;
default:
break;
}
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
//-----------------------------------------------------------------------------
// Tries to retrieve the file name
struct TFileHeader2Ext
{
DWORD dwOffset00Data; // Required data at offset 00 (32-bits)
DWORD dwOffset00Mask; // Mask for data at offset 00 (32 bits). 0 = data are ignored
DWORD dwOffset04Data; // Required data at offset 04 (32-bits)
DWORD dwOffset04Mask; // Mask for data at offset 04 (32 bits). 0 = data are ignored
const char * szExt; // Supplied extension, if the condition is true
};
static TFileHeader2Ext data2ext[] =
{
{0x00005A4D, 0x0000FFFF, 0x00000000, 0x00000000, "exe"}, // EXE files
{0x00000006, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, "dc6"}, // EXE files
{0x1A51504D, 0xFFFFFFFF, 0x00000000, 0x00000000, "mpq"}, // MPQ archive header ID ('MPQ\x1A')
{0x46464952, 0xFFFFFFFF, 0x00000000, 0x00000000, "wav"}, // WAVE header 'RIFF'
{0x324B4D53, 0xFFFFFFFF, 0x00000000, 0x00000000, "smk"}, // Old "Smacker Video" files 'SMK2'
{0x694B4942, 0xFFFFFFFF, 0x00000000, 0x00000000, "bik"}, // Bink video files (new)
{0x0801050A, 0xFFFFFFFF, 0x00000000, 0x00000000, "pcx"}, // PCX images used in Diablo I
{0x544E4F46, 0xFFFFFFFF, 0x00000000, 0x00000000, "fnt"}, // Font files used in Diablo II
{0x6D74683C, 0xFFFFFFFF, 0x00000000, 0x00000000, "html"}, // HTML '<htm'
{0x4D54483C, 0xFFFFFFFF, 0x00000000, 0x00000000, "html"}, // HTML '<HTM
{0x216F6F57, 0xFFFFFFFF, 0x00000000, 0x00000000, "tbl"}, // Table files
{0x31504C42, 0xFFFFFFFF, 0x00000000, 0x00000000, "blp"}, // BLP textures
{0x32504C42, 0xFFFFFFFF, 0x00000000, 0x00000000, "blp"}, // BLP textures (v2)
{0x584C444D, 0xFFFFFFFF, 0x00000000, 0x00000000, "mdx"}, // MDX files
{0x45505954, 0xFFFFFFFF, 0x00000000, 0x00000000, "pud"}, // Warcraft II maps
{0x38464947, 0xFFFFFFFF, 0x00000000, 0x00000000, "gif"}, // GIF images 'GIF8'
{0x3032444D, 0xFFFFFFFF, 0x00000000, 0x00000000, "m2"}, // WoW ??? .m2
{0x43424457, 0xFFFFFFFF, 0x00000000, 0x00000000, "dbc"}, // ??? .dbc
{0x47585053, 0xFFFFFFFF, 0x00000000, 0x00000000, "bls"}, // WoW pixel shaders
{0xE0FFD8FF, 0xFFFFFFFF, 0x00000000, 0x00000000, "jpg"}, // JPEG image
{0x503B4449, 0xFFFFFFFF, 0x3B4C5857, 0xFFFFFFFF, "slk"}, // SLK file (usually starts with "ID;PWXL;N;E")
{0x61754C1B, 0xFFFFFFFF, 0x00000000, 0x00000000, "lua"}, // Compiled LUA files
{0x20534444, 0xFFFFFFFF, 0x00000000, 0x00000000, "dds"}, // DDS textures
{0x43614C66, 0xFFFFFFFF, 0x00000000, 0x00000000, "flac"}, // FLAC sound files
{0x0000FBFF, 0x0000FFFF, 0x00000000, 0x00000000, "mp3"}, // MP3 sound files
{0x0000F3FF, 0x0000FFFF, 0x00000000, 0x00000000, "mp3"}, // MP3 sound files
{0x0000F2FF, 0x0000FFFF, 0x00000000, 0x00000000, "mp3"}, // MP3 sound files
{0x00334449, 0x00FFFFFF, 0x00000000, 0x00000000, "mp3"}, // MP3 sound files
{0x57334D48, 0xFFFFFFFF, 0x00000000, 0x00000000, "w3x"}, // Warcraft III map files, can also be w3m
{0x6F643357, 0xFFFFFFFF, 0x00000000, 0x00000000, "doo"}, // Warcraft III doodad files
{0x21453357, 0xFFFFFFFF, 0x00000000, 0x00000000, "w3e"}, // Warcraft III environment files
{0x5733504D, 0xFFFFFFFF, 0x00000000, 0x00000000, "wpm"}, // Warcraft III pathing map files
{0x21475457, 0xFFFFFFFF, 0x00000000, 0x00000000, "wtg"}, // Warcraft III trigger files
{0x00000000, 0x00000000, 0x00000000, 0x00000000, "xxx"}, // Default extension
{0, 0, 0, 0, NULL} // Terminator
};
static DWORD CreatePseudoFileName(HANDLE hFile, TFileEntry * pFileEntry, char * szFileName)
{
TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle
DWORD FirstBytes[2] = {0, 0}; // The first 4 bytes of the file
DWORD dwBytesRead = 0;
DWORD dwFilePos; // Saved file position
char szPseudoName[20];
// Read the first 2 DWORDs bytes from the file
dwFilePos = SFileSetFilePointer(hFile, 0, NULL, FILE_CURRENT);
SFileReadFile(hFile, FirstBytes, sizeof(FirstBytes), &dwBytesRead, NULL);
SFileSetFilePointer(hFile, dwFilePos, NULL, FILE_BEGIN);
// If we read at least 8 bytes
if(dwBytesRead == sizeof(FirstBytes))
{
// Make sure that the array is properly BSWAP-ed
BSWAP_ARRAY32_UNSIGNED(FirstBytes, sizeof(FirstBytes));
// Try to guess file extension from those 2 DWORDs
for(size_t i = 0; data2ext[i].szExt != NULL; i++)
{
if((FirstBytes[0] & data2ext[i].dwOffset00Mask) == data2ext[i].dwOffset00Data &&
(FirstBytes[1] & data2ext[i].dwOffset04Mask) == data2ext[i].dwOffset04Data)
{
// Format the pseudo-name
StringCreatePseudoFileName(szPseudoName, _countof(szPseudoName), (unsigned int)(pFileEntry - hf->ha->pFileTable), data2ext[i].szExt);
// Save the pseudo-name in the file entry as well
AllocateFileName(hf->ha, pFileEntry, szPseudoName);
// If the caller wants to copy the file name, do it
if(szFileName != NULL)
strcpy(szFileName, szPseudoName);
return ERROR_SUCCESS;
}
}
}
return ERROR_CAN_NOT_COMPLETE;
}
bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
{
TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle
DWORD dwErrCode = ERROR_INVALID_HANDLE;
// Check valid parameters
if(IsValidFileHandle(hFile))
{
TFileEntry * pFileEntry = hf->pFileEntry;
// For MPQ files, retrieve the file name from the file entry
if(hf->pStream == NULL)
{
if(pFileEntry != NULL)
{
// If the file name is not there yet, create a pseudo name
if(pFileEntry->szFileName == NULL)
dwErrCode = CreatePseudoFileName(hFile, pFileEntry, szFileName);
// Copy the file name to the output buffer, if any
if(pFileEntry->szFileName && szFileName)
{
strcpy(szFileName, pFileEntry->szFileName);
dwErrCode = ERROR_SUCCESS;
}
}
}
// For local files, copy the file name from the stream
else
{
if(szFileName != NULL)
{
const TCHAR * szStreamName = FileStream_GetFileName(hf->pStream);
StringCopy(szFileName, MAX_PATH, szStreamName);
}
dwErrCode = ERROR_SUCCESS;
}
}
if(dwErrCode != ERROR_SUCCESS)
SetLastError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}

View File

@ -0,0 +1,687 @@
/*****************************************************************************/
/* 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 "StormCommon.h"
#include <assert.h>
//-----------------------------------------------------------------------------
// Listfile entry structure
#define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer
#define MAX_LISTFILE_SIZE 0x8000000 // Maximum accepted listfile size is 128 MB
union TListFileHandle
{
TFileStream * pStream; // Opened local file
HANDLE hFile; // Opened MPQ file
};
struct TListFileCache
{
char * szWildCard; // Self-relative pointer to file mask
LPBYTE pBegin; // The begin of the listfile cache
LPBYTE pPos; // Current position in the cache
LPBYTE pEnd; // The last character in the file cache
DWORD dwFlags; // Flags from TMPQArchive
// char szWildCard[wildcard_length]; // Followed by the name mask (if any)
// char szListFile[listfile_length]; // Followed by the listfile (if any)
};
typedef bool (*LOAD_LISTFILE)(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead);
//-----------------------------------------------------------------------------
// Local functions (cache)
// In SFileFindFile.cll
bool SFileCheckWildCard(const char * szString, const char * szWildCard);
static char * CopyListLine(char * szListLine, const char * szFileName)
{
// Copy the string
while (szFileName[0] != 0)
{
*szListLine++ = *szFileName++;
}
// Append the end-of-line
*szListLine++ = 0x0D;
*szListLine++ = 0x0A;
return szListLine;
}
static bool LoadListFile_Stream(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead)
{
ULONGLONG ByteOffset = 0;
bool bResult;
bResult = FileStream_Read(pHandle->pStream, &ByteOffset, pvBuffer, cbBuffer);
if(bResult)
*pdwBytesRead = cbBuffer;
return bResult;
}
static bool LoadListFile_MPQ(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead)
{
return SFileReadFile(pHandle->hFile, pvBuffer, cbBuffer, pdwBytesRead, NULL);
}
static bool FreeListFileCache(TListFileCache * pCache)
{
// Valid parameter check
if(pCache != NULL)
STORM_FREE(pCache);
return true;
}
static TListFileCache * CreateListFileCache(
LOAD_LISTFILE PfnLoadFile,
TListFileHandle * pHandle,
const char * szWildCard,
DWORD dwFileSize,
DWORD dwMaxSize,
DWORD dwFlags)
{
TListFileCache * pCache = NULL;
size_t cchWildCardAligned = 0;
size_t cchWildCard = 0;
DWORD dwBytesRead = 0;
// Get the amount of bytes that need to be allocated
if(dwFileSize == 0 || dwFileSize > dwMaxSize)
return NULL;
// Append buffer for name mask, if any
if(szWildCard != NULL)
{
cchWildCard = strlen(szWildCard) + 1;
cchWildCardAligned = (cchWildCard + 3) & 0xFFFFFFFC;
}
// Allocate cache for one file block
pCache = (TListFileCache *)STORM_ALLOC(BYTE, sizeof(TListFileCache) + cchWildCardAligned + dwFileSize + 1);
if(pCache != NULL)
{
// Clear the entire structure
memset(pCache, 0, sizeof(TListFileCache) + cchWildCard);
pCache->dwFlags = dwFlags;
// Shall we copy the mask?
if(cchWildCard != 0)
{
pCache->szWildCard = (char *)(pCache + 1);
memcpy(pCache->szWildCard, szWildCard, cchWildCard);
}
// Fill-in the rest of the cache pointers
pCache->pBegin = (LPBYTE)(pCache + 1) + cchWildCardAligned;
// Load the entire listfile to the cache
PfnLoadFile(pHandle, pCache->pBegin, dwFileSize, &dwBytesRead);
if(dwBytesRead != 0)
{
// Allocate pointers
pCache->pPos = pCache->pBegin;
pCache->pEnd = pCache->pBegin + dwBytesRead;
}
else
{
FreeListFileCache(pCache);
pCache = NULL;
}
}
// Return the cache
return pCache;
}
static TListFileCache * CreateListFileCache(
HANDLE hMpq,
const TCHAR * szListFile,
const char * szWildCard,
DWORD dwMaxSize,
DWORD dwFlags)
{
TListFileCache * pCache = NULL;
TListFileHandle ListHandle = {NULL};
// Put default value to dwMaxSize
if(dwMaxSize == 0)
dwMaxSize = MAX_LISTFILE_SIZE;
// Internal listfile: hMPQ must be non NULL and szListFile must be NULL.
// We load the MPQ::(listfile) file
if(hMpq != NULL && szListFile == NULL)
{
DWORD dwFileSize = 0;
// Open the file from the MPQ
if(SFileOpenFileEx(hMpq, LISTFILE_NAME, 0, &ListHandle.hFile))
{
// Get the file size and create the listfile cache
dwFileSize = SFileGetFileSize(ListHandle.hFile, NULL);
pCache = CreateListFileCache(LoadListFile_MPQ, &ListHandle, szWildCard, dwFileSize, dwMaxSize, dwFlags);
// Close the MPQ file
SFileCloseFile(ListHandle.hFile);
}
// Return the loaded cache
return pCache;
}
// External listfile: hMpq must be NULL and szListFile must be non-NULL.
// We load the file using TFileStream
if(hMpq == NULL && szListFile != NULL)
{
ULONGLONG FileSize = 0;
// Open the local file
ListHandle.pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY);
if(ListHandle.pStream != NULL)
{
// Verify the file size
FileStream_GetSize(ListHandle.pStream, &FileSize);
if(0 < FileSize && FileSize < dwMaxSize)
{
pCache = CreateListFileCache(LoadListFile_Stream, &ListHandle, szWildCard, (DWORD)FileSize, dwMaxSize, dwFlags);
}
// Close the stream
FileStream_Close(ListHandle.pStream);
}
// Return the loaded cache
return pCache;
}
// This combination should never happen
SetLastError(ERROR_INVALID_PARAMETER);
assert(false);
return NULL;
}
#ifdef _DEBUG
/*
TMPQNameCache * CreateNameCache(HANDLE hListFile, const char * szSearchMask)
{
TMPQNameCache * pNameCache;
char * szCachePointer;
size_t cbToAllocate;
size_t nMaskLength = 1;
DWORD dwBytesRead = 0;
DWORD dwFileSize;
// Get the size of the listfile. Ignore zero or too long ones
dwFileSize = SFileGetFileSize(hListFile, NULL);
if(dwFileSize == 0 || dwFileSize > MAX_LISTFILE_SIZE)
return NULL;
// Get the length of the search mask
if(szSearchMask == NULL)
szSearchMask = "*";
nMaskLength = strlen(szSearchMask) + 1;
// Allocate the name cache
cbToAllocate = sizeof(TMPQNameCache) + nMaskLength + dwFileSize + 1;
pNameCache = (TMPQNameCache *)STORM_ALLOC(BYTE, cbToAllocate);
if(pNameCache != NULL)
{
// Initialize the name cache
memset(pNameCache, 0, sizeof(TMPQNameCache));
pNameCache->TotalCacheSize = (DWORD)(nMaskLength + dwFileSize + 1);
szCachePointer = (char *)(pNameCache + 1);
// Copy the search mask, if any
memcpy(szCachePointer, szSearchMask, nMaskLength);
pNameCache->FirstNameOffset = (DWORD)nMaskLength;
pNameCache->FreeSpaceOffset = (DWORD)nMaskLength;
// Read the listfile itself
SFileSetFilePointer(hListFile, 0, NULL, FILE_BEGIN);
SFileReadFile(hListFile, szCachePointer + nMaskLength, dwFileSize, &dwBytesRead, NULL);
// If nothing has been read from the listfile, clear the cache
if(dwBytesRead == 0)
{
STORM_FREE(pNameCache);
return NULL;
}
// Move the free space offset
pNameCache->FreeSpaceOffset = pNameCache->FirstNameOffset + dwBytesRead + 1;
szCachePointer[nMaskLength + dwBytesRead] = 0;
}
return pNameCache;
}
static void FreeNameCache(TMPQNameCache * pNameCache)
{
if(pNameCache != NULL)
STORM_FREE(pNameCache);
pNameCache = NULL;
}
*/
#endif // _DEBUG
static char * ReadListFileLine(TListFileCache * pCache, size_t * PtrLength)
{
LPBYTE pbLineBegin;
LPBYTE pbLineEnd;
// Skip newlines. Keep spaces and tabs, as they can be a legal part of the file name
while(pCache->pPos < pCache->pEnd && (pCache->pPos[0] == 0x0A || pCache->pPos[0] == 0x0D))
pCache->pPos++;
// Set the line begin and end
if(pCache->pPos >= pCache->pEnd)
return NULL;
pbLineBegin = pbLineEnd = pCache->pPos;
// Find the end of the line
while(pCache->pPos < pCache->pEnd && pCache->pPos[0] != 0x0A && pCache->pPos[0] != 0x0D)
pCache->pPos++;
// Remember the end of the line
pbLineEnd = pCache->pPos++;
pbLineEnd[0] = 0;
// Give the line to the caller
if(PtrLength != NULL)
PtrLength[0] = (size_t)(pbLineEnd - pbLineBegin);
return (char *)pbLineBegin;
}
static int STORMLIB_CDECL CompareFileNodes(const void * p1, const void * p2)
{
char * szFileName1 = *(char **)p1;
char * szFileName2 = *(char **)p2;
return _stricmp(szFileName1, szFileName2);
}
static LPBYTE CreateListFile(TMPQArchive * ha, DWORD * pcbListFile)
{
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
TFileEntry * pFileEntry;
char ** SortTable = NULL;
char * szListFile = NULL;
char * szListLine;
size_t nFileNodes = 0;
size_t cbListFile = 0;
size_t nIndex0;
size_t nIndex1;
// Allocate the table for sorting listfile
SortTable = STORM_ALLOC(char*, ha->dwFileTableSize);
if(SortTable == NULL)
return NULL;
// Construct the sort table
// Note: in MPQs with multiple locale versions of the same file,
// this code causes adding multiple listfile entries.
// They will get removed after the listfile sorting
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
{
// Only take existing items
if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->szFileName != NULL)
{
// Ignore pseudo-names and internal names
if(!IsPseudoFileName(pFileEntry->szFileName, NULL) && !IsInternalMpqFileName(pFileEntry->szFileName))
{
for (int i = 0; i < strlen(pFileEntry->szFileName); i++)
{
// OTRTODO
//if (pFileEntry->szFileName[i] == '/')
//pFileEntry->szFileName[i] = '\\';
}
SortTable[nFileNodes++] = pFileEntry->szFileName;
}
}
}
// Remove duplicities
if(nFileNodes > 0)
{
// Sort the table
qsort(SortTable, nFileNodes, sizeof(char *), CompareFileNodes);
// Count the 0-th item
cbListFile += strlen(SortTable[0]) + 2;
// Walk through the items and only use the ones that are not duplicated
for(nIndex0 = 0, nIndex1 = 1; nIndex1 < nFileNodes; nIndex1++)
{
// If the next file node is different, we will include it to the result listfile
if(_stricmp(SortTable[nIndex1], SortTable[nIndex0]) != 0)
{
cbListFile += strlen(SortTable[nIndex1]) + 2;
nIndex0 = nIndex1;
}
}
// Now allocate buffer for the entire listfile
szListFile = szListLine = STORM_ALLOC(char, cbListFile + 1);
if(szListFile != NULL)
{
// Copy the 0-th item
szListLine = CopyListLine(szListLine, SortTable[0]);
// Walk through the items and only use the ones that are not duplicated
for(nIndex0 = 0, nIndex1 = 1; nIndex1 < nFileNodes; nIndex1++)
{
// If the next file node is different, we will include it to the result listfile
if(_stricmp(SortTable[nIndex1], SortTable[nIndex0]) != 0)
{
// Copy the listfile line
szListLine = CopyListLine(szListLine, SortTable[nIndex1]);
nIndex0 = nIndex1;
}
}
// Sanity check - does the size match?
assert((size_t)(szListLine - szListFile) == cbListFile);
}
}
else
{
szListFile = STORM_ALLOC(char, 1);
cbListFile = 0;
}
// Free the sort table
STORM_FREE(SortTable);
// Give away the listfile
if(pcbListFile != NULL)
*pcbListFile = (DWORD)cbListFile;
return (LPBYTE)szListFile;
}
//-----------------------------------------------------------------------------
// Local functions (listfile nodes)
// Adds a name into the list of all names. For each locale in the MPQ,
// one entry will be created
// If the file name is already there, does nothing.
static DWORD SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFileName)
{
TFileEntry * pFileEntry;
TMPQHash * pFirstHash;
TMPQHash * pHash;
// If we have HET table, use that one
if(ha->pHetTable != NULL)
{
pFileEntry = GetFileEntryLocale(ha, szFileName, 0);
if(pFileEntry != NULL)
{
// Allocate file name for the file entry
AllocateFileName(ha, pFileEntry, szFileName);
}
return ERROR_SUCCESS;
}
// If we have hash table, we use it
if(ha->pHashTable != NULL)
{
// Go while we found something
pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
while(pHash != NULL)
{
// Allocate file name for the file entry
AllocateFileName(ha, ha->pFileTable + MPQ_BLOCK_INDEX(pHash), szFileName);
// Now find the next language version of the file
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
}
return ERROR_SUCCESS;
}
return ERROR_CAN_NOT_COMPLETE;
}
// Saves the whole listfile to the MPQ
DWORD SListFileSaveToMpq(TMPQArchive * ha)
{
TMPQFile * hf = NULL;
LPBYTE pbListFile;
DWORD cbListFile = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Only save the listfile if we should do so
if(ha->dwFileFlags1 != 0)
{
// At this point, we expect to have at least one reserved entry in the file table
assert(ha->dwFlags & MPQ_FLAG_LISTFILE_NEW);
assert(ha->dwReservedFiles > 0);
// Create the raw data that is to be written to (listfile)
// Note: Creating the raw data before the (listfile) has been created in the MPQ
// causes that the name of the listfile will not be included in the listfile itself.
// That is OK, because (listfile) in Blizzard MPQs does not contain it either.
pbListFile = CreateListFile(ha, &cbListFile);
if(pbListFile != NULL)
{
// Determine the real flags for (listfile)
if(ha->dwFileFlags1 == MPQ_FILE_DEFAULT_INTERNAL)
ha->dwFileFlags1 = GetDefaultSpecialFileFlags(cbListFile, ha->pHeader->wFormatVersion);
// Create the listfile in the MPQ
dwErrCode = SFileAddFile_Init(ha, LISTFILE_NAME,
0,
cbListFile,
LANG_NEUTRAL,
ha->dwFileFlags1 | MPQ_FILE_REPLACEEXISTING,
&hf);
// Write the listfile raw data to it
if(dwErrCode == ERROR_SUCCESS)
{
// Write the content of the listfile to the MPQ
dwErrCode = SFileAddFile_Write(hf, pbListFile, cbListFile, MPQ_COMPRESSION_ZLIB);
SFileAddFile_Finish(hf);
}
// Clear the listfile flags
ha->dwFlags &= ~(MPQ_FLAG_LISTFILE_NEW | MPQ_FLAG_LISTFILE_NONE);
ha->dwReservedFiles--;
// Free the listfile buffer
STORM_FREE(pbListFile);
}
else
{
// If the (listfile) file would be empty, its OK
dwErrCode = (cbListFile == 0) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;
}
}
return dwErrCode;
}
static DWORD SFileAddArbitraryListFile(
TMPQArchive * ha,
HANDLE hMpq,
const TCHAR * szListFile,
DWORD dwMaxSize)
{
TListFileCache * pCache = NULL;
// Create the listfile cache for that file
pCache = CreateListFileCache(hMpq, szListFile, NULL, dwMaxSize, ha->dwFlags);
if(pCache != NULL)
{
char * szFileName;
size_t nLength = 0;
// Get the next line
while((szFileName = ReadListFileLine(pCache, &nLength)) != NULL)
{
// Add the line to the MPQ
if(nLength != 0)
SListFileCreateNodeForAllLocales(ha, szFileName);
}
// Delete the cache
FreeListFileCache(pCache);
}
return (pCache != NULL) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
}
static DWORD SFileAddInternalListFile(
TMPQArchive * ha,
HANDLE hMpq)
{
TMPQHash * pFirstHash;
TMPQHash * pHash;
LCID lcSaveLocale = g_lcFileLocale;
DWORD dwMaxSize = MAX_LISTFILE_SIZE;
DWORD dwErrCode = ERROR_SUCCESS;
// If there is hash table, we need to support multiple listfiles
// with different locales (BrooDat.mpq)
if(ha->pHashTable != NULL)
{
// If the archive is a malformed map, ignore too large listfiles
if(ha->dwFlags & MPQ_FLAG_MALFORMED)
dwMaxSize = 0x40000;
pFirstHash = pHash = GetFirstHashEntry(ha, LISTFILE_NAME);
while(dwErrCode == ERROR_SUCCESS && pHash != NULL)
{
// Set the prefered locale to that from list file
SFileSetLocale(pHash->lcLocale);
// Add that listfile
dwErrCode = SFileAddArbitraryListFile(ha, hMpq, NULL, dwMaxSize);
// Move to the next hash
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
}
// Restore the original locale
SFileSetLocale(lcSaveLocale);
}
else
{
// Add the single listfile
dwErrCode = SFileAddArbitraryListFile(ha, hMpq, NULL, dwMaxSize);
}
// Return the result of the operation
return dwErrCode;
}
static bool DoListFileSearch(TListFileCache * pCache, SFILE_FIND_DATA * lpFindFileData)
{
// Check for the valid search handle
if(pCache != NULL)
{
char * szFileName;
size_t nLength = 0;
// Get the next line
while((szFileName = ReadListFileLine(pCache, &nLength)) != NULL)
{
// Check search mask
if(nLength != 0 && SFileCheckWildCard(szFileName, pCache->szWildCard))
{
if(nLength >= sizeof(lpFindFileData->cFileName))
nLength = sizeof(lpFindFileData->cFileName) - 1;
memcpy(lpFindFileData->cFileName, szFileName, nLength);
lpFindFileData->cFileName[nLength] = 0;
return true;
}
}
}
// No more files
memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
SetLastError(ERROR_NO_MORE_FILES);
return false;
}
//-----------------------------------------------------------------------------
// File functions
// Adds a listfile into the MPQ archive.
DWORD WINAPI SFileAddListFile(HANDLE hMpq, const TCHAR * szListFile)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
DWORD dwErrCode = ERROR_SUCCESS;
// Add the listfile for each MPQ in the patch chain
while(ha != NULL)
{
if(szListFile != NULL)
dwErrCode = SFileAddArbitraryListFile(ha, NULL, szListFile, MAX_LISTFILE_SIZE);
else
dwErrCode = SFileAddInternalListFile(ha, hMpq);
// Also, add three special files to the listfile:
// (listfile) itself, (attributes) and (signature)
SListFileCreateNodeForAllLocales(ha, LISTFILE_NAME);
SListFileCreateNodeForAllLocales(ha, SIGNATURE_NAME);
SListFileCreateNodeForAllLocales(ha, ATTRIBUTES_NAME);
// Move to the next archive in the chain
ha = ha->haPatch;
}
return dwErrCode;
}
//-----------------------------------------------------------------------------
// Enumerating files in listfile
HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const TCHAR * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData)
{
TListFileCache * pCache = NULL;
// Initialize the structure with zeros
memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
// Open the local/internal listfile
pCache = CreateListFileCache(hMpq, szListFile, szMask, 0, 0);
if(pCache != NULL)
{
if(!DoListFileSearch(pCache, lpFindFileData))
{
memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
SetLastError(ERROR_NO_MORE_FILES);
FreeListFileCache(pCache);
pCache = NULL;
}
}
// Return the listfile cache as handle
return (HANDLE)pCache;
}
bool WINAPI SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
{
return DoListFileSearch((TListFileCache *)hFind, lpFindFileData);
}
bool WINAPI SListFileFindClose(HANDLE hFind)
{
TListFileCache * pCache = (TListFileCache *)hFind;
return FreeListFileCache(pCache);
}

View File

@ -0,0 +1,658 @@
/*****************************************************************************/
/* SFileOpenArchive.cpp Copyright Ladislav Zezula 1999 */
/* */
/* Author : Ladislav Zezula */
/* E-mail : ladik@zezula.net */
/* WWW : www.zezula.net */
/*---------------------------------------------------------------------------*/
/* Implementation of archive functions */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* xx.xx.xx 1.00 Lad Created */
/* 19.11.03 1.01 Dan Big endian handling */
/*****************************************************************************/
#define __STORMLIB_SELF__
#include "StormLib.h"
#include "StormCommon.h"
#define HEADER_SEARCH_BUFFER_SIZE 0x1000
//-----------------------------------------------------------------------------
// Local functions
static MTYPE CheckMapType(LPCTSTR szFileName, LPBYTE pbHeaderBuffer, size_t cbHeaderBuffer)
{
LPDWORD HeaderInt32 = (LPDWORD)pbHeaderBuffer;
LPCTSTR szExtension;
// Don't do any checks if there is not at least 16 bytes
if(cbHeaderBuffer > 0x10)
{
DWORD DwordValue0 = BSWAP_INT32_UNSIGNED(HeaderInt32[0]);
DWORD DwordValue1 = BSWAP_INT32_UNSIGNED(HeaderInt32[1]);
DWORD DwordValue2 = BSWAP_INT32_UNSIGNED(HeaderInt32[2]);
DWORD DwordValue3 = BSWAP_INT32_UNSIGNED(HeaderInt32[3]);
// Test for AVI files (Warcraft III cinematics) - 'RIFF', 'AVI ' or 'LIST'
if(DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C)
return MapTypeAviFile;
// Check for Starcraft II maps
if((szExtension = _tcsrchr(szFileName, _T('.'))) != NULL)
{
// The "NP_Protect" protector places fake Warcraft III header
// into the Starcraft II maps, whilst SC2 maps have no other header but MPQ v4
if(!_tcsicmp(szExtension, _T(".s2ma")) || !_tcsicmp(szExtension, _T(".SC2Map")) || !_tcsicmp(szExtension, _T(".SC2Mod")))
{
return MapTypeStarcraft2;
}
}
// Check for Warcraft III maps
if(DwordValue0 == 0x57334D48 && DwordValue1 == 0x00000000)
return MapTypeWarcraft3;
}
// MIX files are DLL files that contain MPQ in overlay.
// Only Warcraft III is able to load them, so we consider them Warcraft III maps
if(cbHeaderBuffer > 0x200 && pbHeaderBuffer[0] == 'M' && pbHeaderBuffer[1] == 'Z')
{
// Check the value of IMAGE_DOS_HEADER::e_lfanew at offset 0x3C
if(0 < HeaderInt32[0x0F] && HeaderInt32[0x0F] < 0x10000)
return MapTypeWarcraft3;
}
// No special map type recognized
return MapTypeNotRecognized;
}
static TMPQUserData * IsValidMpqUserData(ULONGLONG ByteOffset, ULONGLONG FileSize, void * pvUserData)
{
TMPQUserData * pUserData;
// BSWAP the source data and copy them to our buffer
BSWAP_ARRAY32_UNSIGNED(pvUserData, sizeof(TMPQUserData));
pUserData = (TMPQUserData *)pvUserData;
// Check the sizes
if(pUserData->cbUserDataHeader <= pUserData->cbUserDataSize && pUserData->cbUserDataSize <= pUserData->dwHeaderOffs)
{
// Move to the position given by the userdata
ByteOffset += pUserData->dwHeaderOffs;
// The MPQ header should be within range of the file size
if((ByteOffset + MPQ_HEADER_SIZE_V1) < FileSize)
{
// Note: We should verify if there is the MPQ header.
// However, the header could be at any position below that
// that is multiplier of 0x200
return (TMPQUserData *)pvUserData;
}
}
return NULL;
}
// This function gets the right positions of the hash table and the block table.
static DWORD VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize)
{
TMPQHeader * pHeader = ha->pHeader;
ULONGLONG ByteOffset;
//bool bMalformed = (ha->dwFlags & MPQ_FLAG_MALFORMED) ? true : false;
// Check the begin of HET table
if(pHeader->HetTablePos64)
{
ByteOffset = ha->MpqPos + pHeader->HetTablePos64;
if(ByteOffset > FileSize)
return ERROR_BAD_FORMAT;
}
// Check the begin of BET table
if(pHeader->BetTablePos64)
{
ByteOffset = ha->MpqPos + pHeader->BetTablePos64;
if(ByteOffset > FileSize)
return ERROR_BAD_FORMAT;
}
// Check the begin of hash table
if(pHeader->wHashTablePosHi || pHeader->dwHashTablePos)
{
ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos));
if(ByteOffset > FileSize)
return ERROR_BAD_FORMAT;
}
// Check the begin of block table
if(pHeader->wBlockTablePosHi || pHeader->dwBlockTablePos)
{
ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos));
if(ByteOffset > FileSize)
return ERROR_BAD_FORMAT;
}
// Check the begin of hi-block table
//if(pHeader->HiBlockTablePos64 != 0)
//{
// ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64;
// if(ByteOffset > FileSize)
// return ERROR_BAD_FORMAT;
//}
// All OK.
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------
// Support for alternate markers. Call before opening an archive
#define SFILE_MARKERS_MIN_SIZE (sizeof(DWORD) + sizeof(DWORD) + sizeof(const char *) + sizeof(const char *))
bool WINAPI SFileSetArchiveMarkers(PSFILE_MARKERS pMarkers)
{
// Check structure minimum size
if(pMarkers == NULL || pMarkers->dwSize < SFILE_MARKERS_MIN_SIZE)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Make sure that the MPQ cryptography is initialized at this time
InitializeMpqCryptography();
// Remember the marker for MPQ header
if(pMarkers->dwSignature != 0)
g_dwMpqSignature = pMarkers->dwSignature;
// Remember the encryption key for hash table
if(pMarkers->szHashTableKey != NULL)
g_dwHashTableKey = HashString(pMarkers->szHashTableKey, MPQ_HASH_FILE_KEY);
// Remember the encryption key for block table
if(pMarkers->szBlockTableKey != NULL)
g_dwBlockTableKey = HashString(pMarkers->szBlockTableKey, MPQ_HASH_FILE_KEY);
// Succeeded
return true;
}
//-----------------------------------------------------------------------------
// SFileGetLocale and SFileSetLocale
// Set the locale for all newly opened files
LCID WINAPI SFileGetLocale()
{
return g_lcFileLocale;
}
LCID WINAPI SFileSetLocale(LCID lcNewLocale)
{
g_lcFileLocale = lcNewLocale;
return g_lcFileLocale;
}
//-----------------------------------------------------------------------------
// SFileOpenArchive
//
// szFileName - MPQ archive file name to open
// dwPriority - When SFileOpenFileEx called, this contains the search priority for searched archives
// dwFlags - See MPQ_OPEN_XXX in StormLib.h
// phMpq - Pointer to store open archive handle
bool WINAPI SFileOpenArchive(
const TCHAR * szMpqName,
DWORD dwPriority,
DWORD dwFlags,
HANDLE * phMpq)
{
TMPQUserData * pUserData;
TFileStream * pStream = NULL; // Open file stream
TMPQArchive * ha = NULL; // Archive handle
TFileEntry * pFileEntry;
ULONGLONG FileSize = 0; // Size of the file
LPBYTE pbHeaderBuffer = NULL; // Buffer for searching MPQ header
DWORD dwStreamFlags = (dwFlags & STREAM_FLAGS_MASK);
MTYPE MapType = MapTypeNotChecked;
DWORD dwErrCode = ERROR_SUCCESS;
// Verify the parameters
if(szMpqName == NULL || *szMpqName == 0 || phMpq == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// One time initialization of MPQ cryptography
InitializeMpqCryptography();
dwPriority = dwPriority;
// If not forcing MPQ v 1.0, also use file bitmap
dwStreamFlags |= (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) ? 0 : STREAM_FLAG_USE_BITMAP;
// Open the MPQ archive file
pStream = FileStream_OpenFile(szMpqName, dwStreamFlags);
if(pStream == NULL)
return false;
// Check the file size. There must be at least 0x20 bytes
if(dwErrCode == ERROR_SUCCESS)
{
FileStream_GetSize(pStream, &FileSize);
if(FileSize < MPQ_HEADER_SIZE_V1)
dwErrCode = ERROR_BAD_FORMAT;
}
// Allocate the MPQhandle
if(dwErrCode == ERROR_SUCCESS)
{
if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL)
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
// Allocate buffer for searching MPQ header
if(dwErrCode == ERROR_SUCCESS)
{
pbHeaderBuffer = STORM_ALLOC(BYTE, HEADER_SEARCH_BUFFER_SIZE);
if(pbHeaderBuffer == NULL)
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
// Find the position of MPQ header
if(dwErrCode == ERROR_SUCCESS)
{
ULONGLONG ByteOffset = 0;
ULONGLONG EndOfSearch = FileSize;
DWORD dwStrmFlags = 0;
DWORD dwHeaderSize;
DWORD dwHeaderID;
bool bSearchComplete = false;
memset(ha, 0, sizeof(TMPQArchive));
ha->pfnHashString = HashStringSlash;
ha->pStream = pStream;
pStream = NULL;
// Set the archive read only if the stream is read-only
FileStream_GetFlags(ha->pStream, &dwStrmFlags);
ha->dwFlags |= (dwStrmFlags & STREAM_FLAG_READ_ONLY) ? MPQ_FLAG_READ_ONLY : 0;
// Also remember if we shall check sector CRCs when reading file
ha->dwFlags |= (dwFlags & MPQ_OPEN_CHECK_SECTOR_CRC) ? MPQ_FLAG_CHECK_SECTOR_CRC : 0;
// Also remember if this MPQ is a patch
ha->dwFlags |= (dwFlags & MPQ_OPEN_PATCH) ? MPQ_FLAG_PATCH : 0;
// Limit the header searching to about 130 MB of data
if(EndOfSearch > 0x08000000)
EndOfSearch = 0x08000000;
// Find the offset of MPQ header within the file
while(bSearchComplete == false && ByteOffset < EndOfSearch)
{
// Always read at least 0x1000 bytes for performance.
// This is what Storm.dll (2002) does.
DWORD dwBytesAvailable = HEADER_SEARCH_BUFFER_SIZE;
// Cut the bytes available, if needed
if((FileSize - ByteOffset) < HEADER_SEARCH_BUFFER_SIZE)
dwBytesAvailable = (DWORD)(FileSize - ByteOffset);
// Read the eventual MPQ header
if(!FileStream_Read(ha->pStream, &ByteOffset, pbHeaderBuffer, dwBytesAvailable))
{
dwErrCode = GetLastError();
break;
}
// Check whether the file is AVI file or a Warcraft III/Starcraft II map
if(MapType == MapTypeNotChecked)
{
// Do nothing if the file is an AVI file
if((MapType = CheckMapType(szMpqName, pbHeaderBuffer, dwBytesAvailable)) == MapTypeAviFile)
{
dwErrCode = ERROR_AVI_FILE;
break;
}
}
// Search the header buffer
for(DWORD dwInBufferOffset = 0; dwInBufferOffset < dwBytesAvailable; dwInBufferOffset += 0x200)
{
// Copy the data from the potential header buffer to the MPQ header
memcpy(ha->HeaderData, pbHeaderBuffer + dwInBufferOffset, sizeof(ha->HeaderData));
// If there is the MPQ user data, process it
// Note that Warcraft III does not check for user data, which is abused by many map protectors
dwHeaderID = BSWAP_INT32_UNSIGNED(ha->HeaderData[0]);
if(MapType != MapTypeWarcraft3 && (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0)
{
if(ha->pUserData == NULL && dwHeaderID == ID_MPQ_USERDATA)
{
// Verify if this looks like a valid user data
pUserData = IsValidMpqUserData(ByteOffset, FileSize, ha->HeaderData);
if(pUserData != NULL)
{
// Fill the user data header
ha->UserDataPos = ByteOffset;
ha->pUserData = &ha->UserData;
memcpy(ha->pUserData, pUserData, sizeof(TMPQUserData));
// Continue searching from that position
ByteOffset += ha->pUserData->dwHeaderOffs;
break;
}
}
}
// There must be MPQ header signature. Note that STORM.dll from Warcraft III actually
// tests the MPQ header size. It must be at least 0x20 bytes in order to load it
// Abused by Spazzler Map protector. Note that the size check is not present
// in Storm.dll v 1.00, so Diablo I code would load the MPQ anyway.
dwHeaderSize = BSWAP_INT32_UNSIGNED(ha->HeaderData[1]);
if(dwHeaderID == g_dwMpqSignature && dwHeaderSize >= MPQ_HEADER_SIZE_V1)
{
// Now convert the header to version 4
dwErrCode = ConvertMpqHeaderToFormat4(ha, ByteOffset, FileSize, dwFlags, MapType);
if(dwErrCode != ERROR_FAKE_MPQ_HEADER)
{
bSearchComplete = true;
break;
}
}
// Check for MPK archives (Longwu Online - MPQ fork)
if(MapType == MapTypeNotRecognized && dwHeaderID == ID_MPK)
{
// Now convert the MPK header to MPQ Header version 4
dwErrCode = ConvertMpkHeaderToFormat4(ha, FileSize, dwFlags);
bSearchComplete = true;
break;
}
// If searching for the MPQ header is disabled, return an error
if(dwFlags & MPQ_OPEN_NO_HEADER_SEARCH)
{
dwErrCode = ERROR_NOT_SUPPORTED;
bSearchComplete = true;
break;
}
// Move the pointers
ByteOffset += 0x200;
}
}
// Did we identify one of the supported headers?
if(dwErrCode == ERROR_SUCCESS)
{
// Set the user data position to the MPQ header, if none
if(ha->pUserData == NULL)
ha->UserDataPos = ByteOffset;
// Set the position of the MPQ header
ha->pHeader = (TMPQHeader *)ha->HeaderData;
ha->MpqPos = ByteOffset;
ha->FileSize = FileSize;
// Sector size must be nonzero.
if(ByteOffset >= FileSize || ha->pHeader->wSectorSize == 0)
dwErrCode = ERROR_BAD_FORMAT;
}
}
// Fix table positions according to format
if(dwErrCode == ERROR_SUCCESS)
{
// Dump the header
// DumpMpqHeader(ha->pHeader);
// W3x Map Protectors use the fact that War3's Storm.dll ignores the MPQ user data,
// and ignores the MPQ format version as well. The trick is to
// fake MPQ format 2, with an improper hi-word position of hash table and block table
// We can overcome such protectors by forcing opening the archive as MPQ v 1.0
if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1)
{
ha->pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1;
ha->pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
ha->dwFlags |= MPQ_FLAG_READ_ONLY;
ha->pUserData = NULL;
}
// Anti-overflow. If the hash table size in the header is
// higher than 0x10000000, it would overflow in 32-bit version
// Observed in the malformed Warcraft III maps
// Example map: MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x
ha->pHeader->dwBlockTableSize = (ha->pHeader->dwBlockTableSize & BLOCK_INDEX_MASK);
ha->pHeader->dwHashTableSize = (ha->pHeader->dwHashTableSize & BLOCK_INDEX_MASK);
// Both MPQ_OPEN_NO_LISTFILE or MPQ_OPEN_NO_ATTRIBUTES trigger read only mode
if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES))
ha->dwFlags |= MPQ_FLAG_READ_ONLY;
// Check if the caller wants to force adding listfile
if(dwFlags & MPQ_OPEN_FORCE_LISTFILE)
ha->dwFlags |= MPQ_FLAG_LISTFILE_FORCE;
// Remember whether whis is a map for Warcraft III
if(MapType == MapTypeWarcraft3)
ha->dwFlags |= MPQ_FLAG_WAR3_MAP;
// Set the size of file sector
ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize);
// Verify if any of the tables doesn't start beyond the end of the file
dwErrCode = VerifyMpqTablePositions(ha, FileSize);
}
// Read the hash table. Ignore the result, as hash table is no longer required
// Read HET table. Ignore the result, as HET table is no longer required
if(dwErrCode == ERROR_SUCCESS)
{
dwErrCode = LoadAnyHashTable(ha);
}
// Now, build the file table. It will be built by combining
// the block table, BET table, hi-block table, (attributes) and (listfile).
if(dwErrCode == ERROR_SUCCESS)
{
dwErrCode = BuildFileTable(ha);
}
// Load the internal listfile and include it to the file table
if(dwErrCode == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_LISTFILE) == 0)
{
// Quick check for (listfile)
pFileEntry = GetFileEntryLocale(ha, LISTFILE_NAME, LANG_NEUTRAL);
if(pFileEntry != NULL)
{
// Ignore result of the operation. (listfile) is optional.
SFileAddListFile((HANDLE)ha, NULL);
ha->dwFileFlags1 = pFileEntry->dwFlags;
}
}
// Load the "(attributes)" file and merge it to the file table
if(dwErrCode == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_ATTRIBUTES) == 0 && (ha->dwFlags & MPQ_FLAG_BLOCK_TABLE_CUT) == 0)
{
// Quick check for (attributes)
pFileEntry = GetFileEntryLocale(ha, ATTRIBUTES_NAME, LANG_NEUTRAL);
if(pFileEntry != NULL)
{
// Ignore result of the operation. (attributes) is optional.
SAttrLoadAttributes(ha);
ha->dwFileFlags2 = pFileEntry->dwFlags;
}
}
// Remember whether the archive has weak signature. Only for MPQs format 1.0.
if(dwErrCode == ERROR_SUCCESS)
{
// Quick check for (signature)
pFileEntry = GetFileEntryLocale(ha, SIGNATURE_NAME, LANG_NEUTRAL);
if(pFileEntry != NULL)
{
// Just remember that the archive is weak-signed
assert((pFileEntry->dwFlags & MPQ_FILE_EXISTS) != 0);
ha->dwFileFlags3 = pFileEntry->dwFlags;
}
// Finally, set the MPQ_FLAG_READ_ONLY if the MPQ was found malformed
ha->dwFlags |= (ha->dwFlags & MPQ_FLAG_MALFORMED) ? MPQ_FLAG_READ_ONLY : 0;
}
// Cleanup and exit
if(dwErrCode != ERROR_SUCCESS)
{
FileStream_Close(pStream);
FreeArchiveHandle(ha);
SetLastError(dwErrCode);
ha = NULL;
}
// Free the header buffer
if(pbHeaderBuffer != NULL)
STORM_FREE(pbHeaderBuffer);
if(phMpq != NULL)
*phMpq = ha;
return (dwErrCode == ERROR_SUCCESS);
}
//-----------------------------------------------------------------------------
// bool WINAPI SFileSetDownloadCallback(HANDLE, SFILE_DOWNLOAD_CALLBACK, void *);
//
// Sets a callback that is called when content is downloaded from the master MPQ
//
bool WINAPI SFileSetDownloadCallback(HANDLE hMpq, SFILE_DOWNLOAD_CALLBACK DownloadCB, void * pvUserData)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
// Do nothing if 'hMpq' is bad parameter
if(!IsValidMpqHandle(hMpq))
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
return FileStream_SetCallback(ha->pStream, DownloadCB, pvUserData);
}
//-----------------------------------------------------------------------------
// bool SFileFlushArchive(HANDLE hMpq)
//
// Saves all dirty data into MPQ archive.
// Has similar effect like SFileCloseArchive, but the archive is not closed.
// Use on clients who keep MPQ archive open even for write operations,
// and terminating without calling SFileCloseArchive might corrupt the archive.
//
bool WINAPI SFileFlushArchive(HANDLE hMpq)
{
TMPQArchive * ha;
DWORD dwResultError = ERROR_SUCCESS;
DWORD dwErrCode;
// Do nothing if 'hMpq' is bad parameter
if((ha = IsValidMpqHandle(hMpq)) == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Only if the MPQ was changed
if(ha->dwFlags & MPQ_FLAG_CHANGED)
{
// Indicate that we are saving MPQ internal structures
ha->dwFlags |= MPQ_FLAG_SAVING_TABLES;
// Defragment the file table. This will allow us to put the internal files to the end
DefragmentFileTable(ha);
//
// Create each internal file
// Note that the (signature) file is usually before (listfile) in the file table
//
if(ha->dwFlags & MPQ_FLAG_SIGNATURE_NEW)
{
dwErrCode = SSignFileCreate(ha);
if(dwErrCode != ERROR_SUCCESS)
dwResultError = dwErrCode;
}
if(ha->dwFlags & (MPQ_FLAG_LISTFILE_NEW | MPQ_FLAG_LISTFILE_FORCE))
{
dwErrCode = SListFileSaveToMpq(ha);
if(dwErrCode != ERROR_SUCCESS)
dwResultError = dwErrCode;
}
if(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_NEW)
{
dwErrCode = SAttrFileSaveToMpq(ha);
if(dwErrCode != ERROR_SUCCESS)
dwResultError = dwErrCode;
}
// Save HET table, BET table, hash table, block table, hi-block table
if(ha->dwFlags & MPQ_FLAG_CHANGED)
{
// Rebuild the HET table
if(ha->pHetTable != NULL)
RebuildHetTable(ha);
// Save all MPQ tables first
dwErrCode = SaveMPQTables(ha);
if(dwErrCode != ERROR_SUCCESS)
dwResultError = dwErrCode;
// If the archive has weak signature, we need to finish it
if(ha->dwFileFlags3 != 0)
{
dwErrCode = SSignFileFinish(ha);
if(dwErrCode != ERROR_SUCCESS)
dwResultError = dwErrCode;
}
}
// We are no longer saving internal MPQ structures
ha->dwFlags &= ~MPQ_FLAG_SAVING_TABLES;
}
// Return the error
if(dwResultError != ERROR_SUCCESS)
SetLastError(dwResultError);
return (dwResultError == ERROR_SUCCESS);
}
//-----------------------------------------------------------------------------
// bool SFileCloseArchive(HANDLE hMpq);
//
bool WINAPI SFileCloseArchive(HANDLE hMpq)
{
TMPQArchive * ha = IsValidMpqHandle(hMpq);
bool bResult = false;
// Only if the handle is valid
if(ha == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Invalidate the add file callback so it won't be called
// when saving (listfile) and (attributes)
ha->pfnAddFileCB = NULL;
ha->pvAddFileUserData = NULL;
// Flush all unsaved data to the storage
bResult = SFileFlushArchive(hMpq);
// Free all memory used by MPQ archive
FreeArchiveHandle(ha);
return bResult;
}

View File

@ -0,0 +1,418 @@
/*****************************************************************************/
/* 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 "StormCommon.h"
/*****************************************************************************/
/* Local functions */
/*****************************************************************************/
static DWORD FindHashIndex(TMPQArchive * ha, DWORD dwFileIndex)
{
TMPQHash * pHashTableEnd;
TMPQHash * pHash;
DWORD dwFirstIndex = HASH_ENTRY_FREE;
// Should only be called if the archive has hash table
assert(ha->pHashTable != NULL);
// Multiple hash table entries can point to the file table entry.
// We need to search all of them
pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++)
{
if(MPQ_BLOCK_INDEX(pHash) == dwFileIndex)
{
// Duplicate hash entry found
if(dwFirstIndex != HASH_ENTRY_FREE)
return HASH_ENTRY_FREE;
dwFirstIndex = (DWORD)(pHash - ha->pHashTable);
}
}
// Return the hash table entry index
return dwFirstIndex;
}
static const char * GetPatchFileName(TMPQArchive * ha, const char * szFileName, char * szBuffer)
{
TMPQNamePrefix * pPrefix;
// Are there patches in the current MPQ?
if(ha->dwFlags & MPQ_FLAG_PATCH)
{
// The patch prefix must be already known here
assert(ha->pPatchPrefix != NULL);
pPrefix = ha->pPatchPrefix;
// The patch name for "OldWorld\\XXX\\YYY" is "Base\\XXX\YYY"
// We need to remove the "OldWorld\\" prefix
if(!_strnicmp(szFileName, "OldWorld\\", 9))
szFileName += 9;
// Create the file name from the known patch entry
memcpy(szBuffer, pPrefix->szPatchPrefix, pPrefix->nLength);
strcpy(szBuffer + pPrefix->nLength, szFileName);
szFileName = szBuffer;
}
return szFileName;
}
static bool OpenLocalFile(const char * szFileName, HANDLE * PtrFile)
{
TFileStream * pStream;
TMPQFile * hf = NULL;
TCHAR szFileNameT[MAX_PATH];
// Convert the file name to UNICODE (if needed)
StringCopy(szFileNameT, _countof(szFileNameT), szFileName);
// Open the file and create the TMPQFile structure
pStream = FileStream_OpenFile(szFileNameT, STREAM_FLAG_READ_ONLY);
if(pStream != NULL)
{
// Allocate and initialize file handle
hf = CreateFileHandle(NULL, NULL);
if(hf != NULL)
{
hf->pStream = pStream;
*PtrFile = hf;
return true;
}
else
{
FileStream_Close(pStream);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
}
*PtrFile = NULL;
return false;
}
bool OpenPatchedFile(HANDLE hMpq, const char * szFileName, HANDLE * PtrFile)
{
TMPQArchive * haBase = NULL;
TMPQArchive * ha = (TMPQArchive *)hMpq;
TFileEntry * pFileEntry;
TMPQFile * hfPatch; // Pointer to patch file
TMPQFile * hfBase = NULL; // Pointer to base open file
TMPQFile * hf = NULL;
HANDLE hPatchFile;
char szNameBuffer[MAX_PATH];
// First of all, find the latest archive where the file is in base version
// (i.e. where the original, unpatched version of the file exists)
while(ha != NULL)
{
// If the file is there, then we remember the archive
pFileEntry = GetFileEntryExact(ha, GetPatchFileName(ha, szFileName, szNameBuffer), 0, NULL);
if(pFileEntry != NULL && (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
haBase = ha;
// Move to the patch archive
ha = ha->haPatch;
}
// If we couldn't find the base file in any of the patches, it doesn't exist
if((ha = haBase) != NULL)
{
// Now open the base file
if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szNameBuffer), SFILE_OPEN_BASE_FILE, (HANDLE *)&hfBase))
{
// The file must be a base file, i.e. without MPQ_FILE_PATCH_FILE
assert((hfBase->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0);
hf = hfBase;
// Now open all patches and attach them on top of the base file
for(ha = ha->haPatch; ha != NULL; ha = ha->haPatch)
{
// Prepare the file name with a correct prefix
if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szNameBuffer), SFILE_OPEN_BASE_FILE, &hPatchFile))
{
// Remember the new version
hfPatch = (TMPQFile *)hPatchFile;
// We should not find patch file
assert((hfPatch->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) != 0);
// Attach the patch to the base file
hf->hfPatch = hfPatch;
hf = hfPatch;
}
}
}
}
else
{
SetLastError(ERROR_FILE_NOT_FOUND);
}
// Give the updated base MPQ
if(PtrFile != NULL)
*PtrFile = (HANDLE)hfBase;
return (hfBase != 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.
DWORD WINAPI SFileEnumLocales(
HANDLE hMpq,
const char * szFileName,
LCID * PtrLocales,
LPDWORD PtrMaxLocales,
DWORD dwSearchScope)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
TMPQHash * pFirstHash;
TMPQHash * pHash;
DWORD dwFileIndex = 0;
DWORD dwMaxLocales;
DWORD dwLocales = 0;
// Test the parameters
if(!IsValidMpqHandle(hMpq))
return ERROR_INVALID_HANDLE;
if(szFileName == NULL || *szFileName == 0)
return ERROR_INVALID_PARAMETER;
if(ha->pHashTable == NULL)
return ERROR_NOT_SUPPORTED;
if(PtrMaxLocales == NULL)
return ERROR_INVALID_PARAMETER;
if(IsPseudoFileName(szFileName, &dwFileIndex))
return ERROR_INVALID_PARAMETER;
// Keep compiler happy
dwMaxLocales = PtrMaxLocales[0];
dwSearchScope = dwSearchScope;
// Parse all files with that name
pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
while(pHash != NULL)
{
// Put the locales to the buffer
if(PtrLocales != NULL && dwLocales < dwMaxLocales)
*PtrLocales++ = pHash->lcLocale;
dwLocales++;
// Get the next locale
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
}
// Give the caller the number of locales and return
PtrMaxLocales[0] = dwLocales;
return (dwLocales <= dwMaxLocales) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
}
//-----------------------------------------------------------------------------
// SFileOpenFileEx
//
// hMpq - Handle of opened MPQ archive
// szFileName - Name of file to open
// dwSearchScope - Where to search
// PtrFile - Pointer to store opened file handle
bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * PtrFile)
{
TMPQArchive * ha = IsValidMpqHandle(hMpq);
TFileEntry * pFileEntry = NULL;
TMPQFile * hf = NULL;
DWORD dwHashIndex = HASH_ENTRY_FREE;
DWORD dwFileIndex = 0;
DWORD dwErrCode = ERROR_SUCCESS;
bool bOpenByIndex = false;
// Don't accept NULL pointer to file handle
if(szFileName == NULL || *szFileName == 0)
dwErrCode = ERROR_INVALID_PARAMETER;
// When opening a file from MPQ, the handle must be valid
if(dwSearchScope != SFILE_OPEN_LOCAL_FILE && ha == NULL)
dwErrCode = ERROR_INVALID_HANDLE;
// When not checking for existence, the pointer to file handle must be valid
if(dwSearchScope != SFILE_OPEN_CHECK_EXISTS && PtrFile == NULL)
dwErrCode = ERROR_INVALID_PARAMETER;
// Prepare the file opening
if(dwErrCode == ERROR_SUCCESS)
{
switch(dwSearchScope)
{
case SFILE_OPEN_FROM_MPQ:
case SFILE_OPEN_BASE_FILE:
case SFILE_OPEN_CHECK_EXISTS:
// If this MPQ has no patches, open the file from this MPQ directly
if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE)
{
pFileEntry = GetFileEntryLocale2(ha, szFileName, g_lcFileLocale, &dwHashIndex);
}
// If this MPQ is a patched archive, open the file as patched
else
{
return OpenPatchedFile(hMpq, szFileName, PtrFile);
}
break;
case SFILE_OPEN_ANY_LOCALE:
// This open option is reserved for opening MPQ internal listfile.
// No argument validation. Tries to open file with neutral locale first,
// then any other available.
pFileEntry = GetFileEntryLocale2(ha, szFileName, 0, &dwHashIndex);
break;
case SFILE_OPEN_LOCAL_FILE:
// Open a local file
return OpenLocalFile(szFileName, PtrFile);
default:
// Don't accept any other value
dwErrCode = ERROR_INVALID_PARAMETER;
break;
}
}
// Check whether the file really exists in the MPQ
if(dwErrCode == ERROR_SUCCESS)
{
// If we didn't find the file, try to open it using pseudo file name ("File
if (pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
{
// Check the pseudo-file name ("File00000001.ext")
if ((bOpenByIndex = IsPseudoFileName(szFileName, &dwFileIndex)) == true)
{
// Get the file entry for the file
if (dwFileIndex < ha->dwFileTableSize)
{
pFileEntry = ha->pFileTable + dwFileIndex;
}
}
// Still not found?
if (pFileEntry == NULL)
{
dwErrCode = ERROR_FILE_NOT_FOUND;
}
}
// Perform some checks of invalid files
if (pFileEntry != NULL)
{
// MPQ protectors use insanely amount of fake files, often with very high size.
// We won't open any files whose compressed size is bigger than archive size
// If the file is not compressed, its size cannot be bigger than archive size
if ((pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) == 0 && (pFileEntry->dwFileSize > ha->FileSize))
{
dwErrCode = ERROR_FILE_CORRUPT;
pFileEntry = NULL;
}
// Ignore unknown loading flags (example: MPQ_2016_v1_WME4_4.w3x)
// if(pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS)
// {
// dwErrCode = ERROR_NOT_SUPPORTED;
// pFileEntry = NULL;
// }
}
}
// Did the caller just wanted to know if the file exists?
if(dwErrCode == ERROR_SUCCESS && dwSearchScope != SFILE_OPEN_CHECK_EXISTS)
{
// Allocate file handle
hf = CreateFileHandle(ha, pFileEntry);
if(hf != NULL)
{
// Get the hash index for the file
if(ha->pHashTable != NULL && dwHashIndex == HASH_ENTRY_FREE)
dwHashIndex = FindHashIndex(ha, dwFileIndex);
if(dwHashIndex != HASH_ENTRY_FREE)
hf->pHashEntry = ha->pHashTable + dwHashIndex;
hf->dwHashIndex = dwHashIndex;
// If the MPQ has sector CRC enabled, enable if for the file
if(ha->dwFlags & MPQ_FLAG_CHECK_SECTOR_CRC)
hf->bCheckSectorCRCs = true;
// If we know the real file name, copy it to the file entry
if(bOpenByIndex == false)
{
// If there is no file name yet, allocate it
AllocateFileName(ha, pFileEntry, szFileName);
// If the file is encrypted, we should detect the file key
if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
{
hf->dwFileKey = DecryptFileKey(szFileName,
pFileEntry->ByteOffset,
pFileEntry->dwFileSize,
pFileEntry->dwFlags);
}
}
}
else
{
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
}
// Give the file entry
if(PtrFile != NULL)
PtrFile[0] = hf;
// Return error code
if(dwErrCode != ERROR_SUCCESS)
SetLastError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}
//-----------------------------------------------------------------------------
// SFileHasFile
//
// hMpq - Handle of opened MPQ archive
// szFileName - Name of file to look for
bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName)
{
return SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_CHECK_EXISTS, NULL);
}
//-----------------------------------------------------------------------------
// bool WINAPI SFileCloseFile(HANDLE hFile);
bool WINAPI SFileCloseFile(HANDLE hFile)
{
TMPQFile * hf = (TMPQFile *)hFile;
if(!IsValidFileHandle(hFile))
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Free the structure
FreeFileHandle(hf);
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,897 @@
/*****************************************************************************/
/* 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 "StormCommon.h"
//-----------------------------------------------------------------------------
// Local functions
// hf - MPQ File handle.
// pbBuffer - Pointer to target buffer to store sectors.
// dwByteOffset - Position of sector in the file (relative to file begin)
// dwBytesToRead - Number of bytes to read. Must be multiplier of sector size.
// pdwBytesRead - Stored number of bytes loaded
static DWORD ReadMpqSectors(TMPQFile * hf, LPBYTE pbBuffer, DWORD dwByteOffset, DWORD dwBytesToRead, LPDWORD pdwBytesRead)
{
ULONGLONG RawFilePos;
TMPQArchive * ha = hf->ha;
TFileEntry * pFileEntry = hf->pFileEntry;
LPBYTE pbRawSector = NULL;
LPBYTE pbOutSector = pbBuffer;
LPBYTE pbInSector = pbBuffer;
DWORD dwRawBytesToRead;
DWORD dwRawSectorOffset = dwByteOffset;
DWORD dwSectorsToRead = dwBytesToRead / ha->dwSectorSize;
DWORD dwSectorIndex = dwByteOffset / ha->dwSectorSize;
DWORD dwSectorsDone = 0;
DWORD dwBytesRead = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Note that dwByteOffset must be aligned to size of one sector
// Note that dwBytesToRead must be a multiplier of one sector size
// This is local function, so we won't check if that's true.
// Note that files stored in single units are processed by a separate function
// If there is not enough bytes remaining, cut dwBytesToRead
if((dwByteOffset + dwBytesToRead) > hf->dwDataSize)
dwBytesToRead = hf->dwDataSize - dwByteOffset;
dwRawBytesToRead = dwBytesToRead;
// Perform all necessary work to do with compressed files
if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK)
{
// If the sector positions are not loaded yet, do it
if(hf->SectorOffsets == NULL)
{
dwErrCode = AllocateSectorOffsets(hf, true);
if(dwErrCode != ERROR_SUCCESS || hf->SectorOffsets == NULL)
return dwErrCode;
}
// If the sector checksums are not loaded yet, load them now.
if(hf->SectorChksums == NULL && (pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) && hf->bLoadedSectorCRCs == false)
{
//
// Sector CRCs is plain crap feature. It is almost never present,
// often it's empty, or the end offset of sector CRCs is zero.
// We only try to load sector CRCs once, and regardless if it fails
// or not, we won't try that again for the given file.
//
AllocateSectorChecksums(hf, true);
hf->bLoadedSectorCRCs = true;
}
// TODO: If the raw data MD5s are not loaded yet, load them now
// Only do it if the MPQ is of format 4.0
// if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_4 && ha->pHeader->dwRawChunkSize != 0)
// {
// dwErrCode = AllocateRawMD5s(hf, true);
// if(dwErrCode != ERROR_SUCCESS)
// return dwErrCode;
// }
// Assign the temporary buffer as target for read operation
dwRawSectorOffset = hf->SectorOffsets[dwSectorIndex];
dwRawBytesToRead = hf->SectorOffsets[dwSectorIndex + dwSectorsToRead] - dwRawSectorOffset;
// If the file is compressed, also allocate secondary buffer
pbInSector = pbRawSector = STORM_ALLOC(BYTE, dwRawBytesToRead);
if(pbRawSector == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
}
// Calculate raw file offset where the sector(s) are stored.
RawFilePos = CalculateRawSectorOffset(hf, dwRawSectorOffset);
// Set file pointer and read all required sectors
if(FileStream_Read(ha->pStream, &RawFilePos, pbInSector, dwRawBytesToRead))
{
// Now we have to decrypt and decompress all file sectors that have been loaded
for(DWORD i = 0; i < dwSectorsToRead; i++)
{
DWORD dwRawBytesInThisSector = ha->dwSectorSize;
DWORD dwBytesInThisSector = ha->dwSectorSize;
DWORD dwIndex = dwSectorIndex + i;
// If there is not enough bytes in the last sector,
// cut the number of bytes in this sector
if(dwRawBytesInThisSector > dwBytesToRead)
dwRawBytesInThisSector = dwBytesToRead;
if(dwBytesInThisSector > dwBytesToRead)
dwBytesInThisSector = dwBytesToRead;
// If the file is compressed, we have to adjust the raw sector size
if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK)
dwRawBytesInThisSector = hf->SectorOffsets[dwIndex + 1] - hf->SectorOffsets[dwIndex];
// If the file is encrypted, we have to decrypt the sector
if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
{
BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector);
// If we don't know the key, try to detect it by file content
if(hf->dwFileKey == 0)
{
hf->dwFileKey = DetectFileKeyByContent(pbInSector, dwBytesInThisSector, hf->dwDataSize);
if(hf->dwFileKey == 0)
{
dwErrCode = ERROR_UNKNOWN_FILE_KEY;
break;
}
}
DecryptMpqBlock(pbInSector, dwRawBytesInThisSector, hf->dwFileKey + dwIndex);
BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector);
}
// If the file has sector CRC check turned on, perform it
if(hf->bCheckSectorCRCs && hf->SectorChksums != NULL)
{
DWORD dwAdlerExpected = hf->SectorChksums[dwIndex];
DWORD dwAdlerValue = 0;
// We can only check sector CRC when it's not zero
// Neither can we check it if it's 0xFFFFFFFF.
if(dwAdlerExpected != 0 && dwAdlerExpected != 0xFFFFFFFF)
{
dwAdlerValue = adler32(0, pbInSector, dwRawBytesInThisSector);
if(dwAdlerValue != dwAdlerExpected)
{
dwErrCode = ERROR_CHECKSUM_ERROR;
break;
}
}
}
// If the sector is really compressed, decompress it.
// WARNING : Some sectors may not be compressed, it can be determined only
// by comparing uncompressed and compressed size !!!
if(dwRawBytesInThisSector < dwBytesInThisSector)
{
int cbOutSector = dwBytesInThisSector;
int cbInSector = dwRawBytesInThisSector;
int nResult = 0;
// Is the file compressed by Blizzard's multiple compression ?
if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS)
{
// Remember the last used compression
hf->dwCompression0 = pbInSector[0];
// Decompress the data
if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2)
nResult = SCompDecompress2(pbOutSector, &cbOutSector, pbInSector, cbInSector);
else
nResult = SCompDecompress(pbOutSector, &cbOutSector, pbInSector, cbInSector);
}
// Is the file compressed by PKWARE Data Compression Library ?
else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE)
{
nResult = SCompExplode(pbOutSector, &cbOutSector, pbInSector, cbInSector);
}
// Did the decompression fail ?
if(nResult == 0)
{
dwErrCode = ERROR_FILE_CORRUPT;
break;
}
}
else
{
if(pbOutSector != pbInSector)
memcpy(pbOutSector, pbInSector, dwBytesInThisSector);
}
// Move pointers
dwBytesToRead -= dwBytesInThisSector;
dwByteOffset += dwBytesInThisSector;
dwBytesRead += dwBytesInThisSector;
pbOutSector += dwBytesInThisSector;
pbInSector += dwRawBytesInThisSector;
dwSectorsDone++;
}
}
else
{
dwErrCode = GetLastError();
}
// Free all used buffers
if(pbRawSector != NULL)
STORM_FREE(pbRawSector);
// Give the caller thenumber of bytes read
*pdwBytesRead = dwBytesRead;
return dwErrCode;
}
static DWORD ReadMpqFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead)
{
ULONGLONG RawFilePos = hf->RawFilePos;
TMPQArchive * ha = hf->ha;
TFileEntry * pFileEntry = hf->pFileEntry;
LPBYTE pbCompressed = NULL;
LPBYTE pbRawData;
DWORD dwErrCode = ERROR_SUCCESS;
// If the file buffer is not allocated yet, do it.
if(hf->pbFileSector == NULL)
{
dwErrCode = AllocateSectorBuffer(hf);
if(dwErrCode != ERROR_SUCCESS || hf->pbFileSector == NULL)
return dwErrCode;
}
// If the file is a patch file, adjust raw data offset
if(hf->pPatchInfo != NULL)
RawFilePos += hf->pPatchInfo->dwLength;
pbRawData = hf->pbFileSector;
// If the file sector is not loaded yet, do it
if(hf->dwSectorOffs != 0)
{
// Is the file compressed?
if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK)
{
// Allocate space for compressed data
pbCompressed = STORM_ALLOC(BYTE, pFileEntry->dwCmpSize);
if(pbCompressed == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
pbRawData = pbCompressed;
}
// Load the raw (compressed, encrypted) data
if(!FileStream_Read(ha->pStream, &RawFilePos, pbRawData, pFileEntry->dwCmpSize))
{
STORM_FREE(pbCompressed);
return GetLastError();
}
// If the file is encrypted, we have to decrypt the data first
if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
{
BSWAP_ARRAY32_UNSIGNED(pbRawData, pFileEntry->dwCmpSize);
DecryptMpqBlock(pbRawData, pFileEntry->dwCmpSize, hf->dwFileKey);
BSWAP_ARRAY32_UNSIGNED(pbRawData, pFileEntry->dwCmpSize);
}
// If the file is compressed, we have to decompress it now
if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK)
{
int cbOutBuffer = (int)hf->dwDataSize;
int cbInBuffer = (int)pFileEntry->dwCmpSize;
int nResult = 0;
//
// If the file is an incremental patch, the size of compressed data
// is determined as pFileEntry->dwCmpSize - sizeof(TPatchInfo)
//
// In "wow-update-12694.MPQ" from Wow-Cataclysm BETA:
//
// File CmprSize DcmpSize DataSize Compressed?
// -------------------------------------- ---------- -------- -------- ---------------
// esES\DBFilesClient\LightSkyBox.dbc 0xBE->0xA2 0xBC 0xBC Yes
// deDE\DBFilesClient\MountCapability.dbc 0x93->0x77 0x77 0x77 No
//
if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
cbInBuffer = cbInBuffer - sizeof(TPatchInfo);
// Is the file compressed by Blizzard's multiple compression ?
if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS)
{
// Remember the last used compression
hf->dwCompression0 = pbRawData[0];
// Decompress the file
if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2)
nResult = SCompDecompress2(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer);
else
nResult = SCompDecompress(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer);
}
// Is the file compressed by PKWARE Data Compression Library ?
// Note: Single unit files compressed with IMPLODE are not supported by Blizzard
else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE)
nResult = SCompExplode(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer);
dwErrCode = (nResult != 0) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
}
else
{
if(hf->pbFileSector != NULL && pbRawData != hf->pbFileSector)
memcpy(hf->pbFileSector, pbRawData, hf->dwDataSize);
}
// Free the decompression buffer.
if(pbCompressed != NULL)
STORM_FREE(pbCompressed);
// The file sector is now properly loaded
hf->dwSectorOffs = 0;
}
// At this moment, we have the file loaded into the file buffer.
// Copy as much as the caller wants
if(dwErrCode == ERROR_SUCCESS && hf->dwSectorOffs == 0)
{
// File position is greater or equal to file size ?
if(dwFilePos >= hf->dwDataSize)
{
*pdwBytesRead = 0;
return ERROR_SUCCESS;
}
// If not enough bytes remaining in the file, cut them
if((hf->dwDataSize - dwFilePos) < dwToRead)
dwToRead = (hf->dwDataSize - dwFilePos);
// Copy the bytes
memcpy(pvBuffer, hf->pbFileSector + dwFilePos, dwToRead);
// Give the number of bytes read
*pdwBytesRead = dwToRead;
}
// An error, sorry
return dwErrCode;
}
static DWORD ReadMpkFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead)
{
ULONGLONG RawFilePos = hf->RawFilePos + 0x0C; // For some reason, MPK files start at position (hf->RawFilePos + 0x0C)
TMPQArchive * ha = hf->ha;
TFileEntry * pFileEntry = hf->pFileEntry;
LPBYTE pbCompressed = NULL;
LPBYTE pbRawData = hf->pbFileSector;
DWORD dwErrCode = ERROR_SUCCESS;
// We do not support patch files in MPK archives
assert(hf->pPatchInfo == NULL);
// If the file buffer is not allocated yet, do it.
if(hf->pbFileSector == NULL)
{
dwErrCode = AllocateSectorBuffer(hf);
if(dwErrCode != ERROR_SUCCESS || hf->pbFileSector == NULL)
return dwErrCode;
pbRawData = hf->pbFileSector;
}
// If the file sector is not loaded yet, do it
if(hf->dwSectorOffs != 0)
{
// Is the file compressed?
if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK)
{
// Allocate space for compressed data
pbCompressed = STORM_ALLOC(BYTE, pFileEntry->dwCmpSize);
if(pbCompressed == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
pbRawData = pbCompressed;
}
// Load the raw (compressed, encrypted) data
if(!FileStream_Read(ha->pStream, &RawFilePos, pbRawData, pFileEntry->dwCmpSize))
{
STORM_FREE(pbCompressed);
return GetLastError();
}
// If the file is encrypted, we have to decrypt the data first
if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
{
DecryptMpkTable(pbRawData, pFileEntry->dwCmpSize);
}
// If the file is compressed, we have to decompress it now
if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK)
{
int cbOutBuffer = (int)hf->dwDataSize;
hf->dwCompression0 = pbRawData[0];
if(!SCompDecompressMpk(hf->pbFileSector, &cbOutBuffer, pbRawData, (int)pFileEntry->dwCmpSize))
dwErrCode = ERROR_FILE_CORRUPT;
}
else
{
if(pbRawData != hf->pbFileSector)
memcpy(hf->pbFileSector, pbRawData, hf->dwDataSize);
}
// Free the decompression buffer.
if(pbCompressed != NULL)
STORM_FREE(pbCompressed);
// The file sector is now properly loaded
hf->dwSectorOffs = 0;
}
// At this moment, we have the file loaded into the file buffer.
// Copy as much as the caller wants
if(dwErrCode == ERROR_SUCCESS && hf->dwSectorOffs == 0)
{
// File position is greater or equal to file size ?
if(dwFilePos >= hf->dwDataSize)
{
*pdwBytesRead = 0;
return ERROR_SUCCESS;
}
// If not enough bytes remaining in the file, cut them
if((hf->dwDataSize - dwFilePos) < dwToRead)
dwToRead = (hf->dwDataSize - dwFilePos);
// Copy the bytes
memcpy(pvBuffer, hf->pbFileSector + dwFilePos, dwToRead);
// Give the number of bytes read
*pdwBytesRead = dwToRead;
return ERROR_SUCCESS;
}
// An error, sorry
return ERROR_CAN_NOT_COMPLETE;
}
static DWORD ReadMpqFileSectorFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwBytesToRead, LPDWORD pdwBytesRead)
{
TMPQArchive * ha = hf->ha;
LPBYTE pbBuffer = (BYTE *)pvBuffer;
DWORD dwTotalBytesRead = 0; // Total bytes read in all three parts
DWORD dwSectorSizeMask = ha->dwSectorSize - 1; // Mask for block size, usually 0x0FFF
DWORD dwFileSectorPos; // File offset of the loaded sector
DWORD dwBytesRead; // Number of bytes read (temporary variable)
DWORD dwErrCode;
// If the file position is at or beyond end of file, do nothing
if(dwFilePos >= hf->dwDataSize)
{
*pdwBytesRead = 0;
return ERROR_SUCCESS;
}
// If not enough bytes in the file remaining, cut them
if(dwBytesToRead > (hf->dwDataSize - dwFilePos))
dwBytesToRead = (hf->dwDataSize - dwFilePos);
// Compute sector position in the file
dwFileSectorPos = dwFilePos & ~dwSectorSizeMask; // Position in the block
// If the file sector buffer is not allocated yet, do it now
if(hf->pbFileSector == NULL)
{
dwErrCode = AllocateSectorBuffer(hf);
if(dwErrCode != ERROR_SUCCESS || hf->pbFileSector == NULL)
return dwErrCode;
}
// Load the first (incomplete) file sector
if(dwFilePos & dwSectorSizeMask)
{
DWORD dwBytesInSector = ha->dwSectorSize;
DWORD dwBufferOffs = dwFilePos & dwSectorSizeMask;
DWORD dwToCopy;
// Is the file sector already loaded ?
if(hf->dwSectorOffs != dwFileSectorPos)
{
// Load one MPQ sector into archive buffer
dwErrCode = ReadMpqSectors(hf, hf->pbFileSector, dwFileSectorPos, ha->dwSectorSize, &dwBytesInSector);
if(dwErrCode != ERROR_SUCCESS)
return dwErrCode;
// Remember that the data loaded to the sector have new file offset
hf->dwSectorOffs = dwFileSectorPos;
}
else
{
if((dwFileSectorPos + dwBytesInSector) > hf->dwDataSize)
dwBytesInSector = hf->dwDataSize - dwFileSectorPos;
}
// Copy the data from the offset in the loaded sector to the end of the sector
dwToCopy = dwBytesInSector - dwBufferOffs;
if(dwToCopy > dwBytesToRead)
dwToCopy = dwBytesToRead;
// Copy data from sector buffer into target buffer
memcpy(pbBuffer, hf->pbFileSector + dwBufferOffs, dwToCopy);
// Update pointers and byte counts
dwTotalBytesRead += dwToCopy;
dwFileSectorPos += dwBytesInSector;
pbBuffer += dwToCopy;
dwBytesToRead -= dwToCopy;
}
// Load the whole ("middle") sectors only if there is at least one full sector to be read
if(dwBytesToRead >= ha->dwSectorSize)
{
DWORD dwBlockBytes = dwBytesToRead & ~dwSectorSizeMask;
// Load all sectors to the output buffer
dwErrCode = ReadMpqSectors(hf, pbBuffer, dwFileSectorPos, dwBlockBytes, &dwBytesRead);
if(dwErrCode != ERROR_SUCCESS)
return dwErrCode;
// Update pointers
dwTotalBytesRead += dwBytesRead;
dwFileSectorPos += dwBytesRead;
pbBuffer += dwBytesRead;
dwBytesToRead -= dwBytesRead;
}
// Read the terminating sector
if(dwBytesToRead > 0)
{
DWORD dwToCopy = ha->dwSectorSize;
// Is the file sector already loaded ?
if(hf->dwSectorOffs != dwFileSectorPos)
{
// Load one MPQ sector into archive buffer
dwErrCode = ReadMpqSectors(hf, hf->pbFileSector, dwFileSectorPos, ha->dwSectorSize, &dwBytesRead);
if(dwErrCode != ERROR_SUCCESS)
return dwErrCode;
// Remember that the data loaded to the sector have new file offset
hf->dwSectorOffs = dwFileSectorPos;
}
// Check number of bytes read
if(dwToCopy > dwBytesToRead)
dwToCopy = dwBytesToRead;
// Copy the data from the cached last sector to the caller's buffer
memcpy(pbBuffer, hf->pbFileSector, dwToCopy);
// Update pointers
dwTotalBytesRead += dwToCopy;
}
// Store total number of bytes read to the caller
*pdwBytesRead = dwTotalBytesRead;
return ERROR_SUCCESS;
}
static DWORD ReadMpqFilePatchFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead)
{
TMPQPatcher Patcher;
DWORD dwBytesToRead = dwToRead;
DWORD dwBytesRead = 0;
DWORD dwErrCode = ERROR_SUCCESS;
// Make sure that the patch file is loaded completely
if(dwErrCode == ERROR_SUCCESS && hf->pbFileData == NULL)
{
// Initialize patching process and allocate data
dwErrCode = Patch_InitPatcher(&Patcher, hf);
if(dwErrCode != ERROR_SUCCESS)
return dwErrCode;
// Set the current data size
Patcher.cbFileData = hf->pFileEntry->dwFileSize;
// Initialize the patcher object with initial file data
if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT)
dwErrCode = ReadMpqFileSingleUnit(hf, Patcher.pbFileData1, 0, Patcher.cbFileData, &dwBytesRead);
else
dwErrCode = ReadMpqFileSectorFile(hf, Patcher.pbFileData1, 0, Patcher.cbFileData, &dwBytesRead);
// Perform the patching process
if(dwErrCode == ERROR_SUCCESS)
dwErrCode = Patch_Process(&Patcher, hf);
// Finalize the patcher structure
Patch_Finalize(&Patcher);
dwBytesRead = 0;
}
// If there is something to read, do it
if(dwErrCode == ERROR_SUCCESS)
{
if(dwFilePos < hf->cbFileData)
{
// Make sure we don't copy more than file size
if((dwFilePos + dwToRead) > hf->cbFileData)
dwToRead = hf->cbFileData - dwFilePos;
// Copy the appropriate amount of the file data to the caller's buffer
memcpy(pvBuffer, hf->pbFileData + dwFilePos, dwToRead);
dwBytesRead = dwToRead;
}
// Set the proper error code
dwErrCode = (dwBytesRead == dwBytesToRead) ? ERROR_SUCCESS : ERROR_HANDLE_EOF;
}
// Give the result to the caller
if(pdwBytesRead != NULL)
*pdwBytesRead = dwBytesRead;
return dwErrCode;
}
static DWORD ReadMpqFileLocalFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead)
{
ULONGLONG FilePosition1 = dwFilePos;
ULONGLONG FilePosition2;
DWORD dwBytesRead = 0;
DWORD dwErrCode = ERROR_SUCCESS;
assert(hf->pStream != NULL);
// Because stream I/O functions are designed to read
// "all or nothing", we compare file position before and after,
// and if they differ, we assume that number of bytes read
// is the difference between them
if(!FileStream_Read(hf->pStream, &FilePosition1, pvBuffer, dwToRead))
{
// If not all bytes have been read, then return the number of bytes read
if((dwErrCode = GetLastError()) == ERROR_HANDLE_EOF)
{
FileStream_GetPos(hf->pStream, &FilePosition2);
dwBytesRead = (DWORD)(FilePosition2 - FilePosition1);
}
}
else
{
dwBytesRead = dwToRead;
}
*pdwBytesRead = dwBytesRead;
return dwErrCode;
}
//-----------------------------------------------------------------------------
// SFileReadFile
bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped)
{
TMPQFile * hf = (TMPQFile *)hFile;
DWORD dwBytesRead = 0; // Number of bytes read
DWORD dwErrCode = ERROR_SUCCESS;
// Always zero the result
if(pdwRead != NULL)
*pdwRead = 0;
lpOverlapped = lpOverlapped;
// Check valid parameters
if(!IsValidFileHandle(hFile))
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
if(pvBuffer == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// If we didn't load the patch info yet, do it now
if(hf->pFileEntry != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) && hf->pPatchInfo == NULL)
{
dwErrCode = AllocatePatchInfo(hf, true);
if(dwErrCode != ERROR_SUCCESS || hf->pPatchInfo == NULL)
{
SetLastError(dwErrCode);
return false;
}
}
// Clear the last used compression
hf->dwCompression0 = 0;
// If the file is local file, read the data directly from the stream
if(hf->pStream != NULL)
{
dwErrCode = ReadMpqFileLocalFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);
}
// If the file is a patch file, we have to read it special way
else if(hf->hfPatch != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
{
dwErrCode = ReadMpqFilePatchFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);
}
// If the archive is a MPK archive, we need special way to read the file
else if(hf->ha->dwSubType == MPQ_SUBTYPE_MPK)
{
dwErrCode = ReadMpkFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);
}
// If the file is single unit file, redirect it to read file
else if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT)
{
dwErrCode = ReadMpqFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);
}
// Otherwise read it as sector based MPQ file
else
{
dwErrCode = ReadMpqFileSectorFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);
}
// Increment the file position
hf->dwFilePos += dwBytesRead;
// Give the caller the number of bytes read
if(pdwRead != NULL)
*pdwRead = dwBytesRead;
// If the read operation succeeded, but not full number of bytes was read,
// set the last error to ERROR_HANDLE_EOF
if(dwErrCode == ERROR_SUCCESS && (dwBytesRead < dwToRead))
dwErrCode = ERROR_HANDLE_EOF;
// If something failed, set the last error value
if(dwErrCode != ERROR_SUCCESS)
SetLastError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}
//-----------------------------------------------------------------------------
// SFileGetFileSize
DWORD WINAPI SFileGetFileSize(HANDLE hFile, LPDWORD pdwFileSizeHigh)
{
ULONGLONG FileSize;
TMPQFile * hf = (TMPQFile *)hFile;
// Validate the file handle before we go on
if(IsValidFileHandle(hFile))
{
// Make sure that the variable is initialized
FileSize = 0;
// If the file is patched file, we have to get the size of the last version
if(hf->hfPatch != NULL)
{
// Walk through the entire patch chain, take the last version
while(hf != NULL)
{
// Get the size of the currently pointed version
FileSize = hf->pFileEntry->dwFileSize;
// Move to the next patch file in the hierarchy
hf = hf->hfPatch;
}
}
else
{
// Is it a local file ?
if(hf->pStream != NULL)
{
FileStream_GetSize(hf->pStream, &FileSize);
}
else
{
FileSize = hf->dwDataSize;
}
}
// If opened from archive, return file size
if(pdwFileSizeHigh != NULL)
*pdwFileSizeHigh = (DWORD)(FileSize >> 32);
return (DWORD)FileSize;
}
SetLastError(ERROR_INVALID_HANDLE);
return SFILE_INVALID_SIZE;
}
DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod)
{
TMPQFile * hf = (TMPQFile *)hFile;
ULONGLONG OldPosition;
ULONGLONG NewPosition;
ULONGLONG FileSize;
ULONGLONG DeltaPos;
// If the hFile is not a valid file handle, return an error.
if(!IsValidFileHandle(hFile))
{
SetLastError(ERROR_INVALID_HANDLE);
return SFILE_INVALID_POS;
}
// Retrieve the file size for handling the limits
if(hf->pStream != NULL)
{
FileStream_GetSize(hf->pStream, &FileSize);
}
else
{
FileSize = SFileGetFileSize(hFile, NULL);
}
// Handle the NULL and non-NULL values of plFilePosHigh
// Non-NULL: The DeltaPos is combined from lFilePos and *lpFilePosHigh
// NULL: The DeltaPos is sign-extended value of lFilePos
DeltaPos = (plFilePosHigh != NULL) ? MAKE_OFFSET64(plFilePosHigh[0], lFilePos) : (ULONGLONG)(LONGLONG)lFilePos;
// Get the relative point where to move from
switch(dwMoveMethod)
{
case FILE_BEGIN:
// Move relative to the file begin.
OldPosition = 0;
break;
case FILE_CURRENT:
// Retrieve the current file position
if(hf->pStream != NULL)
{
FileStream_GetPos(hf->pStream, &OldPosition);
}
else
{
OldPosition = hf->dwFilePos;
}
break;
case FILE_END:
// Move relative to the end of the file
OldPosition = FileSize;
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return SFILE_INVALID_POS;
}
// Calculate the new position
NewPosition = OldPosition + DeltaPos;
// If moving backward, don't allow the new position go negative
if((LONGLONG)DeltaPos < 0)
{
if(NewPosition > FileSize) // Position is negative
{
SetLastError(ERROR_NEGATIVE_SEEK);
return SFILE_INVALID_POS;
}
}
// If moving forward, don't allow the new position go past the end of the file
else
{
if(NewPosition > FileSize)
NewPosition = FileSize;
}
// Now apply the file pointer to the file
if(hf->pStream != NULL)
{
if(!FileStream_Read(hf->pStream, &NewPosition, NULL, 0))
return SFILE_INVALID_POS;
}
// Also, store the new file position to the TMPQFile struct
hf->dwFilePos = (DWORD)NewPosition;
// Return the new file position
if(plFilePosHigh != NULL)
*plFilePosHigh = (LONG)(NewPosition >> 32);
return (DWORD)NewPosition;
}

1054
StormLib/src/SFileVerify.cpp Normal file

File diff suppressed because it is too large Load Diff

441
StormLib/src/StormCommon.h Normal file
View File

@ -0,0 +1,441 @@
/*****************************************************************************/
/* 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 */
/* 06.09.10 1.00 Lad Renamed to StormCommon.h */
/*****************************************************************************/
#ifndef __STORMCOMMON_H__
#define __STORMCOMMON_H__
//-----------------------------------------------------------------------------
// Compression support
// Include functions from Pkware Data Compression Library
#include "pklib/pklib.h"
// Include functions from Huffmann compression
#include "huffman/huff.h"
// Include functions from IMA ADPCM compression
#include "adpcm/adpcm.h"
// Include functions from SPARSE compression
#include "sparse/sparse.h"
// Include functions from LZMA compression
#include "lzma/C/LzmaEnc.h"
#include "lzma/C/LzmaDec.h"
// Include functions from zlib
#ifndef __SYS_ZLIB
#include "zlib/zlib.h"
#else
#include <zlib.h>
#endif
// Include functions from bzlib
#ifndef __SYS_BZLIB
#include "bzip2/bzlib.h"
#else
#include <bzlib.h>
#endif
//-----------------------------------------------------------------------------
// Cryptography support
// Headers from LibTomCrypt
#include "libtomcrypt/src/headers/tomcrypt.h"
// For HashStringJenkins
#include "jenkins/lookup.h"
//-----------------------------------------------------------------------------
// StormLib private defines
#define ID_MPQ_FILE 0x46494c45 // Used internally for checking TMPQFile ('FILE')
// Prevent problems with CRT "min" and "max" functions,
// as they are not defined on all platforms
#define STORMLIB_MIN(a, b) ((a < b) ? a : b)
#define STORMLIB_MAX(a, b) ((a > b) ? a : b)
#define STORMLIB_UNUSED(p) ((void)(p))
// Checks for data pointers aligned to 4-byte boundary
#define STORMLIB_DWORD_ALIGNED(ptr) (((size_t)(ptr) & 0x03) == 0)
// Macro for building 64-bit file offset from two 32-bit
#define MAKE_OFFSET64(hi, lo) (((ULONGLONG)hi << 32) | (ULONGLONG)lo)
//-----------------------------------------------------------------------------
// MTYPE definition - specifies what kind of MPQ is the map type
typedef enum _MTYPE
{
MapTypeNotChecked, // The map type was not checked yet
MapTypeNotRecognized, // The file does not seems to be a map
MapTypeAviFile, // The file is actually an AVI file (Warcraft III cinematics)
MapTypeWarcraft3, // The file is a Warcraft III map
MapTypeStarcraft2 // The file is a Starcraft II map
} MTYPE, *PMTYPE;
//-----------------------------------------------------------------------------
// MPQ signature information
// Size of each signature type
#define MPQ_WEAK_SIGNATURE_SIZE 64
#define MPQ_STRONG_SIGNATURE_SIZE 256
#define MPQ_STRONG_SIGNATURE_ID 0x5349474E // ID of the strong signature ("NGIS")
#define MPQ_SIGNATURE_FILE_SIZE (MPQ_WEAK_SIGNATURE_SIZE + 8)
// MPQ signature info
typedef struct _MPQ_SIGNATURE_INFO
{
ULONGLONG BeginMpqData; // File offset where the hashing starts
ULONGLONG BeginExclude; // Begin of the excluded area (used for (signature) file)
ULONGLONG EndExclude; // End of the excluded area (used for (signature) file)
ULONGLONG EndMpqData; // File offset where the hashing ends
ULONGLONG EndOfFile; // Size of the entire file
BYTE Signature[MPQ_STRONG_SIGNATURE_SIZE + 0x10];
DWORD cbSignatureSize; // Length of the signature
DWORD SignatureTypes; // See SIGNATURE_TYPE_XXX
} MPQ_SIGNATURE_INFO, *PMPQ_SIGNATURE_INFO;
//-----------------------------------------------------------------------------
// 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)
// - The allocating function does not need to fill the allocated buffer with zeros
// - Memory freeing function doesn't have to test the pointer to NULL
//
//#if defined(_MSC_VER) && defined(_DEBUG)
//
//#define STORM_ALLOC(type, nitems) (type *)HeapAlloc(GetProcessHeap(), 0, ((nitems) * sizeof(type)))
//#define STORM_REALLOC(type, ptr, nitems) (type *)HeapReAlloc(GetProcessHeap(), 0, ptr, ((nitems) * sizeof(type)))
//#define STORM_FREE(ptr) HeapFree(GetProcessHeap(), 0, ptr)
//
//#else
#define STORM_ALLOC(type, nitems) (type *)malloc((nitems) * sizeof(type))
#define STORM_REALLOC(type, ptr, nitems) (type *)realloc(ptr, ((nitems) * sizeof(type)))
#define STORM_FREE(ptr) free(ptr)
//#endif
//-----------------------------------------------------------------------------
// StormLib internal global variables
extern DWORD g_dwMpqSignature; // Marker for MPQ header
extern DWORD g_dwHashTableKey; // Key for hash table
extern DWORD g_dwBlockTableKey; // Key for block table
extern LCID g_lcFileLocale; // Preferred file locale
//-----------------------------------------------------------------------------
// Conversion to uppercase/lowercase (and "/" to "\")
extern unsigned char AsciiToLowerTable[256];
extern unsigned char AsciiToUpperTable[256];
//-----------------------------------------------------------------------------
// Safe string functions
template <typename XCHAR, typename XINT>
XCHAR * IntToString(XCHAR * szBuffer, size_t cchMaxChars, XINT nValue, size_t nDigitCount = 0)
{
XCHAR * szBufferEnd = szBuffer + cchMaxChars - 1;
XCHAR szNumberRev[0x20];
size_t nLength = 0;
// Always put the first digit
szNumberRev[nLength++] = (XCHAR)(nValue % 10) + '0';
nValue /= 10;
// Continue as long as we have non-zero
while(nValue != 0)
{
szNumberRev[nLength++] = (XCHAR)(nValue % 10) + '0';
nValue /= 10;
}
// Fill zeros, if needed
while(szBuffer < szBufferEnd && nLength < nDigitCount)
{
*szBuffer++ = '0';
nDigitCount--;
}
// Fill the buffer
while(szBuffer < szBufferEnd && nLength > 0)
{
nLength--;
*szBuffer++ = szNumberRev[nLength];
}
// Terminate the number with zeros
szBuffer[0] = 0;
return szBuffer;
}
char * StringCopy(char * szTarget, size_t cchTarget, const char * szSource);
void StringCat(char * szTarget, size_t cchTargetMax, const char * szSource);
void StringCreatePseudoFileName(char * szBuffer, size_t cchMaxChars, unsigned int nIndex, const char * szExtension);
#ifdef _UNICODE
void StringCopy(TCHAR * szTarget, size_t cchTarget, const char * szSource);
void StringCopy(char * szTarget, size_t cchTarget, const TCHAR * szSource);
void StringCopy(TCHAR * szTarget, size_t cchTarget, const TCHAR * szSource);
void StringCat(TCHAR * szTarget, size_t cchTargetMax, const TCHAR * szSource);
#endif
//-----------------------------------------------------------------------------
// Encryption and decryption functions
#define MPQ_HASH_TABLE_INDEX 0x000
#define MPQ_HASH_NAME_A 0x100
#define MPQ_HASH_NAME_B 0x200
#define MPQ_HASH_FILE_KEY 0x300
#define MPQ_HASH_KEY2_MIX 0x400
DWORD HashString(const char * szFileName, DWORD dwHashType);
DWORD HashStringSlash(const char* szFileName, DWORD dwHashType);
DWORD HashStringSlash2(const char * szFileName, DWORD dwHashType);
DWORD HashStringLower(const char * szFileName, DWORD dwHashType);
void InitializeMpqCryptography();
DWORD GetNearestPowerOfTwo(DWORD dwFileCount);
bool IsPseudoFileName(const char * szFileName, LPDWORD pdwFileIndex);
ULONGLONG HashStringJenkins(const char * szFileName);
DWORD GetDefaultSpecialFileFlags(DWORD dwFileSize, USHORT wFormatVersion);
void EncryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey);
void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey);
DWORD DetectFileKeyBySectorSize(LPDWORD EncryptedData, DWORD dwSectorSize, DWORD dwSectorOffsLen);
DWORD DetectFileKeyByContent(void * pvEncryptedData, DWORD dwSectorSize, DWORD dwFileSize);
DWORD DecryptFileKey(const char * szFileName, ULONGLONG MpqPos, DWORD dwFileSize, DWORD dwFlags);
bool IsValidMD5(LPBYTE pbMd5);
bool IsValidSignature(LPBYTE pbSignature);
bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5);
void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash);
//-----------------------------------------------------------------------------
// Handle validation functions
TMPQArchive * IsValidMpqHandle(HANDLE hMpq);
TMPQFile * IsValidFileHandle(HANDLE hFile);
//-----------------------------------------------------------------------------
// Support for MPQ file tables
ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset);
ULONGLONG CalculateRawSectorOffset(TMPQFile * hf, DWORD dwSectorOffset);
DWORD ConvertMpqHeaderToFormat4(TMPQArchive * ha, ULONGLONG MpqOffset, ULONGLONG FileSize, DWORD dwFlags, MTYPE MapType);
bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash);
TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1, DWORD dwName2, LCID lcLocale);
TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName);
TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash * pPrevHash);
TMPQHash * AllocateHashEntry(TMPQArchive * ha, TFileEntry * pFileEntry, LCID lcLocale);
TMPQExtHeader * LoadExtTable(TMPQArchive * ha, ULONGLONG ByteOffset, size_t Size, DWORD dwSignature, DWORD dwKey);
TMPQHetTable * LoadHetTable(TMPQArchive * ha);
TMPQBetTable * LoadBetTable(TMPQArchive * ha);
TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool bDontFixEntries = false);
TMPQBlock * TranslateBlockTable(TMPQArchive * ha, ULONGLONG * pcbTableSize, bool * pbNeedHiBlockTable);
ULONGLONG FindFreeMpqSpace(TMPQArchive * ha);
// Functions that load the HET and BET tables
DWORD CreateHashTable(TMPQArchive * ha, DWORD dwHashTableSize);
DWORD LoadAnyHashTable(TMPQArchive * ha);
DWORD BuildFileTable(TMPQArchive * ha);
DWORD DefragmentFileTable(TMPQArchive * ha);
DWORD CreateFileTable(TMPQArchive * ha, DWORD dwFileTableSize);
DWORD RebuildHetTable(TMPQArchive * ha);
DWORD RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize);
DWORD SaveMPQTables(TMPQArchive * ha);
TMPQHetTable * CreateHetTable(DWORD dwEntryCount, DWORD dwTotalCount, DWORD dwHashBitSize, LPBYTE pbSrcData);
void FreeHetTable(TMPQHetTable * pHetTable);
TMPQBetTable * CreateBetTable(DWORD dwMaxFileCount);
void FreeBetTable(TMPQBetTable * pBetTable);
// Functions for finding files in the file table
TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex);
TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale);
TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex);
// Allocates file name in the file entry
void AllocateFileName(TMPQArchive * ha, TFileEntry * pFileEntry, const char * szFileName);
// Allocates new file entry in the MPQ tables. Reuses existing, if possible
TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex);
DWORD RenameFileEntry(TMPQArchive * ha, TMPQFile * hf, const char * szNewFileName);
DWORD DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf);
// Invalidates entries for (listfile) and (attributes)
void InvalidateInternalFiles(TMPQArchive * ha);
// Retrieves information about the strong signature
bool QueryMpqSignatureInfo(TMPQArchive * ha, PMPQ_SIGNATURE_INFO pSignatureInfo);
//-----------------------------------------------------------------------------
// Support for alternate file formats (SBaseSubTypes.cpp)
DWORD ConvertSqpHeaderToFormat4(TMPQArchive * ha, ULONGLONG FileSize, DWORD dwFlags);
TMPQHash * LoadSqpHashTable(TMPQArchive * ha);
TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha);
DWORD ConvertMpkHeaderToFormat4(TMPQArchive * ha, ULONGLONG FileSize, DWORD dwFlags);
void DecryptMpkTable(void * pvMpkTable, size_t cbSize);
TMPQHash * LoadMpkHashTable(TMPQArchive * ha);
TMPQBlock * LoadMpkBlockTable(TMPQArchive * ha);
int SCompDecompressMpk(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer);
//-----------------------------------------------------------------------------
// Common functions - MPQ File
TMPQFile * CreateFileHandle(TMPQArchive * ha, TFileEntry * pFileEntry);
TMPQFile * CreateWritableHandle(TMPQArchive * ha, DWORD dwFileSize);
void * LoadMpqTable(TMPQArchive * ha, ULONGLONG ByteOffset, LPBYTE pbTableHash, DWORD dwCompressedSize, DWORD dwRealSize, DWORD dwKey, bool * pbTableIsCut);
DWORD AllocateSectorBuffer(TMPQFile * hf);
DWORD AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile);
DWORD AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile);
DWORD AllocateSectorChecksums(TMPQFile * hf, bool bLoadFromFile);
DWORD WritePatchInfo(TMPQFile * hf);
DWORD WriteSectorOffsets(TMPQFile * hf);
DWORD WriteSectorChecksums(TMPQFile * hf);
DWORD WriteMemDataMD5(TFileStream * pStream, ULONGLONG RawDataOffs, void * pvRawData, DWORD dwRawDataSize, DWORD dwChunkSize, LPDWORD pcbTotalSize);
DWORD WriteMpqDataMD5(TFileStream * pStream, ULONGLONG RawDataOffs, DWORD dwRawDataSize, DWORD dwChunkSize);
void FreeFileHandle(TMPQFile *& hf);
void FreeArchiveHandle(TMPQArchive *& ha);
//-----------------------------------------------------------------------------
// Patch functions
// Structure used for the patching process
typedef struct _TMPQPatcher
{
BYTE this_md5[MD5_DIGEST_SIZE]; // MD5 of the current file state
LPBYTE pbFileData1; // Primary working buffer
LPBYTE pbFileData2; // Secondary working buffer
DWORD cbMaxFileData; // Maximum allowed size of the patch data
DWORD cbFileData; // Current size of the result data
DWORD nCounter; // Counter of the patch process
} TMPQPatcher;
bool IsIncrementalPatchFile(const void * pvData, DWORD cbData, LPDWORD pdwPatchedFileSize);
DWORD Patch_InitPatcher(TMPQPatcher * pPatcher, TMPQFile * hf);
DWORD Patch_Process(TMPQPatcher * pPatcher, TMPQFile * hf);
void Patch_Finalize(TMPQPatcher * pPatcher);
//-----------------------------------------------------------------------------
// Utility functions
bool IsInternalMpqFileName(const char * szFileName);
template <typename XCHAR>
const XCHAR * GetPlainFileName(const XCHAR * szFileName)
{
const XCHAR * szPlainName = szFileName;
while(*szFileName != 0)
{
if(*szFileName == '\\' || *szFileName == '/')
szPlainName = szFileName + 1;
szFileName++;
}
return szPlainName;
}
//-----------------------------------------------------------------------------
// Internal support for MPQ modifications
DWORD SFileAddFile_Init(
TMPQArchive * ha,
const char * szArchivedName,
ULONGLONG ft,
DWORD dwFileSize,
LCID lcLocale,
DWORD dwFlags,
TMPQFile ** phf
);
DWORD SFileAddFile_Init(
TMPQArchive * ha,
TMPQFile * hfSrc,
TMPQFile ** phf
);
DWORD SFileAddFile_Write(
TMPQFile * hf,
const void * pvData,
DWORD dwSize,
DWORD dwCompression
);
DWORD SFileAddFile_Finish(
TMPQFile * hf
);
//-----------------------------------------------------------------------------
// Attributes support
DWORD SAttrLoadAttributes(TMPQArchive * ha);
DWORD SAttrFileSaveToMpq(TMPQArchive * ha);
//-----------------------------------------------------------------------------
// Listfile functions
DWORD SListFileSaveToMpq(TMPQArchive * ha);
//-----------------------------------------------------------------------------
// Weak signature support
DWORD SSignFileCreate(TMPQArchive * ha);
DWORD SSignFileFinish(TMPQArchive * ha);
//-----------------------------------------------------------------------------
// Dump data support
#ifdef __STORMLIB_DUMP_DATA__
void DumpMpqHeader(TMPQHeader * pHeader);
void DumpHashTable(TMPQHash * pHashTable, DWORD dwHashTableSize);
void DumpHetAndBetTable(TMPQHetTable * pHetTable, TMPQBetTable * pBetTable);
void DumpFileTable(TFileEntry * pFileTable, DWORD dwFileTableSize);
#else
#define DumpMpqHeader(h) /* */
#define DumpHashTable(t, s) /* */
#define DumpHetAndBetTable(t, s) /* */
#define DumpFileTable(t, s) /* */
#endif
#endif // __STORMCOMMON_H__

74
StormLib/src/StormLib.exp Normal file
View File

@ -0,0 +1,74 @@
#
# Export file for Mac OS X
# Copyright (c) 2009 Sam Wilkins
# swilkins1337@gmail.com
#
_SFileSetLocale
_SFileGetLocale
_SFileOpenArchive
_SFileCreateArchive
_SFileFlushArchive
_SFileCloseArchive
_SFileAddListFile
_SFileSetCompactCallback
_SFileCompactArchive
_SFileGetMaxFileCount
_SFileSetMaxFileCount
_SFileGetAttributes
_SFileSetAttributes
_SFileUpdateFileAttributes
_SFileOpenPatchArchive
_SFileIsPatchedArchive
_SFileOpenFileEx
_SFileGetFileSize
_SFileSetFilePointer
_SFileReadFile
_SFileCloseFile
_SFileHasFile
_SFileGetFileName
_SFileGetFileInfo
_SFileExtractFile
_SFileVerifyFile
_SFileVerifyRawData
_SFileVerifyArchive
_SFileFindFirstFile
_SFileFindNextFile
_SFileFindClose
_SListFileFindFirstFile
_SListFileFindNextFile
_SListFileFindClose
_SFileEnumLocales
_SFileCreateFile
_SFileWriteFile
_SFileFinishFile
_SFileAddFileEx
_SFileAddFile
_SFileAddWave
_SFileRemoveFile
_SFileRenameFile
_SFileSetFileLocale
_SFileSetDataCompression
_SFileSetAddFileCallback
_SCompImplode
_SCompExplode
_SCompCompress
_SCompDecompress
_SetLastError
_GetLastError

View File

@ -117,11 +117,7 @@ extern "C" {
#ifdef _DLL
#pragma comment(lib, "StormLibDUD.lib") // Debug Unicode CRT-DLL version
#else
#ifndef _WIN64
#pragma comment(lib, "StormLibDUS32.lib") // Debug Unicode CRT-LIB version
#else
#pragma comment(lib, "StormLibDUS64.lib") // Debug Unicode CRT-LIB version
#endif
#pragma comment(lib, "StormLibDUS.lib") // Debug Unicode CRT-LIB version
#endif
#endif
#else // RELEASE VERSIONS
@ -135,11 +131,7 @@ extern "C" {
#ifdef _DLL
#pragma comment(lib, "StormLibRUD.lib") // Release Unicode CRT-DLL version
#else
#ifndef _WIN64
#pragma comment(lib, "StormLibRUS32.lib") // Release Unicode CRT-LIB version
#else
#pragma comment(lib, "StormLibRUS64.lib") // Release Unicode CRT-LIB version
#endif
#pragma comment(lib, "StormLibRUS.lib") // Release Unicode CRT-LIB version
#endif
#endif
#endif
@ -857,6 +849,10 @@ typedef struct _TMPQArchive
ULONGLONG CompactBytesProcessed; // Amount of bytes that have been processed during a particular compact call
ULONGLONG CompactTotalBytes; // Total amount of bytes to be compacted
void * pvCompactUserData; // User data thats passed to the callback
// OTR
TFileEntry* lastFreeSpaceEntry;
bool useFreeSpaceOptimization;
} TMPQArchive;
// File handle structure

View File

@ -0,0 +1,401 @@
/*****************************************************************************/
/* adpcm.cpp Copyright (c) Ladislav Zezula 2003 */
/*---------------------------------------------------------------------------*/
/* This module contains implementation of adpcm decompression method 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 */
/* 10.01.13 3.00 Lad Refactored, beautified, documented :-) */
/*****************************************************************************/
#include <stddef.h>
#include "adpcm.h"
//-----------------------------------------------------------------------------
// Tables necessary dor decompression
static int NextStepTable[] =
{
-1, 0, -1, 4, -1, 2, -1, 6,
-1, 1, -1, 5, -1, 3, -1, 7,
-1, 1, -1, 5, -1, 3, -1, 7,
-1, 2, -1, 4, -1, 6, -1, 8
};
static int StepSizeTable[] =
{
7, 8, 9, 10, 11, 12, 13, 14,
16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66,
73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658,
724, 796, 876, 963, 1060, 1166, 1282, 1411,
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
32767
};
//-----------------------------------------------------------------------------
// Helper class for writing output ADPCM data
class TADPCMStream
{
public:
TADPCMStream(void * pvBuffer, size_t cbBuffer)
{
pbBufferEnd = (unsigned char *)pvBuffer + cbBuffer;
pbBuffer = (unsigned char *)pvBuffer;
}
bool ReadByteSample(unsigned char & ByteSample)
{
// Check if there is enough space in the buffer
if(pbBuffer >= pbBufferEnd)
return false;
ByteSample = *pbBuffer++;
return true;
}
bool WriteByteSample(unsigned char ByteSample)
{
// Check if there is enough space in the buffer
if(pbBuffer >= pbBufferEnd)
return false;
*pbBuffer++ = ByteSample;
return true;
}
bool ReadWordSample(short & OneSample)
{
// Check if we have enough space in the output buffer
if((size_t)(pbBufferEnd - pbBuffer) < sizeof(short))
return false;
// Write the sample
OneSample = pbBuffer[0] + (((short)pbBuffer[1]) << 0x08);
pbBuffer += sizeof(short);
return true;
}
bool WriteWordSample(short OneSample)
{
// Check if we have enough space in the output buffer
if((size_t)(pbBufferEnd - pbBuffer) < sizeof(short))
return false;
// Write the sample
*pbBuffer++ = (unsigned char)(OneSample & 0xFF);
*pbBuffer++ = (unsigned char)(OneSample >> 0x08);
return true;
}
int LengthProcessed(void * pvOutBuffer)
{
return (int)((unsigned char *)pbBuffer - (unsigned char *)pvOutBuffer);
}
unsigned char * pbBufferEnd;
unsigned char * pbBuffer;
};
//----------------------------------------------------------------------------
// Local functions
static inline short GetNextStepIndex(int StepIndex, unsigned int EncodedSample)
{
// Get the next step index
StepIndex = StepIndex + NextStepTable[EncodedSample & 0x1F];
// Don't make the step index overflow
if(StepIndex < 0)
StepIndex = 0;
else if(StepIndex > 88)
StepIndex = 88;
return (short)StepIndex;
}
static inline int UpdatePredictedSample(int PredictedSample, int EncodedSample, int Difference)
{
// Is the sign bit set?
if(EncodedSample & 0x40)
{
PredictedSample -= Difference;
if(PredictedSample <= -32768)
PredictedSample = -32768;
}
else
{
PredictedSample += Difference;
if(PredictedSample >= 32767)
PredictedSample = 32767;
}
return PredictedSample;
}
static inline int DecodeSample(int PredictedSample, int EncodedSample, int StepSize, int Difference)
{
if(EncodedSample & 0x01)
Difference += (StepSize >> 0);
if(EncodedSample & 0x02)
Difference += (StepSize >> 1);
if(EncodedSample & 0x04)
Difference += (StepSize >> 2);
if(EncodedSample & 0x08)
Difference += (StepSize >> 3);
if(EncodedSample & 0x10)
Difference += (StepSize >> 4);
if(EncodedSample & 0x20)
Difference += (StepSize >> 5);
return UpdatePredictedSample(PredictedSample, EncodedSample, Difference);
}
//----------------------------------------------------------------------------
// Compression routine
int CompressADPCM(void * pvOutBuffer, int cbOutBuffer, void * pvInBuffer, int cbInBuffer, int ChannelCount, int CompressionLevel)
{
TADPCMStream os(pvOutBuffer, cbOutBuffer); // The output stream
TADPCMStream is(pvInBuffer, cbInBuffer); // The input stream
unsigned char BitShift = (unsigned char)(CompressionLevel - 1);
short PredictedSamples[MAX_ADPCM_CHANNEL_COUNT];// Predicted samples for each channel
short StepIndexes[MAX_ADPCM_CHANNEL_COUNT]; // Step indexes for each channel
short InputSample; // Input sample for the current channel
int TotalStepSize;
int ChannelIndex;
int AbsDifference;
int Difference;
int MaxBitMask;
int StepSize;
// _tprintf(_T("== CMPR Started ==============\n"));
// First byte in the output stream contains zero. The second one contains the compression level
os.WriteByteSample(0);
if(!os.WriteByteSample(BitShift))
return 2;
// Set the initial step index for each channel
PredictedSamples[0] = PredictedSamples[1] = 0;
StepIndexes[0] = StepIndexes[1] = INITIAL_ADPCM_STEP_INDEX;
// Next, InitialSample value for each channel follows
for(int i = 0; i < ChannelCount; i++)
{
// Get the initial sample from the input stream
if(!is.ReadWordSample(InputSample))
return os.LengthProcessed(pvOutBuffer);
// Store the initial sample to our sample array
PredictedSamples[i] = InputSample;
// Also store the loaded sample to the output stream
if(!os.WriteWordSample(InputSample))
return os.LengthProcessed(pvOutBuffer);
}
// Get the initial index
ChannelIndex = ChannelCount - 1;
// Now keep reading the input data as long as there is something in the input buffer
while(is.ReadWordSample(InputSample))
{
int EncodedSample = 0;
// If we have two channels, we need to flip the channel index
ChannelIndex = (ChannelIndex + 1) % ChannelCount;
// Get the difference from the previous sample.
// If the difference is negative, set the sign bit to the encoded sample
AbsDifference = InputSample - PredictedSamples[ChannelIndex];
if(AbsDifference < 0)
{
AbsDifference = -AbsDifference;
EncodedSample |= 0x40;
}
// If the difference is too low (higher that difference treshold),
// write a step index modifier marker
StepSize = StepSizeTable[StepIndexes[ChannelIndex]];
if(AbsDifference < (StepSize >> CompressionLevel))
{
if(StepIndexes[ChannelIndex] != 0)
StepIndexes[ChannelIndex]--;
os.WriteByteSample(0x80);
}
else
{
// If the difference is too high, write marker that
// indicates increase in step size
while(AbsDifference > (StepSize << 1))
{
if(StepIndexes[ChannelIndex] >= 0x58)
break;
// Modify the step index
StepIndexes[ChannelIndex] += 8;
if(StepIndexes[ChannelIndex] > 0x58)
StepIndexes[ChannelIndex] = 0x58;
// Write the "modify step index" marker
StepSize = StepSizeTable[StepIndexes[ChannelIndex]];
os.WriteByteSample(0x81);
}
// Get the limit bit value
MaxBitMask = (1 << (BitShift - 1));
MaxBitMask = (MaxBitMask > 0x20) ? 0x20 : MaxBitMask;
Difference = StepSize >> BitShift;
TotalStepSize = 0;
for(int BitVal = 0x01; BitVal <= MaxBitMask; BitVal <<= 1)
{
if((TotalStepSize + StepSize) <= AbsDifference)
{
TotalStepSize += StepSize;
EncodedSample |= BitVal;
}
StepSize >>= 1;
}
PredictedSamples[ChannelIndex] = (short)UpdatePredictedSample(PredictedSamples[ChannelIndex],
EncodedSample,
Difference + TotalStepSize);
// Write the encoded sample to the output stream
if(!os.WriteByteSample((unsigned char)EncodedSample))
break;
// Calculates the step index to use for the next encode
StepIndexes[ChannelIndex] = GetNextStepIndex(StepIndexes[ChannelIndex], EncodedSample);
}
}
// _tprintf(_T("== CMPR Ended ================\n"));
return os.LengthProcessed(pvOutBuffer);
}
//----------------------------------------------------------------------------
// Decompression routine
int DecompressADPCM(void * pvOutBuffer, int cbOutBuffer, void * pvInBuffer, int cbInBuffer, int ChannelCount)
{
TADPCMStream os(pvOutBuffer, cbOutBuffer); // Output stream
TADPCMStream is(pvInBuffer, cbInBuffer); // Input stream
unsigned char EncodedSample;
unsigned char BitShift;
short PredictedSamples[MAX_ADPCM_CHANNEL_COUNT]; // Predicted sample for each channel
short StepIndexes[MAX_ADPCM_CHANNEL_COUNT]; // Predicted step index for each channel
int ChannelIndex; // Current channel index
// Initialize the StepIndex for each channel
PredictedSamples[0] = PredictedSamples[1] = 0;
StepIndexes[0] = StepIndexes[1] = INITIAL_ADPCM_STEP_INDEX;
// _tprintf(_T("== DCMP Started ==============\n"));
// The first byte is always zero, the second one contains bit shift (compression level - 1)
is.ReadByteSample(BitShift);
is.ReadByteSample(BitShift);
// _tprintf(_T("DCMP: BitShift = %u\n"), (unsigned int)(unsigned char)BitShift);
// Next, InitialSample value for each channel follows
for(int i = 0; i < ChannelCount; i++)
{
// Get the initial sample from the input stream
short InitialSample;
// Attempt to read the initial sample
if(!is.ReadWordSample(InitialSample))
return os.LengthProcessed(pvOutBuffer);
// _tprintf(_T("DCMP: Loaded InitialSample[%u]: %04X\n"), i, (unsigned int)(unsigned short)InitialSample);
// Store the initial sample to our sample array
PredictedSamples[i] = InitialSample;
// Also store the loaded sample to the output stream
if(!os.WriteWordSample(InitialSample))
return os.LengthProcessed(pvOutBuffer);
}
// Get the initial index
ChannelIndex = ChannelCount - 1;
// Keep reading as long as there is something in the input buffer
while(is.ReadByteSample(EncodedSample))
{
// _tprintf(_T("DCMP: Loaded Encoded Sample: %02X\n"), (unsigned int)(unsigned char)EncodedSample);
// If we have two channels, we need to flip the channel index
ChannelIndex = (ChannelIndex + 1) % ChannelCount;
if(EncodedSample == 0x80)
{
if(StepIndexes[ChannelIndex] != 0)
StepIndexes[ChannelIndex]--;
// _tprintf(_T("DCMP: Writing Decoded Sample: %04lX\n"), (unsigned int)(unsigned short)PredictedSamples[ChannelIndex]);
if(!os.WriteWordSample(PredictedSamples[ChannelIndex]))
return os.LengthProcessed(pvOutBuffer);
}
else if(EncodedSample == 0x81)
{
// Modify the step index
StepIndexes[ChannelIndex] += 8;
if(StepIndexes[ChannelIndex] > 0x58)
StepIndexes[ChannelIndex] = 0x58;
// _tprintf(_T("DCMP: New value of StepIndex: %04lX\n"), (unsigned int)(unsigned short)StepIndexes[ChannelIndex]);
// Next pass, keep going on the same channel
ChannelIndex = (ChannelIndex + 1) % ChannelCount;
}
else
{
int StepIndex = StepIndexes[ChannelIndex];
int StepSize = StepSizeTable[StepIndex];
// Encode one sample
PredictedSamples[ChannelIndex] = (short)DecodeSample(PredictedSamples[ChannelIndex],
EncodedSample,
StepSize,
StepSize >> BitShift);
// _tprintf(_T("DCMP: Writing decoded sample: %04X\n"), (unsigned int)(unsigned short)PredictedSamples[ChannelIndex]);
// Write the decoded sample to the output stream
if(!os.WriteWordSample(PredictedSamples[ChannelIndex]))
break;
// Calculates the step index to use for the next encode
StepIndexes[ChannelIndex] = GetNextStepIndex(StepIndex, EncodedSample);
// _tprintf(_T("DCMP: New step index: %04X\n"), (unsigned int)(unsigned short)StepIndexes[ChannelIndex]);
}
}
// _tprintf(_T("DCMP: Total length written: %u\n"), (unsigned int)os.LengthProcessed(pvOutBuffer));
// _tprintf(_T("== DCMP Ended ================\n"));
// Return total bytes written since beginning of the output buffer
return os.LengthProcessed(pvOutBuffer);
}

View File

@ -0,0 +1,26 @@
/*****************************************************************************/
/* adpcm.h Copyright (c) Ladislav Zezula 2003 */
/*---------------------------------------------------------------------------*/
/* Header file for adpcm decompress functions */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 31.03.03 1.00 Lad The first version of adpcm.h */
/*****************************************************************************/
#ifndef __ADPCM_H__
#define __ADPCM_H__
//-----------------------------------------------------------------------------
// Defines
#define MAX_ADPCM_CHANNEL_COUNT 2
#define INITIAL_ADPCM_STEP_INDEX 0x2C
//-----------------------------------------------------------------------------
// Public functions
int CompressADPCM (void * pvOutBuffer, int dwOutLength, void * pvInBuffer, int dwInLength, int nCmpType, int ChannelCount);
int DecompressADPCM(void * pvOutBuffer, int dwOutLength, void * pvInBuffer, int dwInLength, int ChannelCount);
#endif // __ADPCM_H__

File diff suppressed because it is too large Load Diff

1573
StormLib/src/bzip2/bzlib.c Normal file

File diff suppressed because it is too large Load Diff

282
StormLib/src/bzip2/bzlib.h Normal file
View File

@ -0,0 +1,282 @@
/*-------------------------------------------------------------*/
/*--- Public header file for the library. ---*/
/*--- bzlib.h ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.5 of 10 December 2007
Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#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 (tsuneo@rr.iij4u.or.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 ---*/
/*-------------------------------------------------------------*/

View File

@ -0,0 +1,509 @@
/*-------------------------------------------------------------*/
/*--- Private header file for the library. ---*/
/*--- bzlib_private.h ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.5 of 10 December 2007
Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#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.5, 10-Dec-2007"
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) do { } while (0)
#define VPrintf0(zf) do { } while (0)
#define VPrintf1(zf,za1) do { } while (0)
#define VPrintf2(zf,za1,za2) do { } while (0)
#define VPrintf3(zf,za1,za2,za3) do { } while (0)
#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0)
#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
#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) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
s->tPos = s->tt[s->tPos]; \
cccc = (UChar)(s->tPos & 0xff); \
s->tPos >>= 8;
#define BZ_GET_FAST_C(cccc) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
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) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
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 ---*/
/*-------------------------------------------------------------*/

Some files were not shown because too many files have changed in this diff Show More