// NeL - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "nel/misc/types_nl.h"
#include "nel/misc/app_context.h"
#include "nel/misc/path.h"
#include "nel/misc/common.h"
#include "nel/misc/sstring.h"
#include "nel/misc/algo.h"
using namespace std;
using namespace NLMISC;
enum TAction
{
pack,
unpack,
undefined
};
const string DefaultExt("xml_pack");
const uint32 MaxLineSize = 16*1024;
const string ExcludeFiles(".#*;*.log;*.bin;*.xml_pack_index");
const string ExcludeDirs("CVS");
bool isExcludedFile(const std::string &fileName)
{
static vector excludeFileVect;
static bool init = false;
if (!init)
{
explode(ExcludeFiles, string(";"), excludeFileVect, true);
init = true;
}
bool excluded = false;
for (uint i=0; i excludeDirVect;
static bool init = false;
if (!init)
{
explode(ExcludeDirs, string(";"), excludeDirVect, true);
}
bool excluded = false;
for (uint i=0; i 0 && (path[pos] == '\\' || path[pos] == '/'))
--pos;
while(pos > 0 && path[pos] != '\\' && path[pos] != '/' )
dirName = path[pos--] + dirName;
return dirName;
}
int main(int argc, char *argv[])
{
printf("NeL XML Packer/Unpacker V0.3\n");
CApplicationContext appContext;
TAction action = undefined;
bool recursive = false;
// compute the current folder name
string currentPath = CPath::getCurrentPath();
string dirName = getLastDirName(currentPath);;
string filename = dirName + "."+DefaultExt;
// check the params to choose action
for (uint i=0; i dirStack;
printf("Current path is '%s'\n", CPath::getCurrentPath().c_str());
// push the current directory to start the loop
dirStack.push_back(CPath::getCurrentPath());
while(!dirStack.empty())
{
string dirName = dirStack.back();
dirStack.pop_back();
string filename = dirName+"/"+getLastDirName(dirName) + "."+DefaultExt;
switch (action)
{
case pack:
{
printf("Packing directory '%s'...\n", dirName.c_str());
// string packFileName = dirName+"/tmp."+DefaultExt;
string packFileName = filename;
string indexFileName = dirName+"/.xml_pack_index";
// get the current directory content
vector files;
CPath::getPathContent(dirName, false, false, true, files);
vector validFiles;
// first loop to build the list of valid file
for (uint i=0; i fileInIndex;
char lineBuffer[1024];
FILE *fp = nlfopen(indexFileName, "rt");
while (fgets(lineBuffer, 1024, fp))
fileInIndex.insert(CSString(lineBuffer).strip());
fclose(fp);
// loop to check for file time stamp
for (uint i=0; i= packDate)
// no more to check
break;
// remove this file from the file index
fileInIndex.erase(CFile::getFilename(validFiles[i]));
}
// check if there are some some deleted in the directory
if (!fileInIndex.empty())
{
// need to repack, there are erased files
break;
}
// all files are older than the pack file ! no repack needed
needRepack = false;
}
}
// we need to repack and have some file to store ?
if (!validFiles.empty() && needRepack)
{
// open the pack file
// FILE *fp = nlfopen(filename, "wt");
FILE *fp = nlfopen(packFileName, "wt");
fprintf(fp, "\n");
for (uint i=0; i\n", CFile::getFilename(subFileName).c_str());
FILE *subFp = nlfopen(subFileName, "rt");
nlassert(subFp != NULL);
char buffer[MaxLineSize];
char *result;
bool needFinalReturn = false;
result = fgets(buffer, MaxLineSize, subFp);
needFinalReturn = result != NULL ? buffer[strlen(buffer)-1] != '\n' : true;
while(result != 0)
{
fputs(buffer, fp);
result = fgets(buffer, MaxLineSize, subFp);
needFinalReturn = result != NULL ? buffer[strlen(buffer)-1] != '\n' : needFinalReturn;
}
if (needFinalReturn)
{
const char *finalReturn = "\n";
fputs(finalReturn, fp);
}
fclose(subFp);
fprintf(fp, " \n");
}
fprintf(fp, "\n");
fclose(fp);
// write the disposable index file used by pack to check for erased file
fp = nlfopen(indexFileName, "wt");
for (uint i=0; i\n") != 0)
{
printf ("Error : invalid pack file '%s'\n", filename.c_str());
return -1;
}
linecount++;
char *result = NULL;
do
{
// read a file line
linecount++;
if (!fgets(buffer, MaxLineSize, fp))
{
fclose(fp);
printf ("Error : invalid pack file '%s' at line %u", filename.c_str(), linecount);
return -1;
}
CSString parser(buffer);
if (parser.find(" ") == 0)
break;
printf ("Error : invalid pack file '%s' at line %u", filename.c_str(), linecount);
return -1;
}
CSString subFileName = parser.leftCrop(sizeof(" \n") != 0)
{
fputs(result, output);
// read next line
result = fgets(buffer, MaxLineSize, fp);
linecount++;
}
fclose(output);
} while(result != NULL);
}
break;
default:
// this shouldn't happen / keep compiler happy
break;
}
if (recursive)
{
vector subDirs;
CPath::getPathContent(dirName, false, true, false, subDirs);
// filter the directories
for (uint i=(uint)subDirs.size(); i>0; --i)
{
if (!isExcludedDir(subDirs[i-1]))
dirStack.push_back(subDirs[i-1]);
}
}
}
return 0;
}