336 lines
10 KiB
C++
336 lines
10 KiB
C++
// xapmunge.cpp : Defines the entry point for the console application.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "xapmunge.h"
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
|
|
// The one and only application object
|
|
CWinApp theApp;
|
|
|
|
|
|
CString xapBankName;
|
|
CString xapMasterName;
|
|
CString xapOutputName;
|
|
|
|
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
|
|
{
|
|
int nRetCode = 0;
|
|
|
|
// initialize MFC and print and error on failure
|
|
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
|
|
{
|
|
// TODO: change error code to suit your needs
|
|
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
|
|
nRetCode = 1;
|
|
}
|
|
else
|
|
{
|
|
OPTIONS opts;
|
|
opts.isCreate = false;
|
|
opts.isExtract = false;
|
|
opts.isMerge = false;
|
|
opts.isVerbose = false;
|
|
|
|
// fix up the executable name
|
|
char* exename = _tcsrchr((argv[0]), (int)'\\');
|
|
if (exename)
|
|
{
|
|
argv[0] = exename + 1;
|
|
|
|
char* dot = _tcsrchr((argv[0]), (int)'.');;
|
|
if (dot)
|
|
{
|
|
*dot = '\0';
|
|
}
|
|
}
|
|
cout << argv[0] << " v" VERSION " " __DATE__ " " __TIME__ << endl;
|
|
|
|
// get the options
|
|
if (!ParseCommandLine(argc, argv, &opts))
|
|
{
|
|
nRetCode = 2;
|
|
return nRetCode; // early exit - input parameter error
|
|
}
|
|
|
|
CStdioFile* inFile = NULL;
|
|
CStdioFile* outFile = NULL;
|
|
CStdioFile* bankFile = NULL;
|
|
XAPFile* masterXap = NULL;
|
|
XAPFile* bankXap = NULL;
|
|
|
|
try
|
|
{
|
|
if (opts.isVerbose)
|
|
{
|
|
cout << "Parsing: " << xapMasterName << endl;
|
|
}
|
|
|
|
inFile = new CStdioFile(xapMasterName, CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary | CFile::osSequentialScan);
|
|
masterXap = new XAPFile(*inFile, true);
|
|
|
|
if (opts.isCreate || opts.isExtract)
|
|
{
|
|
// create the output file in the same location as the input file
|
|
xapOutputName = inFile->GetFilePath();
|
|
xapOutputName.Replace(inFile->GetFileName(), xapBankName);
|
|
xapOutputName.Append(".xap");
|
|
|
|
// open the output file
|
|
outFile = new CStdioFile(xapOutputName, CFile::modeReadWrite | CFile::modeCreate | CFile::shareDenyWrite | CFile::typeBinary | CFile::osSequentialScan);
|
|
|
|
if (opts.isExtract)
|
|
{
|
|
int wbIndex = masterXap->FindWaveBank(xapBankName);
|
|
int sbIndex = masterXap->FindSoundBank(xapBankName);
|
|
if (wbIndex != -1 && sbIndex != -1)
|
|
{
|
|
if (opts.isVerbose)
|
|
{
|
|
cout << "Extracting: " << xapBankName << " from " << xapMasterName << endl;
|
|
}
|
|
|
|
masterXap->WriteXapGlobalSettings(*outFile);
|
|
masterXap->WriteXapWaveBank(wbIndex, *outFile);
|
|
masterXap->WriteXapSoundBank(sbIndex, *outFile);
|
|
}
|
|
else
|
|
{
|
|
CString msg;
|
|
msg.Format("Unable to find section: %s", xapBankName);
|
|
nRetCode = 3;
|
|
throw XapException((LPCSTR)msg);
|
|
}
|
|
}
|
|
else // opts.isCreate
|
|
{
|
|
if (opts.isVerbose)
|
|
{
|
|
cout << "Creating: " << xapBankName << endl;
|
|
}
|
|
|
|
masterXap->WriteXapGlobalSettings(*outFile);
|
|
masterXap->CreateXapWaveBank(*outFile);
|
|
masterXap->CreateXapSoundBank(*outFile);
|
|
}
|
|
}
|
|
else if (opts.isMerge)
|
|
{
|
|
// create the output file in the same location as the input file
|
|
xapOutputName = inFile->GetFilePath() + ".new";
|
|
|
|
// open the output file
|
|
outFile = new CStdioFile(xapOutputName, CFile::modeReadWrite | CFile::modeCreate | CFile::shareDenyWrite | CFile::typeBinary | CFile::osSequentialScan);
|
|
|
|
// open the bank file
|
|
bankFile = new CStdioFile(xapBankName, CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary);
|
|
|
|
// parse bank file
|
|
if (opts.isVerbose)
|
|
{
|
|
cout << "Parsing: " << xapBankName << endl;
|
|
}
|
|
bankXap = new XAPFile(*bankFile, true);
|
|
|
|
// verify the global settings
|
|
if (!masterXap->MatchGlobalSettings(bankXap))
|
|
{
|
|
CString msg = _T("Global Settings do not match" );
|
|
nRetCode = 4;
|
|
throw XapException((LPCSTR)msg);
|
|
}
|
|
|
|
// check for existing wave and sound banks
|
|
int wbIndex = masterXap->FindWaveBank(bankXap->GetWaveBank(0).GetName());
|
|
int sbIndex = masterXap->FindSoundBank(bankXap->GetSoundBank(0).GetName());
|
|
|
|
// appending
|
|
if (wbIndex == -1 && sbIndex == -1)
|
|
{
|
|
if (opts.isVerbose)
|
|
{
|
|
cout << "Appending wave bank: " << bankXap->GetWaveBank(0).GetName() << " to " << xapMasterName << endl;
|
|
}
|
|
masterXap->AppendXapWaveBank(bankXap, *outFile);
|
|
if (opts.isVerbose)
|
|
{
|
|
cout << "Appending sound bank: " << bankXap->GetSoundBank(0).GetName() << " to " << xapMasterName << endl;
|
|
}
|
|
masterXap->AppendXapSoundBank(bankXap, *outFile);
|
|
}
|
|
else // merging
|
|
{
|
|
if (opts.isVerbose)
|
|
{
|
|
cout << "Replacing wave bank: " << bankXap->GetWaveBank(0).GetName() << " in " << xapMasterName << endl;
|
|
}
|
|
masterXap->ReplaceXapWaveBank(wbIndex, bankXap, *outFile);
|
|
if (opts.isVerbose)
|
|
{
|
|
cout << "Replacing sound bank: " << bankXap->GetSoundBank(0).GetName() << " in " << xapMasterName << endl;
|
|
}
|
|
masterXap->ReplaceXapSoundBank(wbIndex, sbIndex, bankXap, *outFile);
|
|
}
|
|
}
|
|
}
|
|
catch (XapException ex)
|
|
{
|
|
cout << "Error: " << ex.GetMessage() << endl << endl;
|
|
}
|
|
catch (CFileException *ex)
|
|
{
|
|
ex->ReportError();
|
|
ex->Delete();
|
|
nRetCode = 5;
|
|
}
|
|
|
|
delete masterXap;
|
|
delete bankXap;
|
|
|
|
// close the files
|
|
delete inFile;
|
|
delete outFile;
|
|
delete bankFile;
|
|
|
|
try
|
|
{
|
|
CFileStatus status;
|
|
|
|
// remove the output file if any error is detected
|
|
if (nRetCode)
|
|
{
|
|
if (CFile::GetStatus(xapOutputName, status))
|
|
{
|
|
CFile::Remove(xapOutputName);
|
|
}
|
|
}
|
|
|
|
if (opts.isMerge)
|
|
{
|
|
// rename new file to old file
|
|
if (CFile::GetStatus(xapMasterName, status) &&
|
|
CFile::GetStatus(xapOutputName, status))
|
|
{
|
|
CFile::Remove(xapMasterName);
|
|
CFile::Rename(xapOutputName, xapMasterName);
|
|
}
|
|
}
|
|
}
|
|
catch (CFileException *ex)
|
|
{
|
|
ex->ReportError();
|
|
ex->Delete();
|
|
}
|
|
}
|
|
|
|
return nRetCode;
|
|
}
|
|
|
|
|
|
bool ParseCommandLine(int argc, TCHAR *argv[], OPTIONS *opts)
|
|
{
|
|
bool gotargs = true;
|
|
bool haveMaster = false;
|
|
int i = 1;
|
|
|
|
while (i < argc)
|
|
{
|
|
int pos = 0;
|
|
CString arg, command, param;
|
|
|
|
arg = argv[i++];
|
|
command = arg.Tokenize("-=", pos);
|
|
if (command != "")
|
|
{
|
|
param = arg.Tokenize("-=", pos);
|
|
}
|
|
|
|
if (command == "master")
|
|
{
|
|
if (param != "")
|
|
{
|
|
xapMasterName = param;
|
|
haveMaster = true;
|
|
}
|
|
else
|
|
{
|
|
cerr << endl << endl << "No master XAP file specified!" << endl;
|
|
break;
|
|
}
|
|
}
|
|
else if (command == "merge")
|
|
{
|
|
if (param != "")
|
|
{
|
|
xapBankName = param;
|
|
opts->isMerge = true;
|
|
}
|
|
else
|
|
{
|
|
cerr << endl << endl << "No project XAP file specified!" << endl;
|
|
break;
|
|
}
|
|
}
|
|
else if (command == "extract")
|
|
{
|
|
if (param != "")
|
|
{
|
|
xapBankName = param;
|
|
opts->isExtract = true;
|
|
}
|
|
else
|
|
{
|
|
cerr << endl << endl << "No bank name specified!" << endl;
|
|
break;
|
|
}
|
|
}
|
|
else if (command == "create")
|
|
{
|
|
if (param != "")
|
|
{
|
|
xapBankName = param;
|
|
opts->isCreate = true;
|
|
}
|
|
else
|
|
{
|
|
cerr << endl << endl << "No bank name specified!" << endl;
|
|
break;
|
|
}
|
|
}
|
|
else if (command == "verbose")
|
|
{
|
|
opts->isVerbose = true;
|
|
}
|
|
else
|
|
{
|
|
cerr << endl << endl << "Unknown option " << arg << endl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// validate input
|
|
if (!haveMaster ||
|
|
(!opts->isCreate && !opts->isMerge && !opts->isExtract) ||
|
|
(opts->isCreate && opts->isMerge && opts->isExtract))
|
|
{
|
|
ShowUsage(argv[0]);
|
|
gotargs = false;
|
|
}
|
|
|
|
return gotargs;
|
|
}
|
|
|
|
void ShowUsage(char* exename)
|
|
{
|
|
cerr << endl;
|
|
cerr << "Usage: " << exename << " <switches>" << endl << endl;
|
|
cerr << "[-merge=filename.xap | -extract=bank name] - specify only one of these" << endl;
|
|
cerr << "-master=filename.xap - specify the master XAP file" << endl;
|
|
}
|
|
|