server/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp
VladimirMangos ec1d6a3b56 [7910] Resolve problems with vmaps extractor support 3.1.2 archives.
Binary in contrib/vmap_extract_assembler_bin also updated.
2009-05-29 06:25:28 +04:00

574 lines
17 KiB
C++

/*****************************************************************************/
/* 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 <io.h>
#include <conio.h>
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <vector>
#include <list>
#define __STORMLIB_SELF__ // Don't use StormLib.lib
#include "StormLib.h"
#pragma warning(disable : 4505)
#pragma comment(lib, "Winmm.lib")
//From Extractor
#include "adtfile.h"
#include "wdtfile.h"
#include "dbcfile.h"
#include "mpq.h"
#include "wmo.h"
//------------------------------------------------------------------------------
// Defines
#define MPQ_BLOCK_SIZE 0x1000
//-----------------------------------------------------------------------------
// from extractor
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef struct{
char name[64];
unsigned int id;
}map_id;
map_id * map_ids;
uint16 * areas;
uint16 *areamax;
uint32 map_count;
char output_path[128]=".";
char input_path[1024]=".";
bool hasInputPathParam = false;
char tmp[512];
bool preciseVectorData = false;
//char gamepath[1024];
//Convert function
//bool ConvertADT(char*,char*);
// Constants
//static const char * szWorkDirMaps = ".\\Maps";
static const char * szWorkDirWmo = ".\\buildings";
//static LPBYTE pbBuffer1 = NULL;
//static LPBYTE pbBuffer2 = NULL;
// Local testing functions
static void clreol()
{
printf("\r \r");
}
static const char * GetPlainName(const char * szFileName)
{
const char * szTemp;
if((szTemp = strrchr(szFileName, '\\')) != NULL)
szFileName = szTemp + 1;
return szFileName;
}
static void ShowProcessedFile(const char * szFileName)
{
/* not truncate file names in output
char szLine[80];
size_t nLength = strlen(szFileName);
memset(szLine, 0x20, sizeof(szLine));
szLine[sizeof(szLine)-1] = 0;
if(nLength > sizeof(szLine)-1)
nLength = sizeof(szLine)-1;
memcpy(szLine, szFileName, nLength);
printf("\r%s\n", szLine);
*/
printf("\r%s\n", szFileName);
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------
int ExtractWmo()
{
char* szListFile = "";
char szLocalFile[MAX_PATH] = "";
BOOL bResult = FALSE;
//const char* ParsArchiveNames[] = {"patch-2.MPQ", "patch.MPQ", "common.MPQ", "expansion.MPQ"};
int nError = ERROR_SUCCESS;
if(szListFile == NULL || *szListFile == 0)
szListFile = NULL;
for (ArchiveSet::const_iterator ar_itr = gOpenArchives.archives.begin(); ar_itr != gOpenArchives.archives.end(); ++ar_itr)
{
// Copy files from archive
if(nError == ERROR_SUCCESS)
{
SFILE_FIND_DATA wf;
HANDLE hFind = SFileFindFirstFile(ar_itr->hMPQ,"*.wmo*", &wf, szListFile);
bResult = TRUE;
while(hFind != NULL && bResult == TRUE)
{
ShowProcessedFile(wf.cFileName);
SFileSetLocale(wf.lcLocale);
sprintf(szLocalFile, "%s\\%s", szWorkDirWmo, GetPlainName(wf.cFileName));
fixnamen(szLocalFile,strlen(szLocalFile));
FILE * n;
if ((n = fopen(szLocalFile, "rb"))== NULL)
{
int p = 0;
//Select root wmo files
const char * rchr = strrchr(GetPlainName(wf.cFileName),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)
{
//printf("RootWmo!\n");
string s = wf.cFileName;
WMORoot * froot = new WMORoot(s);
if(!froot->open())
{
printf("Not open RootWmo!!!\n");
bResult = SFileFindNextFile(hFind, &wf);
continue;
}
FILE *output=fopen(szLocalFile,"wb");
froot->ConvertToVMAPRootWmo(output);
int Wmo_nVertices = 0;
if(froot->nGroups !=0)
{
for (int i=0; i<froot->nGroups; ++i)
{
char temp[MAX_PATH];
strcpy(temp, wf.cFileName);
temp[strlen(wf.cFileName)-4] = 0;
char groupFileName[MAX_PATH];
sprintf(groupFileName,"%s_%03d.wmo",temp, i);
printf("%s\n",groupFileName);
//printf("GroupWmo!\n");
string s = groupFileName;
WMOGroup * fgroup = new WMOGroup(s);
if(!fgroup->open())
{
printf("Not all open Group file for: %s\n",GetPlainName(wf.cFileName));
bResult = SFileFindNextFile(hFind, &wf);
break;
}
Wmo_nVertices += fgroup->ConvertToVMAPGroupWmo(output, preciseVectorData);
}
}
fseek(output, 8, SEEK_SET); // store the correct no of vertices
fwrite(&Wmo_nVertices,sizeof(int),1,output);
fclose(output);
}
}
else
{
fclose(n);
}
wf.dwFileFlags &= ~MPQ_FILE_HAS_EXTRA;
wf.dwFileFlags &= ~MPQ_FILE_EXISTS;
// Find the next file
bResult = SFileFindNextFile(hFind, &wf);
}
// Delete the extracted file in the case of an error
if(nError != ERROR_SUCCESS)
DeleteFile(szLocalFile);
// Close the search handle
if(hFind != NULL)
SFileFindClose(hFind);
}
}
if(nError == ERROR_SUCCESS)
printf("\nExtract wmo complete (No errors)\n");
return nError;
}
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))
{
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(id_filename);
delete ADT;
}
}
}
}
}
}
#if 0
void ParsMapFiles()
{
char fn[512];
for (unsigned int i=0; i<map_count; ++i)
{
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())
{
for (int x=0; x<64; ++x)
{
for (int y=0; y<64; ++y)
{
if (ADTFile*ADT = WDT.GetMap(x,y))
{
ADT->init();
delete ADT;
}
}
}
}
}
}
#endif
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];
std::list<std::string> matches;
WIN32_FIND_DATA ffData;
HANDLE hFind;
for (i = 1; i <= 99; i++)
{
if (i != 1)
{
sprintf(path, "%s-%d.mpq", scanmatch, i);
}
else
{
sprintf(path, "%s.mpq", scanmatch);
}
hFind = INVALID_HANDLE_VALUE;
hFind = FindFirstFile(path, &ffData);
if (hFind == INVALID_HANDLE_VALUE) break;
FindClose(hFind);
matches.push_back(path);
}
matches.reverse();
for (std::list<std::string>::iterator i = matches.begin(); i != matches.end(); ++i)
{
pArchiveNames.push_back(i->c_str());
}
printf("\n");
return(true);
}
bool fillArchiveNameVector(std::vector<std::string>& pArchiveNames)
{
if(!hasInputPathParam)
getGamePath();
printf("\nGame path: %s\n", input_path);
char path[512];
std::vector<std::string> locales;
// scan game directories
WIN32_FIND_DATA ffData;
HANDLE hFind;
DWORD dwError;
// first, scan for locales (4-letter directories)
printf("Scanning for locales.\n");
sprintf(path, "%s*.*", input_path);
hFind = INVALID_HANDLE_VALUE;
hFind = FindFirstFile(path, &ffData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf("\nCould not open data directory for reading. Aborting.\n");
return(false);
}
do
{
if (ffData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (ffData.cFileName[0] != '.')
{
if (strlen(ffData.cFileName) == 4)
{
printf("Found locale: %s\n", ffData.cFileName);
locales.push_back(ffData.cFileName);
}
}
}
} while (FindNextFile(hFind, &ffData) != 0);
dwError = GetLastError();
FindClose(hFind);
if (dwError != ERROR_NO_MORE_FILES)
{
printf("\nError reading data directory while scanning locales. Aborting.\n");
return(false);
}
printf("\n");
if (locales.size() == 0)
{
printf("Sorry, no locales found. Aborting.\n");
return(false);
}
// now, scan for the patch levels in the core dir
printf("Loading 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("Loading patch levels from locale directories.\n");
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)) return(false);
}
// open expansion and common files
printf("Opening data files from data directory.\n");
sprintf(path, "%slichking.mpq", input_path);
pArchiveNames.push_back(path);
sprintf(path, "%scommon-2.mpq", input_path);
pArchiveNames.push_back(path);
sprintf(path, "%sexpansion.mpq", input_path);
pArchiveNames.push_back(path);
sprintf(path, "%scommon.mpq", input_path);
pArchiveNames.push_back(path);
printf("\n");
// open locale expansion and common files
printf("Opening data files from locale directories.\n");
for (std::vector<std::string>::iterator i = locales.begin(); i != locales.end(); ++i)
{
printf("Locale: %s\n", i->c_str());
sprintf(path, "%s%s\\lichking-locale-%s.mpq", input_path, i->c_str(), i->c_str());
pArchiveNames.push_back(path);
sprintf(path, "%s%s\\expansion-locale-%s.mpq", input_path, i->c_str(), i->c_str());
pArchiveNames.push_back(path);
sprintf(path, "%s%s\\locale-%s.mpq", input_path, i->c_str(), i->c_str());
pArchiveNames.push_back(path);
printf("\n");
}
return true;
}
bool processArgv(int argc, char ** argv, 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)
{
//char tmp[512];
// FILE* pDatei;
// char tmp[512];
// char tmp1[512];
//char tmp2[512];
// char tmp3[512];
// char tmp4[512];
// char szMpqName[MAX_PATH] = "";
// char szListFile[MAX_PATH] = "";
int nError = ERROR_SUCCESS;
char *versionString = "V2.4 2007_07_12";
// Use command line arguments, when some
if(!processArgv(argc, argv, versionString))
return 1;
printf("Extract %s. Beginning work ....\n",versionString);
// Set the lowest priority to allow running in the background
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Create the working directory
if(nError == ERROR_SUCCESS)
{
//if(!CreateDirectory(szWorkDirMaps, NULL))
// nError = GetLastError();
if(!CreateDirectory(szWorkDirWmo, NULL))
nError = GetLastError();
if(nError == ERROR_ALREADY_EXISTS)
nError = ERROR_SUCCESS;
}
// prepare archive name list
std::vector<std::string> archiveNames;
fillArchiveNameVector(archiveNames);
if(!gOpenArchives.Open(archiveNames))
{
printf("FATAL ERROR: None MPQ archive found by path '%s'. Use -d option with proper path.\n",input_path);
return 1;
}
// extract data
ExtractWmo();
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//map.dbc
if(nError == ERROR_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(nError != ERROR_SUCCESS)
{
printf("ERROR: Extract %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n",versionString, preciseVectorData);
_getch();
}
printf("Extract %s. Work complete. No errors.",versionString);
}