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>
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.
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/>.
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>
29 using namespace NLMISC
;
36 PackedFile::PackedFile()
42 NLMISC_SAFE_SINGLETON_IMPL(BNPFileHandle
);
44 BNPFileHandle::BNPFileHandle()
46 m_offsetFromBeginning
= 0;
48 // ***************************************************************************
49 BNPFileHandle::~BNPFileHandle()
52 m_packedFiles
.clear();
54 // ***************************************************************************
55 void BNPFileHandle::releaseInstance()
59 NLMISC::INelContext::getInstance().releaseSingletonPointer("BNPFileHandle", _Instance
);
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
)
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
;
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
);
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
;
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");
133 for (uint32 i
= 0; i
< nNbFile
; ++i
)
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
);
155 // ***************************************************************************
156 void BNPFileHandle::list(TPackedFilesList
& FileList
)
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
);
170 // ***************************************************************************
171 bool BNPFileHandle::writeHeader( const std::string
&filePath
, uint32 offset
)
174 bnp
.open(filePath
, true);
178 uint32 nNbFile
= (uint32
)m_packedFiles
.size();
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
);
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
);
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() )
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
220 tmpFile
.m_size
= CFile::getFileSize(*it_vec
);
221 tmpFile
.m_path
= *it_vec
;
222 m_packedFiles
.push_back( tmpFile
);
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
;
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
);
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
;
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
);
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
);
309 packedfile
.serialBuffer(ptr
, source
.m_size
);
311 // Append the data to the destination
312 bnpfile
.serialBuffer(ptr
, source
.m_size
);
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