Move extractors/assemblers and the revisiongenerator around to accomodate upcoming new treestructure
--HG-- branch : trunk rename : src/tools/genrevision/genrevision.cpp => src/genrevision/genrevision.cpp rename : contrib/map_extractor/CMakeLists.txt => src/tools/map_extractor/CMakeLists.txt rename : contrib/map_extractor/README.linux => src/tools/map_extractor/README.linux rename : contrib/map_extractor/System.cpp => src/tools/map_extractor/System.cpp rename : contrib/map_extractor/VC90_AD.sln => src/tools/map_extractor/VC90_AD.sln rename : contrib/map_extractor/VC90_ad.vcproj => src/tools/map_extractor/VC90_ad.vcproj rename : contrib/map_extractor/ad => src/tools/map_extractor/ad rename : contrib/map_extractor/ad.exe => src/tools/map_extractor/ad.exe rename : contrib/map_extractor/adt.cpp => src/tools/map_extractor/adt.cpp rename : contrib/map_extractor/adt.h => src/tools/map_extractor/adt.h rename : contrib/map_extractor/dbcfile.cpp => src/tools/map_extractor/dbcfile.cpp rename : contrib/map_extractor/dbcfile.h => src/tools/map_extractor/dbcfile.h rename : contrib/map_extractor/debug/zlib.lib => src/tools/map_extractor/debug/zlib.lib rename : contrib/map_extractor/libmpq/CMakeLists.txt => src/tools/map_extractor/libmpq/CMakeLists.txt rename : contrib/map_extractor/libmpq/common.cpp => src/tools/map_extractor/libmpq/common.cpp rename : contrib/map_extractor/libmpq/common.h => src/tools/map_extractor/libmpq/common.h rename : contrib/map_extractor/libmpq/explode.cpp => src/tools/map_extractor/libmpq/explode.cpp rename : contrib/map_extractor/libmpq/explode.h => src/tools/map_extractor/libmpq/explode.h rename : contrib/map_extractor/libmpq/extract.cpp => src/tools/map_extractor/libmpq/extract.cpp rename : contrib/map_extractor/libmpq/huffman.cpp => src/tools/map_extractor/libmpq/huffman.cpp rename : contrib/map_extractor/libmpq/huffman.h => src/tools/map_extractor/libmpq/huffman.h rename : contrib/map_extractor/libmpq/mpq.cpp => src/tools/map_extractor/libmpq/mpq.cpp rename : contrib/map_extractor/libmpq/mpq.h => src/tools/map_extractor/libmpq/mpq.h rename : contrib/map_extractor/libmpq/parser.cpp => src/tools/map_extractor/libmpq/parser.cpp rename : contrib/map_extractor/libmpq/wave.cpp => src/tools/map_extractor/libmpq/wave.cpp rename : contrib/map_extractor/libmpq/wave.h => src/tools/map_extractor/libmpq/wave.h rename : contrib/map_extractor/libmpq/zconf.h => src/tools/map_extractor/libmpq/zconf.h rename : contrib/map_extractor/libmpq/zlib.h => src/tools/map_extractor/libmpq/zlib.h rename : contrib/map_extractor/loadlib/CMakeLists.txt => src/tools/map_extractor/loadlib/CMakeLists.txt rename : contrib/map_extractor/loadlib/adt.cpp => src/tools/map_extractor/loadlib/adt.cpp rename : contrib/map_extractor/loadlib/adt.h => src/tools/map_extractor/loadlib/adt.h rename : contrib/map_extractor/loadlib/loadlib.cpp => src/tools/map_extractor/loadlib/loadlib.cpp rename : contrib/map_extractor/loadlib/loadlib.h => src/tools/map_extractor/loadlib/loadlib.h rename : contrib/map_extractor/loadlib/wdt.cpp => src/tools/map_extractor/loadlib/wdt.cpp rename : contrib/map_extractor/loadlib/wdt.h => src/tools/map_extractor/loadlib/wdt.h rename : contrib/map_extractor/mpq_libmpq.cpp => src/tools/map_extractor/mpq_libmpq.cpp rename : contrib/map_extractor/mpq_libmpq.h => src/tools/map_extractor/mpq_libmpq.h rename : contrib/map_extractor/release/zlib.lib => src/tools/map_extractor/release/zlib.lib rename : contrib/vmap3_assembler/CMakeLists.txt => src/tools/vmap3_assembler/CMakeLists.txt rename : contrib/vmap3_assembler/VC90/vmap_assembler.vcproj => src/tools/vmap3_assembler/VC90/vmap_assembler.vcproj rename : contrib/vmap3_assembler/splitConfig.txt => src/tools/vmap3_assembler/splitConfig.txt rename : contrib/vmap3_assembler/vmap_assembler.cpp => src/tools/vmap3_assembler/vmap_assembler.cpp rename : contrib/vmap3_assembler/vmap_assemblerVC90.sln => src/tools/vmap3_assembler/vmap_assemblerVC90.sln rename : contrib/vmap3_extractor/CMakeLists.txt => src/tools/vmap3_extractor/CMakeLists.txt rename : contrib/vmap3_extractor/vmapextract/CMakeLists.txt => src/tools/vmap3_extractor/vmapextract/CMakeLists.txt rename : contrib/vmap3_extractor/vmapextract/adtfile.cpp => src/tools/vmap3_extractor/vmapextract/adtfile.cpp rename : contrib/vmap3_extractor/vmapextract/adtfile.h => src/tools/vmap3_extractor/vmapextract/adtfile.h rename : contrib/vmap3_extractor/vmapextract/dbcfile.cpp => src/tools/vmap3_extractor/vmapextract/dbcfile.cpp rename : contrib/vmap3_extractor/vmapextract/dbcfile.h => src/tools/vmap3_extractor/vmapextract/dbcfile.h rename : contrib/vmap3_extractor/vmapextract/loadlib/loadlib.h => src/tools/vmap3_extractor/vmapextract/loadlib/loadlib.h rename : contrib/vmap3_extractor/vmapextract/model.cpp => src/tools/vmap3_extractor/vmapextract/model.cpp rename : contrib/vmap3_extractor/vmapextract/model.h => src/tools/vmap3_extractor/vmapextract/model.h rename : contrib/vmap3_extractor/vmapextract/modelheaders.h => src/tools/vmap3_extractor/vmapextract/modelheaders.h rename : contrib/vmap3_extractor/vmapextract/mpq_libmpq.cpp => src/tools/vmap3_extractor/vmapextract/mpq_libmpq.cpp rename : contrib/vmap3_extractor/vmapextract/mpq_libmpq04.h => src/tools/vmap3_extractor/vmapextract/mpq_libmpq04.h rename : contrib/vmap3_extractor/vmapextract/vec3d.h => src/tools/vmap3_extractor/vmapextract/vec3d.h rename : contrib/vmap3_extractor/vmapextract/vmapexport.cpp => src/tools/vmap3_extractor/vmapextract/vmapexport.cpp rename : contrib/vmap3_extractor/vmapextract/vmapexport.h => src/tools/vmap3_extractor/vmapextract/vmapexport.h rename : contrib/vmap3_extractor/vmapextract/wdtfile.cpp => src/tools/vmap3_extractor/vmapextract/wdtfile.cpp rename : contrib/vmap3_extractor/vmapextract/wdtfile.h => src/tools/vmap3_extractor/vmapextract/wdtfile.h rename : contrib/vmap3_extractor/vmapextract/wmo.cpp => src/tools/vmap3_extractor/vmapextract/wmo.cpp rename : contrib/vmap3_extractor/vmapextract/wmo.h => src/tools/vmap3_extractor/vmapextract/wmo.h rename : contrib/vmap3_extractor/win/vmapExtractor3_VC90.sln => src/tools/vmap3_extractor/win/vmapExtractor3_VC90.sln
This commit is contained in:
@@ -1,513 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
std::string build_directive;
|
||||
|
||||
struct RawData
|
||||
{
|
||||
char hash_str[200];
|
||||
char rev_str[200];
|
||||
char date_str[200];
|
||||
char time_str[200];
|
||||
};
|
||||
|
||||
void extractDataFromSvn(FILE* EntriesFile, bool url, RawData& data)
|
||||
{
|
||||
char buf[200];
|
||||
|
||||
char repo_str[200];
|
||||
char num_str[200];
|
||||
|
||||
fgets(buf,200,EntriesFile);
|
||||
fgets(buf,200,EntriesFile);
|
||||
fgets(buf,200,EntriesFile);
|
||||
fgets(buf,200,EntriesFile); sscanf(buf,"%s",num_str);
|
||||
fgets(buf,200,EntriesFile); sscanf(buf,"%s",repo_str);
|
||||
fgets(buf,200,EntriesFile);
|
||||
fgets(buf,200,EntriesFile);
|
||||
fgets(buf,200,EntriesFile);
|
||||
fgets(buf,200,EntriesFile);
|
||||
fgets(buf,200,EntriesFile); sscanf(buf,"%10sT%8s",data.date_str,data.time_str);
|
||||
|
||||
if(url)
|
||||
sprintf(data.rev_str,"%s at %s",num_str,repo_str);
|
||||
else
|
||||
strcpy(data.rev_str,num_str);
|
||||
}
|
||||
|
||||
void extractDataFromHG(FILE* EntriesFile, std::string path, bool url, RawData& data)
|
||||
{
|
||||
char buf[200];
|
||||
|
||||
char hash_str[200];
|
||||
char revision_str[200];
|
||||
|
||||
bool found = false;
|
||||
while(fgets(buf,200,EntriesFile))
|
||||
{
|
||||
if(sscanf(buf,"%s %s",hash_str,revision_str)==2)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
{
|
||||
strcpy(data.hash_str,"*");
|
||||
strcpy(data.rev_str,"*");
|
||||
strcpy(data.date_str,"*");
|
||||
strcpy(data.time_str,"*");
|
||||
return;
|
||||
}
|
||||
|
||||
char thash_str[200];
|
||||
for (int i = 11; i >= 0; --i)
|
||||
{
|
||||
thash_str[i] = hash_str[i];
|
||||
}
|
||||
thash_str[12] = '\0';
|
||||
|
||||
strcpy(data.hash_str,thash_str);
|
||||
strcpy(data.rev_str,revision_str);
|
||||
|
||||
strcpy(data.date_str,"*");
|
||||
strcpy(data.time_str,"*");
|
||||
}
|
||||
|
||||
void extractDataFromArchive(FILE* EntriesFile, std::string path, bool url, RawData& data)
|
||||
{
|
||||
char buf[200];
|
||||
|
||||
char hash_str[200];
|
||||
char revision_str[200];
|
||||
|
||||
bool found = false;
|
||||
fgets(buf,200,EntriesFile);
|
||||
while(fgets(buf,200,EntriesFile))
|
||||
{
|
||||
if(sscanf(buf,"%s %s",revision_str,hash_str)==2)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
{
|
||||
strcpy(data.hash_str,"*");
|
||||
strcpy(data.rev_str,"*");
|
||||
strcpy(data.date_str,"*");
|
||||
strcpy(data.time_str,"*");
|
||||
return;
|
||||
}
|
||||
|
||||
char thash_str[200];
|
||||
for (int i = 11; i >= 0; --i)
|
||||
{
|
||||
thash_str[i] = hash_str[i];
|
||||
}
|
||||
thash_str[12] = '\0';
|
||||
|
||||
strcpy(data.hash_str,thash_str);
|
||||
strcpy(data.rev_str,"Archive");
|
||||
|
||||
strcpy(data.date_str,"*");
|
||||
strcpy(data.time_str,"*");
|
||||
}
|
||||
|
||||
void extractDataFromGit(FILE* EntriesFile, std::string path, bool url, RawData& data)
|
||||
{
|
||||
char buf[200];
|
||||
|
||||
char hash_str[200];
|
||||
char branch_str[200];
|
||||
char url_str[200];
|
||||
|
||||
bool found = false;
|
||||
while(fgets(buf,200,EntriesFile))
|
||||
{
|
||||
if(sscanf(buf,"%s\t\tbranch %s of %s",hash_str,branch_str,url_str)==3)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
{
|
||||
strcpy(data.hash_str,"*");
|
||||
strcpy(data.rev_str,"*");
|
||||
strcpy(data.date_str,"*");
|
||||
strcpy(data.time_str,"*");
|
||||
return;
|
||||
}
|
||||
|
||||
if(url)
|
||||
{
|
||||
char* host_str = NULL;
|
||||
char* acc_str = NULL;
|
||||
char* repo_str = NULL;
|
||||
|
||||
// parse URL like [email protected]:mangos/mangos
|
||||
char url_buf[200];
|
||||
int res = sscanf(url_str,"git@%s",url_buf);
|
||||
if(res)
|
||||
{
|
||||
host_str = strtok(url_buf,":");
|
||||
acc_str = strtok(NULL,"/");
|
||||
repo_str = strtok(NULL," ");
|
||||
}
|
||||
else
|
||||
{
|
||||
res = sscanf(url_str,"git://%s",url_buf);
|
||||
if(res)
|
||||
{
|
||||
host_str = strtok(url_buf,"/");
|
||||
acc_str = strtok(NULL,"/");
|
||||
repo_str = strtok(NULL,".");
|
||||
}
|
||||
}
|
||||
|
||||
// can generate nice link
|
||||
if(res)
|
||||
sprintf(data.rev_str,"http://%s/%s/%s/commit/%s",host_str,acc_str,repo_str,hash_str);
|
||||
// unknonw URL format, use as-is
|
||||
else
|
||||
sprintf(data.rev_str,"%s at %s",hash_str,url_str);
|
||||
}
|
||||
else
|
||||
strcpy(data.rev_str,hash_str);
|
||||
strcpy(data.hash_str,"*");
|
||||
|
||||
time_t rev_time = 0;
|
||||
// extracting date/time
|
||||
FILE* LogFile = fopen((path+".git/logs/HEAD").c_str(), "r");
|
||||
if(LogFile)
|
||||
{
|
||||
while(fgets(buf,200,LogFile))
|
||||
{
|
||||
char buf2[200];
|
||||
char new_hash[200];
|
||||
int unix_time = 0;
|
||||
int res2 = sscanf(buf,"%s %s %s %s %i",buf2,new_hash,buf2,buf2,&unix_time);
|
||||
if(res2!=5)
|
||||
continue;
|
||||
|
||||
if(strcmp(hash_str,new_hash))
|
||||
continue;
|
||||
|
||||
rev_time = unix_time;
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(LogFile);
|
||||
|
||||
if(rev_time)
|
||||
{
|
||||
tm* aTm = localtime(&rev_time);
|
||||
// YYYY year
|
||||
// MM month (2 digits 01-12)
|
||||
// DD day (2 digits 01-31)
|
||||
// HH hour (2 digits 00-23)
|
||||
// MM minutes (2 digits 00-59)
|
||||
// SS seconds (2 digits 00-59)
|
||||
sprintf(data.date_str,"%04d-%02d-%02d",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday);
|
||||
sprintf(data.time_str,"%02d:%02d:%02d",aTm->tm_hour,aTm->tm_min,aTm->tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(data.date_str,"*");
|
||||
strcpy(data.time_str,"*");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(data.date_str,"*");
|
||||
strcpy(data.time_str,"*");
|
||||
}
|
||||
}
|
||||
|
||||
bool extractDataFromSvn(std::string filename, bool url, RawData& data)
|
||||
{
|
||||
FILE* EntriesFile = fopen(filename.c_str(), "r");
|
||||
if(!EntriesFile)
|
||||
return false;
|
||||
|
||||
extractDataFromSvn(EntriesFile,url,data);
|
||||
fclose(EntriesFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool extractDataFromGit(std::string filename, std::string path, bool url, RawData& data)
|
||||
{
|
||||
FILE* EntriesFile = fopen(filename.c_str(), "r");
|
||||
if(!EntriesFile)
|
||||
return false;
|
||||
|
||||
extractDataFromGit(EntriesFile,path,url,data);
|
||||
fclose(EntriesFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool extractDataFromHG(std::string filename, std::string path, bool url, RawData& data)
|
||||
{
|
||||
FILE* EntriesFile = fopen(filename.c_str(), "r");
|
||||
if(!EntriesFile)
|
||||
return false;
|
||||
|
||||
extractDataFromHG(EntriesFile,path,url,data);
|
||||
fclose(EntriesFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool extractDataFromArchive(std::string filename, std::string path, bool url, RawData& data)
|
||||
{
|
||||
FILE* EntriesFile = fopen(filename.c_str(), "r");
|
||||
if(!EntriesFile)
|
||||
return false;
|
||||
|
||||
extractDataFromArchive(EntriesFile,path,url,data);
|
||||
fclose(EntriesFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string generateHeader(char const* rev_str, char const* date_str, char const* time_str, char const* hash_str)
|
||||
{
|
||||
std::ostringstream newData;
|
||||
newData << "#ifndef __REVISION_H__" << std::endl;
|
||||
newData << "#define __REVISION_H__" << std::endl;
|
||||
newData << " #define _BUILD_DIRECTIVE \"" << build_directive << "\"" << std::endl;
|
||||
newData << " #define _REVISION \"" << rev_str << "\"" << std::endl;
|
||||
newData << " #define _HASH \"" << hash_str << "\"" << std::endl;
|
||||
newData << " #define _REVISION_DATE \"" << date_str << "\"" << std::endl;
|
||||
newData << " #define _REVISION_TIME \"" << time_str << "\""<< std::endl;
|
||||
if (!strcmp(rev_str,"Archive") || !strcmp(rev_str,"*"))
|
||||
{
|
||||
newData << " #define FILEVER 0,0,0,0"<< std::endl;
|
||||
newData << " #define PRODUCTVER 0,0,0,0"<< std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
newData << " #define FILEVER 0,0," << rev_str << ",0"<< std::endl;
|
||||
newData << " #define PRODUCTVER 0,0," << rev_str << ",0"<< std::endl;
|
||||
}
|
||||
newData << " #define STRFILEVER \"0, 0, " << rev_str << ", " << hash_str << "\""<< std::endl;
|
||||
newData << " #define STRPRODUCTVER \"0, 0, " << rev_str << ", " << hash_str << "\""<< std::endl;
|
||||
newData << "#endif // __REVISION_H__" << std::endl;
|
||||
|
||||
return newData.str();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool use_url = false;
|
||||
bool hg_prefered = true;
|
||||
bool git_prefered = false;
|
||||
bool svn_prefered = false;
|
||||
bool debug = false;
|
||||
std::string path;
|
||||
|
||||
// Call: tool {options} [path]
|
||||
// -h use hg prefered (default)
|
||||
// -g use git prefered
|
||||
// -s use svn prefered
|
||||
// -r use only revision (without repo URL) (default)
|
||||
// -u include repositire URL as commit URL or "rev at URL"
|
||||
// -d compile directive debug
|
||||
for (int k = 1; k <= argc; ++k)
|
||||
{
|
||||
if(!argv[k] || !*argv[k])
|
||||
break;
|
||||
|
||||
if(argv[k][0]!='-')
|
||||
{
|
||||
path = argv[k];
|
||||
if(path.size() > 0 && (path[path.size()-1]!='/' || path[path.size()-1]!='\\'))
|
||||
path += '/';
|
||||
break;
|
||||
}
|
||||
|
||||
switch(argv[k][1])
|
||||
{
|
||||
case 'h':
|
||||
hg_prefered = true;
|
||||
git_prefered = false;
|
||||
svn_prefered = false;
|
||||
continue;
|
||||
case 'g':
|
||||
hg_prefered = false;
|
||||
git_prefered = true;
|
||||
svn_prefered = false;
|
||||
continue;
|
||||
case 'r':
|
||||
use_url = false;
|
||||
continue;
|
||||
case 's':
|
||||
hg_prefered = false;
|
||||
git_prefered = false;
|
||||
svn_prefered = true;
|
||||
continue;
|
||||
case 'u':
|
||||
use_url = true;
|
||||
continue;
|
||||
case 'd':
|
||||
debug = true;
|
||||
continue;
|
||||
default:
|
||||
printf("Unknown option %s",argv[k]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
build_directive = "Debug";
|
||||
else
|
||||
build_directive = "Release";
|
||||
|
||||
/// new data extraction
|
||||
std::string newData;
|
||||
|
||||
{
|
||||
RawData data;
|
||||
|
||||
bool res = false;
|
||||
|
||||
if(svn_prefered)
|
||||
{
|
||||
/// SVN data
|
||||
res = extractDataFromSvn(path+".svn/entries",use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromSvn(path+"_svn/entries",use_url,data);
|
||||
// HG data
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+".hg/branchheads.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+"_hg/branchheads.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+".hg/branch.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+"_hg/branch.cache",path,use_url,data);
|
||||
// GIT data
|
||||
if (!res)
|
||||
res = extractDataFromGit(path+".git/FETCH_HEAD",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromGit(path+"_git/FETCH_HEAD",path,use_url,data);
|
||||
// Archive data
|
||||
if (!res)
|
||||
res = extractDataFromArchive(path+".hg_archival.txt",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromArchive(path+"_hg_archival.txt",path,use_url,data);
|
||||
}
|
||||
else if(git_prefered)
|
||||
{
|
||||
// GIT data
|
||||
res = extractDataFromGit(path+".git/FETCH_HEAD",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromGit(path+"_git/FETCH_HEAD",path,use_url,data);
|
||||
// HG data
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+".hg/branchheads.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+"_hg/branchheads.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+".hg/branch.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+"_hg/branch.cache",path,use_url,data);
|
||||
/// SVN data
|
||||
if (!res)
|
||||
res = extractDataFromSvn(path+".svn/entries",use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromSvn(path+"_svn/entries",use_url,data);
|
||||
// Archive data
|
||||
if (!res)
|
||||
res = extractDataFromArchive(path+".hg_archival.txt",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromArchive(path+"_hg_archival.txt",path,use_url,data);
|
||||
}
|
||||
|
||||
else if(hg_prefered)
|
||||
{
|
||||
// HG data
|
||||
res = extractDataFromHG(path+".hg/branchheads.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+"_hg/branchheads.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+".hg/branch.cache",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromHG(path+"_hg/branch.cache",path,use_url,data);
|
||||
/// SVN data
|
||||
if (!res)
|
||||
res = extractDataFromSvn(path+".svn/entries",use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromSvn(path+"_svn/entries",use_url,data);
|
||||
// GIT data
|
||||
if (!res)
|
||||
res = extractDataFromGit(path+".git/FETCH_HEAD",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromGit(path+"_git/FETCH_HEAD",path,use_url,data);
|
||||
// Archive data
|
||||
if (!res)
|
||||
res = extractDataFromArchive(path+".hg_archival.txt",path,use_url,data);
|
||||
if (!res)
|
||||
res = extractDataFromArchive(path+"_hg_archival.txt",path,use_url,data);
|
||||
}
|
||||
|
||||
if(res)
|
||||
newData = generateHeader(data.rev_str,data.date_str,data.time_str,data.hash_str);
|
||||
else
|
||||
newData = generateHeader("*", "*", "*", "*");
|
||||
}
|
||||
|
||||
/// get existed header data for compare
|
||||
std::string oldData;
|
||||
|
||||
if(FILE* HeaderFile = fopen("revision.h","rb"))
|
||||
{
|
||||
while(!feof(HeaderFile))
|
||||
{
|
||||
int c = fgetc(HeaderFile);
|
||||
if(c < 0)
|
||||
break;
|
||||
oldData += (char)c;
|
||||
}
|
||||
|
||||
fclose(HeaderFile);
|
||||
}
|
||||
|
||||
/// update header only if different data
|
||||
if(newData != oldData)
|
||||
{
|
||||
if(FILE* OutputFile = fopen("revision.h","wb"))
|
||||
{
|
||||
fprintf(OutputFile,"%s",newData.c_str());
|
||||
fclose(OutputFile);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (MANGOS_MAP_EXTRACTOR)
|
||||
|
||||
add_subdirectory (libmpq)
|
||||
add_subdirectory (loadlib)
|
||||
|
||||
include_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/libmpq)
|
||||
include_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/loadlib)
|
||||
|
||||
link_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/libmpq)
|
||||
link_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/loadlib)
|
||||
|
||||
add_executable (ad dbcfile.cpp mpq_libmpq.cpp System.cpp)
|
||||
|
||||
target_link_libraries (ad libmpq)
|
||||
target_link_libraries (ad loadlib)
|
||||
@@ -0,0 +1,7 @@
|
||||
Linux instructions
|
||||
------------------
|
||||
|
||||
1. install cmake
|
||||
2. cmake -i
|
||||
3. make
|
||||
4. ./ad
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ad", "VC90_ad.vcproj", "{D7552D4F-408F-4F8E-859B-366659150CF4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D7552D4F-408F-4F8E-859B-366659150CF4}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D7552D4F-408F-4F8E-859B-366659150CF4}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D7552D4F-408F-4F8E-859B-366659150CF4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D7552D4F-408F-4F8E-859B-366659150CF4}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,327 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="ad"
|
||||
ProjectGUID="{D7552D4F-408F-4F8E-859B-366659150CF4}"
|
||||
RootNamespace="ad"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="."
|
||||
IntermediateDirectory=".\debug\"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
MkTypLibCompatible="true"
|
||||
SuppressStartupBanner="true"
|
||||
TargetEnvironment="1"
|
||||
TypeLibraryName="./ad.tlb"
|
||||
HeaderFileName=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="libmpq"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
PrecompiledHeaderFile="$(IntDir)ad.pch"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
ObjectFile="$(IntDir)\"
|
||||
ProgramDataBaseFileName="$(IntDir)\"
|
||||
XMLDocumentationFileName="$(IntDir)\"
|
||||
BrowseInformation="1"
|
||||
BrowseInformationFile="$(IntDir)"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
Culture="1049"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="zlib.lib"
|
||||
OutputFile="ad debug.exe"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
AdditionalLibraryDirectories="./debug/"
|
||||
IgnoreDefaultLibraryNames="LIBCD.lib"
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile="./ad debug.pdb"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="."
|
||||
IntermediateDirectory=".\release"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
MkTypLibCompatible="true"
|
||||
SuppressStartupBanner="true"
|
||||
TargetEnvironment="1"
|
||||
TypeLibraryName="./ad.tlb"
|
||||
HeaderFileName=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
InlineFunctionExpansion="1"
|
||||
AdditionalIncludeDirectories="libmpq"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
PrecompiledHeaderFile="$(IntDir)ad.pch"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
ObjectFile="$(IntDir)\"
|
||||
ProgramDataBaseFileName="$(IntDir)\"
|
||||
XMLDocumentationFileName="$(IntDir)\"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
Culture="1049"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="zlib.lib"
|
||||
OutputFile="./ad.exe"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
AdditionalLibraryDirectories="./release/"
|
||||
IgnoreDefaultLibraryNames="LIBC.lib"
|
||||
ProgramDatabaseFile="./ad.pdb"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\loadlib\loadlib.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\loadlib\adt.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\loadlib\wdt.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\common.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\dbcfile.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\explode.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\extract.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\huffman.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\mpq.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mpq_libmpq.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\parser.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="system.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions=""
|
||||
BasicRuntimeChecks="3"
|
||||
BrowseInformation="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
PreprocessorDefinitions=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\wave.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\libmpq\common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\dbcfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\explode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\huffman.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\mpq.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mpq_libmpq.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libmpq\wave.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,381 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include "adt.h"
|
||||
#include "mpq_libmpq.h"
|
||||
|
||||
extern uint16 *areas;
|
||||
extern uint16 *LiqType;
|
||||
extern uint32 maxAreaId;
|
||||
|
||||
vec wmoc;
|
||||
|
||||
Cell *cell;
|
||||
mcell *mcells;
|
||||
int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888};
|
||||
int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000};
|
||||
|
||||
bool LoadADT(char* filename)
|
||||
{
|
||||
size_t size;
|
||||
MPQFile mf(filename);
|
||||
|
||||
if(mf.isEof())
|
||||
{
|
||||
//printf("No such file %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
MapLiqFlag = new uint8[256];
|
||||
for(uint32 j = 0; j < 256; ++j)
|
||||
MapLiqFlag[j] = 0; // no water
|
||||
|
||||
MapLiqHeight = new float[16384];
|
||||
for(uint32 j = 0; j < 16384; ++j)
|
||||
MapLiqHeight[j] = -999999; // no water
|
||||
|
||||
mcells = new mcell;
|
||||
|
||||
wmoc.x = 65 * TILESIZE;
|
||||
wmoc.z = 65 * TILESIZE;
|
||||
|
||||
size_t mcnk_offsets[256], mcnk_sizes[256];
|
||||
|
||||
chunk_num = 0;
|
||||
k = 0;
|
||||
m = 0;
|
||||
while (!mf.isEof())
|
||||
{
|
||||
uint32 fourcc;
|
||||
mf.read(&fourcc, 4);
|
||||
mf.read(&size, 4);
|
||||
|
||||
size_t nextpos = mf.getPos() + size;
|
||||
|
||||
//if(fourcc==0x4d484452) // MHDR header
|
||||
//if(fourcc==0x4d564552) // MVER
|
||||
if(fourcc == 0x4d43494e) // MCIN
|
||||
{
|
||||
for (uint32 i = 0; i < 256; ++i)
|
||||
{
|
||||
mf.read(&mcnk_offsets[i], 4);
|
||||
mf.read(&mcnk_sizes[i], 4);
|
||||
mf.seekRelative(8);
|
||||
}
|
||||
}
|
||||
//if(fourcc == 0x4d544558) // MTEX textures (strings)
|
||||
//if(fourcc == 0x4d4d4458) // MMDX m2 models (strings)
|
||||
//if(fourcc == 0x4d4d4944) // MMID offsets for strings in MMDX
|
||||
//if(fourcc == 0x4d574d4f) // MWMO
|
||||
//if(fourcc == 0x4d574944) // MWID offsets for strings in MWMO
|
||||
//if(fourcc == 0x4d444446) // MDDF
|
||||
//if(fourcc == 0x4d4f4446) // MODF
|
||||
if(fourcc == 0x4d48324f) // MH2O new in WotLK
|
||||
{
|
||||
// 玟羼?磬漕 玎镱祉栩?徉珙怏?镱玷鲨??羿殡?蜿 怦?耢妁屙? 狍潴?铗 礤泐
|
||||
uint32 base_pos = mf.getPos();
|
||||
uint32 header_pos = 0;
|
||||
MH2O_offsData *LiqOffsData = new MH2O_offsData;
|
||||
MH2O_Data1 *LiqChunkData1 = new MH2O_Data1;
|
||||
float *ChunkLiqHeight = new float[81];
|
||||
for(chunk_num = 0; chunk_num < 256; ++chunk_num)
|
||||
{
|
||||
mf.read(LiqOffsData, 0x0C);
|
||||
header_pos = mf.getPos();
|
||||
if(LiqOffsData->offsData1 != 0) // 羼腓 溧眄� ?Data1 ?忸溴 羼螯, 蝾 桴 磬漕 觐礅屦蜩痤忄螯
|
||||
{
|
||||
// 镥疱躅?镱 耢妁屙棹 桤 offsData1 我 桌?牦耜?
|
||||
mf.seek(base_pos + LiqOffsData->offsData1);
|
||||
mf.read(LiqChunkData1, 0x18); // 聍栩�噱?襦扈 溧眄� ?耱痼牝箴?蜩镟 MH2O_Data1
|
||||
// 玎眍耔?溧眄� 綦嚆?潆� 牦耜?
|
||||
if(LiqType[LiqChunkData1->LiquidTypeId] == 0xffff)
|
||||
printf("\nCan't find Liquid type for map %s\nchunk %d\n", filename, chunk_num);
|
||||
else if(LiqType[LiqChunkData1->LiquidTypeId] == LIQUID_TYPE_WATER || LiqType[LiqChunkData1->LiquidTypeId] == LIQUID_TYPE_OCEAN)
|
||||
MapLiqFlag[chunk_num] |= 1; // water/ocean
|
||||
else if(LiqType[LiqChunkData1->LiquidTypeId] == LIQUID_TYPE_MAGMA || LiqType[LiqChunkData1->LiquidTypeId] == LIQUID_TYPE_SLIME)
|
||||
MapLiqFlag[chunk_num] |= 2; // magma/slime
|
||||
// 镳邃忄痂蝈朦眍 玎镱腠�屐 忮顸 牦耦?溧眄�?- 礤?忸潲
|
||||
for(int j = 0; j < 81; ++j)
|
||||
{
|
||||
ChunkLiqHeight[j] = -999999; // no liquid/water
|
||||
}
|
||||
// 蝈镥瘘 恹麒耠�屐 蝈 黩??忸漕??镥疱玎镨覃忄屐 桴 ?牦耜?
|
||||
for(int b = 0; b <= LiqChunkData1->height; ++b)
|
||||
{
|
||||
for(int c = LiqChunkData1->xOffset; c <= (LiqChunkData1->xOffset + LiqChunkData1->width); ++c)
|
||||
{
|
||||
int n = (9 * (LiqChunkData1->yOffset + b)) + c;
|
||||
ChunkLiqHeight[n] = LiqChunkData1->heightLevel1;
|
||||
}
|
||||
}
|
||||
mf.seek(header_pos); // ?礤 玎猁螯 忮痦篁�� 磬 桉躅漤簋 镱玷鲨?桁屙眍 ?杖呐信
|
||||
}
|
||||
else // 羼腓 溧眄� ?Data1 礤? 蝾 磬漕 玎镱腠栩?忮顸 牦耦? 眍 溧眄�?- 礤?忸潲
|
||||
{
|
||||
for(int j = 0; j < 81; ++j)
|
||||
ChunkLiqHeight[j] = -999999; // no liquid/water
|
||||
}
|
||||
|
||||
if(!(chunk_num % 16))
|
||||
m = 1024 * (chunk_num / 16); // 耢妁屙桢 镱 ?溧?牦耜钼 ?镥疱牮�桢?= 1024
|
||||
k = m + (chunk_num % 16) * 8; // 篑蜞磬怆桠噱祚� 磬 磬鬣朦睇?桧溴犟 潆� 玎镱腠屙? ?溧
|
||||
// 玎眍耔?溧眄� 牦耜??爨耨桠 潆� 赅痱? ?镥疱牮�桢??钺疱玎龛屐 牦耜钼 蜿 溧眄� 81
|
||||
// �?囗嚯钽 耱囵钽?钺疱玎龛� 沭囗梓睇?镳噔�-犷觐恹??龛骓桴 溧眄�
|
||||
for(int p = 0; p < 72; p += 9) // 龛骓桢 8 礤 玎眍耔?蜿 铐?潴犭桊箦蝰� 耠邃 牦耜铎
|
||||
{
|
||||
for(int s = 0; s < 8; ++s) // 9 珥圜屙桢 ?耱痤赍 礤 玎眍耔?蜿 铐?潴犭桊箦蝰� 耠邃 牦耜铎, ??镳恹?犷觐恹?钺疱玎弪? 潆� 128?28
|
||||
{
|
||||
MapLiqHeight[k] = ChunkLiqHeight[p + s];
|
||||
++k;
|
||||
}
|
||||
k = k + 120;
|
||||
}
|
||||
}
|
||||
delete LiqOffsData;
|
||||
delete LiqChunkData1;
|
||||
delete []ChunkLiqHeight;
|
||||
|
||||
}
|
||||
//case 0x4d434e4b: // MCNK
|
||||
//case 0x4d46424f: // MFBO new in BC
|
||||
//case 0x4d545846: // MTXF new in WotLK
|
||||
mf.seek(nextpos);
|
||||
}
|
||||
|
||||
//printf("Loading chunks info\n");
|
||||
// read individual map chunks
|
||||
chunk_num = 0;
|
||||
k = 0;
|
||||
m = 0;
|
||||
for (int j = 0; j < 16; ++j)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
mf.seek((int)mcnk_offsets[j * 16 + i]);
|
||||
LoadMapChunk(mf, &(mcells->ch[i][j]));
|
||||
++chunk_num;
|
||||
}
|
||||
}
|
||||
mf.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isHole(int holes, int i, int j)
|
||||
{
|
||||
int testi = i / 2;
|
||||
int testj = j / 4;
|
||||
if(testi > 3) testi = 3;
|
||||
if(testj > 3) testj = 3;
|
||||
return (holes & holetab_h[testi] & holetab_v[testj]) != 0;
|
||||
}
|
||||
|
||||
inline void LoadMapChunk(MPQFile &mf, chunk *_chunk)
|
||||
{
|
||||
float h;
|
||||
uint32 fourcc;
|
||||
uint32 size;
|
||||
MapChunkHeader header;
|
||||
|
||||
mf.seekRelative(4);
|
||||
mf.read(&size, 4);
|
||||
|
||||
size_t lastpos = mf.getPos() + size;
|
||||
mf.read(&header, 0x80); // what if header size got changed?
|
||||
_chunk->area_id = header.areaid;
|
||||
|
||||
float xbase = header.xpos;
|
||||
float ybase = header.ypos;
|
||||
float zbase = header.zpos;
|
||||
zbase = TILESIZE * 32 - zbase;
|
||||
xbase = TILESIZE * 32 - xbase;
|
||||
if(wmoc.x > xbase) wmoc.x = xbase;
|
||||
if(wmoc.z > zbase) wmoc.z = zbase;
|
||||
int chunkflags = header.flags;
|
||||
//printf("LMC: flags %X\n", chunkflags);
|
||||
float zmin = 999999999.0f;
|
||||
float zmax = -999999999.0f;
|
||||
// must be there, bl!zz uses some crazy format
|
||||
while (mf.getPos() < lastpos)
|
||||
{
|
||||
mf.read(&fourcc, 4);
|
||||
mf.read(&size, 4);
|
||||
size_t nextpos = mf.getPos() + size;
|
||||
if(fourcc == 0x4d435654) // MCVT
|
||||
{
|
||||
for (int j = 0; j < 17; ++j)
|
||||
{
|
||||
for (int i = 0; i < ((j % 2) ? 8 : 9); ++i)
|
||||
{
|
||||
mf.read(&h, 4);
|
||||
float z = h + ybase;
|
||||
if (j % 2)
|
||||
{
|
||||
if(isHole(header.holes, i, j))
|
||||
_chunk->v8[i][j / 2] = -1000;
|
||||
else
|
||||
_chunk->v8[i][j / 2] = z;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isHole(header.holes, i, j))
|
||||
_chunk->v9[i][j / 2] = -1000;
|
||||
else
|
||||
_chunk->v9[i][j / 2] = z;
|
||||
}
|
||||
|
||||
if(z > zmax) zmax = z;
|
||||
//if(z < zmin) zmin = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(fourcc == 0x4d434e52) // MCNR
|
||||
{
|
||||
nextpos = mf.getPos() + 0x1C0; // size fix
|
||||
}
|
||||
else if(fourcc == 0x4d434c51) // 礤 狍溴?篦栩�囹?羼腓 箧?猁腓 溧眄� ?MH2O, 镥疱耱疣躅怅?:) // MCLQ
|
||||
{
|
||||
// liquid / water level
|
||||
char fcc1[5];
|
||||
mf.read(fcc1, 4);
|
||||
flipcc(fcc1);
|
||||
fcc1[4] = 0;
|
||||
float *ChunkLiqHeight = new float[81];
|
||||
|
||||
if (!strcmp(fcc1, "MCSE"))
|
||||
{
|
||||
for(int j = 0; j < 81; ++j)
|
||||
{
|
||||
ChunkLiqHeight[j] = -999999; // no liquid/water
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float maxheight;
|
||||
mf.read(&maxheight, 4);
|
||||
for(int j = 0; j < 81; ++j)
|
||||
{
|
||||
LiqData liq;
|
||||
mf.read(&liq, 8);
|
||||
|
||||
if(liq.height > maxheight)
|
||||
ChunkLiqHeight[j] = -999999;
|
||||
else
|
||||
ChunkLiqHeight[j] = h;
|
||||
}
|
||||
|
||||
if(chunkflags & 4 || chunkflags & 8)
|
||||
MapLiqFlag[chunk_num] |= 1; // water
|
||||
if(chunkflags & 16)
|
||||
MapLiqFlag[chunk_num] |= 2; // magma/slime
|
||||
}
|
||||
// 囡铍礤?蜞?驽 赅??MH2O
|
||||
if(!(chunk_num % 16))
|
||||
m = 1024 * (chunk_num / 16);
|
||||
k = m + (chunk_num % 16) * 8;
|
||||
|
||||
for(int p = 0; p < 72; p += 9)
|
||||
{
|
||||
for(int s = 0; s < 8; ++s)
|
||||
{
|
||||
MapLiqHeight[k] = ChunkLiqHeight[p + s];
|
||||
++k;
|
||||
}
|
||||
k = k + 120;
|
||||
}
|
||||
delete []ChunkLiqHeight;
|
||||
break;
|
||||
}
|
||||
mf.seek(nextpos);
|
||||
}
|
||||
}
|
||||
|
||||
inline void TransformData()
|
||||
{
|
||||
cell = new Cell;
|
||||
|
||||
for(uint32 x = 0; x < 128; ++x)
|
||||
{
|
||||
for(uint32 y = 0; y < 128; ++y)
|
||||
{
|
||||
cell->v8[y][x] = (float)mcells->ch[x / 8][y / 8].v8[x % 8][y % 8];
|
||||
cell->v9[y][x] = (float)mcells->ch[x / 8][y / 8].v9[x % 8][y % 8];
|
||||
}
|
||||
|
||||
// extra 1 point on bounds
|
||||
cell->v9[128][x] = (float)mcells->ch[x / 8][15].v9[x % 8][8];
|
||||
// x == y
|
||||
cell->v9[x][128] = (float)mcells->ch[15][x / 8].v9[8][x % 8];
|
||||
}
|
||||
|
||||
// and the last 1
|
||||
cell->v9[128][128] = (float)mcells->ch[15][15].v9[8][8];
|
||||
|
||||
delete mcells;
|
||||
}
|
||||
|
||||
const char MAP_MAGIC[] = "MAP_3.00";
|
||||
|
||||
bool ConvertADT(char *filename, char *filename2)
|
||||
{
|
||||
if(!LoadADT(filename))
|
||||
return false;
|
||||
|
||||
FILE *output=fopen(filename2, "wb");
|
||||
if(!output)
|
||||
{
|
||||
printf("Can't create the output file '%s'\n", filename2);
|
||||
delete [] MapLiqHeight;
|
||||
delete [] MapLiqFlag;
|
||||
return false;
|
||||
}
|
||||
|
||||
// write magic header
|
||||
fwrite(MAP_MAGIC, 1, 8, output);
|
||||
|
||||
for(uint32 x = 0; x < 16; ++x)
|
||||
{
|
||||
for(uint32 y = 0; y < 16; ++y)
|
||||
{
|
||||
if(mcells->ch[y][x].area_id && mcells->ch[y][x].area_id <= maxAreaId)
|
||||
{
|
||||
if(areas[mcells->ch[y][x].area_id] == 0xffff)
|
||||
printf("\nCan't find area flag for areaid %u.\n", mcells->ch[y][x].area_id);
|
||||
|
||||
fwrite(&areas[mcells->ch[y][x].area_id], 1, 2, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16 flag = 0xffff;
|
||||
fwrite(&flag, 1, 2, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fwrite(MapLiqFlag, 1, 256, output);
|
||||
delete [] MapLiqFlag;
|
||||
|
||||
fwrite(MapLiqHeight, sizeof(float), 16384, output);
|
||||
delete [] MapLiqHeight;
|
||||
|
||||
TransformData();
|
||||
|
||||
|
||||
fwrite(&cell->v9, 1, sizeof(cell->v9), output);
|
||||
fwrite(&cell->v8, 1, sizeof(cell->v8), output);
|
||||
fclose(output);
|
||||
delete cell;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#ifndef ADT_H
|
||||
#define ADT_H
|
||||
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
#define UNITSIZE (CHUNKSIZE / 8.0f)
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
class Liquid;
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} svec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} vec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec v[3];
|
||||
} triangle;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float v9[16 * 8 + 1][16 * 8 + 1];
|
||||
float v8[16 * 8][16 * 8];
|
||||
} Cell;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double v9[9][9];
|
||||
double v8[8][8];
|
||||
uint16 area_id;
|
||||
} chunk;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
chunk ch[16][16];
|
||||
} mcell;
|
||||
|
||||
struct MapChunkHeader
|
||||
{
|
||||
uint32 flags;
|
||||
uint32 ix;
|
||||
uint32 iy;
|
||||
uint32 nLayers;
|
||||
uint32 nDoodadRefs;
|
||||
uint32 ofsHeight;
|
||||
uint32 ofsNormal;
|
||||
uint32 ofsLayer;
|
||||
uint32 ofsRefs;
|
||||
uint32 ofsAlpha;
|
||||
uint32 sizeAlpha;
|
||||
uint32 ofsShadow;
|
||||
uint32 sizeShadow;
|
||||
uint32 areaid;
|
||||
uint32 nMapObjRefs;
|
||||
uint32 holes;
|
||||
uint16 s1;
|
||||
uint16 s2;
|
||||
uint32 d1;
|
||||
uint32 d2;
|
||||
uint32 d3;
|
||||
uint32 predTex;
|
||||
uint32 nEffectDoodad;
|
||||
uint32 ofsSndEmitters;
|
||||
uint32 nSndEmitters;
|
||||
uint32 ofsLiquid; // not use in WotLK
|
||||
uint32 sizeLiquid; // not use in WotLK
|
||||
float zpos;
|
||||
float xpos;
|
||||
float ypos;
|
||||
uint32 textureId; // new offsColorValues in WotLK
|
||||
uint32 props;
|
||||
uint32 effectId;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 offsData1;
|
||||
uint32 used;
|
||||
uint32 offsData2;
|
||||
} MH2O_offsData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16 LiquidTypeId;
|
||||
uint16 type;
|
||||
float heightLevel1;
|
||||
float heightLevel2;
|
||||
uint8 xOffset;
|
||||
uint8 yOffset;
|
||||
uint8 width;
|
||||
uint8 height;
|
||||
uint32 ofsData2a;
|
||||
uint32 ofsData2b;
|
||||
} MH2O_Data1;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16 unk1;
|
||||
uint16 unk2;
|
||||
float height;
|
||||
} LiqData;
|
||||
|
||||
enum LiquidType
|
||||
{
|
||||
LIQUID_TYPE_WATER = 0,
|
||||
LIQUID_TYPE_OCEAN = 1,
|
||||
LIQUID_TYPE_MAGMA = 2,
|
||||
LIQUID_TYPE_SLIME = 3
|
||||
};
|
||||
|
||||
class MPQFile;
|
||||
|
||||
float *MapLiqHeight;
|
||||
uint8 *MapLiqFlag;
|
||||
uint32 k, m, chunk_num;
|
||||
void LoadMapChunk(MPQFile &, chunk*);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "dbcfile.h"
|
||||
#include "mpq_libmpq.h"
|
||||
|
||||
DBCFile::DBCFile(const std::string &filename):
|
||||
filename(filename),
|
||||
data(0)
|
||||
{
|
||||
|
||||
}
|
||||
bool DBCFile::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
char header[4];
|
||||
unsigned int na,nb,es,ss;
|
||||
|
||||
if(f.read(header,4)!=4) // Number of records
|
||||
return false;
|
||||
|
||||
if(header[0]!='W' || header[1]!='D' || header[2]!='B' || header[3]!='C')
|
||||
return false;
|
||||
|
||||
if(f.read(&na,4)!=4) // Number of records
|
||||
return false;
|
||||
if(f.read(&nb,4)!=4) // Number of fields
|
||||
return false;
|
||||
if(f.read(&es,4)!=4) // Size of a record
|
||||
return false;
|
||||
if(f.read(&ss,4)!=4) // String size
|
||||
return false;
|
||||
|
||||
recordSize = es;
|
||||
recordCount = na;
|
||||
fieldCount = nb;
|
||||
stringSize = ss;
|
||||
if(fieldCount*4 != recordSize)
|
||||
return false;
|
||||
|
||||
data = new unsigned char[recordSize*recordCount+stringSize];
|
||||
stringTable = data + recordSize*recordCount;
|
||||
|
||||
size_t data_size = recordSize*recordCount+stringSize;
|
||||
if(f.read(data,data_size)!=data_size)
|
||||
return false;
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
DBCFile::~DBCFile()
|
||||
{
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
DBCFile::Record DBCFile::getRecord(size_t id)
|
||||
{
|
||||
assert(data);
|
||||
return Record(*this, data + id*recordSize);
|
||||
}
|
||||
|
||||
size_t DBCFile::getMaxId()
|
||||
{
|
||||
assert(data);
|
||||
|
||||
size_t maxId = 0;
|
||||
for(size_t i = 0; i < getRecordCount(); ++i)
|
||||
{
|
||||
if(maxId < getRecord(i).getUInt(0))
|
||||
maxId = getRecord(i).getUInt(0);
|
||||
}
|
||||
return maxId;
|
||||
}
|
||||
|
||||
DBCFile::Iterator DBCFile::begin()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, data);
|
||||
}
|
||||
DBCFile::Iterator DBCFile::end()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, stringTable);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
#ifndef DBCFILE_H
|
||||
#define DBCFILE_H
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
class DBCFile
|
||||
{
|
||||
public:
|
||||
DBCFile(const std::string &filename);
|
||||
~DBCFile();
|
||||
|
||||
// Open database. It must be openened before it can be used.
|
||||
bool open();
|
||||
|
||||
// Database exceptions
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
Exception(const std::string &message): message(message)
|
||||
{ }
|
||||
virtual ~Exception()
|
||||
{ }
|
||||
const std::string &getMessage() {return message;}
|
||||
private:
|
||||
std::string message;
|
||||
};
|
||||
class NotFound: public Exception
|
||||
{
|
||||
public:
|
||||
NotFound(): Exception("Key was not found")
|
||||
{ }
|
||||
};
|
||||
// Iteration over database
|
||||
class Iterator;
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
float getFloat(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<float*>(offset+field*4);
|
||||
}
|
||||
unsigned int getUInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<unsigned int*>(offset+field*4);
|
||||
}
|
||||
int getInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<int*>(offset+field*4);
|
||||
}
|
||||
const char *getString(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
size_t stringOffset = getUInt(field);
|
||||
assert(stringOffset < file.stringSize);
|
||||
return reinterpret_cast<char*>(file.stringTable + stringOffset);
|
||||
}
|
||||
private:
|
||||
Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {}
|
||||
unsigned char *offset;
|
||||
DBCFile &file;
|
||||
|
||||
friend class DBCFile;
|
||||
friend class DBCFile::Iterator;
|
||||
};
|
||||
/** Iterator that iterates over records
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(DBCFile &file, unsigned char *offset):
|
||||
record(file, offset) {}
|
||||
/// Advance (prefix only)
|
||||
Iterator & operator++() {
|
||||
record.offset += record.file.recordSize;
|
||||
return *this;
|
||||
}
|
||||
/// Return address of current instance
|
||||
Record const & operator*() const { return record; }
|
||||
const Record* operator->() const {
|
||||
return &record;
|
||||
}
|
||||
/// Comparison
|
||||
bool operator==(const Iterator &b) const
|
||||
{
|
||||
return record.offset == b.record.offset;
|
||||
}
|
||||
bool operator!=(const Iterator &b) const
|
||||
{
|
||||
return record.offset != b.record.offset;
|
||||
}
|
||||
private:
|
||||
Record record;
|
||||
};
|
||||
|
||||
// Get record by id
|
||||
Record getRecord(size_t id);
|
||||
/// Get begin iterator over records
|
||||
Iterator begin();
|
||||
/// Get begin iterator over records
|
||||
Iterator end();
|
||||
/// Trivial
|
||||
size_t getRecordCount() const { return recordCount;}
|
||||
size_t getFieldCount() const { return fieldCount; }
|
||||
size_t getMaxId();
|
||||
private:
|
||||
std::string filename;
|
||||
size_t recordSize;
|
||||
size_t recordCount;
|
||||
size_t fieldCount;
|
||||
size_t stringSize;
|
||||
unsigned char *data;
|
||||
unsigned char *stringTable;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
add_library (libmpq common.cpp explode.cpp extract.cpp huffman.cpp mpq.cpp parser.cpp wave.cpp )
|
||||
# link libmpq with zlib
|
||||
target_link_libraries (libmpq z)
|
||||
@@ -0,0 +1,802 @@
|
||||
/*
|
||||
* common.c -- shared functions used by mpq-tools.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* $Id: common.c,v 1.12 2004/02/12 00:42:54 mbroemme Exp $
|
||||
*/
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
//#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
//#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "mpq.h"
|
||||
#include "common.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
* This function decrypts a MPQ block.
|
||||
*/
|
||||
int libmpq_decrypt_block(mpq_archive *mpq_a, unsigned int *block, unsigned int length, unsigned int seed1) {
|
||||
unsigned int seed2 = 0xEEEEEEEE;
|
||||
unsigned int ch;
|
||||
|
||||
/* Round to unsigned int's */
|
||||
length >>= 2;
|
||||
while (length-- > 0) {
|
||||
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
|
||||
ch = *block ^ (seed1 + seed2);
|
||||
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
|
||||
seed2 = ch + seed2 + (seed2 << 5) + 3;
|
||||
*block++ = ch;
|
||||
}
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function decrypts the hashtable for the
|
||||
* file informations.
|
||||
*/
|
||||
int libmpq_decrypt_hashtable(mpq_archive *mpq_a, unsigned char *pbKey) {
|
||||
unsigned int seed1 = 0x7FED7FED;
|
||||
unsigned int seed2 = 0xEEEEEEEE;
|
||||
unsigned int ch; /* One key character */
|
||||
unsigned int *pdwTable = (unsigned int *)(mpq_a->hashtable);
|
||||
unsigned int length = mpq_a->header->hashtablesize * 4;
|
||||
|
||||
/* Prepare seeds */
|
||||
while (*pbKey != 0) {
|
||||
ch = toupper(*pbKey++);
|
||||
seed1 = mpq_a->buf[0x300 + ch] ^ (seed1 + seed2);
|
||||
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
|
||||
}
|
||||
|
||||
/* Decrypt it */
|
||||
seed2 = 0xEEEEEEEE;
|
||||
while (length-- > 0) {
|
||||
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
|
||||
ch = *pdwTable ^ (seed1 + seed2);
|
||||
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
|
||||
seed2 = ch + seed2 + (seed2 << 5) + 3;
|
||||
*pdwTable++ = ch;
|
||||
}
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function decrypts the blocktable.
|
||||
*/
|
||||
int libmpq_decrypt_blocktable(mpq_archive *mpq_a, unsigned char *pbKey) {
|
||||
unsigned int seed1 = 0x7FED7FED;
|
||||
unsigned int seed2 = 0xEEEEEEEE;
|
||||
unsigned int ch; /* One key character */
|
||||
unsigned int *pdwTable = (unsigned int *)(mpq_a->blocktable);
|
||||
unsigned int length = mpq_a->header->blocktablesize * 4;
|
||||
|
||||
/* Prepare seeds */
|
||||
while(*pbKey != 0) {
|
||||
ch = toupper(*pbKey++);
|
||||
seed1 = mpq_a->buf[0x300 + ch] ^ (seed1 + seed2);
|
||||
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
|
||||
}
|
||||
|
||||
/* Decrypt it */
|
||||
seed2 = 0xEEEEEEEE;
|
||||
while(length-- > 0) {
|
||||
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
|
||||
ch = *pdwTable ^ (seed1 + seed2);
|
||||
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
|
||||
seed2 = ch + seed2 + (seed2 << 5) + 3;
|
||||
*pdwTable++ = ch;
|
||||
}
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
int libmpq_read_listfile(mpq_archive *mpq_a, FILE *fp) {
|
||||
int mpq_size;
|
||||
int mpq_ht_size;
|
||||
int mpq_bt_size;
|
||||
int mpq_blocksize;
|
||||
int mpq_files;
|
||||
int mpq_csize;
|
||||
int mpq_fsize;
|
||||
int entries;
|
||||
char listdb_version[10];
|
||||
char libmpq_version[10];
|
||||
int listdb_temp_version = 0;
|
||||
int libmpq_temp_version = 0;
|
||||
|
||||
/* first check header and version */
|
||||
if (libmpq_conf_get_value(fp, "LIBMPQ_VERSION", mpq_a->mpq_l->mpq_version, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_version))) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
} else {
|
||||
|
||||
/* copy to temp buffer for removing . characters */
|
||||
sprintf(listdb_version, (char *)mpq_a->mpq_l->mpq_version);
|
||||
|
||||
/* remove . characters from listfile version */
|
||||
libmpq_conf_delete_char(listdb_version, ".");
|
||||
|
||||
/* get libmpq version */
|
||||
sprintf(libmpq_version, "%i%i%i",LIBMPQ_MAJOR_VERSION, LIBMPQ_MINOR_VERSION, LIBMPQ_PATCH_VERSION);
|
||||
|
||||
/* convert to number */
|
||||
listdb_temp_version = atoi(listdb_version);
|
||||
libmpq_temp_version = atoi(libmpq_version);
|
||||
|
||||
/* check if installed libmpq version is valid for listfile version */
|
||||
if ((libmpq_temp_version < listdb_temp_version) || (libmpq_temp_version == 0) || (listdb_temp_version == 0)) {
|
||||
return LIBMPQ_CONF_EFILE_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
/* check listfile header, the following entries must be set */
|
||||
if (libmpq_conf_get_value(fp, "MPQ_SIZE", &mpq_size, LIBMPQ_CONF_TYPE_INT, 0)) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
if (libmpq_conf_get_value(fp, "MPQ_HASHTABLE_SIZE", &mpq_ht_size, LIBMPQ_CONF_TYPE_INT, 0)) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
if (libmpq_conf_get_value(fp, "MPQ_BLOCKTABLE_SIZE", &mpq_bt_size, LIBMPQ_CONF_TYPE_INT, 0)) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
if (libmpq_conf_get_value(fp, "MPQ_BLOCKSIZE", &mpq_blocksize, LIBMPQ_CONF_TYPE_INT, 0)) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
if (libmpq_conf_get_value(fp, "MPQ_FILES", &mpq_files, LIBMPQ_CONF_TYPE_INT, 0)) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
if (libmpq_conf_get_value(fp, "MPQ_COMPRESSED_SIZE", &mpq_csize, LIBMPQ_CONF_TYPE_INT, 0)) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
if (libmpq_conf_get_value(fp, "MPQ_UNCOMPRESSED_SIZE", &mpq_fsize, LIBMPQ_CONF_TYPE_INT, 0)) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
if (libmpq_conf_get_value(fp, "MPQ_NAME", mpq_a->mpq_l->mpq_name, LIBMPQ_CONF_TYPE_CHAR, PATH_MAX)) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
if (libmpq_conf_get_value(fp, "MPQ_TYPE", mpq_a->mpq_l->mpq_type, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_type))) {
|
||||
return LIBMPQ_CONF_EFILE_CORRUPT;
|
||||
}
|
||||
|
||||
/* these are optional parameters, if they are empty we set the struct members empty */
|
||||
libmpq_conf_get_value(fp, "MPQ_GAME", mpq_a->mpq_l->mpq_game, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_game));
|
||||
libmpq_conf_get_value(fp, "MPQ_GAME_VERSION", mpq_a->mpq_l->mpq_game_version, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_game_version));
|
||||
|
||||
/* check if we found a valid listfile for the given archive */
|
||||
if (mpq_a->header->hashtablesize == mpq_ht_size && mpq_a->header->blocktablesize == mpq_bt_size && mpq_a->blocksize == mpq_blocksize && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_ARCHIVE_SIZE) == mpq_size && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) == mpq_files && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_COMPRESSED_SIZE) == mpq_csize && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_UNCOMPRESSED_SIZE) == mpq_fsize) {
|
||||
|
||||
/* check if the filelist is correct */
|
||||
if (!libmpq_conf_get_array(fp, "FILE_NAMES", (char ***)&mpq_a->mpq_l->mpq_files, &entries)) {
|
||||
|
||||
/* we have a corrupt filelist, so return */
|
||||
return LIBMPQ_CONF_EFILE_LIST_CORRUPT;
|
||||
} else {
|
||||
|
||||
/* now check if filelist entries matches number of files in the archive. */
|
||||
if (entries != libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES)) {
|
||||
libmpq_free_listfile((char **)mpq_a->mpq_l->mpq_files);
|
||||
mpq_a->mpq_l->mpq_files = NULL;
|
||||
return LIBMPQ_CONF_EFILE_LIST_CORRUPT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function frees up the space reserved by libmpq_get_listfile()
|
||||
*/
|
||||
int libmpq_free_listfile(char **filelist) {
|
||||
int i = 0;
|
||||
while (filelist[i]) {
|
||||
free(filelist[i++]);
|
||||
}
|
||||
free(filelist);
|
||||
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reads the directory and the subdirectories
|
||||
* of the listfile database and adds a entry to the lisfile
|
||||
* array.
|
||||
*/
|
||||
/*int libmpq_detect_listfile_rec(char path[PATH_MAX], char ***filelist, int *fl_count, int *fl_size) {
|
||||
char nextpath[PATH_MAX];
|
||||
DIR *dp = opendir(path);
|
||||
FILE *fp;
|
||||
struct dirent *entry;
|
||||
struct stat statbuf;
|
||||
char buf[LIBMPQ_CONF_BUFSIZE];
|
||||
|
||||
if (dp == NULL) {
|
||||
return LIBMPQ_CONF_EOPEN_DIR;
|
||||
} else {
|
||||
while ((entry = readdir(dp)) != NULL) {
|
||||
if (strncmp(entry->d_name, ".", 1) == 0 || strncmp(entry->d_name, "..", 2) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (strnlen(path, PATH_MAX) + strnlen(entry->d_name, PATH_MAX) + 2 > sizeof nextpath) {
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(nextpath, PATH_MAX, "%s/%s", path, entry->d_name);
|
||||
|
||||
// check if file extension matches listdb file extension
|
||||
if (strncmp(&entry->d_name[strlen(entry->d_name) - strlen(LIBMPQ_CONF_EXT)], LIBMPQ_CONF_EXT, strlen(LIBMPQ_CONF_EXT)) == 0) {
|
||||
|
||||
// check if it is really a listdb file
|
||||
if ((fp = fopen(nextpath, "r")) != NULL ) {
|
||||
while (fgets(buf, LIBMPQ_CONF_BUFSIZE, fp) != NULL) {
|
||||
char *line;
|
||||
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
// skip whitespace
|
||||
for (line = buf; isspace(*line); line++) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip empty line
|
||||
if (line[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip comments
|
||||
if (line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
//search for listdb header; dirty but works :)
|
||||
if (!strncasecmp(line, LIBMPQ_CONF_HEADER, strlen(LIBMPQ_CONF_HEADER))) {
|
||||
|
||||
// set the next filelist entry to a copy of the file path
|
||||
(*filelist)[(*fl_count)++] = strdup(nextpath);
|
||||
|
||||
// increase the array size
|
||||
if ((*fl_count) == (*fl_size)) {
|
||||
(*filelist) = realloc((*filelist), ((*fl_size) + LIBMPQ_CONF_FL_INCREMENT) * sizeof(char *));
|
||||
(*fl_size) += LIBMPQ_CONF_FL_INCREMENT;
|
||||
}
|
||||
|
||||
// header found so we could stop reading the file.
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
if (stat(nextpath, &statbuf) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if entry ia a subdirectory, read it
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
libmpq_detect_listfile_rec(nextpath, filelist, fl_count, fl_size);
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* This functions tries to get file decryption key. The trick comes from block
|
||||
* positions which are stored at the begin of each compressed file. We know the
|
||||
* file size, that means we know number of blocks that means we know the first
|
||||
* int value in block position. And if we know encrypted and decrypted value,
|
||||
* we can find the decryption key.
|
||||
*/
|
||||
int libmpq_detect_fileseed(mpq_archive *mpq_a, unsigned int *block, unsigned int decrypted) {
|
||||
unsigned int saveseed1;
|
||||
unsigned int temp = *block ^ decrypted; /* temp = seed1 + seed2 */
|
||||
int i = 0;
|
||||
temp -= 0xEEEEEEEE; /* temp = seed1 + mpq_a->buf[0x400 + (seed1 & 0xFF)] */
|
||||
|
||||
for (i = 0; i < 0x100; i++) { /* Try all 255 possibilities */
|
||||
unsigned int seed1;
|
||||
unsigned int seed2 = 0xEEEEEEEE;
|
||||
unsigned int ch;
|
||||
|
||||
/* Try the first unsigned int's (We exactly know the value) */
|
||||
seed1 = temp - mpq_a->buf[0x400 + i];
|
||||
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
|
||||
ch = block[0] ^ (seed1 + seed2);
|
||||
|
||||
if (ch != decrypted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add 1 because we are decrypting block positions */
|
||||
saveseed1 = seed1 + 1;
|
||||
|
||||
/*
|
||||
* If OK, continue and test the second value. We don't know exactly the value,
|
||||
* but we know that the second one has lower 16 bits set to zero
|
||||
* (no compressed block is larger than 0xFFFF bytes)
|
||||
*/
|
||||
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
|
||||
seed2 = ch + seed2 + (seed2 << 5) + 3;
|
||||
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
|
||||
ch = block[1] ^ (seed1 + seed2);
|
||||
if ((ch & 0xFFFF0000) == 0) {
|
||||
return saveseed1;
|
||||
}
|
||||
}
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initialize the decryption buffer
|
||||
*/
|
||||
int libmpq_init_buffer(mpq_archive *mpq_a) {
|
||||
unsigned int seed = 0x00100001;
|
||||
unsigned int index1 = 0;
|
||||
unsigned int index2 = 0;
|
||||
int i;
|
||||
|
||||
memset(mpq_a->buf, 0, sizeof(mpq_a->buf));
|
||||
|
||||
/* Initialize the decryption buffer. */
|
||||
for (index1 = 0; index1 < 0x100; index1++) {
|
||||
for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100) {
|
||||
unsigned int temp1, temp2;
|
||||
seed = (seed * 125 + 3) % 0x2AAAAB;
|
||||
temp1 = (seed & 0xFFFF) << 0x10;
|
||||
|
||||
seed = (seed * 125 + 3) % 0x2AAAAB;
|
||||
temp2 = (seed & 0xFFFF);
|
||||
|
||||
mpq_a->buf[index2] = (temp1 | temp2);
|
||||
}
|
||||
}
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This functions fills the mpq_hash structure with the
|
||||
* hashtable found in the MPQ file. The hashtable will
|
||||
* be decrypted for later use.
|
||||
*/
|
||||
int libmpq_read_hashtable(mpq_archive *mpq_a) {
|
||||
unsigned int bytes = 0;
|
||||
int rb = 0;
|
||||
|
||||
/*
|
||||
* Allocate memory. Note that the block table should be as large as the
|
||||
* hash table. (for later file additions)
|
||||
*/
|
||||
mpq_a->hashtable = (mpq_hash *)malloc(sizeof(mpq_hash) * mpq_a->header->hashtablesize);
|
||||
|
||||
if (!mpq_a->hashtable) {
|
||||
return LIBMPQ_EALLOCMEM;
|
||||
}
|
||||
|
||||
/* Read the hash table into the buffer */
|
||||
bytes = mpq_a->header->hashtablesize * sizeof(mpq_hash);
|
||||
|
||||
#ifdef WIN32
|
||||
_lseeki64(mpq_a->fd, mpq_a->header->hashtablepos, SEEK_SET);
|
||||
#else
|
||||
lseek64(mpq_a->fd, mpq_a->header->hashtablepos, SEEK_SET);
|
||||
#endif
|
||||
|
||||
rb = _read(mpq_a->fd, mpq_a->hashtable, bytes);
|
||||
if (rb != bytes) {
|
||||
return LIBMPQ_EFILE_CORRUPT;
|
||||
}
|
||||
|
||||
/* Decrypt hash table and check if it is correctly decrypted */
|
||||
mpq_hash *mpq_h_end = mpq_a->hashtable + mpq_a->header->hashtablesize;
|
||||
mpq_hash *mpq_h = NULL;
|
||||
|
||||
libmpq_decrypt_hashtable(mpq_a, (unsigned char *)"(hash table)");
|
||||
|
||||
/* Check hash table if is correctly decrypted */
|
||||
for (mpq_h = mpq_a->hashtable; mpq_h < mpq_h_end; mpq_h++) {
|
||||
if (mpq_h->locale != 0xFFFFFFFF && (mpq_h->locale & 0xFFFF0000) != 0) {
|
||||
return LIBMPQ_EFILE_FORMAT;
|
||||
}
|
||||
|
||||
/* Remember the highest block table entry */
|
||||
if (mpq_h->blockindex < LIBMPQ_HASH_ENTRY_DELETED && mpq_h->blockindex > 0) {
|
||||
mpq_a->maxblockindex = mpq_h->blockindex;
|
||||
}
|
||||
}
|
||||
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This functions fills the mpq_block structure with the
|
||||
* blocktable found in the MPQ file. The blocktable will
|
||||
* be decrypted for later use.
|
||||
*
|
||||
* NOTICE: Some MPQs have decrypted block table, e.g.
|
||||
* cracked Diablo versions.
|
||||
*/
|
||||
int libmpq_read_blocktable(mpq_archive *mpq_a) {
|
||||
unsigned int bytes = 0;
|
||||
int rb = 0;
|
||||
|
||||
/*
|
||||
* Allocate memory. Note that the block table should be as large as the
|
||||
* hash table. (for later file additions)
|
||||
*/
|
||||
mpq_a->blocktable = (mpq_block *)malloc(sizeof(mpq_block) * mpq_a->header->hashtablesize);
|
||||
mpq_a->blockbuf = (unsigned char *)malloc(mpq_a->blocksize);
|
||||
|
||||
if (!mpq_a->blocktable || !mpq_a->blockbuf) {
|
||||
return LIBMPQ_EALLOCMEM;
|
||||
}
|
||||
|
||||
/* Read the block table into the buffer */
|
||||
bytes = mpq_a->header->blocktablesize * sizeof(mpq_block);
|
||||
memset(mpq_a->blocktable, 0, mpq_a->header->blocktablesize * sizeof(mpq_block));
|
||||
|
||||
#ifdef WIN32
|
||||
_lseeki64(mpq_a->fd, mpq_a->header->blocktablepos, SEEK_SET);
|
||||
#else
|
||||
lseek64(mpq_a->fd, mpq_a->header->blocktablepos, SEEK_SET);
|
||||
#endif
|
||||
|
||||
rb = _read(mpq_a->fd, mpq_a->blocktable, bytes);
|
||||
if (rb != bytes) {
|
||||
return LIBMPQ_EFILE_CORRUPT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt block table. Some MPQs don't have encrypted block table,
|
||||
* e.g. cracked Diablo version. We have to check if block table is
|
||||
* already decrypted
|
||||
*/
|
||||
mpq_block *mpq_b_end = mpq_a->blocktable + mpq_a->maxblockindex + 1;
|
||||
mpq_block *mpq_b = NULL;
|
||||
unsigned int archivesize = mpq_a->header->archivesize + mpq_a->mpqpos;
|
||||
|
||||
if (mpq_a->header->offset != mpq_a->blocktable->filepos) {
|
||||
libmpq_decrypt_blocktable(mpq_a, (unsigned char *)"(block table)");
|
||||
}
|
||||
for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
|
||||
if (mpq_b->filepos > archivesize || mpq_b->csize > archivesize) {
|
||||
if ((mpq_a->flags & LIBMPQ_FLAG_PROTECTED) == 0) {
|
||||
return LIBMPQ_EFILE_FORMAT;
|
||||
}
|
||||
}
|
||||
mpq_b->filepos += mpq_a->mpqpos;
|
||||
}
|
||||
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
int libmpq_file_read_block(mpq_archive *mpq_a, mpq_file *mpq_f, unsigned int blockpos, char *buffer, unsigned int blockbytes) {
|
||||
unsigned char *tempbuf = NULL; /* Buffer for reading compressed data from the file */
|
||||
unsigned int readpos; /* Reading position from the file */
|
||||
unsigned int toread = 0; /* Number of bytes to read */
|
||||
unsigned int blocknum; /* Block number (needed for decrypt) */
|
||||
unsigned int bytesread = 0; /* Total number of bytes read */
|
||||
unsigned int nblocks; /* Number of blocks to load */
|
||||
unsigned int i;
|
||||
|
||||
/* Test parameters. Block position and block size must be block-aligned, block size nonzero */
|
||||
if ((blockpos & (mpq_a->blocksize - 1)) || blockbytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check the end of file */
|
||||
if ((blockpos + blockbytes) > mpq_f->mpq_b->fsize) {
|
||||
blockbytes = mpq_f->mpq_b->fsize - blockpos;
|
||||
}
|
||||
blocknum = blockpos / mpq_a->blocksize;
|
||||
nblocks = blockbytes / mpq_a->blocksize;
|
||||
if (blockbytes % mpq_a->blocksize) {
|
||||
nblocks++;
|
||||
}
|
||||
|
||||
/* If file has variable block positions, we have to load them */
|
||||
if ((mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) && mpq_f->blockposloaded == FALSE) {
|
||||
unsigned int nread;
|
||||
|
||||
if (mpq_f->mpq_b->filepos != mpq_a->filepos) {
|
||||
#ifdef WIN32
|
||||
_lseeki64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
|
||||
#else
|
||||
lseek64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Read block positions from begin of file. */
|
||||
nread = (mpq_f->nblocks + 1) * sizeof(int);
|
||||
nread = _read(mpq_a->fd, mpq_f->blockpos, nread);
|
||||
|
||||
/*
|
||||
* If the archive is protected some way, perform additional check
|
||||
* Sometimes, the file appears not to be encrypted, but it is.
|
||||
*/
|
||||
/*if (mpq_f->blockpos[0] != nread) {
|
||||
mpq_f->mpq_b->flags |= LIBMPQ_FILE_ENCRYPTED;
|
||||
}*/
|
||||
|
||||
if ((mpq_f->mpq_b->flags & LIBMPQ_FILE_HAS_METADATA) == 0) {
|
||||
if (mpq_f->blockpos[0] != nread) {
|
||||
mpq_f->mpq_b->flags |= LIBMPQ_FILE_ENCRYPTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrypt loaded block positions if necessary */
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_ENCRYPTED) {
|
||||
|
||||
/* If we don't know the file seed, try to find it. */
|
||||
if (mpq_f->seed == 0) {
|
||||
mpq_f->seed = libmpq_detect_fileseed(mpq_a, mpq_f->blockpos, nread);
|
||||
}
|
||||
|
||||
/* If we don't know the file seed, sorry but we cannot extract the file. */
|
||||
if (mpq_f->seed == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decrypt block positions */
|
||||
libmpq_decrypt_block(mpq_a, mpq_f->blockpos, nread, mpq_f->seed - 1);
|
||||
|
||||
/*
|
||||
* Check if the block positions are correctly decrypted
|
||||
* I don't know why, but sometimes it will result invalid
|
||||
* block positions on some files.
|
||||
*/
|
||||
if (mpq_f->blockpos[0] != nread) {
|
||||
|
||||
/* Try once again to detect file seed and decrypt the blocks */
|
||||
|
||||
#ifdef WIN32
|
||||
_lseeki64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
|
||||
#else
|
||||
lseek64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
|
||||
#endif
|
||||
|
||||
nread = _read(mpq_a->fd, mpq_f->blockpos, (mpq_f->nblocks + 1) * sizeof(int));
|
||||
mpq_f->seed = libmpq_detect_fileseed(mpq_a, mpq_f->blockpos, nread);
|
||||
libmpq_decrypt_block(mpq_a, mpq_f->blockpos, nread, mpq_f->seed - 1);
|
||||
|
||||
/* Check if the block positions are correctly decrypted. */
|
||||
if (mpq_f->blockpos[0] != nread) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update mpq_f's variables */
|
||||
mpq_f->blockposloaded = TRUE;
|
||||
mpq_a->filepos = mpq_f->mpq_b->filepos + nread;
|
||||
}
|
||||
|
||||
/* Get file position and number of bytes to read */
|
||||
readpos = blockpos;
|
||||
toread = blockbytes;
|
||||
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
|
||||
readpos = mpq_f->blockpos[blocknum];
|
||||
toread = mpq_f->blockpos[blocknum + nblocks] - readpos;
|
||||
}
|
||||
|
||||
readpos += mpq_f->mpq_b->filepos;
|
||||
|
||||
/* Get work buffer for store read data */
|
||||
if ((tempbuf = (unsigned char *)malloc(toread)) == NULL) {
|
||||
/* Hmmm... We should add a better error handling here :) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set file pointer, if necessary. */
|
||||
if (mpq_a->filepos != readpos) {
|
||||
|
||||
#ifdef WIN32
|
||||
mpq_a->filepos = _lseeki64(mpq_a->fd, readpos, SEEK_SET);
|
||||
#else
|
||||
mpq_a->filepos = lseek64(mpq_a->fd, readpos, SEEK_SET);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* 15018F87 - Read all requested blocks. */
|
||||
bytesread = _read(mpq_a->fd, tempbuf, toread);
|
||||
mpq_a->filepos = readpos + bytesread;
|
||||
|
||||
/* Block processing part. */
|
||||
unsigned int blockstart = 0; /* Index of block start in work buffer. */
|
||||
unsigned int blocksize = min(blockbytes, mpq_a->blocksize);
|
||||
unsigned int index = blocknum; /* Current block index. */
|
||||
bytesread = 0; /* Clear read byte counter */
|
||||
|
||||
/* Walk through all blocks. */
|
||||
for (i = 0; i < nblocks; i++, index++) {
|
||||
int outlength = mpq_a->blocksize;
|
||||
|
||||
/* Get current block length */
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
|
||||
blocksize = mpq_f->blockpos[index + 1] - mpq_f->blockpos[index];
|
||||
}
|
||||
|
||||
/* If block is encrypted, we have to decrypt it. */
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_ENCRYPTED) {
|
||||
if (mpq_f->seed == 0) {
|
||||
return 0;
|
||||
}
|
||||
libmpq_decrypt_block(mpq_a, (unsigned int *)&tempbuf[blockstart], blocksize, mpq_f->seed + index);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the block is really compressed, recompress it.
|
||||
* WARNING: Some block may not be compressed, it can
|
||||
* only be determined by comparing uncompressed and
|
||||
* compressed size!
|
||||
*/
|
||||
if (blocksize < blockbytes) {
|
||||
|
||||
/* Is the file compressed with PKWARE Data Compression Library? */
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESS_PKWARE) {
|
||||
libmpq_pkzip_decompress(buffer, &outlength, (char *)&tempbuf[blockstart], blocksize);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is it a file compressed by Blizzard's multiple compression ?
|
||||
* Note that Storm.dll v 1.0.9 distributed with Warcraft III
|
||||
* passes the full path name of the opened archive as the new
|
||||
* last parameter.
|
||||
*/
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESS_MULTI) {
|
||||
libmpq_multi_decompress(buffer, &outlength, (char *)&tempbuf[blockstart], blocksize);
|
||||
}
|
||||
bytesread += outlength;
|
||||
buffer += outlength;
|
||||
} else {
|
||||
memcpy(buffer, tempbuf, blocksize);
|
||||
bytesread += blocksize;
|
||||
buffer += blocksize;
|
||||
}
|
||||
blockstart += blocksize;
|
||||
}
|
||||
|
||||
/* Delete input buffer, if necessary. */
|
||||
free(tempbuf);
|
||||
|
||||
return bytesread;
|
||||
}
|
||||
|
||||
int libmpq_file_read_file(mpq_archive *mpq_a, mpq_file *mpq_f, unsigned int filepos, char *buffer, unsigned int toread) {
|
||||
unsigned int bytesread = 0; /* Number of bytes read from the file */
|
||||
unsigned int blockpos; /* Position in the file aligned to the whole blocks */
|
||||
unsigned int loaded = 0;
|
||||
|
||||
/* File position is greater or equal to file size? */
|
||||
if (filepos >= mpq_f->mpq_b->fsize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If to few bytes in the file remaining, cut them */
|
||||
if ((mpq_f->mpq_b->fsize - filepos) < toread) {
|
||||
toread = (mpq_f->mpq_b->fsize - filepos);
|
||||
}
|
||||
|
||||
/* Block position in the file */
|
||||
blockpos = filepos & ~(mpq_a->blocksize - 1);
|
||||
|
||||
/*
|
||||
* Load the first block, if noncomplete. It may be loaded in the cache buffer.
|
||||
* We have to check if this block is loaded. If not, load it.
|
||||
*/
|
||||
if ((filepos % mpq_a->blocksize) != 0) {
|
||||
/* Number of bytes remaining in the buffer */
|
||||
unsigned int tocopy;
|
||||
unsigned int loaded = mpq_a->blocksize;
|
||||
|
||||
/* Check if data are loaded in the cache */
|
||||
if (mpq_f->accessed == FALSE || blockpos != mpq_a->blockpos) {
|
||||
|
||||
/* Load one MPQ block into archive buffer */
|
||||
loaded = libmpq_file_read_block(mpq_a, mpq_f, blockpos, (char *)mpq_a->blockbuf, mpq_a->blocksize);
|
||||
if (loaded == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save lastly accessed file and block position for later use */
|
||||
mpq_f->accessed = TRUE;
|
||||
mpq_a->blockpos = blockpos;
|
||||
mpq_a->bufpos = filepos % mpq_a->blocksize;
|
||||
}
|
||||
tocopy = loaded - mpq_a->bufpos;
|
||||
if (tocopy > toread) {
|
||||
tocopy = toread;
|
||||
}
|
||||
|
||||
/* Copy data from block buffer into target buffer */
|
||||
memcpy(buffer, mpq_a->blockbuf + mpq_a->bufpos, tocopy);
|
||||
|
||||
/* Update pointers */
|
||||
toread -= tocopy;
|
||||
bytesread += tocopy;
|
||||
buffer += tocopy;
|
||||
blockpos += mpq_a->blocksize;
|
||||
mpq_a->bufpos += tocopy;
|
||||
|
||||
/* If all, return. */
|
||||
if (toread == 0) {
|
||||
return bytesread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load the whole ("middle") blocks only if there are more or equal one block */
|
||||
if (toread > mpq_a->blocksize) {
|
||||
unsigned int blockbytes = toread & ~(mpq_a->blocksize - 1);
|
||||
loaded = libmpq_file_read_block(mpq_a, mpq_f, blockpos, buffer, blockbytes);
|
||||
if (loaded == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update pointers */
|
||||
toread -= loaded;
|
||||
bytesread += loaded;
|
||||
buffer += loaded;
|
||||
blockpos += loaded;
|
||||
|
||||
/* If all, return. */
|
||||
if (toread == 0) {
|
||||
return bytesread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load the terminating block */
|
||||
if (toread > 0) {
|
||||
unsigned int tocopy = mpq_a->blocksize;
|
||||
|
||||
/* Check if data are loaded in the cache */
|
||||
if (mpq_f->accessed == FALSE || blockpos != mpq_a->blockpos) {
|
||||
|
||||
/* Load one MPQ block into archive buffer */
|
||||
tocopy = libmpq_file_read_block(mpq_a, mpq_f, blockpos, (char *)mpq_a->blockbuf, mpq_a->blocksize);
|
||||
if (tocopy == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save lastly accessed file and block position for later use */
|
||||
mpq_f->accessed = TRUE;
|
||||
mpq_a->blockpos = blockpos;
|
||||
}
|
||||
mpq_a->bufpos = 0;
|
||||
|
||||
/* Check number of bytes read */
|
||||
if (tocopy > toread) {
|
||||
tocopy = toread;
|
||||
}
|
||||
|
||||
memcpy(buffer, mpq_a->blockbuf, tocopy);
|
||||
bytesread += tocopy;
|
||||
mpq_a->bufpos = tocopy;
|
||||
}
|
||||
|
||||
/* Return what we've read */
|
||||
return bytesread;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* common.h -- defines and structs used by the config files.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* $Id: common.h,v 1.4 2004/02/12 00:41:55 mbroemme Exp $
|
||||
*/
|
||||
|
||||
#define LIBMPQ_CONF_FL_INCREMENT 512 /* i hope we did not need more :) */
|
||||
#define LIBMPQ_CONF_EXT ".conf" /* listdb file seems to be valid with this extension */
|
||||
#define LIBMPQ_CONF_HEADER "LIBMPQ_VERSION" /* listdb file must include this entry to be valid */
|
||||
#define LIBMPQ_CONF_BUFSIZE 4096 /* maximum number of bytes a line in the file could contain */
|
||||
|
||||
#define LIBMPQ_CONF_TYPE_CHAR 1 /* value in config file is from type char */
|
||||
#define LIBMPQ_CONF_TYPE_INT 2 /* value in config file is from type int */
|
||||
|
||||
#define LIBMPQ_CONF_EOPEN_DIR -1 /* error on open directory */
|
||||
#define LIBMPQ_CONF_EVALUE_NOT_FOUND -2 /* value for the option was not found */
|
||||
|
||||
#if defined( __GNUC__ )
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define _lseek lseek
|
||||
#define _read read
|
||||
#define _open open
|
||||
#define _write write
|
||||
#define _close close
|
||||
#define _strdup strdup
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef O_LARGEFILE
|
||||
#define MPQ_FILE_OPEN_FLAGS (O_RDONLY | O_BINARY | O_LARGEFILE)
|
||||
#else
|
||||
#define MPQ_FILE_OPEN_FLAGS (O_RDONLY | O_BINARY)
|
||||
#endif
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) ((a < b) ? a : b)
|
||||
#endif
|
||||
|
||||
int libmpq_init_buffer(mpq_archive *mpq_a);
|
||||
int libmpq_read_hashtable(mpq_archive *mpq_a);
|
||||
int libmpq_read_blocktable(mpq_archive *mpq_a);
|
||||
int libmpq_file_read_file(mpq_archive *mpq_a, mpq_file *mpq_f, unsigned int filepos, char *buffer, unsigned int toread);
|
||||
int libmpq_read_listfile(mpq_archive *mpq_a, FILE *fp);
|
||||
|
||||
int libmpq_conf_get_value(FILE *fp, char *search_value, void *return_value, int type, int size);
|
||||
char *libmpq_conf_delete_char(char *buf, char *chars);
|
||||
int libmpq_conf_get_array(FILE *fp, char *search_value, char ***filelist, int *entries);
|
||||
int libmpq_free_listfile(char **filelist);
|
||||
int libmpq_read_listfile(mpq_archive *mpq_a, FILE *fp);
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* explode.c -- explode function of PKWARE data compression library.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This source was adepted from the C++ version of pkware.cpp included
|
||||
* in stormlib. The C++ version belongs to the following authors,
|
||||
*
|
||||
* Ladislav Zezula <ladik.zezula.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpq.h"
|
||||
#include "explode.h"
|
||||
|
||||
/* Tables */
|
||||
static unsigned char pkzip_dist_bits[] = {
|
||||
0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
|
||||
};
|
||||
|
||||
static unsigned char pkzip_dist_code[] = {
|
||||
0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
|
||||
0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
|
||||
};
|
||||
|
||||
static unsigned char pkzip_clen_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
|
||||
};
|
||||
|
||||
static unsigned short pkzip_len_base[] = {
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106
|
||||
};
|
||||
|
||||
static unsigned char pkzip_slen_bits[] = {
|
||||
0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
|
||||
};
|
||||
|
||||
static unsigned char pkzip_len_code[] = {
|
||||
0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
|
||||
};
|
||||
|
||||
static unsigned char pkzip_bits_asc[] = {
|
||||
0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
|
||||
0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
|
||||
0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
|
||||
0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
|
||||
0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
|
||||
0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
|
||||
0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
|
||||
};
|
||||
|
||||
static unsigned short pkzip_code_asc[] = {
|
||||
0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
|
||||
0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
|
||||
0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
|
||||
0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
|
||||
0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
|
||||
0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
|
||||
0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
|
||||
0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
|
||||
0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
|
||||
0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
|
||||
0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
|
||||
0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
|
||||
0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
|
||||
0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
|
||||
0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
|
||||
0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
|
||||
0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
|
||||
0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
|
||||
0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
|
||||
0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
|
||||
0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
|
||||
0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
|
||||
0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
|
||||
0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
|
||||
0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
|
||||
0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
|
||||
0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
|
||||
0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
|
||||
0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
|
||||
0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
|
||||
0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
|
||||
0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
|
||||
};
|
||||
|
||||
/* Local variables */
|
||||
static char copyright[] = "PKWARE Data Compression Library for Win32\r\n"
|
||||
"Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
|
||||
"Patent No. 5,051,745\r\n"
|
||||
"PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
|
||||
"Version 1.11\r\n";
|
||||
|
||||
/* Local functions */
|
||||
static void libmpq_pkzip_gen_decode_tabs(long count, unsigned char *bits, unsigned char *code, unsigned char *buf2) {
|
||||
long i;
|
||||
|
||||
for (i = count-1; i >= 0; i--) { /* EBX - count */
|
||||
unsigned long idx1 = code[i];
|
||||
unsigned long idx2 = 1 << bits[i];
|
||||
do {
|
||||
buf2[idx1] = (unsigned char)i;
|
||||
idx1 += idx2;
|
||||
} while (idx1 < 0x100);
|
||||
}
|
||||
}
|
||||
|
||||
static void libmpq_pkzip_gen_asc_tabs(pkzip_data_cmp *mpq_pkzip) {
|
||||
unsigned short *code_asc = &pkzip_code_asc[0xFF];
|
||||
unsigned long acc, add;
|
||||
unsigned short count;
|
||||
|
||||
for (count = 0x00FF; code_asc >= pkzip_code_asc; code_asc--, count--) {
|
||||
unsigned char *bits_asc = mpq_pkzip->bits_asc + count;
|
||||
unsigned char bits_tmp = *bits_asc;
|
||||
|
||||
if (bits_tmp <= 8) {
|
||||
add = (1 << bits_tmp);
|
||||
acc = *code_asc;
|
||||
do {
|
||||
mpq_pkzip->offs_2c34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
} while (acc < 0x100);
|
||||
} else {
|
||||
if ((acc = (*code_asc & 0xFF)) != 0) {
|
||||
mpq_pkzip->offs_2c34[acc] = 0xFF;
|
||||
if (*code_asc & 0x3F) {
|
||||
bits_tmp -= 4;
|
||||
*bits_asc = bits_tmp;
|
||||
add = (1 << bits_tmp);
|
||||
acc = *code_asc >> 4;
|
||||
do {
|
||||
mpq_pkzip->offs_2d34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
} while (acc < 0x100);
|
||||
} else {
|
||||
bits_tmp -= 6;
|
||||
*bits_asc = bits_tmp;
|
||||
add = (1 << bits_tmp);
|
||||
acc = *code_asc >> 6;
|
||||
do {
|
||||
mpq_pkzip->offs_2e34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
} while (acc < 0x80);
|
||||
}
|
||||
} else {
|
||||
bits_tmp -= 8;
|
||||
*bits_asc = bits_tmp;
|
||||
add = (1 << bits_tmp);
|
||||
acc = *code_asc >> 8;
|
||||
do {
|
||||
mpq_pkzip->offs_2eb4[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
} while (acc < 0x100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Skips given number of bits in bit buffer. Result is stored in mpq_pkzip->bit_buf
|
||||
* If no data in input buffer, returns true
|
||||
*/
|
||||
static int libmpq_pkzip_skip_bits(pkzip_data_cmp *mpq_pkzip, unsigned long bits) {
|
||||
/* If number of bits required is less than number of (bits in the buffer) ? */
|
||||
if (bits <= mpq_pkzip->extra_bits) {
|
||||
mpq_pkzip->extra_bits -= bits;
|
||||
mpq_pkzip->bit_buf >>= bits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Load input buffer if necessary */
|
||||
mpq_pkzip->bit_buf >>= mpq_pkzip->extra_bits;
|
||||
if (mpq_pkzip->in_pos == mpq_pkzip->in_bytes) {
|
||||
mpq_pkzip->in_pos = sizeof(mpq_pkzip->in_buf);
|
||||
if ((mpq_pkzip->in_bytes = mpq_pkzip->read_buf((char *)mpq_pkzip->in_buf, &mpq_pkzip->in_pos, mpq_pkzip->param)) == 0) {
|
||||
return 1;
|
||||
}
|
||||
mpq_pkzip->in_pos = 0;
|
||||
}
|
||||
|
||||
/* Update bit buffer */
|
||||
mpq_pkzip->bit_buf |= (mpq_pkzip->in_buf[mpq_pkzip->in_pos++] << 8);
|
||||
mpq_pkzip->bit_buf >>= (bits - mpq_pkzip->extra_bits);
|
||||
mpq_pkzip->extra_bits = (mpq_pkzip->extra_bits - bits) + 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompress the imploded data using coded literals.
|
||||
* Returns: 0x000 - 0x0FF : One byte from compressed file.
|
||||
* 0x100 - 0x305 : Copy previous block (0x100 = 1 byte)
|
||||
* 0x306 : Out of buffer (?)
|
||||
*/
|
||||
static unsigned long libmpq_pkzip_explode_lit(pkzip_data_cmp *mpq_pkzip) {
|
||||
unsigned long bits; /* Number of bits to skip */
|
||||
unsigned long value; /* Position in buffers */
|
||||
|
||||
/* Test the current bit in byte buffer. If is not set, simply return the next byte. */
|
||||
if (mpq_pkzip->bit_buf & 1) {
|
||||
|
||||
/* Skip current bit in the buffer. */
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, 1)) {
|
||||
return 0x306;
|
||||
}
|
||||
|
||||
/* The next bits are position in buffers. */
|
||||
value = mpq_pkzip->pos2[(mpq_pkzip->bit_buf & 0xFF)];
|
||||
|
||||
/* Get number of bits to skip */
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, mpq_pkzip->slen_bits[value])) {
|
||||
return 0x306;
|
||||
}
|
||||
if ((bits = mpq_pkzip->clen_bits[value]) != 0) {
|
||||
unsigned long val2 = mpq_pkzip->bit_buf & ((1 << bits) - 1);
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, bits)) {
|
||||
if ((value + val2) != 0x10E) {
|
||||
return 0x306;
|
||||
}
|
||||
}
|
||||
value = mpq_pkzip->len_base[value] + val2;
|
||||
}
|
||||
return value + 0x100; /* Return number of bytes to repeat */
|
||||
}
|
||||
|
||||
/* Skip one bit */
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, 1)) {
|
||||
return 0x306;
|
||||
}
|
||||
|
||||
/* If the binary compression type, read 8 bits and return them as one byte. */
|
||||
if (mpq_pkzip->cmp_type == LIBMPQ_PKZIP_CMP_BINARY) {
|
||||
value = mpq_pkzip->bit_buf & 0xFF;
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, 8)) {
|
||||
return 0x306;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* When ASCII compression ... */
|
||||
if (mpq_pkzip->bit_buf & 0xFF) {
|
||||
value = mpq_pkzip->offs_2c34[mpq_pkzip->bit_buf & 0xFF];
|
||||
if (value == 0xFF) {
|
||||
if (mpq_pkzip->bit_buf & 0x3F) {
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, 4)) {
|
||||
return 0x306;
|
||||
}
|
||||
value = mpq_pkzip->offs_2d34[mpq_pkzip->bit_buf & 0xFF];
|
||||
} else {
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, 6)) {
|
||||
return 0x306;
|
||||
}
|
||||
value = mpq_pkzip->offs_2e34[mpq_pkzip->bit_buf & 0x7F];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, 8)) {
|
||||
return 0x306;
|
||||
}
|
||||
value = mpq_pkzip->offs_2eb4[mpq_pkzip->bit_buf & 0xFF];
|
||||
}
|
||||
return libmpq_pkzip_skip_bits(mpq_pkzip, mpq_pkzip->bits_asc[value]) ? 0x306 : value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves the number of bytes to move back.
|
||||
*/
|
||||
static unsigned long libmpq_pkzip_explode_dist(pkzip_data_cmp *mpq_pkzip, unsigned long length) {
|
||||
unsigned long pos = mpq_pkzip->pos1[(mpq_pkzip->bit_buf & 0xFF)];
|
||||
unsigned long skip = mpq_pkzip->dist_bits[pos]; /* Number of bits to skip */
|
||||
|
||||
/* Skip the appropriate number of bits */
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, skip) == 1) {
|
||||
return 0;
|
||||
}
|
||||
if (length == 2) {
|
||||
pos = (pos << 2) | (mpq_pkzip->bit_buf & 0x03);
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, 2) == 1) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
pos = (pos << mpq_pkzip->dsize_bits) | (mpq_pkzip->bit_buf & mpq_pkzip->dsize_mask);
|
||||
|
||||
/* Skip the bits */
|
||||
if (libmpq_pkzip_skip_bits(mpq_pkzip, mpq_pkzip->dsize_bits) == 1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return pos + 1;
|
||||
}
|
||||
|
||||
static unsigned long libmpq_pkzip_expand(pkzip_data_cmp *mpq_pkzip) {
|
||||
unsigned int copy_bytes; /* Number of bytes to copy */
|
||||
unsigned long one_byte; /* One byte from compressed file */
|
||||
unsigned long result;
|
||||
|
||||
mpq_pkzip->out_pos = 0x1000; /* Initialize output buffer position */
|
||||
|
||||
/* If end of data or error, terminate decompress */
|
||||
while ((result = one_byte = libmpq_pkzip_explode_lit(mpq_pkzip)) < 0x305) {
|
||||
|
||||
/* If one byte is greater than 0x100, means "Repeat n - 0xFE bytes" */
|
||||
if (one_byte >= 0x100) {
|
||||
unsigned char *source; /* ECX */
|
||||
unsigned char *target; /* EDX */
|
||||
unsigned long copy_length = one_byte - 0xFE;
|
||||
unsigned long move_back;
|
||||
|
||||
/* Get length of data to copy */
|
||||
if ((move_back = libmpq_pkzip_explode_dist(mpq_pkzip, copy_length)) == 0) {
|
||||
result = 0x306;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Target and source pointer */
|
||||
target = &mpq_pkzip->out_buf[mpq_pkzip->out_pos];
|
||||
source = target - move_back;
|
||||
mpq_pkzip->out_pos += copy_length;
|
||||
while (copy_length-- > 0) {
|
||||
*target++ = *source++;
|
||||
}
|
||||
} else {
|
||||
mpq_pkzip->out_buf[mpq_pkzip->out_pos++] = (unsigned char)one_byte;
|
||||
}
|
||||
|
||||
/*
|
||||
* If number of extracted bytes has reached 1/2 of output buffer,
|
||||
* flush output buffer.
|
||||
*/
|
||||
if (mpq_pkzip->out_pos >= 0x2000) {
|
||||
|
||||
/* Copy decompressed data into user buffer. */
|
||||
copy_bytes = 0x1000;
|
||||
mpq_pkzip->write_buf((char *)&mpq_pkzip->out_buf[0x1000], ©_bytes, mpq_pkzip->param);
|
||||
|
||||
/* If there are some data left, keep them alive */
|
||||
memcpy(mpq_pkzip->out_buf, &mpq_pkzip->out_buf[0x1000], mpq_pkzip->out_pos - 0x1000);
|
||||
mpq_pkzip->out_pos -= 0x1000;
|
||||
}
|
||||
}
|
||||
copy_bytes = mpq_pkzip->out_pos - 0x1000;
|
||||
mpq_pkzip->write_buf((char *)&mpq_pkzip->out_buf[0x1000], ©_bytes, mpq_pkzip->param);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main exploding function.
|
||||
*/
|
||||
unsigned int libmpq_pkzip_explode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param) {
|
||||
|
||||
pkzip_data_cmp *mpq_pkzip = (pkzip_data_cmp *)work_buf;
|
||||
|
||||
/* Set the whole work buffer to zeros */
|
||||
memset(mpq_pkzip, 0, sizeof(pkzip_data_cmp));
|
||||
|
||||
/* Initialize work struct and load compressed data */
|
||||
mpq_pkzip->read_buf = read_buf;
|
||||
mpq_pkzip->write_buf = write_buf;
|
||||
mpq_pkzip->param = param;
|
||||
mpq_pkzip->in_pos = sizeof(mpq_pkzip->in_buf);
|
||||
mpq_pkzip->in_bytes = mpq_pkzip->read_buf((char *)mpq_pkzip->in_buf, &mpq_pkzip->in_pos, mpq_pkzip->param);
|
||||
if (mpq_pkzip->in_bytes <= 4) {
|
||||
return LIBMPQ_PKZIP_CMP_BAD_DATA;
|
||||
}
|
||||
mpq_pkzip->cmp_type = mpq_pkzip->in_buf[0]; /* Get the compression type */
|
||||
mpq_pkzip->dsize_bits = mpq_pkzip->in_buf[1]; /* Get the dictionary size */
|
||||
mpq_pkzip->bit_buf = mpq_pkzip->in_buf[2]; /* Initialize 16-bit bit buffer */
|
||||
mpq_pkzip->extra_bits = 0; /* Extra (over 8) bits */
|
||||
mpq_pkzip->in_pos = 3; /* Position in input buffer */
|
||||
|
||||
/* Test for the valid dictionary size */
|
||||
if (4 > mpq_pkzip->dsize_bits || mpq_pkzip->dsize_bits > 6) {
|
||||
return LIBMPQ_PKZIP_CMP_INV_DICTSIZE;
|
||||
}
|
||||
mpq_pkzip->dsize_mask = 0xFFFF >> (0x10 - mpq_pkzip->dsize_bits); /* Shifted by 'sar' instruction */
|
||||
if (mpq_pkzip->cmp_type != LIBMPQ_PKZIP_CMP_BINARY) {
|
||||
if (mpq_pkzip->cmp_type != LIBMPQ_PKZIP_CMP_ASCII) {
|
||||
return LIBMPQ_PKZIP_CMP_INV_MODE;
|
||||
}
|
||||
memcpy(mpq_pkzip->bits_asc, pkzip_bits_asc, sizeof(mpq_pkzip->bits_asc));
|
||||
libmpq_pkzip_gen_asc_tabs(mpq_pkzip);
|
||||
}
|
||||
memcpy(mpq_pkzip->slen_bits, pkzip_slen_bits, sizeof(mpq_pkzip->slen_bits));
|
||||
libmpq_pkzip_gen_decode_tabs(0x10, mpq_pkzip->slen_bits, pkzip_len_code, mpq_pkzip->pos2);
|
||||
memcpy(mpq_pkzip->clen_bits, pkzip_clen_bits, sizeof(mpq_pkzip->clen_bits));
|
||||
memcpy(mpq_pkzip->len_base, pkzip_len_base, sizeof(mpq_pkzip->len_base));
|
||||
memcpy(mpq_pkzip->dist_bits, pkzip_dist_bits, sizeof(mpq_pkzip->dist_bits));
|
||||
libmpq_pkzip_gen_decode_tabs(0x40, mpq_pkzip->dist_bits, pkzip_dist_code, mpq_pkzip->pos1);
|
||||
if (libmpq_pkzip_expand(mpq_pkzip) != 0x306) {
|
||||
return LIBMPQ_PKZIP_CMP_NO_ERROR;
|
||||
}
|
||||
return LIBMPQ_PKZIP_CMP_ABORT;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* explode.h -- header file for PKWARE data decompression library
|
||||
* used by mpq-tools.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This source was adepted from the C++ version of pklib.h included
|
||||
* in stormlib. The C++ version belongs to the following authors,
|
||||
*
|
||||
* Ladislav Zezula <ladik.zezula.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EXPLODE_H
|
||||
#define _EXPLODE_H
|
||||
|
||||
#define LIBMPQ_PKZIP_EXP_BUFFER_SIZE 12596 /* Size of decompress buffer */
|
||||
#define LIBMPQ_PKZIP_CMP_BINARY 0 /* Binary compression */
|
||||
#define LIBMPQ_PKZIP_CMP_ASCII 1 /* Ascii compression */
|
||||
#define LIBMPQ_PKZIP_CMP_NO_ERROR 0
|
||||
#define LIBMPQ_PKZIP_CMP_INV_DICTSIZE 1
|
||||
#define LIBMPQ_PKZIP_CMP_INV_MODE 2
|
||||
#define LIBMPQ_PKZIP_CMP_BAD_DATA 3
|
||||
#define LIBMPQ_PKZIP_CMP_ABORT 4
|
||||
|
||||
/* Compression structure (size: 12596 bytes on x86-32) */
|
||||
typedef struct {
|
||||
unsigned long offs0000; /* 0000 */
|
||||
unsigned long cmp_type; /* 0004 - Compression type (LIBMPQ_PZIP_CMP_BINARY or LIBMPQ_PKZIP_CMP_ASCII) */
|
||||
unsigned long out_pos; /* 0008 - Position in output buffer */
|
||||
unsigned long dsize_bits; /* 000C - Dict size (4, 5, 6 for 0x400, 0x800, 0x1000) */
|
||||
unsigned long dsize_mask; /* 0010 - Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000) */
|
||||
unsigned long bit_buf; /* 0014 - 16-bit buffer for processing input data */
|
||||
unsigned long extra_bits; /* 0018 - Number of extra (above 8) bits in bit buffer */
|
||||
unsigned int in_pos; /* 001C - Position in in_buf */
|
||||
unsigned long in_bytes; /* 0020 - Number of bytes in input buffer */
|
||||
void *param; /* 0024 - Custom parameter */
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); /* 0028 */
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param); /* 002C */
|
||||
unsigned char out_buf[0x2000]; /* 0030 - Output circle buffer. Starting position is 0x1000 */
|
||||
unsigned char offs_2030[0x204]; /* 2030 - ??? */
|
||||
unsigned char in_buf[0x800]; /* 2234 - Buffer for data to be decompressed */
|
||||
unsigned char pos1[0x100]; /* 2A34 - Positions in buffers */
|
||||
unsigned char pos2[0x100]; /* 2B34 - Positions in buffers */
|
||||
unsigned char offs_2c34[0x100]; /* 2C34 - Buffer for */
|
||||
unsigned char offs_2d34[0x100]; /* 2D34 - Buffer for */
|
||||
unsigned char offs_2e34[0x80]; /* 2EB4 - Buffer for */
|
||||
unsigned char offs_2eb4[0x100]; /* 2EB4 - Buffer for */
|
||||
unsigned char bits_asc[0x100]; /* 2FB4 - Buffer for */
|
||||
unsigned char dist_bits[0x40]; /* 30B4 - Numbers of bytes to skip copied block length */
|
||||
unsigned char slen_bits[0x10]; /* 30F4 - Numbers of bits for skip copied block length */
|
||||
unsigned char clen_bits[0x10]; /* 3104 - Number of valid bits for copied block */
|
||||
unsigned short len_base[0x10]; /* 3114 - Buffer for */
|
||||
} pkzip_data_cmp;
|
||||
// __attribute__ ((packed)) pkzip_data_cmp;
|
||||
|
||||
typedef struct {
|
||||
char *in_buf; /* Pointer to input data buffer */
|
||||
unsigned int in_pos; /* Current offset in input data buffer */
|
||||
int in_bytes; /* Number of bytes in the input buffer */
|
||||
char *out_buf; /* Pointer to output data buffer */
|
||||
unsigned int out_pos; /* Position in the output buffer */
|
||||
int max_out; /* Maximum number of bytes in the output buffer */
|
||||
} pkzip_data;
|
||||
|
||||
extern unsigned int libmpq_pkzip_explode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param
|
||||
);
|
||||
|
||||
#endif /* _EXPLODE_H */
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* extract.c -- global extracting function for all known file compressions
|
||||
* in a MPQ archive.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define HAVE_LIBZ
|
||||
#ifdef HAVE_LIBZ
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#include "mpq.h"
|
||||
#include "explode.h"
|
||||
#include "huffman.h"
|
||||
|
||||
#include "wave.h"
|
||||
|
||||
/*
|
||||
* Support functions for PKWARE data compression library.
|
||||
*
|
||||
* Function loads data from the input buffer. Used by mpq_pkzip
|
||||
* "implode" and "explode" function as user-defined callback.
|
||||
* Returns number of bytes loaded.
|
||||
*
|
||||
* char * buf - Pointer to a buffer where to store loaded data
|
||||
* unsigned int * size - Max. number of bytes to read
|
||||
* void * param - Custom pointer, parameter of implode/explode
|
||||
*/
|
||||
static unsigned int libmpq_pkzip_read_input_data(char *buf, unsigned int *size, void *param) {
|
||||
pkzip_data *info = (pkzip_data *)param;
|
||||
unsigned int max_avail = (info->in_bytes - info->in_pos);
|
||||
unsigned int to_read = *size;
|
||||
|
||||
/* Check the case when not enough data available */
|
||||
if (to_read > max_avail) {
|
||||
to_read = max_avail;
|
||||
}
|
||||
|
||||
/* Load data and increment offsets */
|
||||
memcpy(buf, info->in_buf + info->in_pos, to_read);
|
||||
info->in_pos += to_read;
|
||||
|
||||
return to_read;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support functions for PKWARE data compression library.
|
||||
*
|
||||
* Function for store output data. Used by mpq_pkzip "implode" and
|
||||
* "explode" as user-defined callback.
|
||||
*
|
||||
* char * buf - Pointer to data to be written
|
||||
* unsigned int * size - Number of bytes to write
|
||||
* void * param - Custom pointer, parameter of implode/explode
|
||||
*/
|
||||
static void libmpq_pkzip_write_output_data(char *buf, unsigned int *size, void *param) {
|
||||
pkzip_data *info = (pkzip_data *)param;
|
||||
unsigned int max_write = (info->max_out - info->out_pos);
|
||||
unsigned int to_write = *size;
|
||||
|
||||
/* Check the case when not enough space in the output buffer */
|
||||
if (to_write > max_write) {
|
||||
to_write = max_write;
|
||||
}
|
||||
|
||||
/* Write output data and increments offsets */
|
||||
memcpy(info->out_buf + info->out_pos, buf, to_write);
|
||||
info->out_pos += to_write;
|
||||
}
|
||||
|
||||
int libmpq_pkzip_decompress(char *out_buf, int *out_length, char *in_buf, int in_length) {
|
||||
pkzip_data info; /* Data information */
|
||||
char *work_buf = (char *)malloc(LIBMPQ_PKZIP_EXP_BUFFER_SIZE); /* mpq_pkzip work buffer */
|
||||
|
||||
/* Fill data information structure */
|
||||
info.in_buf = in_buf;
|
||||
info.in_pos = 0;
|
||||
info.in_bytes = in_length;
|
||||
info.out_buf = out_buf;
|
||||
info.out_pos = 0;
|
||||
info.max_out = *out_length;
|
||||
|
||||
/* Do the decompression */
|
||||
libmpq_pkzip_explode(libmpq_pkzip_read_input_data, libmpq_pkzip_write_output_data, work_buf, &info);
|
||||
*out_length = info.out_pos;
|
||||
free(work_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libmpq_wave_decompress_mono(char *out_buf, int *out_length, char *in_buf, int in_length) {
|
||||
*out_length = libmpq_wave_decompress((unsigned char *)out_buf, *out_length, (unsigned char *)in_buf, in_length, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int libmpq_wave_decompress_stereo(char *out_buf, int *out_length, char *in_buf, int in_length) {
|
||||
*out_length = libmpq_wave_decompress((unsigned char *)out_buf, *out_length, (unsigned char *)in_buf, in_length, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int libmpq_zlib_decompress(char *out_buf, int *out_length, char *in_buf, int in_length) {
|
||||
#ifdef HAVE_LIBZ
|
||||
z_stream z; /* Stream information for zlib */
|
||||
int result;
|
||||
|
||||
/* Fill the stream structure for zlib */
|
||||
z.next_in = (Bytef *)in_buf;
|
||||
z.avail_in = (uInt)in_length;
|
||||
z.total_in = in_length;
|
||||
z.next_out = (Bytef *)out_buf;
|
||||
z.avail_out = *out_length;
|
||||
z.total_out = 0;
|
||||
z.zalloc = NULL;
|
||||
z.zfree = NULL;
|
||||
|
||||
/* Initialize the decompression structure. Storm.dll uses zlib version 1.1.3 */
|
||||
if ((result = inflateInit(&z)) == 0) {
|
||||
|
||||
/* Call zlib to decompress the data */
|
||||
result = inflate(&z, Z_FINISH);
|
||||
*out_length = z.total_out;
|
||||
inflateEnd(&z);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
memset(out_buf, '0', *out_length);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Huffmann decompression routine. The in_length parameter is not used, but needs
|
||||
* to be specified due to compatibility reasons.
|
||||
*
|
||||
* 1500F5F0
|
||||
*/
|
||||
int libmpq_huff_decompress(char *out_buf, int *out_length, char *in_buf, int in_length) {
|
||||
struct huffman_tree *ht = (huffman_tree *)malloc(sizeof(struct huffman_tree));
|
||||
struct huffman_input_stream *is = (huffman_input_stream *)malloc(sizeof(struct huffman_input_stream));
|
||||
struct huffman_tree_item *hi = (huffman_tree_item *)malloc(sizeof(struct huffman_tree_item));
|
||||
memset(ht, 0, sizeof(struct huffman_tree));
|
||||
memset(is, 0, sizeof(struct huffman_input_stream));
|
||||
memset(hi, 0, sizeof(struct huffman_tree_item));
|
||||
|
||||
/* Initialize input stream */
|
||||
is->bit_buf = *(unsigned long *)in_buf;
|
||||
in_buf += sizeof(unsigned long);
|
||||
is->in_buf = (unsigned char *)in_buf;
|
||||
is->bits = 32;
|
||||
|
||||
/* Initialize the Huffmann tree for decompression */
|
||||
libmpq_huff_init_tree(ht, hi, LIBMPQ_HUFF_DECOMPRESS);
|
||||
|
||||
*out_length = libmpq_huff_do_decompress(ht, is, (unsigned char *)out_buf, *out_length);
|
||||
|
||||
free(hi);
|
||||
free(is);
|
||||
free(ht);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libmpq_multi_decompress(char *out_buf, int *pout_length, char *in_buf, int in_length) {
|
||||
char *temp_buf = NULL; /* Temporary storage for decompressed data */
|
||||
char *work_buf = NULL; /* Where to store decompressed data */
|
||||
int out_length = *pout_length; /* For storage number of output bytes */
|
||||
unsigned fDecompressions1; /* Decompressions applied to the block */
|
||||
unsigned fDecompressions2; /* Just another copy of decompressions applied to the block */
|
||||
int count = 0; /* Counter for every use */
|
||||
int entries = (sizeof(dcmp_table) / sizeof(decompress_table));
|
||||
int i;
|
||||
|
||||
/* If the input length is the same as output, do nothing. */
|
||||
if (in_length == out_length) {
|
||||
if (in_buf == out_buf) {
|
||||
return 1;
|
||||
}
|
||||
memcpy(out_buf, in_buf, in_length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get applied compression types and decrement data length */
|
||||
fDecompressions1 = fDecompressions2 = (unsigned char)*in_buf++;
|
||||
in_length--;
|
||||
|
||||
/* Search decompression table type and get all types of compression */
|
||||
for (i = 0; i < entries; i++) {
|
||||
/* We have to apply this decompression? */
|
||||
if (fDecompressions1 & dcmp_table[i].mask) {
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Clear this flag from temporary variable. */
|
||||
fDecompressions2 &= ~dcmp_table[i].mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there is some method unhandled
|
||||
* (E.g. compressed by future versions)
|
||||
*/
|
||||
if (fDecompressions2 != 0) {
|
||||
printf("Unknown Compression\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If there is more than only one compression, we have to allocate extra buffer */
|
||||
if (count >= 2) {
|
||||
temp_buf = (char *)malloc(out_length);
|
||||
}
|
||||
|
||||
/* Apply all decompressions */
|
||||
for (i = 0, count = 0; i < entries; i++) {
|
||||
|
||||
/* If not used this kind of compression, skip the loop */
|
||||
if (fDecompressions1 & dcmp_table[i].mask) {
|
||||
|
||||
/* If odd case, use target buffer for output, otherwise use allocated tempbuf */
|
||||
work_buf = (count++ & 1) ? temp_buf : out_buf;
|
||||
out_length = *pout_length;
|
||||
|
||||
/* Decompress buffer using corresponding function */
|
||||
dcmp_table[i].decompress(work_buf, &out_length, in_buf, in_length);
|
||||
|
||||
/* Move output length to src length for next compression */
|
||||
in_length = out_length;
|
||||
in_buf = work_buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* If output buffer is not the same like target buffer, we have to copy data */
|
||||
if (work_buf != out_buf) {
|
||||
memcpy(out_buf, in_buf, out_length);
|
||||
}
|
||||
*pout_length = out_length;
|
||||
|
||||
/* Delete temporary buffer, if necessary */
|
||||
if (temp_buf != NULL) {
|
||||
free(temp_buf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,834 @@
|
||||
/*
|
||||
* huffman.c -- functions do decompress files in MPQ files which
|
||||
* uses a modified huffman version.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* Differences between C++ and C version:
|
||||
*
|
||||
* - Removed the object oriented stuff.
|
||||
* - Replaced the goto things with some better C code.
|
||||
*
|
||||
* This source was adepted from the C++ version of huffman.cpp included
|
||||
* in stormlib. The C++ version belongs to the following authors,
|
||||
*
|
||||
* Ladislav Zezula <ladik.zezula.net>
|
||||
* ShadowFlare <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpq.h"
|
||||
#include "huffman.h"
|
||||
|
||||
unsigned char table1502A630[] = {
|
||||
|
||||
/* Data for compression type 0x00 */
|
||||
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Data for compression type 0x01 */
|
||||
0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05,
|
||||
0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02,
|
||||
0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
|
||||
0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04,
|
||||
0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
|
||||
0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02,
|
||||
0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03,
|
||||
0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
|
||||
0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
|
||||
0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Data for compression type 0x02 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04,
|
||||
0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02,
|
||||
0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01,
|
||||
0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A,
|
||||
0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Data for compression type 0x03 */
|
||||
0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03,
|
||||
0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
|
||||
0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
|
||||
0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01,
|
||||
0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03,
|
||||
0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03,
|
||||
0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01,
|
||||
0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Data for compression type 0x04 */
|
||||
0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Data for compression type 0x05 */
|
||||
0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82,
|
||||
0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37,
|
||||
0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D,
|
||||
0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Data for compression type 0x06 */
|
||||
0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Data for compression type 0x07 */
|
||||
0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Data for compression type 0x08 */
|
||||
0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10,
|
||||
0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11,
|
||||
0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x5F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
/* Gets previous Huffman tree item (?) */
|
||||
struct huffman_tree_item *libmpq_huff_get_prev_item(struct huffman_tree_item *hi, long value) {
|
||||
if (PTR_INT(hi->prev) < 0) {
|
||||
return PTR_NOT(hi->prev);
|
||||
}
|
||||
if (value < 0) {
|
||||
value = hi - hi->next->prev;
|
||||
}
|
||||
return hi->prev + value;
|
||||
}
|
||||
|
||||
/* 1500BC90 */
|
||||
static void libmpq_huff_remove_item(struct huffman_tree_item *hi) {
|
||||
struct huffman_tree_item *temp; /* EDX */
|
||||
|
||||
if (hi->next != NULL) {
|
||||
temp = hi->prev;
|
||||
if (PTR_INT(temp) <= 0) {
|
||||
temp = PTR_NOT(temp);
|
||||
} else {
|
||||
temp += (hi - hi->next->prev);
|
||||
}
|
||||
temp->next = hi->next;
|
||||
hi->next->prev = hi->prev;
|
||||
hi->next = hi->prev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void libmpq_huff_insert_item(struct huffman_tree_item **p_item, struct huffman_tree_item *item, unsigned long where, struct huffman_tree_item *item2) {
|
||||
struct huffman_tree_item *next = item->next; /* EDI - next to the first item */
|
||||
struct huffman_tree_item *prev = item->prev; /* ESI - prev to the first item */
|
||||
struct huffman_tree_item *prev2; /* Pointer to previous item */
|
||||
long next2; /* Pointer to the next item */
|
||||
|
||||
/* The same code like in mpq_huff_remove_item(); */
|
||||
if (next != 0) { /* If the first item already has next one */
|
||||
if (PTR_INT(prev) < 0) {
|
||||
prev = PTR_NOT(prev);
|
||||
} else {
|
||||
prev += (item - next->prev);
|
||||
}
|
||||
|
||||
/*
|
||||
* 150083C1
|
||||
* Remove the item from the tree
|
||||
*/
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
|
||||
/* Invalidate 'prev' and 'next' pointer */
|
||||
item->next = 0;
|
||||
item->prev = 0;
|
||||
}
|
||||
|
||||
if (item2 == NULL) { /* EDX - If the second item is not entered, */
|
||||
item2 = PTR_PTR(&p_item[1]); /* take the first tree item */
|
||||
}
|
||||
|
||||
switch (where) {
|
||||
case SWITCH_ITEMS: /* Switch the two items */
|
||||
item->next = item2->next; /* item2->next (Pointer to pointer to first) */
|
||||
item->prev = item2->next->prev;
|
||||
item2->next->prev = item;
|
||||
item2->next = item; /* Set the first item */
|
||||
return;
|
||||
case INSERT_ITEM: /* Insert as the last item */
|
||||
item->next = item2; /* Set next item (or pointer to pointer to first item) */
|
||||
item->prev = item2->prev; /* Set prev item (or last item in the tree) */
|
||||
next2 = PTR_INT(p_item[0]); /* Usually NULL */
|
||||
prev2 = item2->prev; /* Prev item to the second (or last tree item) */
|
||||
if (PTR_INT(prev2) < 0) {
|
||||
prev2 = PTR_NOT(prev);
|
||||
prev2->next = item;
|
||||
item2->prev = item; /* Next after last item */
|
||||
return;
|
||||
}
|
||||
if (next2 < 0) {
|
||||
next2 = item2 - item2->next->prev;
|
||||
}
|
||||
prev2 += next2;
|
||||
prev2->next = item;
|
||||
item2->prev = item; /* Set the next/last item */
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Builds Huffman tree. Called with the first 8 bits loaded from input stream. */
|
||||
static void libmpq_huff_build_tree(struct huffman_tree *ht, unsigned int cmp_type) {
|
||||
unsigned long max_byte; /* [ESP+10] - The greatest character found in table */
|
||||
unsigned char *byte_array; /* [ESP+1C] - Pointer to unsigned char in table1502A630 */
|
||||
unsigned long i; /* egcs in linux doesn't like multiple for loops without an explicit i */
|
||||
unsigned int found; /* Thats needed to replace the goto stuff from original source :) */
|
||||
struct huffman_tree_item **p_item; /* [ESP+14] - Pointer to Huffman tree item pointer array */
|
||||
struct huffman_tree_item *child1;
|
||||
|
||||
/* Loop while pointer has a negative value. */
|
||||
while (PTR_INT(ht->last) > 0) { /* ESI - Last entry */
|
||||
struct huffman_tree_item *temp; /* EAX */
|
||||
|
||||
if (ht->last->next != NULL) { /* ESI->next */
|
||||
libmpq_huff_remove_item(ht->last);
|
||||
}
|
||||
ht->item3058 = PTR_PTR(&ht->item3054);/* [EDI+4] */
|
||||
ht->last->prev = ht->item3058; /* EAX */
|
||||
temp = libmpq_huff_get_prev_item(PTR_PTR(&ht->item3054), PTR_INT(&ht->item3050));
|
||||
temp->next = ht->last;
|
||||
ht->item3054 = ht->last;
|
||||
}
|
||||
|
||||
/* Clear all pointers in huffman tree item array. */
|
||||
memset(ht->items306C, 0, sizeof(ht->items306C));
|
||||
|
||||
max_byte = 0; /* Greatest character found init to zero. */
|
||||
p_item = (struct huffman_tree_item **)&ht->items306C; /* Pointer to current entry in huffman tree item pointer array */
|
||||
|
||||
/* Ensure we have low 8 bits only */
|
||||
cmp_type &= 0xFF;
|
||||
byte_array = table1502A630 + cmp_type * 258; /* EDI also */
|
||||
|
||||
for (i = 0; i < 0x100; i++, p_item++) {
|
||||
struct huffman_tree_item *item = ht->item3058; /* Item to be created */
|
||||
struct huffman_tree_item *p_item3 = ht->item3058;
|
||||
unsigned char one_byte = byte_array[i];
|
||||
|
||||
/* Skip all the bytes which are zero. */
|
||||
if (byte_array[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If not valid pointer, take the first available item in the array. */
|
||||
if (PTR_INT(item) <= 0) {
|
||||
item = &ht->items0008[ht->items++];
|
||||
}
|
||||
|
||||
/* Insert this item as the top of the tree. */
|
||||
libmpq_huff_insert_item(&ht->item305C, item, SWITCH_ITEMS, NULL);
|
||||
|
||||
item->parent = NULL; /* Invalidate child and parent */
|
||||
item->child = NULL;
|
||||
*p_item = item; /* Store pointer into pointer array */
|
||||
|
||||
item->dcmp_byte = i; /* Store counter */
|
||||
item->byte_value = one_byte; /* Store byte value */
|
||||
if (one_byte >= max_byte) {
|
||||
max_byte = one_byte;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find the first item which has byte value greater than current one byte */
|
||||
found = 0;
|
||||
if (PTR_INT((p_item3 = ht->last)) > 0) {/* EDI - Pointer to the last item */
|
||||
|
||||
/* 15006AF7 */
|
||||
if (p_item3 != NULL) {
|
||||
do { /* 15006AFB */
|
||||
if (p_item3->byte_value >= one_byte) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
p_item3 = p_item3->prev;
|
||||
} while (PTR_INT(p_item3) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
p_item3 = NULL;
|
||||
}
|
||||
|
||||
/* 15006B09 */
|
||||
if (item->next != NULL) {
|
||||
libmpq_huff_remove_item(item);
|
||||
}
|
||||
|
||||
/* 15006B15 */
|
||||
if (p_item3 == NULL) {
|
||||
p_item3 = PTR_PTR(&ht->first);
|
||||
}
|
||||
|
||||
/* 15006B1F */
|
||||
item->next = p_item3->next;
|
||||
item->prev = p_item3->next->prev;
|
||||
p_item3->next->prev = item;
|
||||
p_item3->next = item;
|
||||
}
|
||||
|
||||
/* 15006B4A */
|
||||
for (; i < 0x102; i++) {
|
||||
struct huffman_tree_item **p_item2 = &ht->items306C[i]; /* EDI */
|
||||
|
||||
/* 15006B59 */
|
||||
struct huffman_tree_item *item2 = ht->item3058; /* ESI */
|
||||
if (PTR_INT(item2) <= 0) {
|
||||
item2 = &ht->items0008[ht->items++];
|
||||
}
|
||||
libmpq_huff_insert_item(&ht->item305C, item2, INSERT_ITEM, NULL);
|
||||
|
||||
/* 15006B89 */
|
||||
item2->dcmp_byte = i;
|
||||
item2->byte_value = 1;
|
||||
item2->parent = NULL;
|
||||
item2->child = NULL;
|
||||
*p_item2++ = item2;
|
||||
}
|
||||
|
||||
/* 15006BAA */
|
||||
if (PTR_INT((child1 = ht->last)) > 0) { /* EDI - last item (first child to item */
|
||||
struct huffman_tree_item *child2; /* EBP */
|
||||
struct huffman_tree_item *item; /* ESI */
|
||||
|
||||
/* 15006BB8 */
|
||||
while (PTR_INT((child2 = child1->prev)) > 0) {
|
||||
if (PTR_INT((item = ht->item3058)) <= 0) {
|
||||
item = &ht->items0008[ht->items++];
|
||||
}
|
||||
/* 15006BE3 */
|
||||
libmpq_huff_insert_item(&ht->item305C, item, SWITCH_ITEMS, NULL);
|
||||
|
||||
/* 15006BF3 */
|
||||
item->parent = NULL;
|
||||
item->child = NULL;
|
||||
|
||||
/*
|
||||
* EDX = child2->byte_value + child1->byte_value;
|
||||
* EAX = child1->byte_value;
|
||||
* ECX = max_byte; The greatest character (0xFF usually)
|
||||
*/
|
||||
item->byte_value = child1->byte_value + child2->byte_value; /* 0x02 */
|
||||
item->child = child1; /* Prev item in the */
|
||||
child1->parent = item;
|
||||
child2->parent = item;
|
||||
|
||||
/* EAX = item->byte_value; */
|
||||
if (item->byte_value >= max_byte) {
|
||||
max_byte = item->byte_value;
|
||||
} else {
|
||||
struct huffman_tree_item *p_item2 = child2->prev; /* EDI */
|
||||
found = 0;
|
||||
if (PTR_INT(p_item2) > 0) {
|
||||
|
||||
/* 15006C2D */
|
||||
do {
|
||||
if (p_item2->byte_value >= item->byte_value) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
p_item2 = p_item2->prev;
|
||||
} while (PTR_INT(p_item2) > 0);
|
||||
}
|
||||
if (found == 0) {
|
||||
p_item2 = NULL;
|
||||
}
|
||||
if (item->next != 0) {
|
||||
struct huffman_tree_item *temp4 = libmpq_huff_get_prev_item(item, -1);
|
||||
temp4->next = item->next; /* The first item changed */
|
||||
item->next->prev = item->prev; /* First->prev changed to negative value */
|
||||
item->next = NULL;
|
||||
item->prev = NULL;
|
||||
}
|
||||
|
||||
/* 15006C62 */
|
||||
if (p_item2 == NULL) {
|
||||
p_item2 = PTR_PTR(&ht->first);
|
||||
}
|
||||
item->next = p_item2->next; /* Set item with 0x100 byte value */
|
||||
item->prev = p_item2->next->prev; /* Set item with 0x17 byte value */
|
||||
p_item2->next->prev = item; /* Changed prev of item with */
|
||||
p_item2->next = item;
|
||||
}
|
||||
|
||||
/* 15006C7B */
|
||||
if (PTR_INT((child1 = child2->prev)) <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 15006C88 */
|
||||
ht->offs0004 = 1;
|
||||
}
|
||||
|
||||
/* Gets the whole byte from the input stream. */
|
||||
static unsigned long libmpq_huff_get_8bits(struct huffman_input_stream *is) {
|
||||
unsigned long one_byte;
|
||||
|
||||
if (is->bits <= 8) {
|
||||
is->bit_buf |= *(unsigned short *)is->in_buf << is->bits;
|
||||
is->in_buf += sizeof(unsigned short);
|
||||
is->bits += 16;
|
||||
}
|
||||
|
||||
one_byte = (is->bit_buf & 0xFF);
|
||||
is->bit_buf >>= 8;
|
||||
is->bits -= 8;
|
||||
|
||||
return one_byte;
|
||||
}
|
||||
|
||||
/* Gets 7 bits from the stream. */
|
||||
static unsigned long libmpq_huff_get_7bits(struct huffman_input_stream *is) {
|
||||
if (is->bits <= 7) {
|
||||
is->bit_buf |= *(unsigned short *)is->in_buf << is->bits;
|
||||
is->in_buf += sizeof(unsigned short);
|
||||
is->bits += 16;
|
||||
}
|
||||
|
||||
/* Get 7 bits from input stream. */
|
||||
return (is->bit_buf & 0x7F);
|
||||
}
|
||||
|
||||
/* Gets one bit from input stream. */
|
||||
unsigned long libmpq_huff_get_bit(struct huffman_input_stream *is) {
|
||||
unsigned long bit = (is->bit_buf & 1);
|
||||
|
||||
is->bit_buf >>= 1;
|
||||
if (--is->bits == 0) {
|
||||
is->bit_buf = *(unsigned long *)is->in_buf;
|
||||
is->in_buf += sizeof(unsigned long);
|
||||
is->bits = 32;
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
|
||||
static struct huffman_tree_item *libmpq_huff_call1500E740(struct huffman_tree *ht, unsigned int value) {
|
||||
struct huffman_tree_item *p_item1 = ht->item3058; /* EDX */
|
||||
struct huffman_tree_item *p_item2; /* EAX */
|
||||
struct huffman_tree_item *p_next;
|
||||
struct huffman_tree_item *p_prev;
|
||||
struct huffman_tree_item **pp_item;
|
||||
|
||||
if (PTR_INT(p_item1) <= 0 || (p_item2 = p_item1) == NULL) {
|
||||
if((p_item2 = &ht->items0008[ht->items++]) != NULL) {
|
||||
p_item1 = p_item2;
|
||||
} else {
|
||||
p_item1 = ht->first;
|
||||
}
|
||||
} else {
|
||||
p_item1 = p_item2;
|
||||
}
|
||||
|
||||
p_next = p_item1->next;
|
||||
if (p_next != NULL) {
|
||||
p_prev = p_item1->prev;
|
||||
if (PTR_INT(p_prev) <= 0) {
|
||||
p_prev = PTR_NOT(p_prev);
|
||||
} else {
|
||||
p_prev += (p_item1 - p_item1->next->prev);
|
||||
}
|
||||
|
||||
p_prev->next = p_next;
|
||||
p_next->prev = p_prev;
|
||||
p_item1->next = NULL;
|
||||
p_item1->prev = NULL;
|
||||
}
|
||||
pp_item = &ht->first; /* ESI */
|
||||
if (value > 1) {
|
||||
|
||||
/* ECX = ht->first->next; */
|
||||
p_item1->next = *pp_item;
|
||||
p_item1->prev = (*pp_item)->prev;
|
||||
|
||||
(*pp_item)->prev = p_item2;
|
||||
*pp_item = p_item1;
|
||||
|
||||
p_item2->parent = NULL;
|
||||
p_item2->child = NULL;
|
||||
} else {
|
||||
p_item1->next = (struct huffman_tree_item *)pp_item;
|
||||
p_item1->prev = pp_item[1];
|
||||
/* EDI = ht->item305C; */
|
||||
p_prev = pp_item[1]; /* ECX */
|
||||
if (p_prev <= 0) {
|
||||
p_prev = PTR_NOT(p_prev);
|
||||
p_prev->next = p_item1;
|
||||
p_prev->prev = p_item2;
|
||||
|
||||
p_item2->parent = NULL;
|
||||
p_item2->child = NULL;
|
||||
} else {
|
||||
if (PTR_INT(ht->item305C) < 0) {
|
||||
p_prev += (struct huffman_tree_item *)pp_item - (*pp_item)->prev;
|
||||
} else {
|
||||
p_prev += PTR_INT(ht->item305C);
|
||||
}
|
||||
|
||||
p_prev->next = p_item1;
|
||||
pp_item[1] = p_item2;
|
||||
p_item2->parent = NULL;
|
||||
p_item2->child = NULL;
|
||||
}
|
||||
}
|
||||
return p_item2;
|
||||
}
|
||||
|
||||
static void libmpq_huff_call1500E820(struct huffman_tree *ht, struct huffman_tree_item *p_item) {
|
||||
struct huffman_tree_item *p_item1; /* EDI */
|
||||
struct huffman_tree_item *p_item2 = NULL; /* EAX */
|
||||
struct huffman_tree_item *p_item3; /* EDX */
|
||||
struct huffman_tree_item *p_prev; /* EBX */
|
||||
|
||||
for (; p_item != NULL; p_item = p_item->parent) {
|
||||
p_item->byte_value++;
|
||||
|
||||
for (p_item1 = p_item; ; p_item1 = p_prev) {
|
||||
p_prev = p_item1->prev;
|
||||
if (PTR_INT(p_prev) <= 0) {
|
||||
p_prev = NULL;
|
||||
break;
|
||||
}
|
||||
if (p_prev->byte_value >= p_item->byte_value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_item1 == p_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_item1->next != NULL) {
|
||||
p_item2 = libmpq_huff_get_prev_item(p_item1, -1);
|
||||
p_item2->next = p_item1->next;
|
||||
p_item1->next->prev = p_item1->prev;
|
||||
p_item1->next = NULL;
|
||||
p_item1->prev = NULL;
|
||||
}
|
||||
p_item2 = p_item->next;
|
||||
p_item1->next = p_item2;
|
||||
p_item1->prev = p_item2->prev;
|
||||
p_item2->prev = p_item1;
|
||||
p_item->next = p_item1;
|
||||
if ((p_item2 = p_item1) != NULL) {
|
||||
p_item2 = libmpq_huff_get_prev_item(p_item, -1);
|
||||
p_item2->next = p_item->next;
|
||||
p_item->next->prev = p_item->prev;
|
||||
p_item->next = NULL;
|
||||
p_item->prev = NULL;
|
||||
}
|
||||
|
||||
if (p_prev == NULL) {
|
||||
p_prev = PTR_PTR(&ht->first);
|
||||
}
|
||||
p_item2 = p_prev->next;
|
||||
p_item->next = p_item2;
|
||||
p_item->prev = p_item2->prev;
|
||||
p_item2->prev = p_item;
|
||||
p_prev->next = p_item;
|
||||
|
||||
p_item3 = p_item1->parent->child;
|
||||
p_item2 = p_item->parent;
|
||||
if (p_item2->child == p_item) {
|
||||
p_item2->child = p_item1;
|
||||
}
|
||||
|
||||
if (p_item3 == p_item1) {
|
||||
p_item1->parent->child = p_item;
|
||||
}
|
||||
|
||||
p_item2 = p_item->parent;
|
||||
p_item->parent = p_item1->parent;
|
||||
p_item1->parent = p_item2;
|
||||
ht->offs0004++;
|
||||
}
|
||||
}
|
||||
|
||||
int libmpq_huff_do_decompress(struct huffman_tree *ht, struct huffman_input_stream *is, unsigned char *out_buf, unsigned int out_length) {
|
||||
unsigned int n8bits; /* 8 bits loaded from input stream */
|
||||
unsigned int n7bits; /* 7 bits loaded from input stream */
|
||||
unsigned int found; /* Thats needed to replace the goto stuff from original source :) */
|
||||
unsigned int dcmp_byte = 0;
|
||||
unsigned long bit_count;
|
||||
struct huffman_decompress *qd;
|
||||
unsigned int has_qd; /* Can we use quick decompression? */
|
||||
struct huffman_tree_item *p_item1;
|
||||
struct huffman_tree_item *p_item2;
|
||||
unsigned char *out_pos = out_buf;
|
||||
|
||||
/* Test the output length. Must not be non zero. */
|
||||
if (out_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the compression type from the input stream. */
|
||||
n8bits = libmpq_huff_get_8bits(is);
|
||||
|
||||
/* Build the Huffman tree */
|
||||
libmpq_huff_build_tree(ht, n8bits);
|
||||
ht->cmp0 = (n8bits == 0) ? TRUE : FALSE;
|
||||
|
||||
for(;;) {
|
||||
n7bits = libmpq_huff_get_7bits(is); /* Get 7 bits from input stream */
|
||||
|
||||
/*
|
||||
* Try to use quick decompression. Check huffman_decompress array for corresponding item.
|
||||
* If found, use the result byte instead.
|
||||
*/
|
||||
qd = &ht->qd3474[n7bits];
|
||||
|
||||
/* If there is a quick-pass possible (ebx) */
|
||||
has_qd = (qd->offs00 >= ht->offs0004) ? TRUE : FALSE;
|
||||
|
||||
/* If we can use quick decompress, use it. */
|
||||
if (has_qd) {
|
||||
found = 0;
|
||||
if (qd->bits > 7) {
|
||||
is->bit_buf >>= 7;
|
||||
is->bits -= 7;
|
||||
p_item1 = qd->p_item;
|
||||
found = 1;
|
||||
}
|
||||
if (found == 0) {
|
||||
is->bit_buf >>= qd->bits;
|
||||
is->bits -= qd->bits;
|
||||
dcmp_byte = qd->dcmp_byte;
|
||||
}
|
||||
} else {
|
||||
found = 1;
|
||||
p_item1 = ht->first->next->prev;
|
||||
if (PTR_INT(p_item1) <= 0) {
|
||||
p_item1 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 1) {
|
||||
bit_count = 0;
|
||||
p_item2 = NULL;
|
||||
do {
|
||||
p_item1 = p_item1->child; /* Move down by one level */
|
||||
if (libmpq_huff_get_bit(is)) { /* If current bit is set, move to previous */
|
||||
p_item1 = p_item1->prev;
|
||||
}
|
||||
if (++bit_count == 7) { /* If we are at 7th bit, save current huffman tree item. */
|
||||
p_item2 = p_item1;
|
||||
}
|
||||
} while (p_item1->child != NULL); /* Walk until tree has no deeper level */
|
||||
|
||||
if (has_qd == FALSE) {
|
||||
if (bit_count > 7) {
|
||||
qd->offs00 = ht->offs0004;
|
||||
qd->bits = bit_count;
|
||||
qd->p_item = p_item2;
|
||||
} else {
|
||||
unsigned long index = n7bits & (0xFFFFFFFF >> (32 - bit_count));
|
||||
unsigned long add = (1 << bit_count);
|
||||
|
||||
for (qd = &ht->qd3474[index]; index <= 0x7F; index += add, qd += add) {
|
||||
qd->offs00 = ht->offs0004;
|
||||
qd->bits = bit_count;
|
||||
qd->dcmp_byte = p_item1->dcmp_byte;
|
||||
}
|
||||
}
|
||||
}
|
||||
dcmp_byte = p_item1->dcmp_byte;
|
||||
}
|
||||
|
||||
if (dcmp_byte == 0x101) { /* Huffman tree needs to be modified */
|
||||
n8bits = libmpq_huff_get_8bits(is);
|
||||
p_item1 = (ht->last <= 0) ? NULL : ht->last;
|
||||
|
||||
p_item2 = libmpq_huff_call1500E740(ht, 1);
|
||||
p_item2->parent = p_item1;
|
||||
p_item2->dcmp_byte = p_item1->dcmp_byte;
|
||||
p_item2->byte_value = p_item1->byte_value;
|
||||
ht->items306C[p_item2->dcmp_byte] = p_item2;
|
||||
|
||||
p_item2 = libmpq_huff_call1500E740(ht, 1);
|
||||
p_item2->parent = p_item1;
|
||||
p_item2->dcmp_byte = n8bits;
|
||||
p_item2->byte_value = 0;
|
||||
ht->items306C[p_item2->dcmp_byte] = p_item2;
|
||||
|
||||
p_item1->child = p_item2;
|
||||
libmpq_huff_call1500E820(ht, p_item2);
|
||||
if (ht->cmp0 == 0) {
|
||||
libmpq_huff_call1500E820(ht, ht->items306C[n8bits]);
|
||||
}
|
||||
dcmp_byte = n8bits;
|
||||
}
|
||||
|
||||
if (dcmp_byte == 0x100) {
|
||||
break;
|
||||
}
|
||||
|
||||
*out_pos++ = (unsigned char)dcmp_byte;
|
||||
if (--out_length == 0) {
|
||||
break;
|
||||
}
|
||||
if (ht->cmp0) {
|
||||
libmpq_huff_call1500E820(ht, ht->items306C[dcmp_byte]);
|
||||
}
|
||||
}
|
||||
return (out_pos - out_buf);
|
||||
}
|
||||
|
||||
int libmpq_huff_init_tree(struct huffman_tree *ht, struct huffman_tree_item *hi, unsigned int cmp) {
|
||||
int count;
|
||||
|
||||
/* Clear links for all the items in the tree */
|
||||
for (hi = ht->items0008, count = 0x203; count != 0; hi++, count--) {
|
||||
hi->next = hi->prev = NULL;
|
||||
}
|
||||
|
||||
ht->item3050 = NULL;
|
||||
ht->item3054 = PTR_PTR(&ht->item3054);
|
||||
ht->item3058 = PTR_NOT(ht->item3054);
|
||||
|
||||
ht->item305C = NULL;
|
||||
ht->first = PTR_PTR(&ht->first);
|
||||
ht->last = PTR_NOT(ht->first);
|
||||
|
||||
ht->offs0004 = 1;
|
||||
ht->items = 0;
|
||||
|
||||
/* Clear all huffman_decompress items. Do this only if preparing for decompression */
|
||||
if (cmp == LIBMPQ_HUFF_DECOMPRESS) {
|
||||
for (count = 0; count < sizeof(ht->qd3474) / sizeof(struct huffman_decompress); count++) {
|
||||
ht->qd3474[count].offs00 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* huffman.h -- structures used for huffman compression.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This source was adepted from the C++ version of huffman.h included
|
||||
* in stormlib. The C++ version belongs to the following authors,
|
||||
*
|
||||
* Ladislav Zezula <ladik.zezula.net>
|
||||
* ShadowFlare <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _HUFFMAN_H
|
||||
#define _HUFFMAN_H
|
||||
|
||||
#define PTR_NOT(ptr) (struct huffman_tree_item *)(~(unsigned long)(ptr))
|
||||
#define PTR_PTR(ptr) ((struct huffman_tree_item *)(ptr))
|
||||
#define PTR_INT(ptr) (long)(ptr)
|
||||
|
||||
#define INSERT_ITEM 1
|
||||
#define SWITCH_ITEMS 2 /* Switch the item1 and item2 */
|
||||
|
||||
/*
|
||||
* Input stream for Huffmann decompression
|
||||
*/
|
||||
struct huffman_input_stream {
|
||||
unsigned char *in_buf; /* 00 - Input data */
|
||||
unsigned long bit_buf; /* 04 - Input bit buffer */
|
||||
unsigned int bits; /* 08 - Number of bits remaining in 'byte' */
|
||||
};
|
||||
|
||||
/*
|
||||
* Huffmann tree item.
|
||||
*/
|
||||
struct huffman_tree_item {
|
||||
struct huffman_tree_item *next; /* 00 - Pointer to next huffman_tree_item */
|
||||
struct huffman_tree_item *prev; /* 04 - Pointer to prev huffman_tree_item (< 0 if none) */
|
||||
unsigned long dcmp_byte; /* 08 - Index of this item in item pointer array, decompressed byte value */
|
||||
unsigned long byte_value; /* 0C - Some byte value */
|
||||
struct huffman_tree_item *parent; /* 10 - Pointer to parent huffman_tree_item (NULL if none) */
|
||||
struct huffman_tree_item *child; /* 14 - Pointer to child huffman_tree_item */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure used for quick decompress. The 'bits' contains
|
||||
* number of bits and dcmp_byte contains result decompressed byte
|
||||
* value. After each walk through Huffman tree are filled all entries
|
||||
* which are multiplies of number of bits loaded from input stream.
|
||||
* These entries contain number of bits and result value. At the next
|
||||
* 7 bits is tested this structure first. If corresponding entry found,
|
||||
* decompression routine will not walk through Huffman tree and
|
||||
* directly stores output byte to output stream.
|
||||
*/
|
||||
struct huffman_decompress {
|
||||
unsigned long offs00; /* 00 - 1 if resolved */
|
||||
unsigned long bits; /* 04 - Bit count */
|
||||
union {
|
||||
unsigned long dcmp_byte; /* 08 - Byte value for decompress (if bitCount <= 7) */
|
||||
struct huffman_tree_item *p_item; /* 08 - THTreeItem (if number of bits is greater than 7 */
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure for Huffman tree.
|
||||
*/
|
||||
struct huffman_tree {
|
||||
unsigned long cmp0; /* 0000 - 1 if compression type 0 */
|
||||
unsigned long offs0004; /* 0004 - Some flag */
|
||||
|
||||
struct huffman_tree_item items0008[0x203]; /* 0008 - huffman tree items */
|
||||
|
||||
/* Sometimes used as huffman tree item */
|
||||
struct huffman_tree_item *item3050; /* 3050 - Always NULL (?) */
|
||||
struct huffman_tree_item *item3054; /* 3054 - Pointer to huffman_tree_item */
|
||||
struct huffman_tree_item *item3058; /* 3058 - Pointer to huffman_tree_item (< 0 if invalid) */
|
||||
|
||||
/* Sometimes used as huffman tree item */
|
||||
struct huffman_tree_item *item305C; /* 305C - Usually NULL */
|
||||
struct huffman_tree_item *first; /* 3060 - Pointer to top (first) Huffman tree item */
|
||||
struct huffman_tree_item *last; /* 3064 - Pointer to bottom (last) Huffman tree item (< 0 if invalid) */
|
||||
unsigned long items; /* 3068 - Number of used huffman tree items */
|
||||
|
||||
struct huffman_tree_item *items306C[0x102]; /* 306C - huffman_tree_item pointer array */
|
||||
struct huffman_decompress qd3474[0x80]; /* 3474 - Array for quick decompression */
|
||||
|
||||
//unsigned char table1502A630[]; /* Some table to make struct size flexible */
|
||||
};
|
||||
|
||||
int libmpq_huff_init_tree(struct huffman_tree *ht, struct huffman_tree_item *hi, unsigned int cmp);
|
||||
int libmpq_huff_do_decompress(struct huffman_tree *ht, struct huffman_input_stream *is, unsigned char *out_buf, unsigned int out_length);
|
||||
#endif /* _HUFFMAN_H */
|
||||
|
||||
@@ -0,0 +1,627 @@
|
||||
/*
|
||||
* mpq.c -- functions for developers using libmpq.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* $Id: mpq.c,v 1.6 2004/02/12 00:49:00 mbroemme Exp $
|
||||
*/
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
//#include <unistd.h>
|
||||
//#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mpq.h"
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* This function returns version information.
|
||||
* format: MAJOR.MINOR.PATCH
|
||||
*/
|
||||
char *libmpq_version() {
|
||||
static char version[10];
|
||||
sprintf(version, "%i.%i.%i", LIBMPQ_MAJOR_VERSION, LIBMPQ_MINOR_VERSION, LIBMPQ_PATCH_VERSION);
|
||||
return version;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reads a file and verify if it is a legit MPQ archive
|
||||
* or not. Then it fills the mpq_header structure and reads the hash
|
||||
* table.
|
||||
*/
|
||||
int libmpq_archive_open(mpq_archive *mpq_a, unsigned char *mpq_filename) {
|
||||
int fd = 0;
|
||||
int rb = 0;
|
||||
int ncnt = FALSE;
|
||||
struct stat fileinfo;
|
||||
|
||||
/* allocate memory */
|
||||
mpq_a->mpq_l = (mpq_list *)malloc(sizeof(mpq_list));
|
||||
memset(mpq_a->mpq_l, 0, sizeof(mpq_list));
|
||||
mpq_a->header = (mpq_header *)malloc(sizeof(mpq_header));
|
||||
memset(mpq_a->header, 0, sizeof(mpq_header));
|
||||
|
||||
/* Check if file exists and is readable */
|
||||
fd = _open((char *)mpq_filename, MPQ_FILE_OPEN_FLAGS);
|
||||
if (fd == LIBMPQ_EFILE) {
|
||||
return LIBMPQ_EFILE;
|
||||
}
|
||||
|
||||
/* fill the structures with informations */
|
||||
strcpy((char *)mpq_a->filename, (char *)mpq_filename);
|
||||
libmpq_init_buffer(mpq_a);
|
||||
mpq_a->fd = fd;
|
||||
mpq_a->header->id = 0;
|
||||
mpq_a->maxblockindex = 0;
|
||||
mpq_a->mpq_l->mpq_files = NULL;
|
||||
|
||||
mpq_a->mpqpos = 0; //k
|
||||
|
||||
while (!ncnt) {
|
||||
mpq_a->header->id = 0;
|
||||
#ifdef WIN32
|
||||
_lseeki64(mpq_a->fd, mpq_a->mpqpos, SEEK_SET);
|
||||
#else
|
||||
lseek64(mpq_a->fd, mpq_a->mpqpos, SEEK_SET);
|
||||
#endif
|
||||
rb = _read(mpq_a->fd, mpq_a->header, sizeof(mpq_header));
|
||||
|
||||
/* if different number of bytes read, break the loop */
|
||||
if (rb != sizeof(mpq_header)) {
|
||||
return LIBMPQ_EFILE_FORMAT;
|
||||
}
|
||||
|
||||
/* special offset for protected MPQs */
|
||||
if (mpq_a->header->offset == LIBMPQ_HEADER_W3M) {
|
||||
mpq_a->flags |= LIBMPQ_FLAG_PROTECTED;
|
||||
mpq_a->header->offset = sizeof(mpq_header);
|
||||
}
|
||||
|
||||
/* if valid signature has been found, break the loop */
|
||||
if (mpq_a->header->id == LIBMPQ_ID_MPQ) {
|
||||
ncnt = true;
|
||||
}
|
||||
/*if (mpq_a->header->id == LIBMPQ_ID_MPQ &&
|
||||
mpq_a->header->offset == sizeof(mpq_header) &&
|
||||
mpq_a->header->hashtablepos < mpq_a->header->archivesize &&
|
||||
mpq_a->header->blocktablepos < mpq_a->header->archivesize) {
|
||||
ncnt = TRUE;
|
||||
}*/
|
||||
|
||||
/* move to the next possible offset */
|
||||
if (!ncnt) {
|
||||
mpq_a->mpqpos += 0x200;
|
||||
}
|
||||
}
|
||||
|
||||
/* get the right positions of the hash table and the block table. */
|
||||
mpq_a->blocksize = (0x200 << mpq_a->header->blocksize);
|
||||
fstat(mpq_a->fd, &fileinfo);
|
||||
|
||||
/* Normal MPQs must have position of */
|
||||
/*if (mpq_a->header->hashtablepos + mpq_a->mpqpos < fileinfo.st_size &&
|
||||
mpq_a->header->blocktablepos + mpq_a->mpqpos < fileinfo.st_size) {
|
||||
mpq_a->header->hashtablepos += mpq_a->mpqpos;
|
||||
mpq_a->header->blocktablepos += mpq_a->mpqpos;
|
||||
} else {
|
||||
return LIBMPQ_EFILE_FORMAT;
|
||||
}*/
|
||||
|
||||
/* Try to read and decrypt the hashtable */
|
||||
if (libmpq_read_hashtable(mpq_a) != 0) {
|
||||
return LIBMPQ_EHASHTABLE;
|
||||
}
|
||||
|
||||
/* Try to read and decrypt the blocktable */
|
||||
if (libmpq_read_blocktable(mpq_a) != 0) {
|
||||
return LIBMPQ_EBLOCKTABLE;
|
||||
}
|
||||
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function closes the file descriptor opened by
|
||||
* mpq_open_archive(); and frees the decryption buffer.
|
||||
*/
|
||||
int libmpq_archive_close(mpq_archive *mpq_a) {
|
||||
memset(mpq_a->buf, 0, sizeof(mpq_a->buf));
|
||||
|
||||
/* free the allocated memory. */
|
||||
free(mpq_a->header);
|
||||
free(mpq_a->mpq_l);
|
||||
|
||||
/* Check if file descriptor is valid. */
|
||||
if ((_close(mpq_a->fd)) == LIBMPQ_EFILE) {
|
||||
return LIBMPQ_EFILE;
|
||||
}
|
||||
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the value for the given infotype.
|
||||
* If an error occurs something < 0 is returned.
|
||||
*/
|
||||
int libmpq_archive_info(mpq_archive *mpq_a, unsigned int infotype) {
|
||||
unsigned int filecount = 0;
|
||||
unsigned int fsize = 0;
|
||||
unsigned int csize = 0;
|
||||
mpq_block *mpq_b_end = mpq_a->blocktable + mpq_a->header->blocktablesize;
|
||||
mpq_block *mpq_b = NULL;
|
||||
|
||||
switch (infotype) {
|
||||
case LIBMPQ_MPQ_ARCHIVE_SIZE:
|
||||
return mpq_a->header->archivesize;
|
||||
case LIBMPQ_MPQ_HASHTABLE_SIZE:
|
||||
return mpq_a->header->hashtablesize;
|
||||
case LIBMPQ_MPQ_BLOCKTABLE_SIZE:
|
||||
return mpq_a->header->blocktablesize;
|
||||
case LIBMPQ_MPQ_BLOCKSIZE:
|
||||
return mpq_a->blocksize;
|
||||
case LIBMPQ_MPQ_NUMFILES:
|
||||
for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
|
||||
filecount++;
|
||||
}
|
||||
return filecount;
|
||||
case LIBMPQ_MPQ_COMPRESSED_SIZE:
|
||||
for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
|
||||
csize += mpq_b->csize;
|
||||
}
|
||||
return csize;
|
||||
case LIBMPQ_MPQ_UNCOMPRESSED_SIZE:
|
||||
for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
|
||||
fsize += mpq_b->fsize;
|
||||
}
|
||||
return fsize;
|
||||
default:
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns some useful file information.
|
||||
*/
|
||||
int libmpq_file_info(mpq_archive *mpq_a, unsigned int infotype, const unsigned int number) {
|
||||
int blockindex = number; //-1;
|
||||
int i = 0;
|
||||
mpq_block *mpq_b = NULL;
|
||||
mpq_hash *mpq_h = NULL;
|
||||
|
||||
/* check if given number is not out of range */
|
||||
if (number < 1 || number > mpq_a->header->blocktablesize) {
|
||||
return LIBMPQ_EINV_RANGE;
|
||||
}
|
||||
|
||||
/* search for correct hashtable */
|
||||
/*for (i = 0; i < mpq_a->header->hashtablesize; i++) {
|
||||
if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
|
||||
blockindex = (mpq_a->hashtable[i]).blockindex;
|
||||
mpq_h = &(mpq_a->hashtable[i]);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
/* check if file was found */
|
||||
/*if (blockindex == -1 || blockindex > mpq_a->header->blocktablesize) {
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
}*/
|
||||
|
||||
/* check if sizes are correct */
|
||||
mpq_b = mpq_a->blocktable + blockindex;
|
||||
if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
|
||||
return LIBMPQ_EFILE_CORRUPT;
|
||||
}
|
||||
|
||||
/* check if file exists */
|
||||
if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
switch (infotype) {
|
||||
case LIBMPQ_FILE_COMPRESSED_SIZE:
|
||||
return mpq_b->csize;
|
||||
case LIBMPQ_FILE_UNCOMPRESSED_SIZE:
|
||||
return mpq_b->fsize;
|
||||
case LIBMPQ_FILE_COMPRESSION_TYPE:
|
||||
if (mpq_b->flags & LIBMPQ_FILE_COMPRESS_PKWARE) {
|
||||
return LIBMPQ_FILE_COMPRESS_PKWARE;
|
||||
}
|
||||
if (mpq_b->flags & LIBMPQ_FILE_COMPRESS_MULTI) {
|
||||
return LIBMPQ_FILE_COMPRESS_MULTI;
|
||||
}
|
||||
default:
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function searches the listfile for the filename.
|
||||
* On success it returns the filename, otherwiese a name
|
||||
* like file000001.xxx and if number is out of range it
|
||||
* returns NULL.
|
||||
*/
|
||||
char *libmpq_file_name(mpq_archive *mpq_a, const int number) {
|
||||
static char tempfile[PATH_MAX];
|
||||
|
||||
/* check if we are in the range of available files. */
|
||||
if (number > libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) || number < 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this is safe because we built a fallback filelist, if something was wrong. */
|
||||
sprintf(tempfile, (char *)mpq_a->mpq_l->mpq_files[number - 1], number);
|
||||
|
||||
return tempfile;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the number to the given
|
||||
* filename.
|
||||
*/
|
||||
int libmpq_file_number(mpq_archive *mpq_a, const char *name) {
|
||||
int i;
|
||||
char tempfile[PATH_MAX];
|
||||
|
||||
for (i = 0; mpq_a->mpq_l->mpq_files[i]; i++) {
|
||||
sprintf(tempfile, (char *)mpq_a->mpq_l->mpq_files[i], i + 1);
|
||||
if (strncmp(tempfile, name, strlen(name)) == 0) {
|
||||
|
||||
/* if file found return the number */
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no matching entry found return LIBMPQ_EFILE_NOT_FOUND */
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function verifies if a given file (by number
|
||||
* or name) is in the opened mpq archive. On success
|
||||
* it returns 0, otherwise LIBMPQ_EFILE_NOT_FOUND.
|
||||
*/
|
||||
int libmpq_file_check(mpq_archive *mpq_a, void *file, int type) {
|
||||
int found = 0;
|
||||
int i;
|
||||
char tempfile[PATH_MAX];
|
||||
|
||||
switch (type) {
|
||||
case LIBMPQ_FILE_TYPE_INT:
|
||||
|
||||
/* check if we are in the range of available files. */
|
||||
if (*(int *)file > libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) || *(int *)file < 1) {
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
} else {
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
case LIBMPQ_FILE_TYPE_CHAR:
|
||||
for (i = 0; mpq_a->mpq_l->mpq_files[i]; i++) {
|
||||
sprintf(tempfile, (char *)mpq_a->mpq_l->mpq_files[i], i);
|
||||
if (strncmp(tempfile, (char *)file, strlen((char *)file)) == 0) {
|
||||
|
||||
/* if file found break */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if a file was found return 0 */
|
||||
if (found == 1) {
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
} else {
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
}
|
||||
default:
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function extracts a file from a MPQ archive
|
||||
* by the given number.
|
||||
*/
|
||||
int libmpq_file_extract(mpq_archive *mpq_a, const int number, const char *filename) {
|
||||
int blockindex = number; //-1;
|
||||
int fd = 0;
|
||||
int i = 0;
|
||||
char buffer[0x1000];
|
||||
//char tempfile[PATH_MAX];
|
||||
unsigned int transferred = 1;
|
||||
mpq_file *mpq_f = NULL;
|
||||
mpq_block *mpq_b = NULL;
|
||||
mpq_hash *mpq_h = NULL;
|
||||
|
||||
/* if (number < 1 || number > mpq_a->header->blocktablesize) {
|
||||
return LIBMPQ_EINV_RANGE;
|
||||
}*/
|
||||
/*
|
||||
sprintf(tempfile, libmpq_file_name(mpq_a, number));
|
||||
*/
|
||||
/* check if mpq_f->filename could be written here. */
|
||||
fd = _open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
|
||||
if (fd == LIBMPQ_EFILE) {
|
||||
return LIBMPQ_EFILE;
|
||||
}
|
||||
|
||||
/* search for correct hashtable */
|
||||
/*for (i = 0; i < mpq_a->header->hashtablesize; i++) {
|
||||
if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
|
||||
blockindex = (mpq_a->hashtable[i]).blockindex;
|
||||
mpq_h = &(mpq_a->hashtable[i]);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
/* check if file was found */
|
||||
if (blockindex == -1 || blockindex > mpq_a->header->blocktablesize) {
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* check if sizes are correct */
|
||||
mpq_b = mpq_a->blocktable + blockindex;
|
||||
if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
|
||||
return LIBMPQ_EFILE_CORRUPT;
|
||||
}
|
||||
|
||||
/* check if file exists */
|
||||
if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* allocate memory for file structure */
|
||||
mpq_f = (mpq_file *)malloc(sizeof(mpq_file));
|
||||
if (!mpq_f) {
|
||||
return LIBMPQ_EALLOCMEM;
|
||||
}
|
||||
|
||||
/* initialize file structure */
|
||||
memset(mpq_f, 0, sizeof(mpq_file));
|
||||
mpq_f->fd = fd;
|
||||
mpq_f->mpq_b = mpq_b;
|
||||
mpq_f->nblocks = (mpq_f->mpq_b->fsize + mpq_a->blocksize - 1) / mpq_a->blocksize;
|
||||
mpq_f->mpq_h = mpq_h;
|
||||
mpq_f->accessed = FALSE;
|
||||
mpq_f->blockposloaded = FALSE;
|
||||
sprintf((char *)mpq_f->filename, filename);
|
||||
|
||||
/* allocate buffers for decompression. */
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
|
||||
|
||||
/*
|
||||
* Allocate buffer for block positions. At the begin of file are stored
|
||||
* unsigned ints holding positions of each block relative from begin of
|
||||
* file in the archive.
|
||||
*/
|
||||
if ((mpq_f->blockpos = (unsigned int *)malloc(sizeof(int) * mpq_f->nblocks + 1)) == NULL) {
|
||||
return LIBMPQ_EALLOCMEM;
|
||||
}
|
||||
}
|
||||
|
||||
while (transferred > 0) {
|
||||
transferred = libmpq_file_read_file(mpq_a, mpq_f, mpq_f->filepos, buffer, sizeof(buffer));
|
||||
if (transferred == 0) {
|
||||
break;
|
||||
} else {
|
||||
mpq_f->accessed = TRUE;
|
||||
mpq_f->filepos += transferred;
|
||||
}
|
||||
|
||||
transferred = _write(mpq_f->fd, buffer, transferred);
|
||||
if (transferred == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_close(fd);
|
||||
|
||||
/* freeing the file structure */
|
||||
free(mpq_f);
|
||||
return LIBMPQ_TOOLS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function tries to get the filenames for the hashes. It uses
|
||||
* an internal listfile database and gets the correct listfile from
|
||||
* some specific archive informations.
|
||||
*/
|
||||
|
||||
int libmpq_listfile_open(mpq_archive *mpq_a, char file[PATH_MAX]) {
|
||||
FILE *fp;
|
||||
//char **filelist;
|
||||
int i = 0;
|
||||
//int fl_count;
|
||||
//int fl_size;
|
||||
int fl_count_fb;
|
||||
int fl_size_fb;
|
||||
int result = LIBMPQ_TOOLS_SUCCESS;
|
||||
struct stat statbuf;
|
||||
|
||||
/* get file status */
|
||||
if (stat(file, &statbuf) < 0) {
|
||||
result = LIBMPQ_CONF_EFILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* check if file is a filename or directory */
|
||||
/*if (S_ISDIR(statbuf.st_mode)) {
|
||||
|
||||
// allocate memory for the file list
|
||||
filelist = (char **)malloc(LIBMPQ_CONF_FL_INCREMENT * sizeof(char *));
|
||||
fl_count = 0;
|
||||
fl_size = LIBMPQ_CONF_FL_INCREMENT;
|
||||
|
||||
// check if it is a valid listfile
|
||||
if (libmpq_detect_listfile_rec(file, &filelist, &fl_count, &fl_size)) {
|
||||
filelist == NULL;
|
||||
}
|
||||
|
||||
filelist[fl_count] = NULL;
|
||||
|
||||
// return if no listfile was found
|
||||
if (filelist == NULL) {
|
||||
result = LIBMPQ_CONF_EFILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
for (i = 0; filelist[i]; i++) {
|
||||
if ((fp = fopen(filelist[i], "r")) != NULL ) {
|
||||
result = libmpq_read_listfile(mpq_a, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
// freeing the listfile struct
|
||||
libmpq_free_listfile(filelist);
|
||||
}*/
|
||||
|
||||
/* if file is a regular file use it */
|
||||
//if (S_ISREG(statbuf.st_mode)) {
|
||||
|
||||
/* if specific listfile was forced. */
|
||||
if ((fp = fopen(file, "r")) != NULL ) {
|
||||
result = libmpq_read_listfile(mpq_a, fp);
|
||||
fclose(fp);
|
||||
} else {
|
||||
result = LIBMPQ_CONF_EFILE_OPEN;
|
||||
}
|
||||
//}
|
||||
|
||||
/* if error occured we need to create a fallback filelist. */
|
||||
if (mpq_a->mpq_l->mpq_files == NULL) {
|
||||
|
||||
/* allocate memory for the file list */
|
||||
mpq_a->mpq_l->mpq_files = (unsigned char **)malloc(LIBMPQ_CONF_FL_INCREMENT * sizeof(char *));
|
||||
fl_count_fb = 0;
|
||||
fl_size_fb = LIBMPQ_CONF_FL_INCREMENT;
|
||||
|
||||
for (i = 0; i < libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES); i++) {
|
||||
|
||||
/* set the next filelist entry to a copy of the file */
|
||||
mpq_a->mpq_l->mpq_files[fl_count_fb++] = (unsigned char *)_strdup("file%06lu.xxx");
|
||||
|
||||
/* increase the array size */
|
||||
if (fl_count_fb == fl_size_fb) {
|
||||
mpq_a->mpq_l->mpq_files = (unsigned char **)realloc(mpq_a->mpq_l->mpq_files, (fl_size_fb + LIBMPQ_CONF_FL_INCREMENT) * sizeof(char *));
|
||||
fl_size_fb += LIBMPQ_CONF_FL_INCREMENT;
|
||||
}
|
||||
}
|
||||
mpq_a->mpq_l->mpq_files[fl_count_fb] = NULL;
|
||||
|
||||
/* if no error occurs and no listfile was assigned, we think there was no matching listfile. */
|
||||
if (result == 0) {
|
||||
result = LIBMPQ_CONF_EFILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function frees the allocated memory for the listfile.
|
||||
*/
|
||||
int libmpq_listfile_close(mpq_archive *mpq_a) {
|
||||
int i = 0;
|
||||
|
||||
/* safety check if we really have a filelist. */
|
||||
if (mpq_a->mpq_l->mpq_files != NULL) {
|
||||
/* freeing the filelist */
|
||||
while (mpq_a->mpq_l->mpq_files[i]) {
|
||||
free(mpq_a->mpq_l->mpq_files[i++]);
|
||||
}
|
||||
free(mpq_a->mpq_l->mpq_files);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libmpq_file_getdata(mpq_archive *mpq_a, mpq_hash mpq_h, const int number, unsigned char *dest) {
|
||||
int blockindex = number; //-1;
|
||||
int i = 0;
|
||||
mpq_file *mpq_f = NULL;
|
||||
mpq_block *mpq_b = NULL;
|
||||
int success = 0;
|
||||
|
||||
/*if (number < 1 || number > mpq_a->header->blocktablesize) {
|
||||
return LIBMPQ_EINV_RANGE;
|
||||
}*/
|
||||
|
||||
/* search for correct hashtable */
|
||||
/*for (i = 0; i < mpq_a->header->hashtablesize; i++) {
|
||||
if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
|
||||
blockindex = (mpq_a->hashtable[i]).blockindex;
|
||||
mpq_h = &(mpq_a->hashtable[i]);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
/* check if file was found */
|
||||
if (blockindex == -1 || blockindex > mpq_a->header->blocktablesize) {
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* check if sizes are correct */
|
||||
mpq_b = mpq_a->blocktable + blockindex;
|
||||
if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
|
||||
return LIBMPQ_EFILE_CORRUPT;
|
||||
}
|
||||
|
||||
/* check if file exists */
|
||||
if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
|
||||
return LIBMPQ_EFILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* allocate memory for file structure */
|
||||
mpq_f = (mpq_file*)malloc(sizeof(mpq_file));
|
||||
if (!mpq_f) {
|
||||
return LIBMPQ_EALLOCMEM;
|
||||
}
|
||||
|
||||
/* initialize file structure */
|
||||
memset(mpq_f, 0, sizeof(mpq_file));
|
||||
mpq_f->mpq_b = mpq_b;
|
||||
mpq_f->nblocks = (mpq_f->mpq_b->fsize + mpq_a->blocksize - 1) / mpq_a->blocksize;
|
||||
mpq_f->mpq_h = &mpq_h;
|
||||
mpq_f->accessed = FALSE;
|
||||
mpq_f->blockposloaded = FALSE;
|
||||
|
||||
/* allocate buffers for decompression. */
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
|
||||
|
||||
/*
|
||||
* Allocate buffer for block positions. At the begin of file are stored
|
||||
* unsigned ints holding positions of each block relative from begin of
|
||||
* file in the archive.
|
||||
*/
|
||||
if ((mpq_f->blockpos = (unsigned int*)malloc(sizeof(int) * (mpq_f->nblocks + 1))) == NULL) {
|
||||
return LIBMPQ_EALLOCMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if(libmpq_file_read_file(mpq_a, mpq_f, 0, (char*)dest, mpq_b->fsize) == mpq_b->fsize)
|
||||
success = 1;
|
||||
|
||||
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
|
||||
// Free buffer for block positions
|
||||
|
||||
free(mpq_f->blockpos);
|
||||
}
|
||||
/* freeing the file structure */
|
||||
free(mpq_f);
|
||||
return success?LIBMPQ_TOOLS_SUCCESS:LIBMPQ_EFILE_CORRUPT;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* mpq.h -- some default types and defines.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This source was adepted from the C++ version of StormLib.h and
|
||||
* StormPort.h included in stormlib. The C++ version belongs to
|
||||
* the following authors,
|
||||
*
|
||||
* Ladislav Zezula <ladik.zezula.net>
|
||||
* Marko Friedemann <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* $Id: mpq.h,v 1.8 2004/02/12 00:45:50 mbroemme Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MPQ_H
|
||||
#define _MPQ_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 260
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE_CC__)
|
||||
#define lseek64 lseek
|
||||
#endif
|
||||
|
||||
#define LIBMPQ_MAJOR_VERSION 0 /* Major version number... maybe sometimes we reach version 1 :) */
|
||||
#define LIBMPQ_MINOR_VERSION 3 /* Minor version number - increased only for small changes */
|
||||
#define LIBMPQ_PATCH_VERSION 0 /* Patchlevel - changed on bugfixes etc... */
|
||||
|
||||
#define LIBMPQ_TOOLS_SUCCESS 0 /* return value for all functions which success */
|
||||
#define LIBMPQ_TOOLS_BUFSIZE 0x500 /* buffer size for the decryption engine */
|
||||
|
||||
#define LIBMPQ_EFILE -1 /* error on file operation */
|
||||
#define LIBMPQ_EFILE_FORMAT -2 /* bad file format */
|
||||
#define LIBMPQ_EFILE_CORRUPT -3 /* file corrupt */
|
||||
#define LIBMPQ_EFILE_NOT_FOUND -4 /* file in archive not found */
|
||||
#define LIBMPQ_EFILE_READ -5 /* Read error in archive */
|
||||
#define LIBMPQ_EALLOCMEM -6 /* maybe not enough memory? :) */
|
||||
#define LIBMPQ_EFREEMEM -7 /* can not free memory */
|
||||
#define LIBMPQ_EINV_RANGE -8 /* Given filenumber is out of range */
|
||||
#define LIBMPQ_EHASHTABLE -9 /* error in reading hashtable */
|
||||
#define LIBMPQ_EBLOCKTABLE -10 /* error in reading blocktable */
|
||||
|
||||
#define LIBMPQ_ID_MPQ 0x1A51504D /* MPQ archive header ID ('MPQ\x1A') */
|
||||
#define LIBMPQ_HEADER_W3M 0x6D9E4B86 /* special value used by W3M Map Protector */
|
||||
#define LIBMPQ_FLAG_PROTECTED 0x00000002 /* Set on protected MPQs (like W3M maps) */
|
||||
#define LIBMPQ_HASH_ENTRY_DELETED 0xFFFFFFFE /* Block index for deleted hash entry */
|
||||
|
||||
#define LIBMPQ_FILE_COMPRESS_PKWARE 0x00000100 /* Compression made by PKWARE Data Compression Library */
|
||||
#define LIBMPQ_FILE_COMPRESS_MULTI 0x00000200 /* Multiple compressions */
|
||||
#define LIBMPQ_FILE_COMPRESSED 0x0000FF00 /* File is compressed */
|
||||
#define LIBMPQ_FILE_EXISTS 0x80000000 /* Set if file exists, reset when the file was deleted */
|
||||
#define LIBMPQ_FILE_ENCRYPTED 0x00010000 /* Indicates whether file is encrypted */
|
||||
#define LIBMPQ_FILE_HAS_METADATA 0x04000000
|
||||
|
||||
#define LIBMPQ_FILE_COMPRESSED_SIZE 1 /* MPQ compressed filesize of given file */
|
||||
#define LIBMPQ_FILE_UNCOMPRESSED_SIZE 2 /* MPQ uncompressed filesize of given file */
|
||||
#define LIBMPQ_FILE_COMPRESSION_TYPE 3 /* MPQ compression type of given file */
|
||||
#define LIBMPQ_FILE_TYPE_INT 4 /* file is given by number */
|
||||
#define LIBMPQ_FILE_TYPE_CHAR 5 /* file is given by name */
|
||||
|
||||
#define LIBMPQ_MPQ_ARCHIVE_SIZE 1 /* MPQ archive size */
|
||||
#define LIBMPQ_MPQ_HASHTABLE_SIZE 2 /* MPQ archive hashtable size */
|
||||
#define LIBMPQ_MPQ_BLOCKTABLE_SIZE 3 /* MPQ archive blocktable size */
|
||||
#define LIBMPQ_MPQ_BLOCKSIZE 4 /* MPQ archive blocksize */
|
||||
#define LIBMPQ_MPQ_NUMFILES 5 /* Number of files in the MPQ archive */
|
||||
#define LIBMPQ_MPQ_COMPRESSED_SIZE 6 /* Compressed archive size */
|
||||
#define LIBMPQ_MPQ_UNCOMPRESSED_SIZE 7 /* Uncompressed archive size */
|
||||
|
||||
#define LIBMPQ_HUFF_DECOMPRESS 0 /* Defines that we want to decompress using huffman trees. */
|
||||
|
||||
#define LIBMPQ_CONF_EFILE_OPEN -1 /* error if a specific listfile was forced and could not be opened. */
|
||||
#define LIBMPQ_CONF_EFILE_CORRUPT -2 /* listfile seems to be corrupt */
|
||||
#define LIBMPQ_CONF_EFILE_LIST_CORRUPT -3 /* listfile seems correct, but filelist is broken */
|
||||
#define LIBMPQ_CONF_EFILE_NOT_FOUND -4 /* error if no matching listfile found */
|
||||
#define LIBMPQ_CONF_EFILE_VERSION -5 /* libmpq version does not match required listfile version */
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
#ifndef min
|
||||
#define min(a, b) ((a < b) ? a : b)
|
||||
#endif
|
||||
*/
|
||||
|
||||
typedef unsigned int mpq_buffer[LIBMPQ_TOOLS_BUFSIZE];
|
||||
typedef int (*DECOMPRESS)(char *, int *, char *, int);
|
||||
typedef struct {
|
||||
unsigned long mask; /* Decompression bit */
|
||||
DECOMPRESS decompress; /* Decompression function */
|
||||
} decompress_table;
|
||||
|
||||
/* MPQ file header */
|
||||
typedef struct {
|
||||
unsigned int id; /* The 0x1A51504D ('MPQ\x1A') signature */
|
||||
unsigned int offset; /* Offset of the first file (Relative to MPQ start) */
|
||||
unsigned int archivesize; /* Size of MPQ archive */
|
||||
unsigned short offsetsc; /* 0000 for SC and BW */
|
||||
unsigned short blocksize; /* Size of file block is (0x200 << blockSize) */
|
||||
unsigned int hashtablepos; /* File position of hashTable */
|
||||
unsigned int blocktablepos; /* File position of blockTable. Each entry has 16 bytes */
|
||||
unsigned int hashtablesize; /* Number of entries in hash table */
|
||||
unsigned int blocktablesize; /* Number of entries in the block table */
|
||||
} mpq_header;
|
||||
//} __attribute__ ((packed)) mpq_header;
|
||||
|
||||
|
||||
/* Hash entry. All files in the archive are searched by their hashes. */
|
||||
typedef struct {
|
||||
unsigned int name1; /* The first two unsigned ints */
|
||||
unsigned int name2; /* are the encrypted file name */
|
||||
unsigned int locale; /* Locale information. */
|
||||
unsigned int blockindex; /* Index to file description block */
|
||||
} mpq_hash;
|
||||
|
||||
/* File description block contains informations about the file */
|
||||
typedef struct {
|
||||
unsigned int filepos; /* Block file starting position in the archive */
|
||||
unsigned int csize; /* Compressed file size */
|
||||
unsigned int fsize; /* Uncompressed file size */
|
||||
unsigned int flags; /* Flags */
|
||||
} mpq_block;
|
||||
|
||||
/* File handle structure used since Diablo 1.00 (0x38 bytes) */
|
||||
typedef struct {
|
||||
unsigned char filename[PATH_MAX]; /* filename of the actual file in the archive */
|
||||
int fd; /* File handle */
|
||||
unsigned int seed; /* Seed used for file decrypt */
|
||||
unsigned int filepos; /* Current file position */
|
||||
unsigned int offset;
|
||||
unsigned int nblocks; /* Number of blocks in the file (incl. the last noncomplete one) */
|
||||
unsigned int *blockpos; /* Position of each file block (only for compressed files) */
|
||||
int blockposloaded; /* TRUE if block positions loaded */
|
||||
unsigned int offset2; /* (Number of bytes somewhere ?) */
|
||||
mpq_hash *mpq_h; /* Hash table entry */
|
||||
mpq_block *mpq_b; /* File block pointer */
|
||||
|
||||
/* Non-Storm.dll members */
|
||||
|
||||
unsigned int accessed; /* Was something from the file already read? */
|
||||
} mpq_file;
|
||||
|
||||
/* List handle structure */
|
||||
typedef struct {
|
||||
unsigned char mpq_version[10]; /* libmpq version required by the listfile */
|
||||
unsigned char mpq_name[PATH_MAX]; /* mpq archive name without full path */
|
||||
unsigned char mpq_type[20]; /* mpq archive type */
|
||||
unsigned char mpq_game[40]; /* blizzard title the file matches */
|
||||
unsigned char mpq_game_version[10]; /* game version */
|
||||
unsigned char **mpq_files; /* filelist */
|
||||
} mpq_list;
|
||||
|
||||
/* Archive handle structure used since Diablo 1.00 */
|
||||
typedef struct {
|
||||
unsigned char filename[PATH_MAX]; /* Opened archive file name */
|
||||
int fd; /* File handle */
|
||||
unsigned int blockpos; /* Position of loaded block in the file */
|
||||
unsigned int blocksize; /* Size of file block */
|
||||
unsigned char *blockbuf; /* Buffer (cache) for file block */
|
||||
unsigned int bufpos; /* Position in block buffer */
|
||||
unsigned int mpqpos; /* MPQ archive position in the file */
|
||||
unsigned int filepos; /* Current file pointer */
|
||||
unsigned int openfiles; /* Number of open files + 1 */
|
||||
mpq_buffer buf; /* MPQ buffer */
|
||||
mpq_header *header; /* MPQ file header */
|
||||
mpq_hash *hashtable; /* Hash table */
|
||||
mpq_block *blocktable; /* Block table */
|
||||
|
||||
/* Non-Storm.dll members */
|
||||
|
||||
mpq_list *mpq_l; /* Handle to file list from database */
|
||||
|
||||
unsigned int flags; /* See LIBMPQ_TOOLS_FLAG_XXXXX */
|
||||
unsigned int maxblockindex; /* The highest block table entry */
|
||||
} mpq_archive;
|
||||
|
||||
extern char *libmpq_version();
|
||||
extern int libmpq_archive_open(mpq_archive *mpq_a, unsigned char *mpq_filename);
|
||||
extern int libmpq_archive_close(mpq_archive *mpq_a);
|
||||
extern int libmpq_archive_info(mpq_archive *mpq_a, unsigned int infotype);
|
||||
//extern int libmpq_file_extract(mpq_archive *mpq_a, const int number);
|
||||
extern int libmpq_file_info(mpq_archive *mpq_a, unsigned int infotype, const unsigned int number);
|
||||
extern char *libmpq_file_name(mpq_archive *mpq_a, const int number);
|
||||
extern int libmpq_file_number(mpq_archive *mpq_a, const char *name);
|
||||
extern int libmpq_file_check(mpq_archive *mpq_a, void *file, int type);
|
||||
extern int libmpq_listfile_open(mpq_archive *mpq_a, char file[PATH_MAX]);
|
||||
extern int libmpq_listfile_close(mpq_archive *mpq_a);
|
||||
|
||||
extern int libmpq_pkzip_decompress(char *out_buf, int *out_length, char *in_buf, int in_length);
|
||||
extern int libmpq_zlib_decompress(char *out_buf, int *out_length, char *in_buf, int in_length);
|
||||
extern int libmpq_huff_decompress(char *out_buf, int *out_length, char *in_buf, int in_length);
|
||||
extern int libmpq_wave_decompress_stereo(char *out_buf, int *out_length, char *in_buf, int in_length);
|
||||
extern int libmpq_wave_decompress_mono(char *out_buf, int *out_length, char *in_buf, int in_length);
|
||||
extern int libmpq_multi_decompress(char *out_buf, int *pout_length, char *in_buf, int in_length);
|
||||
|
||||
static decompress_table dcmp_table[] = {
|
||||
{0x08, libmpq_pkzip_decompress}, /* Decompression with Pkware Data Compression Library */
|
||||
{0x02, libmpq_zlib_decompress}, /* Decompression with the "zlib" library */
|
||||
{0x01, libmpq_huff_decompress}, /* Huffmann decompression */
|
||||
{0x80, libmpq_wave_decompress_stereo}, /* WAVE decompression for stereo waves */
|
||||
{0x40, libmpq_wave_decompress_mono} /* WAVE decompression for mono waves */
|
||||
};
|
||||
|
||||
int libmpq_file_extract(mpq_archive *mpq_a, const int number, const char *filename);
|
||||
int libmpq_file_getdata(mpq_archive *mpq_a, mpq_hash mpq_h, const int number, unsigned char *dest);
|
||||
#endif /* _MPQ_H */
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* parser.c -- functions used to parse list or config file.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* $Id: parser.c,v 1.5 2004/02/12 00:47:53 mbroemme Exp $
|
||||
*/
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mpq.h"
|
||||
#include "common.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
* This function deletes the specified characters, but leaves
|
||||
* escape sequences unaffected. This means that " would be
|
||||
* deleted but \" would not.
|
||||
*/
|
||||
char *libmpq_conf_delete_char(char *buf, char *chars) {
|
||||
static char *temp;
|
||||
char ch;
|
||||
|
||||
temp = buf;
|
||||
|
||||
/* strip out special chars like " */
|
||||
while (temp = strpbrk(temp, chars)) {
|
||||
ch = temp[0];
|
||||
memmove(&temp[0], &temp[1], strlen(temp));
|
||||
if (ch == '\\') {
|
||||
temp++;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function parses a line for the value to the given option. It
|
||||
* return 1 on success and the byte array or 0 and null.
|
||||
*/
|
||||
int libmpq_conf_parse_line(char *line, char *search_value, char *return_value, int size) {
|
||||
int level = 0;
|
||||
int found = 0;
|
||||
int i = 0;
|
||||
int pos = 0;
|
||||
|
||||
/* search value */
|
||||
while (*(++line)) {
|
||||
|
||||
/* check for spaces */
|
||||
if (!isspace(*line) && level == 1) {
|
||||
|
||||
/* we found our value so break */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* check for '=' so the value follows as next parameter */
|
||||
if (*line == '=' && level == 0) {
|
||||
level = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* now search for comment in this line */
|
||||
for (i = 0; i < int(strlen(line)); i++) {
|
||||
if (line[i] == '#') {
|
||||
pos = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* now set end of byte array behind value, but only if comment was found */
|
||||
if (pos != 0) {
|
||||
for (i = pos; i >= 0; i--) {
|
||||
if (line[i] != ' ' && line[i] != '\t') {
|
||||
line[i + 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* now check if line has trailing spaces */
|
||||
for (i = strlen(line); i >= 0; i--) {
|
||||
if (line[i] != ' ' && line[i] != '\t') {
|
||||
line[i + 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* now check if value is quoted with "" and if there is a char behind. */
|
||||
for (i = strlen(line); i >= 0; i--) {
|
||||
if (line[i] == '"') {
|
||||
line[i + 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the values */
|
||||
strncpy(return_value, line, size);
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the value for a given option in the
|
||||
* listdb or config file. On success it returns 1, otherwise 0.
|
||||
*/
|
||||
int libmpq_conf_get_value(FILE *fp, char *search_value, void *return_value, int type, int size) {
|
||||
char buf[LIBMPQ_CONF_BUFSIZE];
|
||||
int found = 0;
|
||||
int result = LIBMPQ_TOOLS_SUCCESS;
|
||||
|
||||
while (fgets(buf, LIBMPQ_CONF_BUFSIZE, fp) != NULL) {
|
||||
char *line;
|
||||
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
/* skip whitespace */
|
||||
for (line = buf; isspace(*line); line++) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip empty line */
|
||||
if (line[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip comments */
|
||||
if (line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* process the line */
|
||||
//if (!strncasecmp(line, search_value, strlen(search_value))) {
|
||||
if (!strcmp(line, search_value)) {
|
||||
found = libmpq_conf_parse_line(line, search_value, line, LIBMPQ_CONF_BUFSIZE);
|
||||
if (found == 1) {
|
||||
libmpq_conf_delete_char(line, "\"\\");
|
||||
|
||||
switch (type) {
|
||||
case LIBMPQ_CONF_TYPE_INT:
|
||||
|
||||
/* if it is no valid number it is safe to return 0 */
|
||||
*(int *)return_value = atoi(line);
|
||||
break;
|
||||
default:
|
||||
strncpy((char *)return_value, line, size);
|
||||
break;
|
||||
}
|
||||
|
||||
/* value found, so rewind stream */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if value was not found */
|
||||
if (found == 0) {
|
||||
switch (type) {
|
||||
case LIBMPQ_CONF_TYPE_INT:
|
||||
*(int *)return_value = 0;
|
||||
result = LIBMPQ_CONF_EVALUE_NOT_FOUND;
|
||||
break;
|
||||
default:
|
||||
strncpy((char *)return_value, "", size);
|
||||
result = LIBMPQ_CONF_EVALUE_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns a pointer to a byte array, with all values
|
||||
* found in the config file. As second value it returns th number of
|
||||
* entries in the byte array. On success it returns 1, otherwise 0.
|
||||
*/
|
||||
int libmpq_conf_get_array(FILE *fp, char *search_value, char ***filelist, int *entries) {
|
||||
char buf[LIBMPQ_CONF_BUFSIZE];
|
||||
char temp[LIBMPQ_CONF_BUFSIZE];
|
||||
int level = 0;
|
||||
int array_start = 0;
|
||||
int array_end = 0;
|
||||
int fl_count;
|
||||
int fl_size;
|
||||
int found = 0;
|
||||
int i = 0;
|
||||
|
||||
*entries = 0;
|
||||
|
||||
/* allocate memory for the file list */
|
||||
(*filelist) = (char **)malloc(LIBMPQ_CONF_FL_INCREMENT * sizeof(char *));
|
||||
fl_count = 0;
|
||||
fl_size = LIBMPQ_CONF_FL_INCREMENT;
|
||||
|
||||
while (fgets(buf, LIBMPQ_CONF_BUFSIZE, fp) != NULL) {
|
||||
char *line;
|
||||
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
/* skip whitespace */
|
||||
for (line = buf; isspace(*line); line++) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip empty line */
|
||||
if (line[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip comments */
|
||||
if (line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check for array end ) */
|
||||
if (*line == ')') {
|
||||
array_end = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* process entries between () */
|
||||
if (array_start == 1 && array_end == 0) {
|
||||
|
||||
/* add dummy option to use with libmpq_conf_parse_line() */
|
||||
strncpy(temp, "MPQ_BUFFER = ", LIBMPQ_CONF_BUFSIZE);
|
||||
strncat(temp, line, LIBMPQ_CONF_BUFSIZE);
|
||||
found = libmpq_conf_parse_line(temp, "MPQ_BUFFER", temp, LIBMPQ_CONF_BUFSIZE);
|
||||
|
||||
if (found == 1) {
|
||||
libmpq_conf_delete_char(temp, "\"\\");
|
||||
|
||||
/* set the next filelist entry to a copy of the file */
|
||||
(*filelist)[fl_count++] = _strdup(temp);
|
||||
|
||||
/* increase the array size */
|
||||
if (fl_count == fl_size) {
|
||||
(*filelist) = (char **)realloc((*filelist), (fl_size + LIBMPQ_CONF_FL_INCREMENT) * sizeof(char *));
|
||||
fl_size += LIBMPQ_CONF_FL_INCREMENT;
|
||||
}
|
||||
|
||||
/* increase number of entries */
|
||||
(*entries)++;
|
||||
}
|
||||
}
|
||||
|
||||
/* process the line and search array start */
|
||||
//if (!strncasecmp(line, search_value, strlen(search_value))) {
|
||||
if (!strcmp(line, search_value)) {
|
||||
|
||||
/* search value */
|
||||
while (*(++line)) {
|
||||
|
||||
/* check for array start ( */
|
||||
if (*line == '(' && level == 1) {
|
||||
|
||||
/* we found our value so break */
|
||||
array_start = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* check for '=' so the value follows as next parameter */
|
||||
if (*line == '=' && level == 0) {
|
||||
level = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we got all files, so rewind stream */
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
|
||||
(*filelist)[fl_count] = NULL;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* wave.c -- this file contains decompression methods used by Storm.dll
|
||||
* to decompress wave files.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This source was adepted from the C++ version of wave.cpp included
|
||||
* in stormlib. The C++ version belongs to the following authors,
|
||||
*
|
||||
* Ladislav Zezula <ladik.zezula.net>
|
||||
* Tom Amigo <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "wave.h"
|
||||
|
||||
/* Tables necessary dor decompression */
|
||||
static unsigned long wave_table_1503f120[] = {
|
||||
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006,
|
||||
0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
|
||||
0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
|
||||
0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008
|
||||
};
|
||||
|
||||
static unsigned long wave_table_1503f1a0[] = {
|
||||
0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
|
||||
0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F,
|
||||
0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042,
|
||||
0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F,
|
||||
0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133,
|
||||
0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292,
|
||||
0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583,
|
||||
0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0,
|
||||
0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954,
|
||||
0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B,
|
||||
0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462,
|
||||
0x00007FFF
|
||||
};
|
||||
|
||||
/*
|
||||
* Decompress a wave file, mono or stereo
|
||||
*
|
||||
* Offset: 1500F230
|
||||
*/
|
||||
int libmpq_wave_decompress(unsigned char *out_buf, int out_length, unsigned char *in_buf, int in_length, int channels) {
|
||||
byte_and_short out;
|
||||
byte_and_short in;
|
||||
unsigned char *in_end = in_buf + in_length; /* End on input buffer */
|
||||
unsigned long index;
|
||||
long nr_array1[2];
|
||||
long nr_array2[2];
|
||||
int count = 0;
|
||||
|
||||
out.pb = out_buf;
|
||||
in.pb = in_buf;
|
||||
nr_array1[0] = 0x2C;
|
||||
nr_array1[1] = 0x2C;
|
||||
in.pw++;
|
||||
|
||||
/* 15007AD7 */
|
||||
for (count = 0; count < channels; count++) {
|
||||
long temp;
|
||||
temp = *(short *)in.pw++;
|
||||
nr_array2[count] = temp;
|
||||
if (out_length < 2) {
|
||||
return out.pb - out_buf;
|
||||
}
|
||||
*out.pw++ = (unsigned short)temp;
|
||||
out_length -= 2;
|
||||
}
|
||||
index = channels - 1;
|
||||
while (in.pb < in_end) {
|
||||
unsigned char one_byte = *in.pb++;
|
||||
if (channels == 2) {
|
||||
index = (index == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get one byte from input buffer
|
||||
* 15007B25
|
||||
*/
|
||||
if (one_byte & 0x80) {
|
||||
/* 15007B32 */
|
||||
switch(one_byte & 0x7F) {
|
||||
case 0: /* 15007B8E */
|
||||
if (nr_array1[index] != 0) {
|
||||
nr_array1[index]--;
|
||||
}
|
||||
if (out_length < 2) {
|
||||
break;
|
||||
}
|
||||
*out.pw++ = (unsigned short)nr_array2[index];
|
||||
out_length -= 2;
|
||||
continue;
|
||||
case 1: /* 15007B72 */
|
||||
nr_array1[index] += 8; /* EBX also */
|
||||
if (nr_array1[index] > 0x58) {
|
||||
nr_array1[index] = 0x58;
|
||||
}
|
||||
if (channels == 2) {
|
||||
index = (index == 0) ? 1 : 0;
|
||||
}
|
||||
continue;
|
||||
case 2:
|
||||
continue;
|
||||
default:
|
||||
nr_array1[index] -= 8;
|
||||
if (nr_array1[index] < 0) {
|
||||
nr_array1[index] = 0;
|
||||
}
|
||||
if (channels != 2) {
|
||||
continue;
|
||||
}
|
||||
index = (index == 0) ? 1 : 0;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
unsigned long temp1 = wave_table_1503f1a0[nr_array1[index]]; /* EDI */
|
||||
unsigned long temp2 = temp1 >> in_buf[1]; /* ESI */
|
||||
long temp3 = nr_array2[index]; /* ECX */
|
||||
if (one_byte & 0x01) { /* EBX = one_byte */
|
||||
temp2 += (temp1 >> 0);
|
||||
}
|
||||
if (one_byte & 0x02) {
|
||||
temp2 += (temp1 >> 1);
|
||||
}
|
||||
if (one_byte & 0x04) {
|
||||
temp2 += (temp1 >> 2);
|
||||
}
|
||||
if (one_byte & 0x08) {
|
||||
temp2 += (temp1 >> 3);
|
||||
}
|
||||
if (one_byte & 0x10) {
|
||||
temp2 += (temp1 >> 4);
|
||||
}
|
||||
if (one_byte & 0x20) {
|
||||
temp2 += (temp1 >> 5);
|
||||
}
|
||||
if(one_byte & 0x40) {
|
||||
temp3 -= temp2;
|
||||
if (temp3 <= (long)0xFFFF8000) {
|
||||
temp3 = (long)0xFFFF8000;
|
||||
}
|
||||
} else {
|
||||
temp3 += temp2;
|
||||
if (temp3 >= 0x7FFF) {
|
||||
temp3 = 0x7FFF;
|
||||
}
|
||||
}
|
||||
nr_array2[index] = temp3;
|
||||
if (out_length < 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
temp2 = nr_array1[index];
|
||||
one_byte &= 0x1F;
|
||||
*out.pw++ = (unsigned short)temp3;
|
||||
out_length -= 2;
|
||||
temp2 += wave_table_1503f120[one_byte];
|
||||
nr_array1[index] = temp2;
|
||||
|
||||
if (nr_array1[index] < 0) {
|
||||
nr_array1[index] = 0;
|
||||
} else {
|
||||
if (nr_array1[index] > 0x58) {
|
||||
nr_array1[index] = 0x58;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (out.pb - out_buf);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* wave.h -- header file for WAVe unplode functions used by mpq-tools.
|
||||
*
|
||||
* Copyright (C) 2003 Maik Broemme <[email protected]>
|
||||
*
|
||||
* This source was adepted from the C++ version of wave.h included
|
||||
* in stormlib. The C++ version belongs to the following authors,
|
||||
*
|
||||
* Ladislav Zezula <ladik.zezula.net>
|
||||
* Tom Amigo <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _WAVE_H
|
||||
#define _WAVE_H
|
||||
|
||||
typedef union {
|
||||
unsigned short *pw;
|
||||
unsigned char *pb;
|
||||
} byte_and_short;
|
||||
|
||||
int libmpq_wave_decompress(unsigned char *out_buf, int out_length, unsigned char *in_buf, int in_length, int channels);
|
||||
|
||||
#endif /* _WAVE_H */
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2003 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
/*
|
||||
* If you *really* need a unique prefix for all types and library functions,
|
||||
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
|
||||
*/
|
||||
#ifdef Z_PREFIX
|
||||
# define deflateInit_ z_deflateInit_
|
||||
# define deflate z_deflate
|
||||
# define deflateEnd z_deflateEnd
|
||||
# define inflateInit_ z_inflateInit_
|
||||
# define inflate z_inflate
|
||||
# define inflateEnd z_inflateEnd
|
||||
# define deflateInit2_ z_deflateInit2_
|
||||
# define deflateSetDictionary z_deflateSetDictionary
|
||||
# define deflateCopy z_deflateCopy
|
||||
# define deflateReset z_deflateReset
|
||||
# define deflatePrime z_deflatePrime
|
||||
# define deflateParams z_deflateParams
|
||||
# define deflateBound z_deflateBound
|
||||
# define inflateInit2_ z_inflateInit2_
|
||||
# define inflateSetDictionary z_inflateSetDictionary
|
||||
# define inflateSync z_inflateSync
|
||||
# define inflateSyncPoint z_inflateSyncPoint
|
||||
# define inflateCopy z_inflateCopy
|
||||
# define inflateReset z_inflateReset
|
||||
# define compress z_compress
|
||||
# define compress2 z_compress2
|
||||
# define compressBound z_compressBound
|
||||
# define uncompress z_uncompress
|
||||
# define adler32 z_adler32
|
||||
# define crc32 z_crc32
|
||||
# define get_crc_table z_get_crc_table
|
||||
|
||||
# define Byte z_Byte
|
||||
# define uInt z_uInt
|
||||
# define uLong z_uLong
|
||||
# define Bytef z_Bytef
|
||||
# define charf z_charf
|
||||
# define intf z_intf
|
||||
# define uIntf z_uIntf
|
||||
# define uLongf z_uLongf
|
||||
# define voidpf z_voidpf
|
||||
# define voidp z_voidp
|
||||
#endif
|
||||
|
||||
#if defined(__MSDOS__) && !defined(MSDOS)
|
||||
# define MSDOS
|
||||
#endif
|
||||
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
|
||||
# define OS2
|
||||
#endif
|
||||
#if defined(_WINDOWS) && !defined(WINDOWS)
|
||||
# define WINDOWS
|
||||
#endif
|
||||
#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
|
||||
# define WIN32
|
||||
#endif
|
||||
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
|
||||
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
|
||||
# ifndef SYS16BIT
|
||||
# define SYS16BIT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
|
||||
* than 64k bytes at a time (needed on systems with 16-bit int).
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# define MAXSEG_64K
|
||||
#endif
|
||||
#ifdef MSDOS
|
||||
# define UNALIGNED_OK
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_VERSION__
|
||||
# ifndef STDC
|
||||
# define STDC
|
||||
# endif
|
||||
# if __STDC_VERSION__ >= 199901L
|
||||
# ifndef STDC99
|
||||
# define STDC99
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#ifndef STDC
|
||||
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
|
||||
# define const /* note: need a more gentle solution here */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Some Mac compilers merge all .h files incorrectly: */
|
||||
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
|
||||
# define NO_DUMMY_DECL
|
||||
#endif
|
||||
|
||||
/* Maximum value for memLevel in deflateInit2 */
|
||||
#ifndef MAX_MEM_LEVEL
|
||||
# ifdef MAXSEG_64K
|
||||
# define MAX_MEM_LEVEL 8
|
||||
# else
|
||||
# define MAX_MEM_LEVEL 9
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
|
||||
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
|
||||
* created by gzip. (Files created by minigzip can still be extracted by
|
||||
* gzip.)
|
||||
*/
|
||||
#ifndef MAX_WBITS
|
||||
# define MAX_WBITS 15 /* 32K LZ77 window */
|
||||
#endif
|
||||
|
||||
/* The memory requirements for deflate are (in bytes):
|
||||
(1 << (windowBits+2)) + (1 << (memLevel+9))
|
||||
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
|
||||
plus a few kilobytes for small objects. For example, if you want to reduce
|
||||
the default memory requirements from 256K to 128K, compile with
|
||||
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
|
||||
Of course this will generally degrade compression (there's no free lunch).
|
||||
|
||||
The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||
that is, 32K for windowBits=15 (default value) plus a few kilobytes
|
||||
for small objects.
|
||||
*/
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
#ifndef OF /* function prototypes */
|
||||
# ifdef STDC
|
||||
# define OF(args) args
|
||||
# else
|
||||
# define OF(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The following definitions for FAR are needed only for MSDOS mixed
|
||||
* model programming (small or medium model with some far allocations).
|
||||
* This was tested only with MSC; for other MSDOS compilers you may have
|
||||
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
|
||||
* just define FAR to be empty.
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# if defined(M_I86SM) || defined(M_I86MM)
|
||||
/* MSC small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef _MSC_VER
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
# if (defined(__SMALL__) || defined(__MEDIUM__))
|
||||
/* Turbo C small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef __BORLANDC__
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(WINDOWS) || defined(WIN32)
|
||||
/* If building or using zlib as a DLL, define ZLIB_DLL.
|
||||
* This is not mandatory, but it offers a little performance increase.
|
||||
*/
|
||||
# ifdef ZLIB_DLL
|
||||
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
|
||||
# ifdef ZLIB_INTERNAL
|
||||
# define ZEXTERN extern __declspec(dllexport)
|
||||
# else
|
||||
# define ZEXTERN extern __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
# endif /* ZLIB_DLL */
|
||||
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
|
||||
* define ZLIB_WINAPI.
|
||||
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
|
||||
*/
|
||||
# ifdef ZLIB_WINAPI
|
||||
# ifdef FAR
|
||||
# undef FAR
|
||||
# endif
|
||||
# include <windows.h>
|
||||
/* No need for _export, use ZLIB.DEF instead. */
|
||||
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
||||
# define ZEXPORT WINAPI
|
||||
# ifdef WIN32
|
||||
# define ZEXPORTVA WINAPIV
|
||||
# else
|
||||
# define ZEXPORTVA FAR CDECL
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (__BEOS__)
|
||||
# ifdef ZLIB_DLL
|
||||
# ifdef ZLIB_INTERNAL
|
||||
# define ZEXPORT __declspec(dllexport)
|
||||
# define ZEXPORTVA __declspec(dllexport)
|
||||
# else
|
||||
# define ZEXPORT __declspec(dllimport)
|
||||
# define ZEXPORTVA __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ZEXTERN
|
||||
# define ZEXTERN extern
|
||||
#endif
|
||||
#ifndef ZEXPORT
|
||||
# define ZEXPORT
|
||||
#endif
|
||||
#ifndef ZEXPORTVA
|
||||
# define ZEXPORTVA
|
||||
#endif
|
||||
|
||||
#ifndef FAR
|
||||
# define FAR
|
||||
#endif
|
||||
|
||||
#if !defined(__MACTYPES__)
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
#endif
|
||||
typedef unsigned int uInt; /* 16 bits or more */
|
||||
typedef unsigned long uLong; /* 32 bits or more */
|
||||
|
||||
#ifdef SMALL_MEDIUM
|
||||
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
|
||||
# define Bytef Byte FAR
|
||||
#else
|
||||
typedef Byte FAR Bytef;
|
||||
#endif
|
||||
typedef char FAR charf;
|
||||
typedef int FAR intf;
|
||||
typedef uInt FAR uIntf;
|
||||
typedef uLong FAR uLongf;
|
||||
|
||||
#ifdef STDC
|
||||
typedef void const *voidpc;
|
||||
typedef void FAR *voidpf;
|
||||
typedef void *voidp;
|
||||
#else
|
||||
typedef Byte const *voidpc;
|
||||
typedef Byte FAR *voidpf;
|
||||
typedef Byte *voidp;
|
||||
#endif
|
||||
|
||||
#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
|
||||
# include <sys/types.h> /* for off_t */
|
||||
# include <unistd.h> /* for SEEK_* and off_t */
|
||||
# ifdef VMS
|
||||
# include <unixio.h> /* for off_t */
|
||||
# endif
|
||||
# define z_off_t off_t
|
||||
#endif
|
||||
#ifndef SEEK_SET
|
||||
# define SEEK_SET 0 /* Seek from beginning of file. */
|
||||
# define SEEK_CUR 1 /* Seek from current position. */
|
||||
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
|
||||
#endif
|
||||
#ifndef z_off_t
|
||||
# define z_off_t long
|
||||
#endif
|
||||
|
||||
#if defined(__OS400__)
|
||||
#define NO_vsnprintf
|
||||
#endif
|
||||
|
||||
#if defined(__MVS__)
|
||||
# define NO_vsnprintf
|
||||
# ifdef FAR
|
||||
# undef FAR
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
#if defined(__MVS__)
|
||||
# pragma map(deflateInit_,"DEIN")
|
||||
# pragma map(deflateInit2_,"DEIN2")
|
||||
# pragma map(deflateEnd,"DEEND")
|
||||
# pragma map(deflateBound,"DEBND")
|
||||
# pragma map(inflateInit_,"ININ")
|
||||
# pragma map(inflateInit2_,"ININ2")
|
||||
# pragma map(inflateEnd,"INEND")
|
||||
# pragma map(inflateSync,"INSY")
|
||||
# pragma map(inflateSetDictionary,"INSEDI")
|
||||
# pragma map(compressBound,"CMBND")
|
||||
# pragma map(inflate_table,"INTABL")
|
||||
# pragma map(inflate_fast,"INFA")
|
||||
# pragma map(inflate_copyright,"INCOPY")
|
||||
#endif
|
||||
|
||||
#endif /* ZCONF_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
add_library (loadlib loadlib.cpp adt.cpp wdt.cpp)
|
||||
# link loadlib with zlib
|
||||
target_link_libraries (loadlib z)
|
||||
@@ -0,0 +1,131 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "adt.h"
|
||||
|
||||
// Helper
|
||||
int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888};
|
||||
int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000};
|
||||
|
||||
bool isHole(int holes, int i, int j)
|
||||
{
|
||||
int testi = i / 2;
|
||||
int testj = j / 4;
|
||||
if(testi > 3) testi = 3;
|
||||
if(testj > 3) testj = 3;
|
||||
return (holes & holetab_h[testi] & holetab_v[testj]) != 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Adt file loader class
|
||||
//
|
||||
ADT_file::ADT_file()
|
||||
{
|
||||
a_grid = 0;
|
||||
}
|
||||
|
||||
ADT_file::~ADT_file()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void ADT_file::free()
|
||||
{
|
||||
a_grid = 0;
|
||||
FileLoader::free();
|
||||
}
|
||||
|
||||
//
|
||||
// Adt file check function
|
||||
//
|
||||
bool ADT_file::prepareLoadedData()
|
||||
{
|
||||
// Check parent
|
||||
if (!FileLoader::prepareLoadedData())
|
||||
return false;
|
||||
|
||||
// Check and prepare MHDR
|
||||
a_grid = (adt_MHDR *)(GetData()+8+version->size);
|
||||
if (!a_grid->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MHDR::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MHDR')
|
||||
return false;
|
||||
|
||||
if (size!=sizeof(adt_MHDR)-8)
|
||||
return false;
|
||||
|
||||
// Check and prepare MCIN
|
||||
if (offsMCIN && !getMCIN()->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
// Check and prepare MH2O
|
||||
if (offsMH2O && !getMH2O()->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MCIN::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MCIN')
|
||||
return false;
|
||||
|
||||
// Check cells data
|
||||
for (int i=0; i<ADT_CELLS_PER_GRID;i++)
|
||||
for (int j=0; j<ADT_CELLS_PER_GRID;j++)
|
||||
if (cells[i][j].offsMCNK && !getMCNK(i,j)->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MH2O::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MH2O')
|
||||
return false;
|
||||
|
||||
// Check liquid data
|
||||
// for (int i=0; i<ADT_CELLS_PER_GRID;i++)
|
||||
// for (int j=0; j<ADT_CELLS_PER_GRID;j++)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MCNK::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MCNK')
|
||||
return false;
|
||||
|
||||
// Check height map
|
||||
if (offsMCVT && !getMCVT()->prepareLoadedData())
|
||||
return false;
|
||||
// Check liquid data
|
||||
if (offsMCLQ && !getMCLQ()->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MCVT::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MCVT')
|
||||
return false;
|
||||
|
||||
if (size != sizeof(adt_MCVT)-8)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MCLQ::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MCLQ')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
#ifndef ADT_H
|
||||
#define ADT_H
|
||||
|
||||
#include "loadlib.h"
|
||||
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
#define UNITSIZE (CHUNKSIZE / 8.0f)
|
||||
|
||||
enum LiquidType
|
||||
{
|
||||
LIQUID_TYPE_WATER = 0,
|
||||
LIQUID_TYPE_OCEAN = 1,
|
||||
LIQUID_TYPE_MAGMA = 2,
|
||||
LIQUID_TYPE_SLIME = 3
|
||||
};
|
||||
|
||||
//**************************************************************************************
|
||||
// ADT file class
|
||||
//**************************************************************************************
|
||||
#define ADT_CELLS_PER_GRID 16
|
||||
#define ADT_CELL_SIZE 8
|
||||
#define ADT_GRID_SIZE (ADT_CELLS_PER_GRID*ADT_CELL_SIZE)
|
||||
|
||||
//
|
||||
// Adt file height map chunk
|
||||
//
|
||||
class adt_MCVT
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
public:
|
||||
float height_map[(ADT_CELL_SIZE+1)*(ADT_CELL_SIZE+1)+ADT_CELL_SIZE*ADT_CELL_SIZE];
|
||||
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file liquid map chunk (old)
|
||||
//
|
||||
class adt_MCLQ
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
public:
|
||||
float height1;
|
||||
float height2;
|
||||
struct liquid_data{
|
||||
uint32 light;
|
||||
float height;
|
||||
} liquid[ADT_CELL_SIZE+1][ADT_CELL_SIZE+1];
|
||||
|
||||
// 1<<0 - ochen
|
||||
// 1<<1 - lava/slime
|
||||
// 1<<2 - water
|
||||
// 1<<6 - all water
|
||||
// 1<<7 - dark water
|
||||
// == 0x0F - not show liquid
|
||||
uint8 flags[ADT_CELL_SIZE][ADT_CELL_SIZE];
|
||||
uint8 data[84];
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file cell chunk
|
||||
//
|
||||
class adt_MCNK
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
public:
|
||||
uint32 flags;
|
||||
uint32 ix;
|
||||
uint32 iy;
|
||||
uint32 nLayers;
|
||||
uint32 nDoodadRefs;
|
||||
uint32 offsMCVT; // height map
|
||||
uint32 offsMCNR; // Normal vectors for each vertex
|
||||
uint32 offsMCLY; // Texture layer definitions
|
||||
uint32 offsMCRF; // A list of indices into the parent file's MDDF chunk
|
||||
uint32 offsMCAL; // Alpha maps for additional texture layers
|
||||
uint32 sizeMCAL;
|
||||
uint32 offsMCSH; // Shadow map for static shadows on the terrain
|
||||
uint32 sizeMCSH;
|
||||
uint32 areaid;
|
||||
uint32 nMapObjRefs;
|
||||
uint32 holes;
|
||||
uint16 s[2];
|
||||
uint32 data1;
|
||||
uint32 data2;
|
||||
uint32 data3;
|
||||
uint32 predTex;
|
||||
uint32 nEffectDoodad;
|
||||
uint32 offsMCSE;
|
||||
uint32 nSndEmitters;
|
||||
uint32 offsMCLQ; // Liqid level (old)
|
||||
uint32 sizeMCLQ; //
|
||||
float zpos;
|
||||
float xpos;
|
||||
float ypos;
|
||||
uint32 offsMCCV; // offsColorValues in WotLK
|
||||
uint32 props;
|
||||
uint32 effectId;
|
||||
|
||||
bool prepareLoadedData();
|
||||
adt_MCVT *getMCVT()
|
||||
{
|
||||
if (offsMCVT)
|
||||
return (adt_MCVT *)((uint8 *)this + offsMCVT);
|
||||
return 0;
|
||||
}
|
||||
adt_MCLQ *getMCLQ()
|
||||
{
|
||||
if (offsMCLQ)
|
||||
return (adt_MCLQ *)((uint8 *)this + offsMCLQ);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file grid chunk
|
||||
//
|
||||
class adt_MCIN
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
public:
|
||||
struct adt_CELLS{
|
||||
uint32 offsMCNK;
|
||||
uint32 size;
|
||||
uint32 flags;
|
||||
uint32 asyncId;
|
||||
} cells[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
|
||||
|
||||
bool prepareLoadedData();
|
||||
// offset from begin file (used this-84)
|
||||
adt_MCNK *getMCNK(int x, int y)
|
||||
{
|
||||
if (cells[x][y].offsMCNK)
|
||||
return (adt_MCNK *)((uint8 *)this + cells[x][y].offsMCNK - 84);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#define ADT_LIQUID_HEADER_FULL_LIGHT 0x01
|
||||
#define ADT_LIQUID_HEADER_NO_HIGHT 0x02
|
||||
|
||||
struct adt_liquid_header{
|
||||
uint16 liquidType; // Index from LiquidType.dbc
|
||||
uint16 formatFlags;
|
||||
float heightLevel1;
|
||||
float heightLevel2;
|
||||
uint8 xOffset;
|
||||
uint8 yOffset;
|
||||
uint8 width;
|
||||
uint8 height;
|
||||
uint32 offsData2a;
|
||||
uint32 offsData2b;
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file liquid data chunk (new)
|
||||
//
|
||||
class adt_MH2O
|
||||
{
|
||||
public:
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
|
||||
struct adt_LIQUID{
|
||||
uint32 offsData1;
|
||||
uint32 used;
|
||||
uint32 offsData2;
|
||||
} liquid[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
|
||||
|
||||
bool prepareLoadedData();
|
||||
|
||||
adt_liquid_header *getLiquidData(int x, int y)
|
||||
{
|
||||
if (liquid[x][y].used && liquid[x][y].offsData1)
|
||||
return (adt_liquid_header *)((uint8*)this + 8 + liquid[x][y].offsData1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float *getLiquidHeightMap(adt_liquid_header *h)
|
||||
{
|
||||
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
|
||||
return 0;
|
||||
if (h->offsData2b)
|
||||
return (float *)((uint8*)this + 8 + h->offsData2b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 *getLiquidLightMap(adt_liquid_header *h)
|
||||
{
|
||||
if (h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT)
|
||||
return 0;
|
||||
if (h->offsData2b)
|
||||
{
|
||||
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
|
||||
return (uint8 *)((uint8*)this + 8 + h->offsData2b);
|
||||
return (uint8 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 *getLiquidFullLightMap(adt_liquid_header *h)
|
||||
{
|
||||
if (!(h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT))
|
||||
return 0;
|
||||
if (h->offsData2b)
|
||||
{
|
||||
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
|
||||
return (uint32 *)((uint8*)this + 8 + h->offsData2b);
|
||||
return (uint32 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64 getLiquidShowMap(adt_liquid_header *h)
|
||||
{
|
||||
if (h->offsData2a)
|
||||
return *((uint64 *)((uint8*)this + 8 + h->offsData2a));
|
||||
else
|
||||
return 0xFFFFFFFFFFFFFFFFLL;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file header chunk
|
||||
//
|
||||
class adt_MHDR
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
|
||||
uint32 pad;
|
||||
uint32 offsMCIN; // MCIN
|
||||
uint32 offsTex; // MTEX
|
||||
uint32 offsModels; // MMDX
|
||||
uint32 offsModelsIds; // MMID
|
||||
uint32 offsMapObejcts; // MWMO
|
||||
uint32 offsMapObejctsIds; // MWID
|
||||
uint32 offsDoodsDef; // MDDF
|
||||
uint32 offsObjectsDef; // MODF
|
||||
uint32 offsMFBO; // MFBO
|
||||
uint32 offsMH2O; // MH2O
|
||||
uint32 data1;
|
||||
uint32 data2;
|
||||
uint32 data3;
|
||||
uint32 data4;
|
||||
uint32 data5;
|
||||
public:
|
||||
bool prepareLoadedData();
|
||||
adt_MCIN *getMCIN(){ return (adt_MCIN *)((uint8 *)&pad+offsMCIN);}
|
||||
adt_MH2O *getMH2O(){ return offsMH2O ? (adt_MH2O *)((uint8 *)&pad+offsMH2O) : 0;}
|
||||
|
||||
};
|
||||
|
||||
class ADT_file : public FileLoader{
|
||||
public:
|
||||
bool prepareLoadedData();
|
||||
ADT_file();
|
||||
~ADT_file();
|
||||
void free();
|
||||
|
||||
adt_MHDR *a_grid;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "loadlib.h"
|
||||
#include "../mpq_libmpq.h"
|
||||
|
||||
class MPQFile;
|
||||
|
||||
FileLoader::FileLoader()
|
||||
{
|
||||
data = 0;
|
||||
data_size = 0;
|
||||
version = 0;
|
||||
}
|
||||
|
||||
FileLoader::~FileLoader()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
bool FileLoader::loadFile(char *filename, bool log)
|
||||
{
|
||||
free();
|
||||
MPQFile mf(filename);
|
||||
if(mf.isEof())
|
||||
{
|
||||
if (log)
|
||||
printf("No such file %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
data_size = mf.getSize();
|
||||
|
||||
data = new uint8 [data_size];
|
||||
if (data)
|
||||
{
|
||||
mf.read(data, data_size);
|
||||
mf.close();
|
||||
if (prepareLoadedData())
|
||||
return true;
|
||||
}
|
||||
printf("Error loading %s", filename);
|
||||
mf.close();
|
||||
free();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileLoader::prepareLoadedData()
|
||||
{
|
||||
// Check version
|
||||
version = (file_MVER *) data;
|
||||
if (version->fcc != 'MVER')
|
||||
return false;
|
||||
if (version->ver != FILE_FORMAT_VERSION)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileLoader::free()
|
||||
{
|
||||
if (data) delete[] data;
|
||||
data = 0;
|
||||
data_size = 0;
|
||||
version = 0;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef LOAD_LIB_H
|
||||
#define LOAD_LIB_H
|
||||
|
||||
#ifdef WIN32
|
||||
typedef __int64 int64;
|
||||
typedef long int32;
|
||||
typedef short int16;
|
||||
typedef char int8;
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef unsigned long uint32;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned char uint8;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#ifndef uint64_t
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
typedef int64_t int64;
|
||||
typedef long int32;
|
||||
typedef short int16;
|
||||
typedef char int8;
|
||||
typedef uint64_t uint64;
|
||||
typedef unsigned long uint32;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned char uint8;
|
||||
#endif
|
||||
|
||||
#define FILE_FORMAT_VERSION 18
|
||||
|
||||
//
|
||||
// File version chunk
|
||||
//
|
||||
struct file_MVER
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
uint32 ver;
|
||||
};
|
||||
|
||||
class FileLoader{
|
||||
uint8 *data;
|
||||
uint32 data_size;
|
||||
public:
|
||||
virtual bool prepareLoadedData();
|
||||
uint8 *GetData() {return data;}
|
||||
uint32 GetDataSize() {return data_size;}
|
||||
|
||||
file_MVER *version;
|
||||
FileLoader();
|
||||
~FileLoader();
|
||||
bool loadFile(char *filename, bool log = true);
|
||||
virtual void free();
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "wdt.h"
|
||||
|
||||
bool wdt_MWMO::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MWMO')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wdt_MPHD::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MPHD')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wdt_MAIN::prepareLoadedData()
|
||||
{
|
||||
if (fcc != 'MAIN')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
WDT_file::WDT_file()
|
||||
{
|
||||
mphd = 0;
|
||||
main = 0;
|
||||
wmo = 0;
|
||||
}
|
||||
|
||||
WDT_file::~WDT_file()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void WDT_file::free()
|
||||
{
|
||||
mphd = 0;
|
||||
main = 0;
|
||||
wmo = 0;
|
||||
FileLoader::free();
|
||||
}
|
||||
|
||||
bool WDT_file::prepareLoadedData()
|
||||
{
|
||||
// Check parent
|
||||
if (!FileLoader::prepareLoadedData())
|
||||
return false;
|
||||
|
||||
mphd = (wdt_MPHD *)((uint8*)version+version->size+8);
|
||||
if (!mphd->prepareLoadedData())
|
||||
return false;
|
||||
main = (wdt_MAIN *)((uint8*)mphd + mphd->size+8);
|
||||
if (!main->prepareLoadedData())
|
||||
return false;
|
||||
wmo = (wdt_MWMO *)((uint8*)main+ main->size+8);
|
||||
if (!wmo->prepareLoadedData())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef WDT_H
|
||||
#define WDT_H
|
||||
#include "loadlib.h"
|
||||
|
||||
//**************************************************************************************
|
||||
// WDT file class and structures
|
||||
//**************************************************************************************
|
||||
#define WDT_MAP_SIZE 64
|
||||
|
||||
class wdt_MWMO{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
class wdt_MPHD{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
|
||||
uint32 data1;
|
||||
uint32 data2;
|
||||
uint32 data3;
|
||||
uint32 data4;
|
||||
uint32 data5;
|
||||
uint32 data6;
|
||||
uint32 data7;
|
||||
uint32 data8;
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
class wdt_MAIN{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
|
||||
struct adtData{
|
||||
uint32 exist;
|
||||
uint32 data1;
|
||||
} adt_list[64][64];
|
||||
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
class WDT_file : public FileLoader{
|
||||
public:
|
||||
bool prepareLoadedData();
|
||||
|
||||
WDT_file();
|
||||
~WDT_file();
|
||||
void free();
|
||||
|
||||
wdt_MPHD *mphd;
|
||||
wdt_MAIN *main;
|
||||
wdt_MWMO *wmo;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
#include "mpq_libmpq.h"
|
||||
#include <deque>
|
||||
|
||||
ArchiveSet gOpenArchives;
|
||||
|
||||
MPQArchive::MPQArchive(const char* filename)
|
||||
{
|
||||
int result = libmpq_archive_open(&mpq_a, (unsigned char*)filename);
|
||||
printf("Opening %s\n", filename);
|
||||
if(result) {
|
||||
switch(result) {
|
||||
case LIBMPQ_EFILE : /* error on file operation */
|
||||
printf("Error opening archive '%s': File operation Error\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EFILE_FORMAT : /* bad file format */
|
||||
printf("Error opening archive '%s': Bad file format\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EFILE_CORRUPT : /* file corrupt */
|
||||
printf("Error opening archive '%s': File corrupt\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EFILE_NOT_FOUND : /* file in archive not found */
|
||||
printf("Error opening archive '%s': File in archive not found\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EFILE_READ : /* Read error in archive */
|
||||
printf("Error opening archive '%s': Read error in archive\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EALLOCMEM : /* maybe not enough memory? :) */
|
||||
printf("Error opening archive '%s': Maybe not enough memory\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EFREEMEM : /* can not free memory */
|
||||
printf("Error opening archive '%s': Cannot free memory\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EINV_RANGE : /* Given filenumber is out of range */
|
||||
printf("Error opening archive '%s': Given filenumber is out of range\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EHASHTABLE : /* error in reading hashtable */
|
||||
printf("Error opening archive '%s': Error in reading hashtable\n", filename);
|
||||
break;
|
||||
case LIBMPQ_EBLOCKTABLE : /* error in reading blocktable */
|
||||
printf("Error opening archive '%s': Error in reading blocktable\n", filename);
|
||||
break;
|
||||
default:
|
||||
printf("Error opening archive '%s': Unknown error\n", filename);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
gOpenArchives.push_front(this);
|
||||
}
|
||||
|
||||
void MPQArchive::close()
|
||||
{
|
||||
//gOpenArchives.erase(erase(&mpq_a);
|
||||
libmpq_archive_close(&mpq_a);
|
||||
}
|
||||
|
||||
MPQFile::MPQFile(const char* filename):
|
||||
eof(false),
|
||||
buffer(0),
|
||||
pointer(0),
|
||||
size(0)
|
||||
{
|
||||
for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i)
|
||||
{
|
||||
mpq_archive &mpq_a = (*i)->mpq_a;
|
||||
|
||||
mpq_hash hash = (*i)->GetHashEntry(filename);
|
||||
uint32 blockindex = hash.blockindex;
|
||||
|
||||
if ((blockindex == 0xFFFFFFFF) || (blockindex == 0)) {
|
||||
continue; //file not found
|
||||
}
|
||||
|
||||
uint32 fileno = blockindex;
|
||||
|
||||
//int fileno = libmpq_file_number(&mpq_a, filename);
|
||||
//if(fileno == LIBMPQ_EFILE_NOT_FOUND)
|
||||
// continue;
|
||||
|
||||
// Found!
|
||||
size = libmpq_file_info(&mpq_a, LIBMPQ_FILE_UNCOMPRESSED_SIZE, fileno);
|
||||
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
|
||||
if (size<=1) {
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
return;
|
||||
}
|
||||
buffer = new char[size];
|
||||
|
||||
//libmpq_file_getdata
|
||||
libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);
|
||||
return;
|
||||
|
||||
}
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
}
|
||||
|
||||
size_t MPQFile::read(void* dest, size_t bytes)
|
||||
{
|
||||
if (eof) return 0;
|
||||
|
||||
size_t rpos = pointer + bytes;
|
||||
if (rpos > size) {
|
||||
bytes = size - pointer;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
memcpy(dest, &(buffer[pointer]), bytes);
|
||||
|
||||
pointer = rpos;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void MPQFile::seek(int offset)
|
||||
{
|
||||
pointer = offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::seekRelative(int offset)
|
||||
{
|
||||
pointer += offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::close()
|
||||
{
|
||||
if (buffer) delete[] buffer;
|
||||
buffer = 0;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#ifndef MPQ_H
|
||||
#define MPQ_H
|
||||
|
||||
#include "loadlib/loadlib.h"
|
||||
#include "libmpq/mpq.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MPQArchive
|
||||
{
|
||||
|
||||
public:
|
||||
mpq_archive mpq_a;
|
||||
|
||||
MPQArchive(const char* filename);
|
||||
void close();
|
||||
|
||||
uint32 HashString(const char* Input, uint32 Offset) {
|
||||
uint32 seed1 = 0x7fed7fed;
|
||||
uint32 seed2 = 0xeeeeeeee;
|
||||
|
||||
for (uint32 i = 0; i < strlen(Input); i++) {
|
||||
uint32 val = toupper(Input[i]);
|
||||
seed1 = mpq_a.buf[Offset + val] ^ (seed1 + seed2);
|
||||
seed2 = val + seed1 + seed2 + (seed2 << 5) + 3;
|
||||
}
|
||||
|
||||
return seed1;
|
||||
}
|
||||
mpq_hash GetHashEntry(const char* Filename) {
|
||||
uint32 index = HashString(Filename, 0);
|
||||
index &= mpq_a.header->hashtablesize - 1;
|
||||
uint32 name1 = HashString(Filename, 0x100);
|
||||
uint32 name2 = HashString(Filename, 0x200);
|
||||
|
||||
for(uint32 i = index; i < mpq_a.header->hashtablesize; ++i) {
|
||||
mpq_hash hash = mpq_a.hashtable[i];
|
||||
if (hash.name1 == name1 && hash.name2 == name2) return hash;
|
||||
}
|
||||
|
||||
mpq_hash nullhash;
|
||||
nullhash.blockindex = 0xFFFFFFFF;
|
||||
return nullhash;
|
||||
}
|
||||
|
||||
void GetFileListTo(vector<string>& filelist) {
|
||||
mpq_hash hash = GetHashEntry("(listfile)");
|
||||
uint32 blockindex = hash.blockindex;
|
||||
|
||||
if ((blockindex == 0xFFFFFFFF) || (blockindex == 0))
|
||||
return;
|
||||
|
||||
uint32 size = libmpq_file_info(&mpq_a, LIBMPQ_FILE_UNCOMPRESSED_SIZE, blockindex);
|
||||
char *buffer = new char[size];
|
||||
|
||||
libmpq_file_getdata(&mpq_a, hash, blockindex, (unsigned char*)buffer);
|
||||
|
||||
char seps[] = "\n";
|
||||
char *token;
|
||||
|
||||
token = strtok( buffer, seps );
|
||||
uint32 counter = 0;
|
||||
while ((token != NULL) && (counter < size)) {
|
||||
//cout << token << endl;
|
||||
token[strlen(token) - 1] = 0;
|
||||
string s = token;
|
||||
filelist.push_back(s);
|
||||
counter += strlen(token) + 2;
|
||||
token = strtok(NULL, seps);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
};
|
||||
typedef std::deque<MPQArchive*> ArchiveSet;
|
||||
|
||||
class MPQFile
|
||||
{
|
||||
//MPQHANDLE handle;
|
||||
bool eof;
|
||||
char *buffer;
|
||||
size_t pointer,size;
|
||||
|
||||
// disable copying
|
||||
MPQFile(const MPQFile &f) {}
|
||||
void operator=(const MPQFile &f) {}
|
||||
|
||||
public:
|
||||
MPQFile(const char* filename); // filenames are not case sensitive
|
||||
~MPQFile() { close(); }
|
||||
size_t read(void* dest, size_t bytes);
|
||||
size_t getSize() { return size; }
|
||||
size_t getPos() { return pointer; }
|
||||
char* getBuffer() { return buffer; }
|
||||
char* getPointer() { return buffer + pointer; }
|
||||
bool isEof() { return eof; }
|
||||
void seek(int offset);
|
||||
void seekRelative(int offset);
|
||||
void close();
|
||||
};
|
||||
|
||||
inline void flipcc(char *fcc)
|
||||
{
|
||||
char t;
|
||||
t=fcc[0];
|
||||
fcc[0]=fcc[3];
|
||||
fcc[3]=t;
|
||||
t=fcc[1];
|
||||
fcc[1]=fcc[2];
|
||||
fcc[2]=t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,85 @@
|
||||
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (MANGOS_VMAP_ASSEMB_IO)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE true)
|
||||
|
||||
# uncomment next line to disable debug mode
|
||||
ADD_DEFINITIONS("-DIOMAP_DEBUG")
|
||||
|
||||
ADD_DEFINITIONS("-Wall")
|
||||
ADD_DEFINITIONS("-ggdb")
|
||||
ADD_DEFINITIONS("-O3")
|
||||
|
||||
include_directories(../../src/shared/vmap/)
|
||||
include_directories(../../dep/include/g3dlite/)
|
||||
include_directories(../../dep/ACE_wrappers/)
|
||||
include_directories(../../objdir/dep/ACE_wrappers)
|
||||
include_directories(../../src/framework/)
|
||||
|
||||
add_library(g3dlite ../../dep/src/g3dlite/AABox.cpp
|
||||
../../dep/src/g3dlite/Box.cpp
|
||||
../../dep/src/g3dlite/Crypto.cpp
|
||||
../../dep/src/g3dlite/format.cpp
|
||||
../../dep/src/g3dlite/Matrix3.cpp
|
||||
../../dep/src/g3dlite/Plane.cpp
|
||||
../../dep/src/g3dlite/System.cpp
|
||||
../../dep/src/g3dlite/Triangle.cpp
|
||||
../../dep/src/g3dlite/Vector3.cpp
|
||||
../../dep/src/g3dlite/Vector4.cpp
|
||||
../../dep/src/g3dlite/debugAssert.cpp
|
||||
../../dep/src/g3dlite/fileutils.cpp
|
||||
../../dep/src/g3dlite/g3dmath.cpp
|
||||
../../dep/src/g3dlite/g3dfnmatch.cpp
|
||||
../../dep/src/g3dlite/prompt.cpp
|
||||
../../dep/src/g3dlite/stringutils.cpp
|
||||
../../dep/src/g3dlite/Any.cpp
|
||||
../../dep/src/g3dlite/BinaryFormat.cpp
|
||||
../../dep/src/g3dlite/BinaryInput.cpp
|
||||
../../dep/src/g3dlite/BinaryOutput.cpp
|
||||
../../dep/src/g3dlite/Capsule.cpp
|
||||
../../dep/src/g3dlite/CollisionDetection.cpp
|
||||
../../dep/src/g3dlite/CoordinateFrame.cpp
|
||||
../../dep/src/g3dlite/Cylinder.cpp
|
||||
../../dep/src/g3dlite/Line.cpp
|
||||
../../dep/src/g3dlite/LineSegment.cpp
|
||||
../../dep/src/g3dlite/Log.cpp
|
||||
../../dep/src/g3dlite/Matrix4.cpp
|
||||
../../dep/src/g3dlite/MemoryManager.cpp
|
||||
../../dep/src/g3dlite/Quat.cpp
|
||||
../../dep/src/g3dlite/Random.cpp
|
||||
../../dep/src/g3dlite/Ray.cpp
|
||||
../../dep/src/g3dlite/ReferenceCount.cpp
|
||||
../../dep/src/g3dlite/Sphere.cpp
|
||||
../../dep/src/g3dlite/TextInput.cpp
|
||||
../../dep/src/g3dlite/TextOutput.cpp
|
||||
../../dep/src/g3dlite/UprightFrame.cpp
|
||||
../../dep/src/g3dlite/Vector2.cpp
|
||||
)
|
||||
|
||||
add_library(vmap
|
||||
../../src/shared/vmap/BIH.cpp
|
||||
../../src/shared/vmap/VMapManager2.cpp
|
||||
../../src/shared/vmap/MapTree.cpp
|
||||
../../src/shared/vmap/TileAssembler.cpp
|
||||
../../src/shared/vmap/WorldModel.cpp
|
||||
../../src/shared/vmap/ModelInstance.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(vmap g3dlite z)
|
||||
|
||||
add_executable(vmap_assembler vmap_assembler.cpp)
|
||||
target_link_libraries(vmap_assembler vmap)
|
||||
|
||||
# add_executable(vmap_test coordinate_test.cpp)
|
||||
# target_link_libraries(vmap_test vmap)
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="vmap_assembler"
|
||||
ProjectGUID="{572FFF74-480C-4472-8ABF-81733BB4049D}"
|
||||
RootNamespace="vmap_assembler"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="..\bin\$(PlatformName)_$(ConfigurationName)\"
|
||||
IntermediateDirectory="bin\$(ProjectName)__$(PlatformName)_$(ConfigurationName)\"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\..\dep\include\g3dlite;..\..\..\src\shared\vmap;"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
EnableEnhancedInstructionSet="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/vmap_assembler.exe"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile="$(OutDir)/vmap_assembler.pdb"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="..\bin\$(PlatformName)_$(ConfigurationName)\"
|
||||
IntermediateDirectory="bin\$(ProjectName)__$(PlatformName)_$(ConfigurationName)\"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\..\dep\include\g3dlite;..\..\..\src\shared\vmap;..\..\..\src\framework;..\..\..\dep\ACE_wrappers"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableEnhancedInstructionSet="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/vmap_assembler.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\..\vmap_assembler.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="vmaplib"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\BIH.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\BIH.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\MapTree.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\MapTree.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\ModelInstance.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\ModelInstance.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\TileAssembler.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\TileAssembler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\VMapManager2.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\VMapManager2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\VMapTools.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\WorldModel.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\shared\vmap\WorldModel.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,21 @@
|
||||
# list of map names
|
||||
|
||||
509 #AhnQiraj
|
||||
469 #BlackwingLair
|
||||
189 #MonasteryInstances
|
||||
030 #PVPZone01
|
||||
037 #PVPZone02
|
||||
033 #Shadowfang
|
||||
533 #Stratholme Raid
|
||||
209 #TanarisInstance
|
||||
309 #Zul'gurub
|
||||
560 #HillsbradPast
|
||||
534 #HyjalPast
|
||||
532 #Karazahn
|
||||
543 #HellfireRampart
|
||||
568 #ZulAman
|
||||
564 #BlackTemple
|
||||
574 #UtgardeKeep
|
||||
575 #UtgardePinnacle
|
||||
609 #EbonHold
|
||||
628 #IsleOfConquest
|
||||
@@ -0,0 +1,120 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "TileAssembler.h"
|
||||
|
||||
//=======================================================
|
||||
// remove last return or LF and tailing SPACE
|
||||
// remove all char after a #
|
||||
|
||||
void chompAndTrim(std::string& str)
|
||||
{
|
||||
for(unsigned int i=0;i<str.length(); ++i) {
|
||||
char lc = str[i];
|
||||
if(lc == '#') {
|
||||
str = str.substr(0,i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while(str.length() >0) {
|
||||
char lc = str[str.length()-1];
|
||||
if(lc == '\r' || lc == '\n' || lc == ' ') {
|
||||
str = str.substr(0,str.length()-1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
/**
|
||||
This callback method is called for each model found in the dir file.
|
||||
return true if it should be included in the vmap
|
||||
*/
|
||||
bool modelNameFilter(char *pName)
|
||||
{
|
||||
#if 0
|
||||
bool result;
|
||||
result = !Wildcard::wildcardfit("*bush[0-9]*", pName);
|
||||
if(result) result = !Wildcard::wildcardfit("*shrub[0-9]*", pName);
|
||||
if(result) result = !Wildcard::wildcardfit("*_Bushes_*", pName);
|
||||
if(result) result = !Wildcard::wildcardfit("*_Bush_*", pName);
|
||||
if(!result) {
|
||||
printf("%s",pName);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
/**
|
||||
File contains map names that should be split into tiles
|
||||
A '#' at the beginning of a line defines a comment
|
||||
*/
|
||||
|
||||
/* bool readConfigFile(char *pConffile, VMAP::TileAssembler* pTa)
|
||||
{
|
||||
bool result = false;
|
||||
char buffer[501];
|
||||
FILE *cf = fopen(pConffile, "rb");
|
||||
if(cf) {
|
||||
while(fgets(buffer, 500, cf)) {
|
||||
std::string name = std::string(buffer);
|
||||
size_t pos = name.find_first_not_of(' ');
|
||||
name = name.substr(pos);
|
||||
chompAndTrim(name); // just to be sure
|
||||
if(name[0] != '#' && name.size() >0) { // comment?
|
||||
unsigned int mapId = atoi(name.c_str());
|
||||
pTa->addWorldAreaMapId(mapId);
|
||||
}
|
||||
}
|
||||
fclose(cf);
|
||||
result = true;
|
||||
}
|
||||
return(result);
|
||||
} */
|
||||
//=======================================================
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if(argc != 3 && argc != 4)
|
||||
{
|
||||
printf("\nusage: %s <raw data dir> <vmap dest dir> [config file name]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *src = argv[1];
|
||||
char *dest = argv[2];
|
||||
char *conffile = NULL;
|
||||
if(argc >= 4)
|
||||
conffile = argv[3];
|
||||
|
||||
VMAP::TileAssembler* ta = new VMAP::TileAssembler(std::string(src), std::string(dest));
|
||||
ta->setModelNameFilterMethod(modelNameFilter);
|
||||
|
||||
/*
|
||||
All the names in the list are considered to be world maps or huge instances.
|
||||
These maps will be spilt into tiles in the vmap assemble process
|
||||
*/
|
||||
/* if(conffile != NULL)
|
||||
{
|
||||
if(!readConfigFile(conffile, ta))
|
||||
{
|
||||
printf("Can not open file config file: %s\n", conffile);
|
||||
delete ta;
|
||||
return 1;
|
||||
}
|
||||
} */
|
||||
|
||||
if(!ta->convertWorld2())
|
||||
{
|
||||
printf("exit with errors\n");
|
||||
delete ta;
|
||||
return 1;
|
||||
}
|
||||
|
||||
delete ta;
|
||||
printf("Ok, all done\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmap_assembler", "VC90\vmap_assembler.vcproj", "{572FFF74-480C-4472-8ABF-81733BB4049D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} = {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}
|
||||
{8072769E-CF10-48BF-B9E1-12752A5DAC6E} = {8072769E-CF10-48BF-B9E1-12752A5DAC6E}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\..\win\VC90\zlib.vcproj", "{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "g3dlite", "..\..\win\VC90\g3dlite.vcproj", "{8072769E-CF10-48BF-B9E1-12752A5DAC6E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug_NoPCH|Win32 = Debug_NoPCH|Win32
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{572FFF74-480C-4472-8ABF-81733BB4049D}.Debug_NoPCH|Win32.ActiveCfg = Debug|Win32
|
||||
{572FFF74-480C-4472-8ABF-81733BB4049D}.Debug_NoPCH|Win32.Build.0 = Debug|Win32
|
||||
{572FFF74-480C-4472-8ABF-81733BB4049D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{572FFF74-480C-4472-8ABF-81733BB4049D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{572FFF74-480C-4472-8ABF-81733BB4049D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{572FFF74-480C-4472-8ABF-81733BB4049D}.Release|Win32.Build.0 = Release|Win32
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug_NoPCH|Win32.ActiveCfg = Debug_NoPCH|Win32
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug_NoPCH|Win32.Build.0 = Debug_NoPCH|Win32
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Release|Win32.Build.0 = Release|Win32
|
||||
{8072769E-CF10-48BF-B9E1-12752A5DAC6E}.Debug_NoPCH|Win32.ActiveCfg = Debug_NoPCH|Win32
|
||||
{8072769E-CF10-48BF-B9E1-12752A5DAC6E}.Debug_NoPCH|Win32.Build.0 = Debug_NoPCH|Win32
|
||||
{8072769E-CF10-48BF-B9E1-12752A5DAC6E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{8072769E-CF10-48BF-B9E1-12752A5DAC6E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{8072769E-CF10-48BF-B9E1-12752A5DAC6E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{8072769E-CF10-48BF-B9E1-12752A5DAC6E}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (MANGOS_VMAP_EXTRACT_IO)
|
||||
|
||||
|
||||
# uncomment next line to disable debug mode
|
||||
ADD_DEFINITIONS("-DIOMAP_DEBUG")
|
||||
# build setup currently only supports libmpq 0.4.x
|
||||
ADD_DEFINITIONS("-DUSE_LIBMPQ04")
|
||||
ADD_DEFINITIONS("-Wall")
|
||||
ADD_DEFINITIONS("-ggdb")
|
||||
ADD_DEFINITIONS("-O3")
|
||||
|
||||
include_directories(../libmpq)
|
||||
#add_subdirectory(stormlib)
|
||||
|
||||
add_subdirectory(vmapextract)
|
||||
@@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (MANGOS_IOMAP_EXTRACTOR)
|
||||
|
||||
LINK_DIRECTORIES( ${LINK_DIRECTORIES} ../../libmpq/libmpq/.libs/ )
|
||||
add_executable(vmapextractor adtfile.cpp dbcfile.cpp model.cpp mpq_libmpq.cpp vmapexport.cpp wdtfile.cpp wmo.cpp)
|
||||
target_link_libraries(vmapextractor mpq)
|
||||
@@ -0,0 +1,203 @@
|
||||
#include "adtfile.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef WIN32
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
char * GetPlainName(char * FileName)
|
||||
{
|
||||
char * szTemp;
|
||||
|
||||
if((szTemp = strrchr(FileName, '\\')) != NULL)
|
||||
FileName = szTemp + 1;
|
||||
return FileName;
|
||||
}
|
||||
|
||||
void fixnamen(char *name, size_t len)
|
||||
{
|
||||
for (size_t i=0; i<len-3; i++)
|
||||
{
|
||||
if (i>0 && name[i]>='A' && name[i]<='Z' && isalpha(name[i-1]))
|
||||
{
|
||||
name[i] |= 0x20;
|
||||
} else if ((i==0 || !isalpha(name[i-1])) && name[i]>='a' && name[i]<='z')
|
||||
{
|
||||
name[i] &= ~0x20;
|
||||
}
|
||||
}
|
||||
//extension in lowercase
|
||||
for(size_t i=len-3; i<len; i++)
|
||||
name[i] |= 0x20;
|
||||
}
|
||||
|
||||
void fixname2(char *name, size_t len)
|
||||
{
|
||||
for (size_t i=0; i<len-3; i++)
|
||||
{
|
||||
if(name[i] == ' ')
|
||||
name[i] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
ADTFile::ADTFile(char* filename): ADT(filename)
|
||||
{
|
||||
Adtfilename.append(filename);
|
||||
}
|
||||
|
||||
bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
|
||||
{
|
||||
if(ADT.isEof ())
|
||||
return false;
|
||||
|
||||
uint32 size;
|
||||
|
||||
string xMap;
|
||||
string yMap;
|
||||
|
||||
Adtfilename.erase(Adtfilename.find(".adt"),4);
|
||||
string TempMapNumber;
|
||||
TempMapNumber = Adtfilename.substr(Adtfilename.length()-6,6);
|
||||
xMap = TempMapNumber.substr(TempMapNumber.find("_")+1,(TempMapNumber.find_last_of("_")-1) - (TempMapNumber.find("_")));
|
||||
yMap = TempMapNumber.substr(TempMapNumber.find_last_of("_")+1,(TempMapNumber.length()) - (TempMapNumber.find_last_of("_")));
|
||||
Adtfilename.erase((Adtfilename.length()-xMap.length()-yMap.length()-2), (xMap.length()+yMap.length()+2));
|
||||
string AdtMapNumber = xMap + ' ' + yMap + ' ' + GetPlainName((char*)Adtfilename.c_str());
|
||||
//printf("Processing map %s...\n", AdtMapNumber.c_str());
|
||||
//printf("MapNumber = %s\n", TempMapNumber.c_str());
|
||||
//printf("xMap = %s\n", xMap.c_str());
|
||||
//printf("yMap = %s\n", yMap.c_str());
|
||||
|
||||
const char dirname[] = "Buildings/dir_bin";
|
||||
FILE *dirfile;
|
||||
dirfile = fopen(dirname, "ab");
|
||||
if(!dirfile)
|
||||
{
|
||||
printf("Can't open dirfile!'%s'\n", dirname);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!ADT.isEof())
|
||||
{
|
||||
char fourcc[5];
|
||||
ADT.read(&fourcc,4);
|
||||
ADT.read(&size, 4);
|
||||
flipcc(fourcc);
|
||||
fourcc[4] = 0;
|
||||
|
||||
size_t nextpos = ADT.getPos() + size;
|
||||
|
||||
if (!strcmp(fourcc,"MCIN"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MTEX"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MMDX"))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
char *buf = new char[size];
|
||||
ADT.read(buf, size);
|
||||
char *p=buf;
|
||||
int t=0;
|
||||
ModelInstansName = new string[size];
|
||||
while (p<buf+size)
|
||||
{
|
||||
fixnamen(p,strlen(p));
|
||||
string path(p);
|
||||
char* s=GetPlainName(p);
|
||||
fixname2(s,strlen(s));
|
||||
p=p+strlen(p)+1;
|
||||
ModelInstansName[t++] = s;
|
||||
|
||||
// < 3.1.0 ADT MMDX section store filename.mdx filenames for corresponded .m2 file
|
||||
std::string ext3 = path.size() >= 4 ? path.substr(path.size()-4,4) : "";
|
||||
std::transform( ext3.begin(), ext3.end(), ext3.begin(), ::tolower );
|
||||
if(ext3 == ".mdx")
|
||||
{
|
||||
// replace .mdx -> .m2
|
||||
path.erase(path.length()-2,2);
|
||||
path.append("2");
|
||||
}
|
||||
// >= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file
|
||||
// nothing do
|
||||
|
||||
char szLocalFile[1024];
|
||||
snprintf(szLocalFile, 1024, "./Buildings/%s", s);
|
||||
FILE * output = fopen(szLocalFile,"rb");
|
||||
if(!output)
|
||||
{
|
||||
Model m2(path);
|
||||
if(m2.open())
|
||||
m2.ConvertToVMAPModel(szLocalFile);
|
||||
}
|
||||
else
|
||||
fclose(output);
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(fourcc,"MWMO"))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
char *buf = new char[size];
|
||||
ADT.read(buf, size);
|
||||
char *p=buf;
|
||||
int q = 0;
|
||||
WmoInstansName = new string[size];
|
||||
while (p<buf+size)
|
||||
{
|
||||
string path(p);
|
||||
char* s=GetPlainName(p);
|
||||
fixnamen(s,strlen(s));
|
||||
fixname2(s,strlen(s));
|
||||
p=p+strlen(p)+1;
|
||||
WmoInstansName[q++] = s;
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
//======================
|
||||
else if (!strcmp(fourcc,"MDDF"))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
nMDX = (int)size / 36;
|
||||
for (int i=0; i<nMDX; ++i)
|
||||
{
|
||||
uint32 id;
|
||||
ADT.read(&id, 4);
|
||||
ModelInstance inst(ADT,ModelInstansName[id].c_str(), map_num, tileX, tileY, dirfile);
|
||||
}
|
||||
delete[] ModelInstansName;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(fourcc,"MODF"))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
nWMO = (int)size / 64;
|
||||
for (int i=0; i<nWMO; ++i)
|
||||
{
|
||||
uint32 id;
|
||||
ADT.read(&id, 4);
|
||||
WMOInstance inst(ADT,WmoInstansName[id].c_str(), map_num, tileX, tileY, dirfile);
|
||||
}
|
||||
delete[] WmoInstansName;
|
||||
}
|
||||
}
|
||||
//======================
|
||||
ADT.seek(nextpos);
|
||||
}
|
||||
ADT.close();
|
||||
fclose(dirfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
ADTFile::~ADTFile()
|
||||
{
|
||||
ADT.close();
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
#ifndef ADT_H
|
||||
#define ADT_H
|
||||
|
||||
#include "mpq_libmpq04.h"
|
||||
#include "wmo.h"
|
||||
#include "model.h"
|
||||
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
#define UNITSIZE (CHUNKSIZE / 8.0f)
|
||||
|
||||
class Liquid;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
}svec;
|
||||
|
||||
struct vec
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct triangle
|
||||
{
|
||||
vec v[3];
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float v9[16*8+1][16*8+1];
|
||||
float v8[16*8][16*8];
|
||||
}Cell;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double v9[9][9];
|
||||
double v8[8][8];
|
||||
uint16 area_id;
|
||||
//Liquid *lq;
|
||||
float waterlevel[9][9];
|
||||
uint8 flag;
|
||||
}chunk;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
chunk ch[16][16];
|
||||
}mcell;
|
||||
|
||||
struct MapChunkHeader
|
||||
{
|
||||
uint32 flags;
|
||||
uint32 ix;
|
||||
uint32 iy;
|
||||
uint32 nLayers;
|
||||
uint32 nDoodadRefs;
|
||||
uint32 ofsHeight;
|
||||
uint32 ofsNormal;
|
||||
uint32 ofsLayer;
|
||||
uint32 ofsRefs;
|
||||
uint32 ofsAlpha;
|
||||
uint32 sizeAlpha;
|
||||
uint32 ofsShadow;
|
||||
uint32 sizeShadow;
|
||||
uint32 areaid;
|
||||
uint32 nMapObjRefs;
|
||||
uint32 holes;
|
||||
uint16 s1;
|
||||
uint16 s2;
|
||||
uint32 d1;
|
||||
uint32 d2;
|
||||
uint32 d3;
|
||||
uint32 predTex;
|
||||
uint32 nEffectDoodad;
|
||||
uint32 ofsSndEmitters;
|
||||
uint32 nSndEmitters;
|
||||
uint32 ofsLiquid;
|
||||
uint32 sizeLiquid;
|
||||
float zpos;
|
||||
float xpos;
|
||||
float ypos;
|
||||
uint32 textureId;
|
||||
uint32 props;
|
||||
uint32 effectId;
|
||||
};
|
||||
|
||||
|
||||
class ADTFile
|
||||
{
|
||||
public:
|
||||
ADTFile(char* filename);
|
||||
~ADTFile();
|
||||
int nWMO;
|
||||
int nMDX;
|
||||
string* WmoInstansName;
|
||||
string* ModelInstansName;
|
||||
bool init(uint32 map_num, uint32 tileX, uint32 tileY);
|
||||
//void LoadMapChunks();
|
||||
|
||||
//uint32 wmo_count;
|
||||
/*
|
||||
const mcell& Getmcell() const
|
||||
{
|
||||
return Mcell;
|
||||
}
|
||||
*/
|
||||
private:
|
||||
//size_t mcnk_offsets[256], mcnk_sizes[256];
|
||||
MPQFile ADT;
|
||||
//mcell Mcell;
|
||||
string Adtfilename;
|
||||
};
|
||||
|
||||
void fixnamen(char *name, size_t len);
|
||||
//void fixMapNamen(char *name, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "dbcfile.h"
|
||||
#include "mpq_libmpq04.h"
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
DBCFile::DBCFile(const std::string &filename) : filename(filename)
|
||||
{
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
bool DBCFile::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
|
||||
// Need some error checking, otherwise an unhandled exception error occurs
|
||||
// if people screw with the data path.
|
||||
if (f.isEof() == true)
|
||||
return false;
|
||||
|
||||
unsigned char header[4];
|
||||
unsigned int na,nb,es,ss;
|
||||
|
||||
f.read(header,4); // File Header
|
||||
|
||||
if (header[0]!='W' || header[1]!='D' || header[2]!='B' || header[3] != 'C')
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Critical Error: An error occured while trying to read the DBCFile %s.", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
//assert(header[0]=='W' && header[1]=='D' && header[2]=='B' && header[3] == 'C');
|
||||
|
||||
f.read(&na,4); // Number of records
|
||||
f.read(&nb,4); // Number of fields
|
||||
f.read(&es,4); // Size of a record
|
||||
f.read(&ss,4); // String size
|
||||
|
||||
recordSize = es;
|
||||
recordCount = na;
|
||||
fieldCount = nb;
|
||||
stringSize = ss;
|
||||
//assert(fieldCount*4 == recordSize);
|
||||
assert(fieldCount*4 >= recordSize);
|
||||
|
||||
data = new unsigned char[recordSize*recordCount+stringSize];
|
||||
stringTable = data + recordSize*recordCount;
|
||||
f.read(data,recordSize*recordCount+stringSize);
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
DBCFile::~DBCFile()
|
||||
{
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
DBCFile::Record DBCFile::getRecord(size_t id)
|
||||
{
|
||||
assert(data);
|
||||
return Record(*this, data + id*recordSize);
|
||||
}
|
||||
|
||||
DBCFile::Iterator DBCFile::begin()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, data);
|
||||
}
|
||||
|
||||
DBCFile::Iterator DBCFile::end()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, stringTable);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
#ifndef DBCFILE_H
|
||||
#define DBCFILE_H
|
||||
#define __STORMLIB_SELF__
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
//#include "StormLib.h"
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
class DBCFile
|
||||
{
|
||||
public:
|
||||
DBCFile(const std::string &filename);
|
||||
~DBCFile();
|
||||
|
||||
// Open database. It must be openened before it can be used.
|
||||
bool open();
|
||||
|
||||
// TODO: Add a close function?
|
||||
|
||||
// Database exceptions
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
Exception(const std::string &message): message(message)
|
||||
{ }
|
||||
virtual ~Exception()
|
||||
{ }
|
||||
const std::string &getMessage() {return message;}
|
||||
private:
|
||||
std::string message;
|
||||
};
|
||||
|
||||
//
|
||||
class NotFound: public Exception
|
||||
{
|
||||
public:
|
||||
NotFound(): Exception("Key was not found")
|
||||
{ }
|
||||
};
|
||||
|
||||
// Iteration over database
|
||||
class Iterator;
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
Record& operator= (const Record& r)
|
||||
{
|
||||
file = r.file;
|
||||
offset = r.offset;
|
||||
return *this;
|
||||
}
|
||||
float getFloat(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<float*>(offset+field*4);
|
||||
}
|
||||
unsigned int getUInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<unsigned int*>(offset+(field*4));
|
||||
}
|
||||
int getInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<int*>(offset+field*4);
|
||||
}
|
||||
unsigned char getByte(size_t ofs) const
|
||||
{
|
||||
assert(ofs < file.recordSize);
|
||||
return *reinterpret_cast<unsigned char*>(offset+ofs);
|
||||
}
|
||||
const char *getString(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
size_t stringOffset = getUInt(field);
|
||||
assert(stringOffset < file.stringSize);
|
||||
//char * tmp = (char*)file.stringTable + stringOffset;
|
||||
//unsigned char * tmp2 = file.stringTable + stringOffset;
|
||||
return reinterpret_cast<char*>(file.stringTable + stringOffset);
|
||||
}
|
||||
private:
|
||||
Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {}
|
||||
DBCFile &file;
|
||||
unsigned char *offset;
|
||||
|
||||
friend class DBCFile;
|
||||
friend class Iterator;
|
||||
};
|
||||
|
||||
/* Iterator that iterates over records */
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(DBCFile &file, unsigned char *offset):
|
||||
record(file, offset) {}
|
||||
/// Advance (prefix only)
|
||||
Iterator & operator++() {
|
||||
record.offset += record.file.recordSize;
|
||||
return *this;
|
||||
}
|
||||
/// Return address of current instance
|
||||
Record const & operator*() const { return record; }
|
||||
const Record* operator->() const {
|
||||
return &record;
|
||||
}
|
||||
/// Comparison
|
||||
bool operator==(const Iterator &b) const
|
||||
{
|
||||
return record.offset == b.record.offset;
|
||||
}
|
||||
bool operator!=(const Iterator &b) const
|
||||
{
|
||||
return record.offset != b.record.offset;
|
||||
}
|
||||
private:
|
||||
Record record;
|
||||
};
|
||||
|
||||
// Get record by id
|
||||
Record getRecord(size_t id);
|
||||
/// Get begin iterator over records
|
||||
Iterator begin();
|
||||
/// Get begin iterator over records
|
||||
Iterator end();
|
||||
/// Trivial
|
||||
size_t getRecordCount() const { return recordCount;}
|
||||
size_t getFieldCount() const { return fieldCount; }
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
size_t recordSize;
|
||||
size_t recordCount;
|
||||
size_t fieldCount;
|
||||
size_t stringSize;
|
||||
unsigned char *data;
|
||||
unsigned char *stringTable;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef LOAD_LIB_H
|
||||
#define LOAD_LIB_H
|
||||
|
||||
#ifdef WIN32
|
||||
typedef __int64 int64;
|
||||
typedef __int32 int32;
|
||||
typedef __int16 int16;
|
||||
typedef __int8 int8;
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef unsigned __int32 uint32;
|
||||
typedef unsigned __int16 uint16;
|
||||
typedef unsigned __int8 uint8;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#ifndef uint64_t
|
||||
#ifdef __linux__
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
#endif
|
||||
typedef int64_t int64;
|
||||
typedef int32_t int32;
|
||||
typedef int16_t int16;
|
||||
typedef int8_t int8;
|
||||
typedef uint64_t uint64;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint8_t uint8;
|
||||
#endif
|
||||
|
||||
#define FILE_FORMAT_VERSION 18
|
||||
|
||||
//
|
||||
// File version chunk
|
||||
//
|
||||
struct file_MVER
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
uint32 ver;
|
||||
};
|
||||
|
||||
class FileLoader{
|
||||
uint8 *data;
|
||||
uint32 data_size;
|
||||
public:
|
||||
virtual bool prepareLoadedData();
|
||||
uint8 *GetData() {return data;}
|
||||
uint32 GetDataSize() {return data_size;}
|
||||
|
||||
file_MVER *version;
|
||||
FileLoader();
|
||||
~FileLoader();
|
||||
bool loadFile(char *filename, bool log = true);
|
||||
virtual void free();
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,187 @@
|
||||
#include "vmapexport.h"
|
||||
#include "model.h"
|
||||
#include "wmo.h"
|
||||
#include "mpq_libmpq04.h"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
Model::Model(std::string &filename) : filename(filename)
|
||||
{
|
||||
}
|
||||
|
||||
bool Model::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
|
||||
ok = !f.isEof();
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
f.close();
|
||||
printf("Error loading model %s\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&header, f.getBuffer(), sizeof(ModelHeader));
|
||||
if(header.nBoundingTriangles > 0)
|
||||
{
|
||||
f.seek(0);
|
||||
f.seekRelative(header.ofsBoundingVertices);
|
||||
vertices = new Vec3D[header.nBoundingVertices];
|
||||
f.read(vertices,header.nBoundingVertices*12);
|
||||
for (uint32 i=0; i<header.nBoundingVertices; i++)
|
||||
{
|
||||
vertices[i] = fixCoordSystem(vertices[i]);
|
||||
}
|
||||
f.seek(0);
|
||||
f.seekRelative(header.ofsBoundingTriangles);
|
||||
indices = new uint16[header.nBoundingTriangles];
|
||||
f.read(indices,header.nBoundingTriangles*2);
|
||||
f.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("not included %s\n", filename.c_str());
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Model::ConvertToVMAPModel(char * outfilename)
|
||||
{
|
||||
int N[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
FILE * output=fopen(outfilename,"wb");
|
||||
if(!output)
|
||||
{
|
||||
printf("Can't create the output file '%s'\n",outfilename);
|
||||
return false;
|
||||
}
|
||||
fwrite("VMAP003",8,1,output);
|
||||
uint32 nVertices = 0;
|
||||
nVertices = header.nBoundingVertices;
|
||||
fwrite(&nVertices, sizeof(int), 1, output);
|
||||
uint32 nofgroups = 1;
|
||||
fwrite(&nofgroups,sizeof(uint32), 1, output);
|
||||
fwrite(N,4*3,1,output);// rootwmoid, flags, groupid
|
||||
fwrite(N,sizeof(float),3*2,output);//bbox, only needed for WMO currently
|
||||
fwrite(N,4,1,output);// liquidflags
|
||||
fwrite("GRP ",4,1,output);
|
||||
uint32 branches = 1;
|
||||
int wsize;
|
||||
wsize = sizeof(branches) + sizeof(uint32) * branches;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&branches,sizeof(branches), 1, output);
|
||||
uint32 nIndexes = 0;
|
||||
nIndexes = header.nBoundingTriangles;
|
||||
fwrite(&nIndexes,sizeof(uint32), 1, output);
|
||||
fwrite("INDX",4, 1, output);
|
||||
wsize = sizeof(uint32) + sizeof(unsigned short) * nIndexes;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&nIndexes, sizeof(uint32), 1, output);
|
||||
if(nIndexes >0)
|
||||
{
|
||||
fwrite(indices, sizeof(unsigned short), nIndexes, output);
|
||||
}
|
||||
fwrite("VERT",4, 1, output);
|
||||
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&nVertices, sizeof(int), 1, output);
|
||||
if(nVertices >0)
|
||||
{
|
||||
for(uint32 vpos=0; vpos <nVertices; ++vpos)
|
||||
{
|
||||
float sy = vertices[vpos].y;
|
||||
vertices[vpos].y = vertices[vpos].z;
|
||||
vertices[vpos].z = sy;
|
||||
}
|
||||
fwrite(vertices, sizeof(float)*3, nVertices, output);
|
||||
}
|
||||
|
||||
delete[] vertices;
|
||||
delete[] indices;
|
||||
|
||||
fclose(output);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
}
|
||||
|
||||
Vec3D fixCoordSystem(Vec3D v)
|
||||
{
|
||||
return Vec3D(v.x, v.z, -v.y);
|
||||
}
|
||||
|
||||
Vec3D fixCoordSystem2(Vec3D v)
|
||||
{
|
||||
return Vec3D(v.x, v.z, v.y);
|
||||
}
|
||||
|
||||
ModelInstance::ModelInstance(MPQFile &f,const char* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile)
|
||||
{
|
||||
float ff[3];
|
||||
f.read(&id, 4);
|
||||
f.read(ff,12);
|
||||
pos = fixCoords(Vec3D(ff[0],ff[1],ff[2]));
|
||||
f.read(ff,12);
|
||||
rot = Vec3D(ff[0],ff[1],ff[2]);
|
||||
f.read(&scale,4);
|
||||
// scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
|
||||
sc = scale / 1024.0f;
|
||||
|
||||
char tempname[512];
|
||||
sprintf(tempname, "./Buildings/%s", ModelInstName);
|
||||
FILE *input;
|
||||
input = fopen(tempname, "r+b");
|
||||
|
||||
if(!input)
|
||||
{
|
||||
//printf("ModelInstance::ModelInstance couldn't open %s\n", tempname);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(input, 8, SEEK_SET); // get the correct no of vertices
|
||||
int nVertices;
|
||||
fread(&nVertices, sizeof (int), 1, input);
|
||||
fclose(input);
|
||||
|
||||
if(nVertices == 0)
|
||||
return;
|
||||
|
||||
uint16 adtId = 0;// not used for models
|
||||
uint32 flags = MOD_M2;
|
||||
if(tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN;
|
||||
//write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name
|
||||
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&flags, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&adtId, sizeof(uint16), 1, pDirfile);
|
||||
fwrite(&id, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&pos, sizeof(float), 3, pDirfile);
|
||||
fwrite(&rot, sizeof(float), 3, pDirfile);
|
||||
fwrite(&sc, sizeof(float), 1, pDirfile);
|
||||
uint32 nlen=strlen(ModelInstName);
|
||||
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(ModelInstName, sizeof(char), nlen, pDirfile);
|
||||
|
||||
/* int realx1 = (int) ((float) pos.x / 533.333333f);
|
||||
int realy1 = (int) ((float) pos.z / 533.333333f);
|
||||
int realx2 = (int) ((float) pos.x / 533.333333f);
|
||||
int realy2 = (int) ((float) pos.z / 533.333333f);
|
||||
|
||||
fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n",
|
||||
MapName,
|
||||
ModelInstName,
|
||||
(float) pos.x, (float) pos.y, (float) pos.z,
|
||||
(float) rot.x, (float) rot.y, (float) rot.z,
|
||||
sc,
|
||||
nVertices,
|
||||
realx1, realy1,
|
||||
realx2, realy2
|
||||
); */
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include "loadlib/loadlib.h"
|
||||
#include "vec3d.h"
|
||||
//#include "mpq.h"
|
||||
#include "modelheaders.h"
|
||||
#include <vector>
|
||||
|
||||
class Model;
|
||||
class WMOInstance;
|
||||
class MPQFile;
|
||||
|
||||
Vec3D fixCoordSystem(Vec3D v);
|
||||
|
||||
class Model
|
||||
{
|
||||
public:
|
||||
ModelHeader header;
|
||||
uint32 offsBB_vertices, offsBB_indices;
|
||||
Vec3D *BB_vertices, *vertices;
|
||||
uint16 *BB_indices, *indices;
|
||||
size_t nIndices;
|
||||
|
||||
bool open();
|
||||
bool ConvertToVMAPModel(char * outfilename);
|
||||
|
||||
bool ok;
|
||||
|
||||
Model(std::string &filename);
|
||||
~Model();
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
char outfilename;
|
||||
};
|
||||
|
||||
class ModelInstance
|
||||
{
|
||||
public:
|
||||
Model *model;
|
||||
|
||||
uint32 id;
|
||||
Vec3D pos, rot;
|
||||
unsigned int d1, scale;
|
||||
float w,sc;
|
||||
|
||||
ModelInstance() {}
|
||||
ModelInstance(MPQFile &f,const char* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
#ifndef MODELHEADERS_H
|
||||
#define MODELHEADERS_H
|
||||
|
||||
/* typedef unsigned char uint8;
|
||||
typedef char int8;
|
||||
typedef unsigned short uint16;
|
||||
typedef short int16;
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32; */
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
struct ModelHeader
|
||||
{
|
||||
char id[4];
|
||||
uint8 version[4];
|
||||
uint32 nameLength;
|
||||
uint32 nameOfs;
|
||||
uint32 type;
|
||||
uint32 nGlobalSequences;
|
||||
uint32 ofsGlobalSequences;
|
||||
uint32 nAnimations;
|
||||
uint32 ofsAnimations;
|
||||
uint32 nAnimationLookup;
|
||||
uint32 ofsAnimationLookup;
|
||||
uint32 nBones;
|
||||
uint32 ofsBones;
|
||||
uint32 nKeyBoneLookup;
|
||||
uint32 ofsKeyBoneLookup;
|
||||
uint32 nVertices;
|
||||
uint32 ofsVertices;
|
||||
uint32 nViews;
|
||||
uint32 nColors;
|
||||
uint32 ofsColors;
|
||||
uint32 nTextures;
|
||||
uint32 ofsTextures;
|
||||
uint32 nTransparency;
|
||||
uint32 ofsTransparency;
|
||||
uint32 nTextureanimations;
|
||||
uint32 ofsTextureanimations;
|
||||
uint32 nTexReplace;
|
||||
uint32 ofsTexReplace;
|
||||
uint32 nRenderFlags;
|
||||
uint32 ofsRenderFlags;
|
||||
uint32 nBoneLookupTable;
|
||||
uint32 ofsBoneLookupTable;
|
||||
uint32 nTexLookup;
|
||||
uint32 ofsTexLookup;
|
||||
uint32 nTexUnits;
|
||||
uint32 ofsTexUnits;
|
||||
uint32 nTransLookup;
|
||||
uint32 ofsTransLookup;
|
||||
uint32 nTexAnimLookup;
|
||||
uint32 ofsTexAnimLookup;
|
||||
float floats[14];
|
||||
uint32 nBoundingTriangles;
|
||||
uint32 ofsBoundingTriangles;
|
||||
uint32 nBoundingVertices;
|
||||
uint32 ofsBoundingVertices;
|
||||
uint32 nBoundingNormals;
|
||||
uint32 ofsBoundingNormals;
|
||||
uint32 nAttachments;
|
||||
uint32 ofsAttachments;
|
||||
uint32 nAttachLookup;
|
||||
uint32 ofsAttachLookup;
|
||||
uint32 nAttachments_2;
|
||||
uint32 ofsAttachments_2;
|
||||
uint32 nLights;
|
||||
uint32 ofsLights;
|
||||
uint32 nCameras;
|
||||
uint32 ofsCameras;
|
||||
uint32 nCameraLookup;
|
||||
uint32 ofsCameraLookup;
|
||||
uint32 nRibbonEmitters;
|
||||
uint32 ofsRibbonEmitters;
|
||||
uint32 nParticleEmitters;
|
||||
uint32 ofsParticleEmitters;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
#include "mpq_libmpq04.h"
|
||||
#include <deque>
|
||||
#include <cstdio>
|
||||
|
||||
ArchiveSet gOpenArchives;
|
||||
|
||||
MPQArchive::MPQArchive(const char* filename)
|
||||
{
|
||||
int result = libmpq__archive_open(&mpq_a, filename, -1);
|
||||
printf("Opening %s\n", filename);
|
||||
if(result) {
|
||||
switch(result) {
|
||||
case LIBMPQ_ERROR_OPEN :
|
||||
printf("Error opening archive '%s': Does file really exist?\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_FORMAT : /* bad file format */
|
||||
printf("Error opening archive '%s': Bad file format\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_SEEK : /* seeking in file failed */
|
||||
printf("Error opening archive '%s': Seeking in file failed\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_READ : /* Read error in archive */
|
||||
printf("Error opening archive '%s': Read error in archive\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_MALLOC : /* maybe not enough memory? :) */
|
||||
printf("Error opening archive '%s': Maybe not enough memory\n", filename);
|
||||
break;
|
||||
default:
|
||||
printf("Error opening archive '%s': Unknown error\n", filename);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
gOpenArchives.push_front(this);
|
||||
}
|
||||
|
||||
void MPQArchive::close()
|
||||
{
|
||||
//gOpenArchives.erase(erase(&mpq_a);
|
||||
libmpq__archive_close(mpq_a);
|
||||
}
|
||||
|
||||
MPQFile::MPQFile(const char* filename):
|
||||
eof(false),
|
||||
buffer(0),
|
||||
pointer(0),
|
||||
size(0)
|
||||
{
|
||||
for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i)
|
||||
{
|
||||
mpq_archive *mpq_a = (*i)->mpq_a;
|
||||
|
||||
uint32 filenum;
|
||||
if(libmpq__file_number(mpq_a, filename, &filenum)) continue;
|
||||
libmpq__off_t transferred;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
|
||||
if (size<=1) {
|
||||
printf("warning: file %s has size %d; cannot read.\n", filename, size);
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
return;
|
||||
}
|
||||
buffer = new char[size];
|
||||
|
||||
//libmpq_file_getdata
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
/*libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);*/
|
||||
return;
|
||||
|
||||
}
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
}
|
||||
|
||||
size_t MPQFile::read(void* dest, size_t bytes)
|
||||
{
|
||||
if (eof) return 0;
|
||||
|
||||
size_t rpos = pointer + bytes;
|
||||
if (rpos > size) {
|
||||
bytes = size - pointer;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
memcpy(dest, &(buffer[pointer]), bytes);
|
||||
|
||||
pointer = rpos;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void MPQFile::seek(int offset)
|
||||
{
|
||||
pointer = offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::seekRelative(int offset)
|
||||
{
|
||||
pointer += offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::close()
|
||||
{
|
||||
if (buffer) delete[] buffer;
|
||||
buffer = 0;
|
||||
eof = true;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#ifndef MPQ_H
|
||||
#define MPQ_H
|
||||
|
||||
#include "loadlib/loadlib.h"
|
||||
#include "libmpq/mpq.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MPQArchive
|
||||
{
|
||||
|
||||
public:
|
||||
mpq_archive_s *mpq_a;
|
||||
|
||||
MPQArchive(const char* filename);
|
||||
void close();
|
||||
|
||||
void GetFileListTo(vector<string>& filelist) {
|
||||
uint32 filenum;
|
||||
if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
|
||||
libmpq__off_t size, transferred;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
char *buffer = new char[size];
|
||||
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
|
||||
char seps[] = "\n";
|
||||
char *token;
|
||||
|
||||
token = strtok( buffer, seps );
|
||||
uint32 counter = 0;
|
||||
while ((token != NULL) && (counter < size)) {
|
||||
//cout << token << endl;
|
||||
token[strlen(token) - 1] = 0;
|
||||
string s = token;
|
||||
filelist.push_back(s);
|
||||
counter += strlen(token) + 2;
|
||||
token = strtok(NULL, seps);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
};
|
||||
typedef std::deque<MPQArchive*> ArchiveSet;
|
||||
|
||||
class MPQFile
|
||||
{
|
||||
//MPQHANDLE handle;
|
||||
bool eof;
|
||||
char *buffer;
|
||||
libmpq__off_t pointer,size;
|
||||
|
||||
// disable copying
|
||||
MPQFile(const MPQFile &f) {}
|
||||
void operator=(const MPQFile &f) {}
|
||||
|
||||
public:
|
||||
MPQFile(const char* filename); // filenames are not case sensitive
|
||||
~MPQFile() { close(); }
|
||||
size_t read(void* dest, size_t bytes);
|
||||
size_t getSize() { return size; }
|
||||
size_t getPos() { return pointer; }
|
||||
char* getBuffer() { return buffer; }
|
||||
char* getPointer() { return buffer + pointer; }
|
||||
bool isEof() { return eof; }
|
||||
void seek(int offset);
|
||||
void seekRelative(int offset);
|
||||
void close();
|
||||
};
|
||||
|
||||
inline void flipcc(char *fcc)
|
||||
{
|
||||
char t;
|
||||
t=fcc[0];
|
||||
fcc[0]=fcc[3];
|
||||
fcc[3]=t;
|
||||
t=fcc[1];
|
||||
fcc[1]=fcc[2];
|
||||
fcc[2]=t;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,230 @@
|
||||
#ifndef VEC3D_H
|
||||
#define VEC3D_H
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
class Vec3D
|
||||
{
|
||||
public:
|
||||
float x,y,z;
|
||||
|
||||
Vec3D(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f) : x(x0), y(y0), z(z0) {}
|
||||
|
||||
Vec3D(const Vec3D& v) : x(v.x), y(v.y), z(v.z) {}
|
||||
|
||||
Vec3D& operator= (const Vec3D &v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3D operator+ (const Vec3D &v) const
|
||||
{
|
||||
Vec3D r(x+v.x,y+v.y,z+v.z);
|
||||
return r;
|
||||
}
|
||||
|
||||
Vec3D operator- (const Vec3D &v) const
|
||||
{
|
||||
Vec3D r(x-v.x,y-v.y,z-v.z);
|
||||
return r;
|
||||
}
|
||||
|
||||
float operator* (const Vec3D &v) const
|
||||
{
|
||||
return x*v.x + y*v.y + z*v.z;
|
||||
}
|
||||
|
||||
Vec3D operator* (float d) const
|
||||
{
|
||||
Vec3D r(x*d,y*d,z*d);
|
||||
return r;
|
||||
}
|
||||
|
||||
friend Vec3D operator* (float d, const Vec3D& v)
|
||||
{
|
||||
return v * d;
|
||||
}
|
||||
|
||||
Vec3D operator% (const Vec3D &v) const
|
||||
{
|
||||
Vec3D r(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x);
|
||||
return r;
|
||||
}
|
||||
|
||||
Vec3D& operator+= (const Vec3D &v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3D& operator-= (const Vec3D &v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3D& operator*= (float d)
|
||||
{
|
||||
x *= d;
|
||||
y *= d;
|
||||
z *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float lengthSquared() const
|
||||
{
|
||||
return x*x+y*y+z*z;
|
||||
}
|
||||
|
||||
float length() const
|
||||
{
|
||||
return sqrt(x*x+y*y+z*z);
|
||||
}
|
||||
|
||||
Vec3D& normalize()
|
||||
{
|
||||
this->operator*= (1.0f/length());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3D operator~ () const
|
||||
{
|
||||
Vec3D r(*this);
|
||||
r.normalize();
|
||||
return r;
|
||||
}
|
||||
|
||||
friend std::istream& operator>>(std::istream& in, Vec3D& v)
|
||||
{
|
||||
in >> v.x >> v.y >> v.z;
|
||||
return in;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const Vec3D& v)
|
||||
{
|
||||
out << v.x << " " << v.y << " " << v.z;
|
||||
return out;
|
||||
}
|
||||
|
||||
operator float*()
|
||||
{
|
||||
return (float*)this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Vec2D
|
||||
{
|
||||
public:
|
||||
float x,y;
|
||||
|
||||
Vec2D(float x0 = 0.0f, float y0 = 0.0f) : x(x0), y(y0) {}
|
||||
|
||||
Vec2D(const Vec2D& v) : x(v.x), y(v.y) {}
|
||||
|
||||
Vec2D& operator= (const Vec2D &v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2D operator+ (const Vec2D &v) const
|
||||
{
|
||||
Vec2D r(x+v.x,y+v.y);
|
||||
return r;
|
||||
}
|
||||
|
||||
Vec2D operator- (const Vec2D &v) const
|
||||
{
|
||||
Vec2D r(x-v.x,y-v.y);
|
||||
return r;
|
||||
}
|
||||
|
||||
float operator* (const Vec2D &v) const
|
||||
{
|
||||
return x*v.x + y*v.y;
|
||||
}
|
||||
|
||||
Vec2D operator* (float d) const
|
||||
{
|
||||
Vec2D r(x*d,y*d);
|
||||
return r;
|
||||
}
|
||||
|
||||
friend Vec2D operator* (float d, const Vec2D& v)
|
||||
{
|
||||
return v * d;
|
||||
}
|
||||
|
||||
Vec2D& operator+= (const Vec2D &v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2D& operator-= (const Vec2D &v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2D& operator*= (float d)
|
||||
{
|
||||
x *= d;
|
||||
y *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float lengthSquared() const
|
||||
{
|
||||
return x*x+y*y;
|
||||
}
|
||||
|
||||
float length() const
|
||||
{
|
||||
return sqrt(x*x+y*y);
|
||||
}
|
||||
|
||||
Vec2D& normalize()
|
||||
{
|
||||
this->operator*= (1.0f/length());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2D operator~ () const
|
||||
{
|
||||
Vec2D r(*this);
|
||||
r.normalize();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
friend std::istream& operator>>(std::istream& in, Vec2D& v)
|
||||
{
|
||||
in >> v.x >> v.y;
|
||||
return in;
|
||||
}
|
||||
|
||||
operator float*()
|
||||
{
|
||||
return (float*)this;
|
||||
}
|
||||
};
|
||||
|
||||
inline void rotate(float x0, float y0, float *x, float *y, float angle)
|
||||
{
|
||||
float xa = *x - x0, ya = *y - y0;
|
||||
*x = xa*cosf(angle) - ya*sinf(angle) + x0;
|
||||
*y = xa*sinf(angle) + ya*cosf(angle) + y0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,522 @@
|
||||
/*****************************************************************************/
|
||||
/* StormLibTest.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* This module uses very brutal test methods for StormLib. It extracts all */
|
||||
/* files from the archive with Storm.dll and with stormlib and compares them,*/
|
||||
/* then tries to build a copy of the entire archive, then removes a few files*/
|
||||
/* from the archive and adds them back, then compares the two archives, ... */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 25.03.03 1.00 Lad The first version of StormLibTest.cpp */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#include <sys/stat.h>
|
||||
#include <direct.h>
|
||||
#define mkdir _mkdir
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
//#pragma warning(disable : 4505)
|
||||
//#pragma comment(lib, "Winmm.lib")
|
||||
|
||||
#include <map>
|
||||
|
||||
//From Extractor
|
||||
#include "adtfile.h"
|
||||
#include "wdtfile.h"
|
||||
#include "dbcfile.h"
|
||||
#include "wmo.h"
|
||||
#include "mpq_libmpq04.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define MPQ_BLOCK_SIZE 0x1000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
extern ArchiveSet gOpenArchives;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[64];
|
||||
unsigned int id;
|
||||
}map_id;
|
||||
|
||||
map_id * map_ids;
|
||||
uint16 *LiqType = 0;
|
||||
uint32 map_count;
|
||||
char output_path[128]=".";
|
||||
char input_path[1024]=".";
|
||||
bool hasInputPathParam = false;
|
||||
bool preciseVectorData = false;
|
||||
|
||||
// Constants
|
||||
|
||||
//static const char * szWorkDirMaps = ".\\Maps";
|
||||
static const char * szWorkDirWmo = "./Buildings";
|
||||
|
||||
// Local testing functions
|
||||
|
||||
static void clreol()
|
||||
{
|
||||
printf("\r \r");
|
||||
}
|
||||
|
||||
void strToLower(char* str)
|
||||
{
|
||||
while(*str)
|
||||
{
|
||||
*str=tolower(*str);
|
||||
++str;
|
||||
}
|
||||
}
|
||||
|
||||
static const char * GetPlainName(const char * szFileName)
|
||||
{
|
||||
const char * szTemp;
|
||||
|
||||
if((szTemp = strrchr(szFileName, '\\')) != NULL)
|
||||
szFileName = szTemp + 1;
|
||||
return szFileName;
|
||||
}
|
||||
|
||||
// copied from contrib/extractor/System.cpp
|
||||
void ReadLiquidTypeTableDBC()
|
||||
{
|
||||
printf("Read LiquidType.dbc file...");
|
||||
DBCFile dbc("DBFilesClient\\LiquidType.dbc");
|
||||
if(!dbc.open())
|
||||
{
|
||||
printf("Fatal error: Invalid LiquidType.dbc file format!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
size_t LiqType_count = dbc.getRecordCount();
|
||||
size_t LiqType_maxid = dbc.getRecord(LiqType_count - 1).getUInt(0);
|
||||
LiqType = new uint16[LiqType_maxid + 1];
|
||||
memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16));
|
||||
|
||||
for(uint32 x = 0; x < LiqType_count; ++x)
|
||||
LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
|
||||
|
||||
printf("Done! (%u LiqTypes loaded)\n", LiqType_count);
|
||||
}
|
||||
|
||||
int ExtractWmo()
|
||||
{
|
||||
char szLocalFile[1024] = "";
|
||||
bool success=true;
|
||||
|
||||
//const char* ParsArchiveNames[] = {"patch-2.MPQ", "patch.MPQ", "common.MPQ", "expansion.MPQ"};
|
||||
|
||||
for (ArchiveSet::const_iterator ar_itr = gOpenArchives.begin(); ar_itr != gOpenArchives.end() && success; ++ar_itr)
|
||||
{
|
||||
vector<string> filelist;
|
||||
|
||||
(*ar_itr)->GetFileListTo(filelist);
|
||||
for (vector<string>::iterator fname=filelist.begin(); fname != filelist.end() && success; ++fname)
|
||||
{
|
||||
bool file_ok=true;
|
||||
if (fname->find(".wmo") != string::npos)
|
||||
{
|
||||
// Copy files from archive
|
||||
//std::cout << "found *.wmo file " << *fname << std::endl;
|
||||
sprintf(szLocalFile, "%s/%s", szWorkDirWmo, GetPlainName(fname->c_str()));
|
||||
fixnamen(szLocalFile,strlen(szLocalFile));
|
||||
FILE * n;
|
||||
if ((n = fopen(szLocalFile, "rb"))== NULL)
|
||||
{
|
||||
int p = 0;
|
||||
//Select root wmo files
|
||||
const char * rchr = strrchr(GetPlainName(fname->c_str()),0x5f);
|
||||
if(rchr != NULL)
|
||||
{
|
||||
char cpy[4];
|
||||
strncpy((char*)cpy,rchr,4);
|
||||
for (int i=0;i<4; ++i)
|
||||
{
|
||||
int m = cpy[i];
|
||||
if(isdigit(m))
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if(p != 3)
|
||||
{
|
||||
std::cout << "Extracting " << *fname << std::endl;
|
||||
WMORoot * froot = new WMORoot(*fname);
|
||||
if(!froot->open())
|
||||
{
|
||||
printf("Couldn't open RootWmo!!!\n");
|
||||
delete froot;
|
||||
continue;
|
||||
}
|
||||
FILE *output=fopen(szLocalFile,"wb");
|
||||
if(!output)
|
||||
{
|
||||
printf("couldn't open %s for writing!\n", szLocalFile);
|
||||
success=false;
|
||||
}
|
||||
froot->ConvertToVMAPRootWmo(output);
|
||||
int Wmo_nVertices = 0;
|
||||
//printf("root has %d groups\n", froot->nGroups);
|
||||
if(froot->nGroups !=0)
|
||||
{
|
||||
for (uint32 i=0; i<froot->nGroups; ++i)
|
||||
{
|
||||
char temp[1024];
|
||||
strcpy(temp, fname->c_str());
|
||||
temp[fname->length()-4] = 0;
|
||||
char groupFileName[1024];
|
||||
sprintf(groupFileName,"%s_%03d.wmo",temp, i);
|
||||
//printf("Trying to open groupfile %s\n",groupFileName);
|
||||
string s = groupFileName;
|
||||
WMOGroup * fgroup = new WMOGroup(s);
|
||||
if(!fgroup->open())
|
||||
{
|
||||
printf("Could not open all Group file for: %s\n",GetPlainName(fname->c_str()));
|
||||
file_ok=false;
|
||||
break;
|
||||
}
|
||||
|
||||
Wmo_nVertices += fgroup->ConvertToVMAPGroupWmo(output, froot, preciseVectorData);
|
||||
delete fgroup;
|
||||
}
|
||||
}
|
||||
fseek(output, 8, SEEK_SET); // store the correct no of vertices
|
||||
fwrite(&Wmo_nVertices,sizeof(int),1,output);
|
||||
fclose(output);
|
||||
delete froot;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(n);
|
||||
}
|
||||
}
|
||||
// Delete the extracted file in the case of an error
|
||||
if(!file_ok)
|
||||
remove(szLocalFile);
|
||||
}
|
||||
}
|
||||
|
||||
if(success)
|
||||
printf("\nExtract wmo complete (No (fatal) errors)\n");
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void ExtractMapsFromMpq()
|
||||
{
|
||||
}
|
||||
|
||||
void ParsMapFiles()
|
||||
{
|
||||
char fn[512];
|
||||
//char id_filename[64];
|
||||
char id[10];
|
||||
for (unsigned int i=0; i<map_count; ++i)
|
||||
{
|
||||
sprintf(id,"%03u",map_ids[i].id);
|
||||
sprintf(fn,"World\\Maps\\%s\\%s.wdt", map_ids[i].name, map_ids[i].name);
|
||||
WDTFile WDT(fn,map_ids[i].name);
|
||||
if(WDT.init(id, map_ids[i].id))
|
||||
{
|
||||
for (int x=0; x<64; ++x)
|
||||
{
|
||||
for (int y=0; y<64; ++y)
|
||||
{
|
||||
if (ADTFile*ADT = WDT.GetMap(x,y))
|
||||
{
|
||||
//sprintf(id_filename,"%02u %02u %03u",x,y,map_ids[i].id);//!!!!!!!!!
|
||||
ADT->init(map_ids[i].id, x, y);
|
||||
delete ADT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getGamePath()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HKEY key;
|
||||
DWORD t,s;
|
||||
LONG l;
|
||||
s = sizeof(input_path);
|
||||
memset(input_path,0,s);
|
||||
l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Blizzard Entertainment\\World of Warcraft",0,KEY_QUERY_VALUE,&key);
|
||||
//l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Blizzard Entertainment\\Burning Crusade Closed Beta",0,KEY_QUERY_VALUE,&key);
|
||||
l = RegQueryValueEx(key,"InstallPath",0,&t,(LPBYTE)input_path,&s);
|
||||
RegCloseKey(key);
|
||||
if (strlen(input_path) > 0)
|
||||
{
|
||||
if (input_path[strlen(input_path) - 1] != '\\') strcat(input_path, "\\");
|
||||
}
|
||||
strcat(input_path,"Data\\");
|
||||
#else
|
||||
strcpy(input_path,"Data/");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool scan_patches(char* scanmatch, std::vector<std::string>& pArchiveNames)
|
||||
{
|
||||
int i;
|
||||
char path[512];
|
||||
|
||||
for (i = 1; i <= 99; i++)
|
||||
{
|
||||
if (i != 1)
|
||||
{
|
||||
sprintf(path, "%s-%d.MPQ", scanmatch, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(path, "%s.MPQ", scanmatch);
|
||||
}
|
||||
#ifdef __linux__
|
||||
if(FILE* h = fopen64(path, "rb"))
|
||||
#else
|
||||
if(FILE* h = fopen(path, "rb"))
|
||||
#endif
|
||||
{
|
||||
fclose(h);
|
||||
//matches.push_back(path);
|
||||
pArchiveNames.push_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool fillArchiveNameVector(std::vector<std::string>& pArchiveNames)
|
||||
{
|
||||
if(!hasInputPathParam)
|
||||
getGamePath();
|
||||
|
||||
printf("\nGame path: %s\n", input_path);
|
||||
|
||||
char path[512];
|
||||
string in_path(input_path);
|
||||
std::vector<std::string> locales, searchLocales;
|
||||
|
||||
searchLocales.push_back("enGB");
|
||||
searchLocales.push_back("enUS");
|
||||
searchLocales.push_back("deDE");
|
||||
searchLocales.push_back("esES");
|
||||
searchLocales.push_back("frFR");
|
||||
searchLocales.push_back("koKR");
|
||||
searchLocales.push_back("ruRU");
|
||||
|
||||
for (std::vector<std::string>::iterator i = searchLocales.begin(); i != searchLocales.end(); ++i)
|
||||
{
|
||||
std::string localePath = in_path + *i;
|
||||
// check if locale exists:
|
||||
struct stat status;
|
||||
if (stat(localePath.c_str(), &status))
|
||||
continue;
|
||||
if ((status.st_mode & S_IFDIR) == 0)
|
||||
continue;
|
||||
printf("Found locale '%s'\n", i->c_str());
|
||||
locales.push_back(*i);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// open locale expansion and common files
|
||||
printf("Adding data files from locale directories.\n");
|
||||
for (std::vector<std::string>::iterator i = locales.begin(); i != locales.end(); ++i)
|
||||
{
|
||||
pArchiveNames.push_back(in_path + *i + "/locale-" + *i + ".MPQ");
|
||||
pArchiveNames.push_back(in_path + *i + "/expansion-locale-" + *i + ".MPQ");
|
||||
pArchiveNames.push_back(in_path + *i + "/lichking-locale-" + *i + ".MPQ");
|
||||
}
|
||||
|
||||
// open expansion and common files
|
||||
pArchiveNames.push_back(input_path + string("common.MPQ"));
|
||||
pArchiveNames.push_back(input_path + string("common-2.MPQ"));
|
||||
pArchiveNames.push_back(input_path + string("expansion.MPQ"));
|
||||
pArchiveNames.push_back(input_path + string("lichking.MPQ"));
|
||||
|
||||
// now, scan for the patch levels in the core dir
|
||||
printf("Scanning patch levels from data directory.\n");
|
||||
sprintf(path, "%spatch", input_path);
|
||||
if (!scan_patches(path, pArchiveNames))
|
||||
return(false);
|
||||
|
||||
// now, scan for the patch levels in locale dirs
|
||||
printf("Scanning patch levels from locale directories.\n");
|
||||
bool foundOne = false;
|
||||
for (std::vector<std::string>::iterator i = locales.begin(); i != locales.end(); ++i)
|
||||
{
|
||||
printf("Locale: %s\n", i->c_str());
|
||||
sprintf(path, "%s%s/patch-%s", input_path, i->c_str(), i->c_str());
|
||||
if(scan_patches(path, pArchiveNames))
|
||||
foundOne = true;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if(!foundOne)
|
||||
{
|
||||
printf("no locale found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool processArgv(int argc, char ** argv, const char *versionString)
|
||||
{
|
||||
bool result = true;
|
||||
hasInputPathParam = false;
|
||||
bool preciseVectorData = false;
|
||||
|
||||
for(int i=1; i< argc; ++i)
|
||||
{
|
||||
if(strcmp("-s",argv[i]) == 0)
|
||||
{
|
||||
preciseVectorData = false;
|
||||
}
|
||||
else if(strcmp("-d",argv[i]) == 0)
|
||||
{
|
||||
if((i+1)<argc)
|
||||
{
|
||||
hasInputPathParam = true;
|
||||
strcpy(input_path, argv[i+1]);
|
||||
if (input_path[strlen(input_path) - 1] != '\\' || input_path[strlen(input_path) - 1] != '/')
|
||||
strcat(input_path, "/");
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else if(strcmp("-?",argv[1]) == 0)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else if(strcmp("-l",argv[i]) == 0)
|
||||
{
|
||||
preciseVectorData = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!result)
|
||||
{
|
||||
printf("Extract %s.\n",versionString);
|
||||
printf("%s [-?][-s][-l][-d <path>]\n", argv[0]);
|
||||
printf(" -s : (default) small size (data size optimization), ~500MB less vmap data.\n");
|
||||
printf(" -l : large size, ~500MB more vmap data. (might contain more details)\n");
|
||||
printf(" -d <path>: Path to the vector data source folder.\n");
|
||||
printf(" -? : This message.\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
// Main
|
||||
//
|
||||
// The program must be run with two command line arguments
|
||||
//
|
||||
// Arg1 - The source MPQ name (for testing reading and file find)
|
||||
// Arg2 - Listfile name
|
||||
//
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
bool success=true;
|
||||
const char *versionString = "V2.90 2010_05";
|
||||
|
||||
// Use command line arguments, when some
|
||||
if(!processArgv(argc, argv, versionString))
|
||||
return 1;
|
||||
|
||||
printf("Extract %s. Beginning work ....\n",versionString);
|
||||
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
// Create the working directory
|
||||
if(mkdir(szWorkDirWmo
|
||||
#ifdef __linux__
|
||||
, 0711
|
||||
#endif
|
||||
))
|
||||
success = (errno == EEXIST);
|
||||
|
||||
// prepare archive name list
|
||||
std::vector<std::string> archiveNames;
|
||||
fillArchiveNameVector(archiveNames);
|
||||
for (size_t i=0; i < archiveNames.size(); ++i)
|
||||
{
|
||||
MPQArchive *archive = new MPQArchive(archiveNames[i].c_str());
|
||||
if(!gOpenArchives.size() || gOpenArchives.front() != archive)
|
||||
delete archive;
|
||||
}
|
||||
|
||||
if(gOpenArchives.empty())
|
||||
{
|
||||
printf("FATAL ERROR: None MPQ archive found by path '%s'. Use -d option with proper path.\n",input_path);
|
||||
return 1;
|
||||
}
|
||||
ReadLiquidTypeTableDBC();
|
||||
|
||||
// extract data
|
||||
if(success)
|
||||
success = ExtractWmo();
|
||||
|
||||
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
//map.dbc
|
||||
if(success)
|
||||
{
|
||||
DBCFile * dbc = new DBCFile("DBFilesClient\\Map.dbc");
|
||||
if(!dbc->open())
|
||||
{
|
||||
delete dbc;
|
||||
printf("FATAL ERROR: Map.dbc not found in data file.\n");
|
||||
return 1;
|
||||
}
|
||||
map_count=dbc->getRecordCount ();
|
||||
map_ids=new map_id[map_count];
|
||||
for(unsigned int x=0;x<map_count;++x)
|
||||
{
|
||||
map_ids[x].id=dbc->getRecord (x).getUInt(0);
|
||||
strcpy(map_ids[x].name,dbc->getRecord(x).getString(1));
|
||||
printf("Map - %s\n",map_ids[x].name);
|
||||
}
|
||||
|
||||
|
||||
delete dbc;
|
||||
ParsMapFiles();
|
||||
delete [] map_ids;
|
||||
//nError = ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
clreol();
|
||||
if(!success)
|
||||
{
|
||||
printf("ERROR: Extract %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n",versionString, preciseVectorData);
|
||||
getchar();
|
||||
}
|
||||
|
||||
printf("Extract %s. Work complete. No errors.\n",versionString);
|
||||
delete [] LiqType;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef VMAPEXPORT_H
|
||||
#define VMAPEXPORT_H
|
||||
|
||||
enum ModelFlags
|
||||
{
|
||||
MOD_M2 = 1,
|
||||
MOD_WORLDSPAWN = 1<<1,
|
||||
MOD_HAS_BOUND = 1<<2
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,117 @@
|
||||
#define __STORMLIB_SELF__
|
||||
|
||||
#include "wdtfile.h"
|
||||
#include "adtfile.h"
|
||||
#include <cstdio>
|
||||
|
||||
char * wdtGetPlainName(char * FileName)
|
||||
{
|
||||
char * szTemp;
|
||||
|
||||
if((szTemp = strrchr(FileName, '\\')) != NULL)
|
||||
FileName = szTemp + 1;
|
||||
return FileName;
|
||||
}
|
||||
|
||||
WDTFile::WDTFile(char* file_name, char* file_name1):WDT(file_name)
|
||||
{
|
||||
filename.append(file_name1,strlen(file_name1));
|
||||
}
|
||||
|
||||
bool WDTFile::init(char *map_id, unsigned int mapID)
|
||||
{
|
||||
if (WDT.isEof())
|
||||
{
|
||||
//printf("Can't find WDT file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char fourcc[5];
|
||||
uint32 size;
|
||||
|
||||
const char dirname[] = "Buildings/dir_bin";
|
||||
FILE *dirfile;
|
||||
dirfile = fopen(dirname, "ab");
|
||||
if(!dirfile)
|
||||
{
|
||||
printf("Can't open dirfile!'%s'\n", dirname);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!WDT.isEof())
|
||||
{
|
||||
WDT.read(fourcc,4);
|
||||
WDT.read(&size, 4);
|
||||
|
||||
flipcc(fourcc);
|
||||
fourcc[4] = 0;
|
||||
|
||||
size_t nextpos = WDT.getPos() + size;
|
||||
|
||||
if (!strcmp(fourcc,"MAIN"))
|
||||
{
|
||||
}
|
||||
if (!strcmp(fourcc,"MWMO"))
|
||||
{
|
||||
// global map objects
|
||||
if (size)
|
||||
{
|
||||
char *buf = new char[size];
|
||||
WDT.read(buf, size);
|
||||
char *p=buf;
|
||||
int q = 0;
|
||||
gWmoInstansName = new string[size];
|
||||
while (p<buf+size)
|
||||
{
|
||||
string path(p);
|
||||
char* s=wdtGetPlainName(p);
|
||||
fixnamen(s,strlen(s));
|
||||
p=p+strlen(p)+1;
|
||||
gWmoInstansName[q++] = s;
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(fourcc,"MODF"))
|
||||
{
|
||||
// global wmo instance data
|
||||
if (size)
|
||||
{
|
||||
gnWMO = (int)size / 64;
|
||||
string gWMO_mapname;
|
||||
string fake_mapname;
|
||||
fake_mapname = "65 65 ";
|
||||
//gWMO_mapname = fake_mapname + filename;
|
||||
gWMO_mapname = fake_mapname + std::string(map_id);
|
||||
for (int i=0; i<gnWMO; ++i)
|
||||
{
|
||||
int id;
|
||||
WDT.read(&id, 4);
|
||||
WMOInstance inst(WDT,gWmoInstansName[id].c_str(),mapID, 65, 65, dirfile);
|
||||
}
|
||||
delete[] gWmoInstansName;
|
||||
}
|
||||
}
|
||||
WDT.seek((int)nextpos);
|
||||
}
|
||||
|
||||
WDT.close();
|
||||
fclose(dirfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
WDTFile::~WDTFile(void)
|
||||
{
|
||||
WDT.close();
|
||||
}
|
||||
|
||||
ADTFile* WDTFile::GetMap(int x, int z)
|
||||
{
|
||||
if(!(x>=0 && z >= 0 && x<64 && z<64))
|
||||
return NULL;
|
||||
|
||||
char name[512];
|
||||
|
||||
sprintf(name,"World\\Maps\\%s\\%s_%d_%d.adt", filename.c_str(), filename.c_str(), x, z);
|
||||
return new ADTFile(name);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef WDTFILE_H
|
||||
#define WDTFILE_H
|
||||
|
||||
#include "mpq_libmpq04.h"
|
||||
#include "wmo.h"
|
||||
#include <string>
|
||||
#include "stdlib.h"
|
||||
|
||||
class ADTFile;
|
||||
|
||||
class WDTFile
|
||||
{
|
||||
public:
|
||||
WDTFile(char* file_name, char* file_name1);
|
||||
~WDTFile(void);
|
||||
bool init(char *map_id, unsigned int mapID);
|
||||
|
||||
string* gWmoInstansName;
|
||||
int gnWMO, nMaps;
|
||||
|
||||
ADTFile* GetMap(int x, int z);
|
||||
|
||||
private:
|
||||
MPQFile WDT;
|
||||
bool maps[64][64];
|
||||
string filename;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,506 @@
|
||||
|
||||
#include "vmapexport.h"
|
||||
#include "wmo.h"
|
||||
#include "vec3d.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#undef min
|
||||
#undef max
|
||||
#include "mpq_libmpq04.h"
|
||||
|
||||
using namespace std;
|
||||
extern uint16 *LiqType;
|
||||
|
||||
WMORoot::WMORoot(std::string &filename) : filename(filename)
|
||||
{
|
||||
}
|
||||
|
||||
bool WMORoot::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
if(f.isEof ())
|
||||
{
|
||||
printf("No such file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 size;
|
||||
char fourcc[5];
|
||||
|
||||
while (!f.isEof())
|
||||
{
|
||||
f.read(fourcc,4);
|
||||
f.read(&size, 4);
|
||||
|
||||
flipcc(fourcc);
|
||||
fourcc[4] = 0;
|
||||
|
||||
size_t nextpos = f.getPos() + size;
|
||||
|
||||
if (!strcmp(fourcc,"MOHD"))//header
|
||||
{
|
||||
f.read(&nTextures, 4);
|
||||
f.read(&nGroups, 4);
|
||||
f.read(&nP, 4);
|
||||
f.read(&nLights, 4);
|
||||
f.read(&nModels, 4);
|
||||
f.read(&nDoodads, 4);
|
||||
f.read(&nDoodadSets, 4);
|
||||
f.read(&col, 4);
|
||||
f.read(&RootWMOID, 4);
|
||||
f.read(bbcorn1,12);
|
||||
f.read(bbcorn2,12);
|
||||
f.read(&liquidType, 4);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
else if (!strcmp(fourcc,"MOTX"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOMT"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOGN"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOGI"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOLT"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MODN"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MODS"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MODD"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOSB"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOPV"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOPT"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOPR"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MFOG"))
|
||||
{
|
||||
}
|
||||
*/
|
||||
f.seek((int)nextpos);
|
||||
}
|
||||
f.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WMORoot::ConvertToVMAPRootWmo(FILE *pOutfile)
|
||||
{
|
||||
//printf("Convert RootWmo...\n");
|
||||
|
||||
fwrite("VMAP003",1,8,pOutfile);
|
||||
unsigned int nVectors = 0;
|
||||
fwrite(&nVectors,sizeof(nVectors),1,pOutfile); // will be filled later
|
||||
fwrite(&nGroups,4,1,pOutfile);
|
||||
fwrite(&RootWMOID,4,1,pOutfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
WMORoot::~WMORoot()
|
||||
{
|
||||
}
|
||||
|
||||
WMOGroup::WMOGroup(std::string &filename) : filename(filename),
|
||||
MOPY(0), MOVI(0), MoviEx(0), MOVT(0), MOBA(0), MobaEx(0), hlq(0), LiquEx(0), LiquBytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool WMOGroup::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
if(f.isEof ())
|
||||
{
|
||||
printf("No such file.\n");
|
||||
return false;
|
||||
}
|
||||
uint32 size;
|
||||
char fourcc[5];
|
||||
while (!f.isEof())
|
||||
{
|
||||
f.read(fourcc,4);
|
||||
f.read(&size, 4);
|
||||
flipcc(fourcc);
|
||||
if (!strcmp(fourcc,"MOGP"))//Fix sizeoff = Data size.
|
||||
{
|
||||
size = 68;
|
||||
}
|
||||
fourcc[4] = 0;
|
||||
size_t nextpos = f.getPos() + size;
|
||||
LiquEx_size = 0;
|
||||
liquflags = 0;
|
||||
|
||||
if (!strcmp(fourcc,"MOGP"))//header
|
||||
{
|
||||
f.read(&groupName, 4);
|
||||
f.read(&descGroupName, 4);
|
||||
f.read(&mogpFlags, 4);
|
||||
f.read(bbcorn1, 12);
|
||||
f.read(bbcorn2, 12);
|
||||
f.read(&moprIdx, 2);
|
||||
f.read(&moprNItems, 2);
|
||||
f.read(&nBatchA, 2);
|
||||
f.read(&nBatchB, 2);
|
||||
f.read(&nBatchC, 4);
|
||||
f.read(&fogIdx, 4);
|
||||
f.read(&liquidType, 4);
|
||||
f.read(&groupWMOID,4);
|
||||
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOPY"))
|
||||
{
|
||||
MOPY = new char[size];
|
||||
mopy_size = size;
|
||||
nTriangles = (int)size / 2;
|
||||
f.read(MOPY, size);
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOVI"))
|
||||
{
|
||||
MOVI = new uint16[size/2];
|
||||
f.read(MOVI, size);
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOVT"))
|
||||
{
|
||||
MOVT = new float[size/4];
|
||||
f.read(MOVT, size);
|
||||
nVertices = (int)size / 12;
|
||||
}
|
||||
else if (!strcmp(fourcc,"MONR"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOTV"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOBA"))
|
||||
{
|
||||
MOBA = new uint16[size/2];
|
||||
moba_size = size/2;
|
||||
f.read(MOBA, size);
|
||||
}
|
||||
else if (!strcmp(fourcc,"MLIQ"))
|
||||
{
|
||||
liquflags |= 1;
|
||||
hlq = new WMOLiquidHeader;
|
||||
f.read(hlq, 0x1E);
|
||||
LiquEx_size = sizeof(WMOLiquidVert) * hlq->xverts * hlq->yverts;
|
||||
LiquEx = new WMOLiquidVert[hlq->xverts * hlq->yverts];
|
||||
f.read(LiquEx, LiquEx_size);
|
||||
int nLiquBytes = hlq->xtiles * hlq->ytiles;
|
||||
LiquBytes = new char[nLiquBytes];
|
||||
f.read(LiquBytes, nLiquBytes);
|
||||
|
||||
/* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app);
|
||||
llog << filename;
|
||||
llog << "\nbbox: " << bbcorn1[0] << ", " << bbcorn1[1] << ", " << bbcorn1[2] << " | " << bbcorn2[0] << ", " << bbcorn2[1] << ", " << bbcorn2[2];
|
||||
llog << "\nlpos: " << hlq->pos_x << ", " << hlq->pos_y << ", " << hlq->pos_z;
|
||||
llog << "\nx-/yvert: " << hlq->xverts << "/" << hlq->yverts << " size: " << size << " expected size: " << 30 + hlq->xverts*hlq->yverts*8 + hlq->xtiles*hlq->ytiles << std::endl;
|
||||
llog.close(); */
|
||||
}
|
||||
f.seek((int)nextpos);
|
||||
}
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool pPreciseVectorData)
|
||||
{
|
||||
fwrite(&mogpFlags,sizeof(uint32),1,output);
|
||||
fwrite(&groupWMOID,sizeof(uint32),1,output);
|
||||
// group bound
|
||||
fwrite(bbcorn1, sizeof(float), 3, output);
|
||||
fwrite(bbcorn2, sizeof(float), 3, output);
|
||||
fwrite(&liquflags,sizeof(uint32),1,output);
|
||||
int nColTriangles = 0;
|
||||
if(pPreciseVectorData)
|
||||
{
|
||||
char GRP[] = "GRP ";
|
||||
fwrite(GRP,1,4,output);
|
||||
|
||||
int k = 0;
|
||||
int moba_batch = moba_size/12;
|
||||
MobaEx = new int[moba_batch*4];
|
||||
for(int i=8; i<moba_size; i+=12)
|
||||
{
|
||||
MobaEx[k++] = MOBA[i];
|
||||
}
|
||||
int moba_size_grp = moba_batch*4+4;
|
||||
fwrite(&moba_size_grp,4,1,output);
|
||||
fwrite(&moba_batch,4,1,output);
|
||||
fwrite(MobaEx,4,k,output);
|
||||
delete [] MobaEx;
|
||||
|
||||
uint32 nIdexes = nTriangles * 3;
|
||||
|
||||
if(fwrite("INDX",4, 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file nbraches ID");
|
||||
exit(0);
|
||||
}
|
||||
int wsize = sizeof(uint32) + sizeof(unsigned short) * nIdexes;
|
||||
if(fwrite(&wsize, sizeof(int), 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file wsize");
|
||||
// no need to exit?
|
||||
}
|
||||
if(fwrite(&nIdexes, sizeof(uint32), 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file nIndexes");
|
||||
exit(0);
|
||||
}
|
||||
if(nIdexes >0)
|
||||
{
|
||||
if(fwrite(MOVI, sizeof(unsigned short), nIdexes, output) != nIdexes)
|
||||
{
|
||||
printf("Error while writing file indexarray");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(fwrite("VERT",4, 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file nbraches ID");
|
||||
exit(0);
|
||||
}
|
||||
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
|
||||
if(fwrite(&wsize, sizeof(int), 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file wsize");
|
||||
// no need to exit?
|
||||
}
|
||||
if(fwrite(&nVertices, sizeof(int), 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file nVertices");
|
||||
exit(0);
|
||||
}
|
||||
if(nVertices >0)
|
||||
{
|
||||
if(fwrite(MOVT, sizeof(float)*3, nVertices, output) != nVertices)
|
||||
{
|
||||
printf("Error while writing file vectors");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
nColTriangles = nTriangles;
|
||||
}
|
||||
else
|
||||
{
|
||||
char GRP[] = "GRP ";
|
||||
fwrite(GRP,1,4,output);
|
||||
int k = 0;
|
||||
int moba_batch = moba_size/12;
|
||||
MobaEx = new int[moba_batch*4];
|
||||
for(int i=8; i<moba_size; i+=12)
|
||||
{
|
||||
MobaEx[k++] = MOBA[i];
|
||||
}
|
||||
|
||||
int moba_size_grp = moba_batch*4+4;
|
||||
fwrite(&moba_size_grp,4,1,output);
|
||||
fwrite(&moba_batch,4,1,output);
|
||||
fwrite(MobaEx,4,k,output);
|
||||
delete [] MobaEx;
|
||||
|
||||
//-------INDX------------------------------------
|
||||
//-------MOPY--------
|
||||
MoviEx = new uint16[nTriangles*3]; // "worst case" size...
|
||||
int *IndexRenum = new int[nVertices];
|
||||
memset(IndexRenum, 0xFF, nVertices*sizeof(int));
|
||||
for (int i=0; i<nTriangles; ++i)
|
||||
{
|
||||
// Skip no collision triangles
|
||||
if (MOPY[2*i]&WMO_MATERIAL_NO_COLLISION ||
|
||||
!(MOPY[2*i]&(WMO_MATERIAL_HINT|WMO_MATERIAL_COLLIDE_HIT)) )
|
||||
continue;
|
||||
// Use this triangle
|
||||
for (int j=0; j<3; ++j)
|
||||
{
|
||||
IndexRenum[MOVI[3*i + j]] = 1;
|
||||
MoviEx[3*nColTriangles + j] = MOVI[3*i + j];
|
||||
}
|
||||
++nColTriangles;
|
||||
}
|
||||
|
||||
// assign new vertex index numbers
|
||||
int nColVertices = 0;
|
||||
for (uint32 i=0; i<nVertices; ++i)
|
||||
{
|
||||
if (IndexRenum[i] == 1)
|
||||
{
|
||||
IndexRenum[i] = nColVertices;
|
||||
++nColVertices;
|
||||
}
|
||||
}
|
||||
|
||||
// translate triangle indices to new numbers
|
||||
for (int i=0; i<3*nColTriangles; ++i)
|
||||
{
|
||||
assert(MoviEx[i] < nVertices);
|
||||
MoviEx[i] = IndexRenum[MoviEx[i]];
|
||||
}
|
||||
|
||||
// write triangle indices
|
||||
int INDX[] = {0x58444E49, nColTriangles*6+4, nColTriangles*3};
|
||||
fwrite(INDX,4,3,output);
|
||||
fwrite(MoviEx,2,nColTriangles*3,output);
|
||||
|
||||
// write vertices
|
||||
int VERT[] = {0x54524556, nColVertices*3*sizeof(float)+4, nColVertices};// "VERT"
|
||||
int check = 3*nColVertices;
|
||||
fwrite(VERT,4,3,output);
|
||||
for (uint32 i=0; i<nVertices; ++i)
|
||||
if(IndexRenum[i] >= 0)
|
||||
check -= fwrite(MOVT+3*i, sizeof(float), 3, output);
|
||||
|
||||
assert(check==0);
|
||||
|
||||
delete [] MoviEx;
|
||||
delete [] IndexRenum;
|
||||
}
|
||||
|
||||
//------LIQU------------------------
|
||||
if(LiquEx_size != 0)
|
||||
{
|
||||
int LIQU_h[] = {0x5551494C, sizeof(WMOLiquidHeader) + LiquEx_size + hlq->xtiles*hlq->ytiles};// "LIQU"
|
||||
fwrite(LIQU_h, 4, 2, output);
|
||||
|
||||
// according to WoW.Dev Wiki:
|
||||
uint32 liquidEntry;
|
||||
if (rootWMO->liquidType & 4)
|
||||
liquidEntry = liquidType;
|
||||
else if (liquidType == 15)
|
||||
liquidEntry = 0;
|
||||
else
|
||||
liquidEntry = liquidType + 1;
|
||||
// overwrite material type in header...
|
||||
hlq->type = LiqType[liquidEntry];
|
||||
|
||||
/* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app);
|
||||
llog << filename;
|
||||
llog << ":\nliquidEntry: " << liquidEntry << " type: " << hlq->type << " (root:" << rootWMO->liquidType << " group:" << liquidType << ")\n";
|
||||
llog.close(); */
|
||||
|
||||
fwrite(hlq, sizeof(WMOLiquidHeader), 1, output);
|
||||
// only need height values, the other values are unknown anyway
|
||||
for (uint32 i = 0; i<LiquEx_size/sizeof(WMOLiquidVert); ++i)
|
||||
fwrite(&LiquEx[i].height, sizeof(float), 1, output);
|
||||
// todo: compress to bit field
|
||||
fwrite(LiquBytes, 1, hlq->xtiles*hlq->ytiles, output);
|
||||
}
|
||||
|
||||
return nColTriangles;
|
||||
}
|
||||
|
||||
WMOGroup::~WMOGroup()
|
||||
{
|
||||
delete [] MOPY;
|
||||
delete [] MOVI;
|
||||
delete [] MOVT;
|
||||
delete [] MOBA;
|
||||
delete hlq;
|
||||
delete [] LiquEx;
|
||||
delete [] LiquBytes;
|
||||
}
|
||||
|
||||
WMOInstance::WMOInstance(MPQFile &f,const char* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile)
|
||||
{
|
||||
pos = Vec3D(0,0,0);
|
||||
|
||||
float ff[3];
|
||||
f.read(&id, 4);
|
||||
f.read(ff,12);
|
||||
pos = Vec3D(ff[0],ff[1],ff[2]);
|
||||
f.read(ff,12);
|
||||
rot = Vec3D(ff[0],ff[1],ff[2]);
|
||||
f.read(ff,12);
|
||||
pos2 = Vec3D(ff[0],ff[1],ff[2]);
|
||||
f.read(ff,12);
|
||||
pos3 = Vec3D(ff[0],ff[1],ff[2]);
|
||||
f.read(&d2,4);
|
||||
|
||||
uint16 trash,adtId;
|
||||
f.read(&adtId,2);
|
||||
f.read(&trash,2);
|
||||
|
||||
//-----------add_in _dir_file----------------
|
||||
|
||||
char tempname[512];
|
||||
sprintf(tempname, "Buildings/%s", WmoInstName);
|
||||
FILE *input;
|
||||
input = fopen(tempname, "r+b");
|
||||
|
||||
if(!input)
|
||||
{
|
||||
printf("WMOInstance::WMOInstance: couldn't open %s\n", tempname);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(input, 8, SEEK_SET); // get the correct no of vertices
|
||||
int nVertices;
|
||||
fread(&nVertices, sizeof (int), 1, input);
|
||||
fclose(input);
|
||||
|
||||
if(nVertices == 0)
|
||||
return;
|
||||
|
||||
float x,z;
|
||||
x = pos.x;
|
||||
z = pos.z;
|
||||
if(x==0 && z == 0)
|
||||
{
|
||||
pos.x = 533.33333f*32;
|
||||
pos.z = 533.33333f*32;
|
||||
}
|
||||
pos = fixCoords(pos);
|
||||
pos2 = fixCoords(pos2);
|
||||
pos3 = fixCoords(pos3);
|
||||
|
||||
float scale = 1.0f;
|
||||
uint32 flags = MOD_HAS_BOUND;
|
||||
if(tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN;
|
||||
//write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&flags, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&adtId, sizeof(uint16), 1, pDirfile);
|
||||
fwrite(&id, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&pos, sizeof(float), 3, pDirfile);
|
||||
fwrite(&rot, sizeof(float), 3, pDirfile);
|
||||
fwrite(&scale, sizeof(float), 1, pDirfile);
|
||||
fwrite(&pos2, sizeof(float), 3, pDirfile);
|
||||
fwrite(&pos3, sizeof(float), 3, pDirfile);
|
||||
uint32 nlen=strlen(WmoInstName);
|
||||
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(WmoInstName, sizeof(char), nlen, pDirfile);
|
||||
|
||||
/* fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n",
|
||||
MapName,
|
||||
WmoInstName,
|
||||
(float) x, (float) pos.y, (float) z,
|
||||
(float) rot.x, (float) rot.y, (float) rot.z,
|
||||
nVertices,
|
||||
realx1, realy1,
|
||||
realx2, realy2
|
||||
); */
|
||||
|
||||
// fclose(dirfile);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#ifndef WMO_H
|
||||
#define WMO_H
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "vec3d.h"
|
||||
#include "loadlib/loadlib.h"
|
||||
|
||||
// MOPY flags
|
||||
#define WMO_MATERIAL_NOCAMCOLLIDE 0x01
|
||||
#define WMO_MATERIAL_DETAIL 0x02
|
||||
#define WMO_MATERIAL_NO_COLLISION 0x04
|
||||
#define WMO_MATERIAL_HINT 0x08
|
||||
#define WMO_MATERIAL_RENDER 0x10
|
||||
#define WMO_MATERIAL_COLLIDE_HIT 0x20
|
||||
#define WMO_MATERIAL_WALL_SURFACE 0x40
|
||||
|
||||
class WMOInstance;
|
||||
class WMOManager;
|
||||
class MPQFile;
|
||||
|
||||
/* for whatever reason a certain company just can't stick to one coordinate system... */
|
||||
static inline Vec3D fixCoords(const Vec3D &v){ return Vec3D(v.z, v.x, v.y); }
|
||||
|
||||
class WMORoot
|
||||
{
|
||||
public:
|
||||
uint32 nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootWMOID, liquidType;
|
||||
unsigned int col;
|
||||
float bbcorn1[3];
|
||||
float bbcorn2[3];
|
||||
|
||||
WMORoot(std::string &filename);
|
||||
~WMORoot();
|
||||
|
||||
bool open();
|
||||
bool ConvertToVMAPRootWmo(FILE *output);
|
||||
private:
|
||||
std::string filename;
|
||||
char outfilename;
|
||||
};
|
||||
|
||||
struct WMOLiquidHeader
|
||||
{
|
||||
int xverts, yverts, xtiles, ytiles;
|
||||
float pos_x;
|
||||
float pos_y;
|
||||
float pos_z;
|
||||
short type;
|
||||
};
|
||||
|
||||
struct WMOLiquidVert
|
||||
{
|
||||
uint16 unk1;
|
||||
uint16 unk2;
|
||||
float height;
|
||||
};
|
||||
|
||||
class WMOGroup
|
||||
{
|
||||
public:
|
||||
// MOGP
|
||||
int groupName, descGroupName, mogpFlags;
|
||||
float bbcorn1[3];
|
||||
float bbcorn2[3];
|
||||
uint16 moprIdx;
|
||||
uint16 moprNItems;
|
||||
uint16 nBatchA;
|
||||
uint16 nBatchB;
|
||||
uint32 nBatchC, fogIdx, liquidType, groupWMOID;
|
||||
|
||||
int mopy_size,moba_size;
|
||||
int LiquEx_size;
|
||||
unsigned int nVertices; // number when loaded
|
||||
int nTriangles; // number when loaded
|
||||
char *MOPY;
|
||||
uint16 *MOVI;
|
||||
uint16 *MoviEx;
|
||||
float *MOVT;
|
||||
uint16 *MOBA;
|
||||
int *MobaEx;
|
||||
WMOLiquidHeader *hlq;
|
||||
WMOLiquidVert *LiquEx;
|
||||
char *LiquBytes;
|
||||
uint32 liquflags;
|
||||
|
||||
WMOGroup(std::string &filename);
|
||||
~WMOGroup();
|
||||
|
||||
bool open();
|
||||
int ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool pPreciseVectorData);
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
char outfilename;
|
||||
};
|
||||
|
||||
class WMOInstance
|
||||
{
|
||||
static std::set<int> ids;
|
||||
public:
|
||||
std::string MapName;
|
||||
int currx;
|
||||
int curry;
|
||||
WMOGroup *wmo;
|
||||
Vec3D pos;
|
||||
Vec3D pos2, pos3, rot;
|
||||
uint32 indx,id, d2, d3;
|
||||
int doodadset;
|
||||
|
||||
WMOInstance(MPQFile &f,const char* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile);
|
||||
|
||||
static void reset();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmapExtractor3", "VC90\vmapExtractor3.vcproj", "{D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user