Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / pd_lib / db_reference_file.cpp
blobd80c66d885a6ca6352748467453d19a34e31c589
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "db_reference_file.h"
21 #include "pds_table_buffer.h"
23 #include <nel/misc/debug.h>
25 using namespace NLMISC;
26 using namespace std;
29 * Constructor
31 CDBReferenceFile::CDBReferenceFile()
33 clear();
37 * Destructor
39 CDBReferenceFile::~CDBReferenceFile()
41 clear();
46 * Clear initial setup
48 void CDBReferenceFile::clear()
50 _Init = false;
52 close();
54 _Name.clear();
55 _Path.clear();
57 _Header.BaseIndex = 0;
58 _Header.EndIndex = 0;
59 _Header.OverIndex = 0;
60 _Header.RowSize = 0;
61 _Header.FullRowSize = 0;
62 _Header.Timestamp = 0;
64 _Mode = Read;
66 _DataStart = 0;
70 * close file
72 void CDBReferenceFile::close()
74 if (_File != NULL)
76 PDS_LOG_DEBUG(1)("CDBReferenceFile::clear(): closing file '%s%s' in %s mode", _Path.c_str(), _Name.c_str(), (_Mode == Read ? "Read" : "Update"));
78 // in update mode, postwrite to validate file
79 if (_Mode == Update)
81 postwrite();
85 CMixedStreamFile::close();
90 * Setup file name and path
92 void CDBReferenceFile::setup(const string& name, const string& path, uint32 baseIndex, uint32 overIndex, uint32 rowSize)
94 clear();
96 uint32 tableId;
97 uint32 refFile;
98 nlassert(isRefFile(name, tableId, refFile));
100 _Name = name;
101 _Path = path;
103 _Header.BaseIndex = baseIndex;
104 _Header.EndIndex = baseIndex;
105 _Header.OverIndex = overIndex;
106 _Header.RowSize = rowSize;
107 _Header.FullRowSize = rowSize + getRowHeaderSize();
108 _Header.Timestamp = CTableBuffer::getCommonStamp(); //CStampHandler::getStamp();
110 _Init = true;
116 * Builds an empty file
118 bool CDBReferenceFile::buildEmptyRef()
120 string filepath = _Path+_Name;
122 if (_File != NULL)
124 nlwarning("CDBReferenceFile::buildEmptyRef(): failed, file '%s' already open", filepath.c_str());
125 return false;
128 // check file doesn't exist yet
129 if (CFile::fileExists(filepath))
131 nlwarning("CDBReferenceFile::buildEmptyRef(): failed, file '%s' already exists", filepath.c_str());
132 return false;
135 if (!prewrite())
137 nlwarning("CDBReferenceFile::buildEmptyRef(): failed, cannot prewrite file '%s'", filepath.c_str());
138 close();
139 return false;
142 close();
144 return true;
150 * Prewrite reference file.
151 * At least, read file header to known the base and index index in file
153 bool CDBReferenceFile::prewrite(bool failIfNotExist)
155 // check file already open
156 if (_File != NULL)
157 return true;
159 string filepath = _Path+_Name;
161 // not?
162 // check file exists
163 if (!CFile::fileExists(filepath))
165 if (failIfNotExist)
167 nlwarning("CDBReferenceFile::prewrite(): failed, file '%s' does not exist", filepath.c_str());
168 return false;
171 // open file
172 if (!open(filepath.c_str(), "wb"))
174 nlwarning("CDBReferenceFile::prewrite(): failed, cannot open file '%s' for write", filepath.c_str());
175 return false;
178 // write header, set to output mode
179 setInOut(false);
181 else
183 // open file
184 if (!open(filepath.c_str(), "r+b"))
186 nlwarning("CDBReferenceFile::prewrite(): failed, cannot open file '%s' for read", filepath.c_str());
187 return false;
190 if (fseek(_File, 0, SEEK_SET) != 0)
192 nlwarning("CDBReferenceFile::prewrite(): failed, cannot seek start of '%s' to read header", filepath.c_str());
193 return false;
196 // read header, set to input mode
197 setInOut(true);
200 // serial header
203 if (!serialHeader())
205 nlwarning("CDBReferenceFile::prewrite(): failed, cannot read file '%s' header", filepath.c_str());
206 return false;
209 catch (const Exception& e)
211 nlwarning("CDBReferenceFile::prewrite(): failed, cannot read file '%s' header, exception '%s'", filepath.c_str(), e.what());
212 return false;
215 // write data, set to output mode
216 setInOut(false);
218 _Mode = Update;
221 PDS_LOG_DEBUG(1)("CDBReferenceFile::prewrite(): opened file '%s' in Update mode", filepath.c_str());
223 return true;
227 * Postwrite reference file
228 * Mark file as valid, close file, flush anything still alive...
230 bool CDBReferenceFile::postwrite()
232 if (_File == NULL)
233 return true;
235 string filepath = _Path+_Name;
237 if (fseek(_File, 0, SEEK_SET) != 0)
239 nlwarning("CDBReferenceFile::postwrite(): failed, cannot seek start of '%s' to read header", filepath.c_str());
240 return false;
243 // serial header
246 if (!serialHeader())
248 nlwarning("CDBReferenceFile::postwrite(): failed, cannot read file '%s' header", filepath.c_str());
249 return false;
252 catch (const Exception& e)
254 nlwarning("CDBReferenceFile::postwrite(): failed, cannot read file '%s' header, exception '%s'", filepath.c_str(), e.what());
255 return false;
258 return true;
263 * Update Start/End Delta Ids
265 bool CDBReferenceFile::updateDeltaIds(uint32 startId, uint32 endId)
267 if (_Header.StartDeltaId == 0 && _Header.EndDeltaId == 0)
269 _Header.StartDeltaId = startId;
270 _Header.EndDeltaId = endId;
271 return true;
274 if (_Header.EndDeltaId != startId && _Header.EndDeltaId != startId-1)
276 string filepath = _Path+_Name;
277 nlwarning("CDBReferenceFile::updateDeltaIds(): non consecutive delta ids, file '%s' end=%d, update start=%d", filepath.c_str(), _Header.EndDeltaId, startId);
278 return false;
281 _Header.EndDeltaId = endId;
282 return true;
287 * Get Start/End Delta Ids
289 void CDBReferenceFile::getUpdateDeltaIds(uint32& startId, uint32& endId)
291 startId = _Header.StartDeltaId;
292 endId = _Header.EndDeltaId;
297 * Update a row in the reference file
298 * \param index is the absolute row index to update, not relative to file base index
299 * \param data is the data buffer to store in file
301 bool CDBReferenceFile::update(uint32 index, const uint8* rowdata)
303 string filepath = _Path+_Name;
305 if (!prewrite())
307 nlwarning("CDBReferenceFile::update(): failed, failed to prewrite '%s'", filepath.c_str());
308 return false;
311 if (_Mode != Update)
313 nlwarning("CDBReferenceFile::update(): failed, file '%s' not opened in Update mode", filepath.c_str());
314 return false;
317 // check row belongs to file (not over OverIndex)
318 if (index >= _Header.OverIndex)
320 nlwarning("CDBReferenceFile::update(): failed, index '%d' is over file '%s' limit '%s'", index, filepath.c_str(), _Header.OverIndex);
321 return false;
324 // check row is not beyong physical file data
325 if (index >= _Header.EndIndex)
327 // not?
328 // increase file size by filling blank, fill row indices where needed)
330 // seek to end
331 if (fseek(_File, getSeekPos(_Header.EndIndex), SEEK_SET) != 0)
333 nlwarning("CDBReferenceFile::update(): failed, can't seek to end in file '%s'", filepath.c_str());
334 return false;
337 // allocate blank buffer
338 uint8* tempRowBuffer = new uint8[_Header.FullRowSize];
339 memset(tempRowBuffer, 0, _Header.FullRowSize);
341 // dump empty rows till we get to end index
342 while (_Header.EndIndex <= index)
344 // setup row index
345 *(uint32*)tempRowBuffer = index;
346 if (!writeBuffer(tempRowBuffer, _Header.FullRowSize))
348 nlwarning("CDBReferenceFile::update(): failed, can't increase file '%s' size", filepath.c_str());
349 delete[] tempRowBuffer;
350 return false;
353 ++_Header.EndIndex;
356 delete[] tempRowBuffer;
359 // seek to row in file
360 if (fseek(_File, getSeekPos(index)+getRowHeaderSize(), SEEK_SET) != 0)
362 nlwarning("CDBReferenceFile::update(): failed, can't seek to index '%d' data in file '%s'", index, filepath.c_str());
363 return false;
366 // write data
367 if (!writeBuffer(rowdata, _Header.RowSize))
369 nlwarning("CDBReferenceFile::update(): failed, can't write index '%d' data in file '%s'", index, filepath.c_str());
370 return false;
373 return true;
378 * Preload reference file.
379 * At least, read file header to known the base and index index in file
381 bool CDBReferenceFile::preload()
383 // check file already open
384 if (_File != NULL)
385 return true;
387 // force read mode
388 _Mode = Read;
390 string filepath = _Path+_Name;
392 // file doesn't exist, do nothing
393 if (!CFile::fileExists(filepath))
394 return true;
396 // open file
397 if (!open(filepath.c_str(), "rb"))
399 nlwarning("CDBReferenceFile::preload(): failed, cannot open file '%s'", filepath.c_str());
400 return false;
404 PDS_LOG_DEBUG(1)("CDBReferenceFile::preload(): opened file '%s' in Read mode", filepath.c_str());
406 setInOut(true);
408 // serial header
411 if (!serialHeader())
413 nlwarning("CDBReferenceFile::preload(): failed, cannot read file '%s' header", filepath.c_str());
414 return false;
417 catch (const Exception& e)
419 nlwarning("CDBReferenceFile::preload(): failed, cannot read file '%s' header, exception '%s'", filepath.c_str(), e.what());
420 return false;
423 return true;
427 * Read a row in the reference file
428 * \param index is the absolute row index to read, not relative to file base index
429 * \param data is the data buffer to store data read from file
431 bool CDBReferenceFile::read(uint32 index, uint8* rowdata)
433 string filepath = _Path+_Name;
435 // preload will fail only if file exists and cannot be read
436 // preload returns true when everything ok or file doesn't exist
437 if (!preload())
439 nlwarning("CDBReferenceFile::read(): failed, failed to preload '%s'", filepath.c_str());
440 return false;
443 // check mode...
444 if (_Mode != Read)
446 nlwarning("CDBReferenceFile::read(): failed, file '%s' not opened in Read mode", filepath.c_str());
447 return false;
450 // check row belongs to file (not over OverIndex)
451 if (index >= _Header.OverIndex)
453 nlwarning("CDBReferenceFile::read(): failed, index '%d' is over file '%s' end '%d'", index, filepath.c_str(), _Header.OverIndex);
454 return false;
457 // check file opened or row is not beyond file end
458 if (_File == NULL || index >= _Header.EndIndex)
460 PDS_LOG_DEBUG(1)("CDBReferenceFile::read(): row '%d' is beyond file '%s' end '%d', row is empty", index, filepath.c_str(), _Header.EndIndex);
461 memset(rowdata, 0, _Header.RowSize);
462 return true;
465 // seek to row in file
466 if (fseek(_File, getSeekPos(index)+getRowHeaderSize(), SEEK_SET) != 0)
468 nlwarning("CDBReferenceFile::read(): failed, can't seek to index '%d' data in file '%s'", index, filepath.c_str());
469 return false;
472 // write data
473 if (!readBuffer(rowdata, _Header.RowSize))
475 nlwarning("CDBReferenceFile::read(): failed, can't read index '%d' data in file '%s'", index, filepath.c_str());
476 return false;
479 return true;
487 * Serial file header
489 bool CDBReferenceFile::serialHeader()
491 serialCheck(NELID("DbRf"));
492 uint version = serialVersion(0);
494 if (isReading())
496 // on reading, read header in a temp buffer
497 CRefHeader hdr;
498 serial(hdr);
500 // check header complies
501 if ((_Header.BaseIndex != 0 && hdr.BaseIndex != _Header.BaseIndex) || (isReading() && _Header.RowSize != 0 && hdr.RowSize != _Header.RowSize))
502 return false;
504 // compy temp to header
505 _Header = hdr;
507 else
509 serial(_Header);
512 serialCheck(NELID("Data"));
514 _DataStart = ftell(_File);
516 if (isReading())
518 // get file size to compute real EndIndex
519 uint32 filesize = CFile::getFileSize(_File);
521 uint32 numRows = (filesize-_DataStart) / _Header.FullRowSize;
522 // check exact number of rows in file...
523 if ((filesize-_DataStart) % _Header.FullRowSize != 0)
525 nlwarning("CDBReferenceFile::serialHeader(): failed, file doesn't contain an exact number of rows");
526 return false;
529 // compute exact end index
530 _Header.EndIndex = _Header.BaseIndex + numRows;
533 return true;