Linux multi-monitor fullscreen support
[ryzomcore.git] / studio / src / plugins / bnp_manager / bnp_file.cpp
blobb56fe1c2ba30812db40a72e42cc120cf5769fc58
1 // Object Viewer Qt - BNP Manager Plugin - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2011 Roland WINKLMEIER <roland.m.winklmeier@gmail.com>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // Project includes
18 #include "bnp_file.h"
20 // Nel includes
21 #include <nel/misc/debug.h>
22 #include <nel/misc/file.h>
23 #include <nel/misc/path.h>
24 #include <nel/misc/algo.h>
25 #include <nel/misc/common.h>
27 // Qt includes
29 using namespace NLMISC;
30 using namespace std;
33 namespace BNPManager
36 PackedFile::PackedFile()
38 m_size = 0;
39 m_pos = 0;
42 NLMISC_SAFE_SINGLETON_IMPL(BNPFileHandle);
44 BNPFileHandle::BNPFileHandle()
46 m_offsetFromBeginning = 0;
48 // ***************************************************************************
49 BNPFileHandle::~BNPFileHandle()
51 // Erase the list
52 m_packedFiles.clear();
54 // ***************************************************************************
55 void BNPFileHandle::releaseInstance()
57 if (_Instance)
59 NLMISC::INelContext::getInstance().releaseSingletonPointer("BNPFileHandle", _Instance);
60 delete _Instance;
61 _Instance = NULL;
64 // ***************************************************************************
65 void BNPFileHandle::createFile(string filePath)
67 // Only set the filepath. Header will be created after files have been added
68 m_openedBNPFile = filePath;
69 m_packedFiles.clear();
71 nlinfo("Created file %s.", filePath.c_str() );
73 // ***************************************************************************
74 bool BNPFileHandle::unpack(const string &dirName, const vector<string>& fileList)
76 CIFile bnp;
77 bnp.open(m_openedBNPFile);
79 TPackedFilesList::iterator it_files = m_packedFiles.begin();
81 for (it_files; it_files != m_packedFiles.end(); it_files++)
83 // Check if the file should be unpacked or not
84 if (find(fileList.begin(), fileList.end(), it_files->m_name) != fileList.end())
86 string filename = dirName + "/" + it_files->m_name;
88 COFile out;
89 if ( out.open(filename) )
91 bnp.seek(it_files->m_pos, IStream::begin);
92 uint8 *ptr = new uint8[it_files->m_size];
93 bnp.serialBuffer(ptr,it_files->m_size);
94 out.serialBuffer(ptr,it_files->m_size);
95 delete [] ptr;
97 out.close();
101 bnp.close();
102 return true;
104 // ***************************************************************************
105 // Read the header from a big file
106 bool BNPFileHandle::readHeader(const std::string &filePath)
108 m_packedFiles.clear();
110 m_openedBNPFile = filePath;
112 CIFile bnp;
113 bnp.open (filePath);
115 bnp.seek(0, IStream::end);
116 uint32 nFileSize = bnp.getFileSize();
117 bnp.seek(nFileSize-sizeof(uint32), IStream::begin);
119 uint32 nOffsetFromBeginning;
121 bnp.serial(nOffsetFromBeginning);
123 if ( !bnp.seek (nOffsetFromBeginning, IStream::begin) )
125 nlwarning("Could not read offset from beginning");
126 bnp.close();
127 return false;
130 uint32 nNbFile;
131 bnp.serial(nNbFile);
133 for (uint32 i = 0; i < nNbFile; ++i)
135 uint8 nStringSize;
136 char sName[256];
138 bnp.serial(nStringSize);
139 bnp.serialBuffer( (uint8*)sName, nStringSize);
140 sName[nStringSize] = 0;
142 PackedFile tmpPackedFile;
143 tmpPackedFile.m_name = sName;
144 tmpPackedFile.m_path = m_openedBNPFile;
146 bnp.serial(tmpPackedFile.m_size);
147 bnp.serial(tmpPackedFile.m_pos);
149 m_packedFiles.push_back (tmpPackedFile);
152 bnp.close();
153 return true;
155 // ***************************************************************************
156 void BNPFileHandle::list(TPackedFilesList& FileList)
158 PackedFile tmpFile;
159 TPackedFilesList::iterator it = m_packedFiles.begin();
160 while (it != m_packedFiles.end() )
162 tmpFile.m_name = it->m_name;
163 tmpFile.m_pos = it->m_pos;
164 tmpFile.m_size = it->m_size;
165 tmpFile.m_path = it->m_path;
166 FileList.push_back(tmpFile);
167 it++;
170 // ***************************************************************************
171 bool BNPFileHandle::writeHeader( const std::string &filePath, uint32 offset )
173 COFile bnp;
174 bnp.open(filePath, true);
175 if ( !bnp.isOpen() )
176 return false;
178 uint32 nNbFile = (uint32)m_packedFiles.size();
179 bnp.serial(nNbFile);
181 for (uint32 i = 0; i < nNbFile; ++i)
183 uint8 nStringSize = (uint8)m_packedFiles[i].m_name.size();
184 bnp.serial( nStringSize );
185 bnp.serialBuffer( (uint8*)m_packedFiles[i].m_name.c_str(), nStringSize );
186 bnp.serial(m_packedFiles[i].m_size);
187 bnp.serial(m_packedFiles[i].m_pos);
190 bnp.serial(offset);
192 bnp.close();
194 return true;
196 // ***************************************************************************
197 void BNPFileHandle::fileNames(std::vector<std::string> &fileNames)
199 TPackedFilesList::iterator it = m_packedFiles.begin();
200 while (it != m_packedFiles.end() )
202 fileNames.push_back(it->m_name);
203 it++;
206 // ***************************************************************************
207 void BNPFileHandle::addFiles( const vector<string> &filePathes)
209 uint32 OffsetFromBeginning = 0;
211 // create packed files and add them to the private vector
212 vector<string>::const_iterator it_vec = filePathes.begin();
213 while (it_vec != filePathes.end() )
215 PackedFile tmpFile;
216 tmpFile.m_name = CFile::getFilename (*it_vec);
217 // Leave position to 0 and set the value during the new bnp file is creating
218 // We need the position only for the header at the end
219 tmpFile.m_pos = 0;
220 tmpFile.m_size = CFile::getFileSize(*it_vec);
221 tmpFile.m_path = *it_vec;
222 m_packedFiles.push_back( tmpFile );
224 it_vec++;
227 // sort packed files alphabetic
228 std::sort ( m_packedFiles.begin(), m_packedFiles.end(), compare );
230 // create a new temporary bnp file with extension *.tmp
231 TPackedFilesList::iterator it_packed = m_packedFiles.begin();
232 while (it_packed != m_packedFiles.end() )
234 append(m_openedBNPFile + ".tmp", *it_packed);
235 // Set now the new offset for the new header
236 it_packed->m_pos = OffsetFromBeginning;
237 OffsetFromBeginning += it_packed->m_size;
239 it_packed++;
242 writeHeader(m_openedBNPFile + ".tmp", OffsetFromBeginning);
244 // Delete any previous existing file
245 if (CFile::fileExists( m_openedBNPFile ))
246 CFile::deleteFile( m_openedBNPFile );
247 string src = m_openedBNPFile + ".tmp";
248 CFile::moveFile(m_openedBNPFile, src);
250 // ***************************************************************************
251 void BNPFileHandle::deleteFiles( const vector<string>& fileNames)
253 vector<string>::const_iterator it_vec;
254 TPackedFilesList::iterator it_packed;
255 uint32 OffsetFromBeginning = 0;
256 string tmpFile = m_openedBNPFile + ".tmp";
258 // create a new temporary bnp file with extension *.tmp
259 it_packed = m_packedFiles.begin();
260 while (it_packed != m_packedFiles.end() )
262 // check each packed file if it should be deleted
263 it_vec = find (fileNames.begin(), fileNames.end(), it_packed->m_name );
264 if ( it_vec != fileNames.end() )
266 nlinfo("Deleting file %s.", it_packed->m_name.c_str() );
267 it_packed = m_packedFiles.erase(it_packed);
269 else
271 append(tmpFile, *it_packed);
272 // Set now the new offset for the new header
273 it_packed->m_pos = OffsetFromBeginning;
274 OffsetFromBeginning += it_packed->m_size;
276 it_packed++;
280 writeHeader(tmpFile, OffsetFromBeginning);
282 CFile::deleteFile( m_openedBNPFile );
283 string src = m_openedBNPFile + ".tmp";
284 CFile::moveFile(m_openedBNPFile, src);
286 // ***************************************************************************
287 void BNPFileHandle::append(const string &destination, const PackedFile &source)
289 // check if the file exists and create one if not
290 if ( !CFile::fileExists(destination) )
291 CFile::createEmptyFile( destination );
293 COFile bnpfile;
294 CIFile packedfile;
295 bnpfile.open(destination, true);
296 packedfile.open(source.m_path);
297 if ( !bnpfile.isOpen() ) return;
300 uint8 *ptr = new uint8[source.m_size];
302 // check if the source is a bnp file.
303 if ( nlstricmp( CFile::getExtension(source.m_path), "bnp" ) == 0 )
305 // Jump to the file position inside the bnp
306 packedfile.seek(source.m_pos, IStream::begin);
308 // Read the source
309 packedfile.serialBuffer(ptr, source.m_size);
311 // Append the data to the destination
312 bnpfile.serialBuffer(ptr, source.m_size);
314 delete [] ptr;
316 packedfile.close();
317 bnpfile.close();
319 // ***************************************************************************
320 bool BNPFileHandle::compare(const PackedFile &left, const PackedFile &right)
322 return nlstricmp (left.m_name.c_str(), right.m_name.c_str()) < 0;
324 } // namespace BNPManager