Changed: Use CBigFile to manage BNP and CCmdArgs for command-line in bnp_make

This commit is contained in:
kervala 2016-01-23 12:30:01 +01:00
parent 0ff951d94c
commit 3446cb4038

View file

@ -32,6 +32,8 @@
#include "nel/misc/path.h" #include "nel/misc/path.h"
#include "nel/misc/algo.h" #include "nel/misc/algo.h"
#include "nel/misc/common.h" #include "nel/misc/common.h"
#include "nel/misc/big_file.h"
#include "nel/misc/cmd_args.h"
using namespace std; using namespace std;
@ -49,7 +51,7 @@ std::vector<CWildCard> WildCards;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
bool keepFile (const char *fileName) bool keepFile (const std::string &fileName)
{ {
uint i; uint i;
bool ifPresent = false; bool ifPresent = false;
@ -60,13 +62,13 @@ bool keepFile (const char *fileName)
if (WildCards[i].Not) if (WildCards[i].Not)
{ {
// One ifnot condition met and the file is not added // One ifnot condition met and the file is not added
if (testWildCard(file.c_str(), WildCards[i].Expression.c_str())) if (testWildCard(file, WildCards[i].Expression))
return false; return false;
} }
else else
{ {
ifPresent = true; ifPresent = true;
ifTrue |= testWildCard(file.c_str(), WildCards[i].Expression.c_str()); ifTrue |= testWildCard(file, WildCards[i].Expression);
} }
} }
@ -75,199 +77,7 @@ bool keepFile (const char *fileName)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
struct BNPFile NLMISC::CBigFile::BNP gBNPHeader;
{
string Name;
uint32 Size;
uint32 Pos;
};
struct BNPHeader
{
vector<BNPFile> Files;
uint32 OffsetFromBeginning;
// Append the header to the big file
bool append (const string &filename)
{
FILE *f = fopen (filename.c_str(), "ab");
if (f == NULL) return false;
uint32 nNbFile = (uint32)Files.size();
// value to be serialized
uint32 nNbFile2 = nNbFile;
#ifdef NL_BIG_ENDIAN
NLMISC_BSWAP32(nNbFile2);
#endif
if (fwrite (&nNbFile2, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
for (uint32 i = 0; i < nNbFile; ++i)
{
uint8 nStringSize = (uint8)Files[i].Name.size();
if (fwrite (&nStringSize, 1, 1, f) != 1)
{
fclose(f);
return false;
}
if (fwrite (Files[i].Name.c_str(), 1, nStringSize, f) != nStringSize)
{
fclose(f);
return false;
}
uint32 nFileSize = Files[i].Size;
#ifdef NL_BIG_ENDIAN
NLMISC_BSWAP32(nFileSize);
#endif
if (fwrite (&nFileSize, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
uint32 nFilePos = Files[i].Pos;
#ifdef NL_BIG_ENDIAN
NLMISC_BSWAP32(nFilePos);
#endif
if (fwrite (&nFilePos, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
}
uint32 nOffsetFromBeginning = OffsetFromBeginning;
#ifdef NL_BIG_ENDIAN
NLMISC_BSWAP32(nOffsetFromBeginning);
#endif
if (fwrite (&nOffsetFromBeginning, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
fclose (f);
return true;
}
// Read the header from a big file
bool read (const string &filename)
{
FILE *f = fopen (filename.c_str(), "rb");
if (f == NULL) return false;
nlfseek64 (f, 0, SEEK_END);
uint32 nFileSize=CFile::getFileSize (filename);
nlfseek64 (f, nFileSize-sizeof(uint32), SEEK_SET);
uint32 nOffsetFromBeginning;
if (fread (&nOffsetFromBeginning, sizeof(uint32), 1, f) != 1)
{
fclose (f);
return false;
}
#ifdef NL_BIG_ENDIAN
NLMISC_BSWAP32(nOffsetFromBeginning);
#endif
if (nlfseek64 (f, nOffsetFromBeginning, SEEK_SET) != 0)
{
fclose (f);
return false;
}
uint32 nNbFile;
if (fread (&nNbFile, sizeof(uint32), 1, f) != 1)
{
fclose (f);
return false;
}
#ifdef NL_BIG_ENDIAN
NLMISC_BSWAP32(nNbFile);
#endif
for (uint32 i = 0; i < nNbFile; ++i)
{
uint8 nStringSize;
char sName[256];
if (fread (&nStringSize, 1, 1, f) != 1)
{
fclose (f);
return false;
}
if (fread (sName, 1, nStringSize, f) != nStringSize)
{
fclose (f);
return false;
}
sName[nStringSize] = 0;
BNPFile tmpBNPFile;
tmpBNPFile.Name = sName;
if (fread (&tmpBNPFile.Size, sizeof(uint32), 1, f) != 1)
{
fclose (f);
return false;
}
#ifdef NL_BIG_ENDIAN
NLMISC_BSWAP32(tmpBNPFile.Size);
#endif
if (fread (&tmpBNPFile.Pos, sizeof(uint32), 1, f) != 1)
{
fclose (f);
return false;
}
#ifdef NL_BIG_ENDIAN
NLMISC_BSWAP32(tmpBNPFile.Pos);
#endif
Files.push_back (tmpBNPFile);
}
fclose (f);
return true;
}
};
string gDestBNPFile;
BNPHeader gBNPHeader;
// ---------------------------------------------------------------------------
void append(const string &filename1, const string &filename2, uint32 sizeToRead)
{
FILE *f1 = fopen(filename1.c_str(), "ab");
FILE *f2 = fopen(filename2.c_str(), "rb");
if (f1 == NULL) return;
if (f2 == NULL) { fclose(f1); return; }
uint8 *ptr = new uint8[sizeToRead];
if (fread (ptr, sizeToRead, 1, f2) != 1)
nlwarning("%s read error", filename2.c_str());
if (fwrite (ptr, sizeToRead, 1, f1) != 1)
nlwarning("%s write error", filename1.c_str());
delete [] ptr;
fclose(f2);
fclose(f1);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
bool i_comp(const string &s0, const string &s1) bool i_comp(const string &s0, const string &s1)
@ -275,35 +85,24 @@ bool i_comp(const string &s0, const string &s1)
return nlstricmp (CFile::getFilename(s0).c_str(), CFile::getFilename(s1).c_str()) < 0; return nlstricmp (CFile::getFilename(s0).c_str(), CFile::getFilename(s1).c_str()) < 0;
} }
void packSubRecurse () void packSubRecurse(const std::string &srcDirectory)
{ {
vector<string> pathContent; vector<string> pathContent;
string cp = CPath::getCurrentPath(); printf ("Treating directory: %s\n", srcDirectory.c_str());
printf ("Treating directory : %s\n", cp.c_str()); CPath::getPathContent(srcDirectory, true, false, true, pathContent);
CPath::getPathContent(cp, true, false, true, pathContent);
// TODO: remove duplicate files
// Sort filename // Sort filename
sort (pathContent.begin(), pathContent.end(), i_comp); sort (pathContent.begin(), pathContent.end(), i_comp);
uint i; for (uint i=0; i<pathContent.size(); ++i)
for (i=0; i<pathContent.size(); i++)
{ {
if (keepFile (pathContent[i].c_str())) if (keepFile(pathContent[i]))
{ {
BNPFile ftmp; if (gBNPHeader.appendFile(pathContent[i]))
// Check if we can read the source file
FILE *f = fopen (pathContent[i].c_str(), "rb");
if (f != NULL)
{ {
fclose (f);
ftmp.Name = CFile::getFilename(pathContent[i]);
ftmp.Size = CFile::getFileSize(pathContent[i]);
ftmp.Pos = gBNPHeader.OffsetFromBeginning;
gBNPHeader.Files.push_back(ftmp);
gBNPHeader.OffsetFromBeginning += ftmp.Size;
append(gDestBNPFile, pathContent[i].c_str(), ftmp.Size);
printf("adding %s\n", pathContent[i].c_str()); printf("adding %s\n", pathContent[i].c_str());
} }
else else
@ -315,261 +114,115 @@ void packSubRecurse ()
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
void unpack (const string &dirName) int main(int argc, char **argv)
{
FILE *bnp = fopen (gDestBNPFile.c_str(), "rb");
FILE *out;
if (bnp == NULL)
return;
for (uint32 i = 0; i < gBNPHeader.Files.size(); ++i)
{
BNPFile &rBNPFile = gBNPHeader.Files[i];
string filename = dirName + "/" + rBNPFile.Name;
out = fopen (filename.c_str(), "wb");
if (out != NULL)
{
nlfseek64 (bnp, rBNPFile.Pos, SEEK_SET);
uint8 *ptr = new uint8[rBNPFile.Size];
if (fread (ptr, rBNPFile.Size, 1, bnp) != 1)
nlwarning("%s read error", filename.c_str());
if (fwrite (ptr, rBNPFile.Size, 1, out) != 1)
nlwarning("%s write error", filename.c_str());
fclose (out);
delete [] ptr;
}
}
fclose (bnp);
}
// ---------------------------------------------------------------------------
void usage()
{
printf ("USAGE : \n");
printf (" bnp_make /p <directory_name> [<destination_path>] [<destination_filename>] [option] ... [option]\n");
printf (" option : \n");
printf (" -if wildcard : add the file if it matches the wilcard (at least one 'if' conditions must be met for a file to be adding)\n");
printf (" -ifnot wildcard : add the file if it doesn't match the wilcard (all the 'ifnot' conditions must be met for a file to be adding)\n");
printf (" Pack the directory to a bnp file\n");
printf (" bnp_make /u <bnp_file>\n");
printf (" Unpack the bnp file to a directory\n");
printf (" bnp_make /l <bnp_file>\n");
printf (" List the files contained in the bnp file\n");
}
// ---------------------------------------------------------------------------
uint readOptions (int nNbArg, char **ppArgs)
{
uint i;
uint optionCount = 0;
for (i=0; i<(uint)nNbArg; i++)
{
// If ?
if ((strcmp (ppArgs[i], "-if") == 0) && ((i+1)<(uint)nNbArg))
{
CWildCard card;
card.Expression = toLower(string(ppArgs[i+1]));
card.Not = false;
WildCards.push_back (card);
optionCount += 2;
}
// If not ?
if ((strcmp (ppArgs[i], "-ifnot") == 0) && ((i+1)<(uint)nNbArg))
{
CWildCard card;
card.Expression = toLower(string(ppArgs[i+1]));
card.Not = true;
WildCards.push_back (card);
optionCount += 2;
}
}
return optionCount;
}
// ---------------------------------------------------------------------------
int main (int nNbArg, char **ppArgs)
{ {
NLMISC::CApplicationContext myApplicationContext; NLMISC::CApplicationContext myApplicationContext;
if (nNbArg < 3) NLMISC::CCmdArgs args;
args.addArg("p", "pack", "", "Pack the directory to a BNP file");
args.addArg("u", "unpack", "", "Unpack the BNP file to a directory");
args.addArg("l", "list", "", "List the files contained in the BNP file");
args.addArg("o", "output", "destination", "Output directory or file");
args.addArg("i", "if", "wildcard", "Add the file if it matches the wilcard (at least one 'if' conditions must be met for a file to be adding)");
args.addArg("n", "ifnot", "wildcard", "Add the file if it doesn't match the wilcard (all the 'ifnot' conditions must be met for a file to be adding)");
args.addAdditionalArg("input", "Input directory or BNP file depending on command");
if (!args.parse(argc, argv)) return 1;
if (args.haveArg("p"))
{ {
usage(); std::vector<std::string> filters;
return -1;
}
if ((strcmp(ppArgs[1], "/p") == 0) || (strcmp(ppArgs[1], "/P") == 0) || // If ?
(strcmp(ppArgs[1], "-p") == 0) || (strcmp(ppArgs[1], "-P") == 0)) filters = args.getLongArg("if");
{
// Pack a directory
uint count = readOptions (nNbArg, ppArgs);
nNbArg -= count;
// Read options for (uint i = 0; i < filters.size(); ++i)
string sCurDir;
if (nNbArg >= 4)
{ {
// store current path CWildCard card;
sCurDir = CPath::getCurrentPath(); card.Expression = toLower(filters[i]);
card.Not = false;
WildCards.push_back(card);
}
// go to the dest path // If not ?
string sDestDir; filters = args.getLongArg("ifnot");
if (CPath::setCurrentPath(ppArgs[3]))
for (uint i = 0; i < filters.size(); ++i)
{
CWildCard card;
card.Expression = toLower(filters[i]);
card.Not = true;
WildCards.push_back(card);
}
// Pack a directory
std::string srcDirectory = args.getAdditionalArg("input").front();
if (!CFile::isDirectory(srcDirectory) || !CFile::isExists(srcDirectory))
{
nlwarning("Error: %s doesn't exist or is not a directory!", srcDirectory.c_str());
}
// Output directory or filename
if (args.haveArg("o"))
{
gBNPHeader.BigFileName = args.getArg("o").front();
if (CFile::isDirectory(gBNPHeader.BigFileName))
{ {
sDestDir = CPath::getCurrentPath(); gBNPHeader.BigFileName = CPath::standardizePath(gBNPHeader.BigFileName) + CFile::getFilename(srcDirectory);
bool tmp = CPath::setCurrentPath(sCurDir.c_str());
// restore current path, should not failed
nlassert (tmp); // removed in release
// go to the source dir
if (CPath::setCurrentPath(ppArgs[2]))
{
sCurDir = CPath::getCurrentPath();
gDestBNPFile = CPath::standardizePath(sDestDir);
if(nNbArg == 5)
{
gDestBNPFile += ppArgs[4];
// add ext if necessary
if (string(ppArgs[4]).find(".") == string::npos)
gDestBNPFile += string(".bnp");
}
else
{
const char *pos = strrchr (sCurDir.c_str(), '/');
if (pos != NULL)
{
gDestBNPFile += string(pos+1);
}
// get the dest file name
gDestBNPFile += string(".bnp");
}
}
else
{
nlwarning ("ERROR (bnp_make) : can't set current directory to %s", ppArgs[2]);
return -1;
}
}
else
{
nlwarning ("ERROR (bnp_make) : can't set current directory to %s", ppArgs[3]);
return -1;
} }
} }
else else
{ {
if (chdir (ppArgs[2]) == -1) gBNPHeader.BigFileName = CFile::getFilename(srcDirectory);
{
nlwarning ("ERROR (bnp_make) : can't set current directory to %s", ppArgs[2]);
return -1;
}
//getcwd (sCurDir, MAX_PATH);
gDestBNPFile = CPath::getCurrentPath() + string(".bnp");
} }
remove (gDestBNPFile.c_str()); if (CFile::getExtension(gBNPHeader.BigFileName) != "bnp")
gBNPHeader.OffsetFromBeginning = 0; gBNPHeader.BigFileName += ".bnp";
packSubRecurse();
gBNPHeader.append (gDestBNPFile); CFile::deleteFile(gBNPHeader.BigFileName);
return 0;
packSubRecurse(srcDirectory);
return gBNPHeader.appendHeader() ? 0:-1;
} }
if ((strcmp(ppArgs[1], "/u") == 0) || (strcmp(ppArgs[1], "/U") == 0) || if (args.haveArg("u"))
(strcmp(ppArgs[1], "-u") == 0) || (strcmp(ppArgs[1], "-U") == 0))
{ {
string::size_type i; gBNPHeader.BigFileName = args.getAdditionalArg("input").front();
string path;
gDestBNPFile = ppArgs[2];
if ((gDestBNPFile.rfind('/') != string::npos) || (gDestBNPFile.rfind('/') != string::npos))
{
string::size_type pos = gDestBNPFile.rfind('/');
if (pos == string::npos)
pos = gDestBNPFile.rfind('/');
for (i = 0; i <= pos; ++i)
path += gDestBNPFile[i];
string wholeName = gDestBNPFile;
gDestBNPFile = "";
for (; i < wholeName.size(); ++i)
gDestBNPFile += wholeName[i];
if (CPath::setCurrentPath(path.c_str()))
{
path = CPath::getCurrentPath();
}
else
{
nlwarning ("ERROR (bnp_make) : can't set current directory to %s", path.c_str());
return -1;
}
}
if (stricmp (gDestBNPFile.c_str()+gDestBNPFile.size()-4, ".bnp") != 0)
{
gDestBNPFile += ".bnp";
}
string dirName;
for (i = 0; i < gDestBNPFile.size()-4; ++i)
dirName += gDestBNPFile[i];
// Unpack a bnp file
if (!gBNPHeader.read (gDestBNPFile))
return -1;
//mkdir (dirName.c_str()); std::string dirName;
CFile::createDirectory(dirName);
unpack (dirName); // Output directory or filename
if (args.haveArg("o"))
return 0;
}
if ((strcmp(ppArgs[1], "/l") == 0) || (strcmp(ppArgs[1], "/L") == 0) ||
(strcmp(ppArgs[1], "-l") == 0) || (strcmp(ppArgs[1], "-L") == 0))
{
string::size_type i;
string path;
gDestBNPFile = ppArgs[2];
if ((gDestBNPFile.rfind('/') != string::npos) || (gDestBNPFile.rfind('/') != string::npos))
{ {
string::size_type pos = gDestBNPFile.rfind('/'); dirName = args.getArg("o").front();
if (pos == string::npos)
pos = gDestBNPFile.rfind('/');
for (i = 0; i <= pos; ++i)
path += gDestBNPFile[i];
string wholeName = gDestBNPFile;
gDestBNPFile = "";
for (; i < wholeName.size(); ++i)
gDestBNPFile += wholeName[i];
if (CPath::setCurrentPath(path.c_str()))
{
path = CPath::getCurrentPath();
}
else
{
nlwarning ("ERROR (bnp_make) : can't set current directory to %s", path.c_str());
return -1;
}
} }
if (stricmp (gDestBNPFile.c_str()+gDestBNPFile.size()-4, ".bnp") != 0) else
{ {
gDestBNPFile += ".bnp"; dirName = CFile::getFilenameWithoutExtension(gBNPHeader.BigFileName);
} }
string dirName;
for (i = 0; i < gDestBNPFile.size()-4; ++i)
dirName += gDestBNPFile[i];
// Unpack a bnp file // Unpack a bnp file
if (!gBNPHeader.read (gDestBNPFile)) return gBNPHeader.unpack(dirName) ? 0:-1;
return -1; }
for (i = 0; i < gBNPHeader.Files.size(); ++i) if (args.haveArg("l"))
printf ("%s\n", gBNPHeader.Files[i].Name.c_str()); {
gBNPHeader.BigFileName = args.getAdditionalArg("input").front();
// Read header of BNP file
if (!gBNPHeader.readHeader()) return -1;
for (uint i = 0; i < gBNPHeader.SFiles.size(); ++i)
{
printf("%s\n", gBNPHeader.SFiles[i].Name.c_str());
}
return 0; return 0;
} }
usage (); args.displayHelp();
return -1; return -1;
} }