Added: Implemented bnp_manager_plugin add and delete files

--HG--
branch : branch-bnp-manager-plugin
This commit is contained in:
Krolock 2012-01-11 20:54:54 +01:00
parent e61e79eee3
commit ba66f5e070
4 changed files with 306 additions and 19 deletions

View file

@ -33,6 +33,12 @@ using namespace std;
namespace BNPManager namespace BNPManager
{ {
PackedFile::PackedFile()
{
m_size = 0;
m_pos = 0;
}
NLMISC_SAFE_SINGLETON_IMPL(BNPFileHandle); NLMISC_SAFE_SINGLETON_IMPL(BNPFileHandle);
BNPFileHandle::BNPFileHandle() BNPFileHandle::BNPFileHandle()
@ -58,7 +64,7 @@ void BNPFileHandle::releaseInstance()
// *************************************************************************** // ***************************************************************************
bool BNPFileHandle::unpack(const string &dirName, const vector<string>& fileList) bool BNPFileHandle::unpack(const string &dirName, const vector<string>& fileList)
{ {
FILE *bnp = fopen (m_activeBNPFile.c_str(), "rb"); FILE *bnp = fopen (m_openedBNPFile.c_str(), "rb");
FILE *out; FILE *out;
if (bnp == NULL) if (bnp == NULL)
return false; return false;
@ -97,13 +103,13 @@ bool BNPFileHandle::unpack(const string &dirName, const vector<string>& fileList
} }
// *************************************************************************** // ***************************************************************************
// Read the header from a big file // Read the header from a big file
bool BNPFileHandle::readHeader(const std::string &filename) bool BNPFileHandle::readHeader(const std::string &filePath)
{ {
m_packedFiles.clear(); m_packedFiles.clear();
m_activeBNPFile = filename; m_openedBNPFile = filePath;
FILE *f = fopen (filename.c_str(), "rb"); FILE *f = fopen (filePath.c_str(), "rb");
if (f == NULL) if (f == NULL)
{ {
nlwarning("Could not open file!"); nlwarning("Could not open file!");
@ -111,7 +117,7 @@ bool BNPFileHandle::readHeader(const std::string &filename)
} }
nlfseek64 (f, 0, SEEK_END); nlfseek64 (f, 0, SEEK_END);
uint32 nFileSize=CFile::getFileSize (filename ); uint32 nFileSize=CFile::getFileSize (filePath );
nlfseek64 (f, nFileSize-sizeof(uint32), SEEK_SET); nlfseek64 (f, nFileSize-sizeof(uint32), SEEK_SET);
uint32 nOffsetFromBegining; uint32 nOffsetFromBegining;
@ -162,6 +168,7 @@ bool BNPFileHandle::readHeader(const std::string &filename)
sName[nStringSize] = 0; sName[nStringSize] = 0;
PackedFile tmpPackedFile; PackedFile tmpPackedFile;
tmpPackedFile.m_name = sName; tmpPackedFile.m_name = sName;
tmpPackedFile.m_path = m_openedBNPFile;
if (fread (&tmpPackedFile.m_size, sizeof(uint32), 1, f) != 1) if (fread (&tmpPackedFile.m_size, sizeof(uint32), 1, f) != 1)
{ {
nlwarning("Error reading packed file size!"); nlwarning("Error reading packed file size!");
@ -196,9 +203,186 @@ void BNPFileHandle::list(TPackedFilesList& FileList)
tmpFile.m_name = it->m_name; tmpFile.m_name = it->m_name;
tmpFile.m_pos = it->m_pos; tmpFile.m_pos = it->m_pos;
tmpFile.m_size = it->m_size; tmpFile.m_size = it->m_size;
tmpFile.m_path = it->m_path;
FileList.push_back(tmpFile); FileList.push_back(tmpFile);
it++; it++;
} }
} }
// *************************************************************************** // ***************************************************************************
bool BNPFileHandle::writeHeader( const std::string &filePath, uint32 offset )
{
FILE *f = fopen (filePath.c_str(), "ab");
if (f == NULL) return false;
uint32 nNbFile = (uint32)m_packedFiles.size();
if (fwrite (&nNbFile, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
for (uint32 i = 0; i < nNbFile; ++i)
{
uint8 nStringSize = (uint8)m_packedFiles[i].m_name.size();
if (fwrite (&nStringSize, 1, 1, f) != 1)
{
fclose(f);
return false;
}
if (fwrite (m_packedFiles[i].m_name.c_str(), 1, nStringSize, f) != nStringSize)
{
fclose(f);
return false;
}
if (fwrite (&m_packedFiles[i].m_size, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fwrite (&m_packedFiles[i].m_pos, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
}
if (fwrite (&offset, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
fclose (f);
return true;
}
// ***************************************************************************
void BNPFileHandle::fileNames(std::vector<std::string> &fileNames)
{
TPackedFilesList::iterator it = m_packedFiles.begin();
while (it != m_packedFiles.end() )
{
fileNames.push_back(it->m_name);
it++;
}
}
// ***************************************************************************
void BNPFileHandle::addFiles( const vector<string> &filePathes)
{
uint32 OffsetFromBegining = 0;
// create packed files and add them to the private vector
vector<string>::const_iterator it_vec = filePathes.begin();
while (it_vec != filePathes.end() )
{
PackedFile tmpFile;
tmpFile.m_name = CFile::getFilename (*it_vec);
// Leave position to 0 and set the value during the new bnp file is creating
// We need the position only for the header at the end
tmpFile.m_pos = 0;
tmpFile.m_size = CFile::getFileSize(*it_vec);
tmpFile.m_path = *it_vec;
m_packedFiles.push_back( tmpFile );
it_vec++;
}
// sort packed files alphabetic
std::sort ( m_packedFiles.begin(), m_packedFiles.end(), compare );
// create a new temporary bnp file with extension *.tmp
TPackedFilesList::iterator it_packed = m_packedFiles.begin();
while (it_packed != m_packedFiles.end() )
{
append(m_openedBNPFile + ".tmp", *it_packed);
// Set now the new offset for the new header
it_packed->m_pos = OffsetFromBegining;
OffsetFromBegining += it_packed->m_size;
it_packed++;
}
writeHeader(m_openedBNPFile + ".tmp", OffsetFromBegining);
CFile::deleteFile( m_openedBNPFile );
string src = m_openedBNPFile + ".tmp";
CFile::moveFile( m_openedBNPFile.c_str(), src.c_str() );
}
// ***************************************************************************
void BNPFileHandle::deleteFiles( const vector<string>& fileNames)
{
vector<string>::const_iterator it_vec;
TPackedFilesList::iterator it_packed;
uint32 OffsetFromBegining = 0;
string tmpFile = m_openedBNPFile + ".tmp";
// create a new temporary bnp file with extension *.tmp
it_packed = m_packedFiles.begin();
while (it_packed != m_packedFiles.end() )
{
// check each packed file if it should be deleted
it_vec = find (fileNames.begin(), fileNames.end(), it_packed->m_name );
if ( it_vec != fileNames.end() )
{
nlinfo("Deleting file %s.", it_packed->m_name.c_str() );
it_packed = m_packedFiles.erase(it_packed);
}
else
{
append(tmpFile, *it_packed);
// Set now the new offset for the new header
it_packed->m_pos = OffsetFromBegining;
OffsetFromBegining += it_packed->m_size;
it_packed++;
}
}
nldebug("Writing header...");
writeHeader(tmpFile, OffsetFromBegining);
CFile::deleteFile( m_openedBNPFile );
string src = m_openedBNPFile + ".tmp";
CFile::moveFile( m_openedBNPFile.c_str(), src.c_str() );
}
// ***************************************************************************
void BNPFileHandle::append(const string &destination, const PackedFile &source)
{
// check if the file exists and create one if not
if ( !CFile::fileExists(destination) )
CFile::createEmptyFile( destination );
FILE *bnpfile = fopen(destination.c_str(), "ab");
FILE *packedfile = fopen(source.m_path.c_str(), "rb");
if (bnpfile == NULL) return;
if (packedfile == NULL) { fclose(bnpfile); return; }
uint8 *ptr = new uint8[source.m_size];
// check if the source is a bnp file.
if ( nlstricmp( CFile::getExtension(source.m_path), "bnp" ) == 0 )
{
// Jump to the file position inside the bnp
nlfseek64(packedfile, source.m_pos, SEEK_SET);
}
// Read the source
if (fread (ptr, source.m_size, 1, packedfile) != 1)
nlwarning("%s read error", source.m_path.c_str());
// Append the data to the destination
if (fwrite (ptr, source.m_size, 1, bnpfile) != 1)
nlwarning("%s write error", destination.c_str());
delete [] ptr;
fclose(packedfile);
fclose(bnpfile);
}
// ***************************************************************************
bool BNPFileHandle::compare(const PackedFile &left, const PackedFile &right)
{
return nlstricmp (left.m_name.c_str(), right.m_name.c_str()) < 0;
}
} // namespace BNPManager } // namespace BNPManager

View file

@ -32,9 +32,11 @@ namespace BNPManager
struct PackedFile struct PackedFile
{ {
PackedFile();
std::string m_name; std::string m_name;
uint32 m_size; uint32 m_size;
uint32 m_pos; uint32 m_pos;
std::string m_path;
}; };
typedef std::vector<PackedFile> TPackedFilesList; typedef std::vector<PackedFile> TPackedFilesList;
@ -64,7 +66,9 @@ public:
* Read the header from the bnp file and create a filelist * Read the header from the bnp file and create a filelist
* \param filename (consisting the whole path) * \param filename (consisting the whole path)
*/ */
bool readHeader (const std::string &filename); bool readHeader (const std::string &filePath);
bool writeHeader (const std::string &filePath, uint32 offset);
/** /**
* Append the header to a created bnp file * Append the header to a created bnp file
@ -73,11 +77,29 @@ public:
void appendHeader (const std::string &filename) {}; void appendHeader (const std::string &filename) {};
/** /**
* Create a list of all packed files inside the bnp file * Create a vector of all packed files inside the bnp file
* \param reference to the list, which has to be filled * \param reference to the vector, which has to be filled
*/ */
void list (TPackedFilesList& FileList); void list (TPackedFilesList& FileList);
/**
* Create a vector of all file names inside the bnp file
* \param reference to the vector, which has to be filled
*/
void fileNames( std::vector<std::string>& fileNames );
/**
* Add files to the current aktive bnp file
* \param vector of file pathes to add
*/
void addFiles( const std::vector<std::string>& filePathes );
/**
* Delete files from the current aktive bnp file
* \param vector of files names
*/
void deleteFiles (const std::vector<std::string>& fileNames);
/** /**
* Unpack the selected packed files into user defined dir * Unpack the selected packed files into user defined dir
* \param directory path, where the files should be unpacked * \param directory path, where the files should be unpacked
@ -85,19 +107,33 @@ public:
*/ */
bool unpack (const std::string &dirName, const std::vector<std::string>& fileList); bool unpack (const std::string &dirName, const std::vector<std::string>& fileList);
/**
* Compares two filenames
* \param left: left packed file
* \param right: right packed file
* \return: TODO
*/
static bool compare(const PackedFile &left, const PackedFile &right);
private: private:
/**
* Append one file to an existing bnp file
* \param destination: the active bnp file to append the file
* \param source: the source file to pack
*/
void append( const std::string& destination, const PackedFile& source );
TPackedFilesList m_packedFiles; TPackedFilesList m_packedFiles;
// currently opened and displayed bnp file // currently opened and displayed bnp file
std::string m_activeBNPFile; std::string m_openedBNPFile;
// offset where the header of the bnp file begins // offset where the header of the bnp file begins
uint32 m_offsetFromBeginning; uint32 m_offsetFromBeginning;
}; };
} }
#endif #endif

View file

@ -28,6 +28,7 @@
// NeL includes // NeL includes
#include <nel/misc/debug.h> #include <nel/misc/debug.h>
#include <nel/misc/path.h>
// Qt includes // Qt includes
#include <QDebug> #include <QDebug>
@ -153,9 +154,11 @@ void BNPManagerWindow::open()
fileName = QFileDialog::getOpenFileName(this, fileName = QFileDialog::getOpenFileName(this,
tr("Open BNP file"), tr(m_DataPath.toStdString().c_str()), tr("BNP Files (*.bnp)")); tr("Open BNP file"), tr(m_DataPath.toStdString().c_str()), tr("BNP Files (*.bnp)"));
// check if there is a filename // Check if filename is empty
if (fileName.isNull()) if (fileName.isNull())
return; return;
m_openedBNPFile = fileName;
loadFile(fileName); loadFile(fileName);
} }
// *************************************************************************** // ***************************************************************************
@ -166,12 +169,73 @@ void BNPManagerWindow::close()
// *************************************************************************** // ***************************************************************************
void BNPManagerWindow::addFiles() void BNPManagerWindow::addFiles()
{ {
//TODO // reference to the BNPFileHandle singletone instance
BNPFileHandle& myBNPFileHandle = BNPFileHandle::getInstance();
// vector of all current packed filenames
vector<string> currentFiles;
// vector of files to add
vector<string> addFiles;
// open a file dialog and to add files
QStringList FileList;
FileList = QFileDialog::getOpenFileNames(this,tr("Add Files..."),
QDir::currentPath(), tr("All Files (*.*)") );
// get all current filenames from the opened bnp file
myBNPFileHandle.fileNames(currentFiles);
QStringList::iterator it_list = FileList.begin();
while (it_list != FileList.end() )
{
string fileName = CFile::getFilename (it_list->toStdString() );
if ( std::find(currentFiles.begin(), currentFiles.end(), fileName ) != currentFiles.end() )
{
// Ask the user if he wants to override the existing file
// atm only warn the user and do not override
QMessageBox::warning(this, tr("BNP Manager"),
tr("File is already in the list!"),
QMessageBox::Ok,
QMessageBox::Ok);
}
else
{
addFiles.push_back( it_list->toStdString() );
// log it
nlinfo("Add file %s", fileName.c_str() );
}
it_list++;
}
if ( !addFiles.empty() )
{
myBNPFileHandle.addFiles( addFiles );
}
loadFile(m_openedBNPFile);
} }
// *************************************************************************** // ***************************************************************************
void BNPManagerWindow::deleteFiles() void BNPManagerWindow::deleteFiles()
{ {
//TODO QFileDialog filedialog(this);
BNPFileHandle& myBNPFileHandle = BNPFileHandle::getInstance();
vector<string> selectedRows;
m_BnpFileListDialog->getSelections(selectedRows);
// Check if files were selected. If not, inform the user.
if (selectedRows.empty())
{
QMessageBox::information(this, tr("BNP Manager"),
tr("No files selected!"),
QMessageBox::Ok,
QMessageBox::Ok);
return;
}
myBNPFileHandle.deleteFiles(selectedRows);
loadFile(m_openedBNPFile);
} }
// *************************************************************************** // ***************************************************************************
void BNPManagerWindow::unpackFiles() void BNPManagerWindow::unpackFiles()
@ -188,7 +252,7 @@ void BNPManagerWindow::unpackFiles()
if (selectedrows.empty()) if (selectedrows.empty())
{ {
QMessageBox::information(this, tr("BNP Manager"), QMessageBox::information(this, tr("BNP Manager"),
tr("No files were selected to unpack!"), tr("No files selected!"),
QMessageBox::Ok, QMessageBox::Ok,
QMessageBox::Ok); QMessageBox::Ok);
return; return;
@ -199,6 +263,10 @@ void BNPManagerWindow::unpackFiles()
QFileDialog::ShowDirsOnly QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks); | QFileDialog::DontResolveSymlinks);
// If anything went wrong or the user pressed "cancel"
if ( dir.isEmpty() )
return;
if (myBNPFileHandle.unpack(dir.toStdString(),selectedrows)) if (myBNPFileHandle.unpack(dir.toStdString(),selectedrows))
{ {
QMessageBox::information(this, tr("BNP Manager"), QMessageBox::information(this, tr("BNP Manager"),

View file

@ -136,8 +136,7 @@ private:
BnpFileListDialog *m_BnpFileListDialog; BnpFileListDialog *m_BnpFileListDialog;
QString m_DataPath; QString m_DataPath;
QString m_openedBNPFile;
BNPFileHandle *m_BNPFileHandle;
}; /* class BNPManagerWindow */ }; /* class BNPManagerWindow */