ff7tk  0.02
Toolkit for making FF7 Tools
Lgp_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  ** Makou Reactor Final Fantasy VII Field Script Editor
3  ** Copyright (C) 2009-2012 Arzel Jérôme <myst6re@gmail.com>
4  **
5  ** This program is free software: you can redistribute it and/or modify
6  ** it under the terms of the GNU General Public License as published by
7  ** the Free Software Foundation, either version 3 of the License, or
8  ** (at your option) any later version.
9  **
10  ** This program is distributed in the hope that it will be useful,
11  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  ** GNU General Public License for more details.
14  **
15  ** You should have received a copy of the GNU General Public License
16  ** along with this program. If not, see <http://www.gnu.org/licenses/>.
17  ****************************************************************************/
18 /*
19  * This file may contains some code (especially the conflict part)
20  * inspired from LGP/UnLGP tool written by Aali.
21  * http://forums.qhimm.com/index.php?topic=8641.0
22  */
23 #include "Lgp_p.h"
24 
25 LgpHeaderEntry::LgpHeaderEntry(const QString &fileName, quint32 filePosition) :
26  _fileName(fileName), _filePosition(filePosition),
27  _hasFileSize(false), _io(NULL), _newIO(NULL)
28 {
29 }
30 
32 {
33  if(_io != NULL) {
34  _io->deleteLater();
35  }
36  if(_newIO != NULL) {
37  _newIO->deleteLater();
38  }
39 }
40 
41 const QString &LgpHeaderEntry::fileName() const
42 {
43  return _fileName;
44 }
45 
46 const QString &LgpHeaderEntry::fileDir() const
47 {
48  return _fileDir;
49 }
50 
51 QString LgpHeaderEntry::filePath() const
52 {
53  return _fileDir.isEmpty()
54  ? _fileName
55  : _fileDir + '/' + _fileName;
56 }
57 
59 {
60  return _filePosition;
61 }
62 
64 {
65  if(_hasFileSize) {
66  return _fileSize;
67  }
68  return -1;
69 }
70 
72 {
73  if(fileName.size() > 20) {
74  _fileName = fileName.left(20);
75  } else {
77  }
78 }
79 
80 void LgpHeaderEntry::setFileDir(const QString &fileDir)
81 {
82  if(fileDir.size() > 128) {
83  _fileDir = fileDir.left(128);
84  } else {
85  _fileDir = fileDir;
86  }
87 }
88 
90 {
91  int index = filePath.lastIndexOf('/');
92 
93  if(index < 0) {
94  setFileName(filePath);
95  } else {
96  setFileDir(filePath.left(index));
97  setFileName(filePath.mid(index + 1));
98  }
99 }
100 
102 {
104 }
105 
107 {
109  _hasFileSize = true;
110 }
111 
112 QIODevice *LgpHeaderEntry::file(QIODevice *lgp)
113 {
114  if(_io) {
115  _io->close();
116  return _io;
117  } else {
118  return createFile(lgp);
119  }
120 }
121 
122 QIODevice *LgpHeaderEntry::modifiedFile(QIODevice *lgp)
123 {
124  if(_newIO) {
125  _newIO->close();
126  return _newIO;
127  } else {
128  return file(lgp);
129  }
130 }
131 
132 void LgpHeaderEntry::setFile(QIODevice *io)
133 {
134  _io = io;
135 }
136 
138 {
139  _newIO = io;
140 }
141 
142 QIODevice *LgpHeaderEntry::createFile(QIODevice *lgp)
143 {
144  if(!lgp->seek(filePosition())) {
145  return NULL;
146  }
147  QByteArray name = lgp->read(20);
148  if(name.size() != 20) {
149  return NULL;
150  }
151  if(QString(name).compare(fileName(), Qt::CaseInsensitive) != 0) {
152  qWarning() << "different name";
153  return NULL;
154  }
155 
156  quint32 size;
157  if(lgp->read((char *)&size, 4) != 4) {
158  return NULL;
159  }
160 
161  setFileSize(size);
162  setFileName(name);
163  QIODevice *io = new LgpIO(lgp, this);
164  setFile(io);
165  return io;
166 }
167 
168 LgpIO::LgpIO(QIODevice *lgp, const LgpHeaderEntry *header, QObject *parent) :
169  QIODevice(parent), _lgp(lgp), _header(header)
170 {
171 }
172 
173 bool LgpIO::open(OpenMode mode) {
174  if(mode.testFlag(QIODevice::Append)
175  || mode.testFlag(QIODevice::Truncate)) {
176  return false;
177  }
178  return QIODevice::open(mode);
179 }
180 
181 qint64 LgpIO::size() const
182 {
183  return _header->fileSize();
184 }
185 
186 qint64 LgpIO::readData(char *data, qint64 maxSize)
187 {
188  if(_lgp->seek(_header->filePosition() + 24 + pos())) {
189  qint64 size = this->size();
190  if(size < 0) {
191  return -1;
192  }
193  return _lgp->read(data, qMin(maxSize, size - pos()));
194  }
195  return -1;
196 }
197 
201 qint64 LgpIO::writeData(const char *data, qint64 maxSize)
202 {
203  if(_lgp->seek(_header->filePosition() + 24 + pos())) {
204  qint64 size = this->size();
205  if(size < 0) {
206  return -1;
207  }
208  return _lgp->write(data, qMin(maxSize, size - pos()));
209  }
210  return -1;
211 }
212 
213 bool LgpIO::canReadLine() const
214 {
215  return pos() < size();
216 }
217 
219 {
220 }
221 
222 LgpToc::LgpToc(const LgpToc &other)
223 {
224  foreach(LgpHeaderEntry *headerEntry, other.table()) {
225  addEntry(new LgpHeaderEntry(*headerEntry));
226  }
227 }
228 
230 {
231  qDeleteAll(_header);
232 }
233 
235 {
236  qint32 v = lookupValue(entry->fileName());
237  if(v < 0) {
238  return false;
239  }
240 
241  if(contains(entry->fileName())) {
242  return false;
243  }
244 
245  _header.insert(v, entry);
246 
247  return true;
248 }
249 
250 LgpHeaderEntry *LgpToc::entry(const QString &filePath) const
251 {
252  qint32 v = lookupValue(filePath);
253  if(v < 0) {
254  return NULL; // invalid file name
255  }
256 
257  return entry(filePath, v);
258 }
259 
260 QList<LgpHeaderEntry *> LgpToc::entries(quint16 id) const
261 {
262  return _header.values(id);
263 }
264 
265 const QMultiHash<quint16, LgpHeaderEntry *> &LgpToc::table() const
266 {
267  return _header;
268 }
269 
270 bool LgpToc::hasEntries(quint16 id) const
271 {
272  return _header.contains(id);
273 }
274 
275 LgpHeaderEntry *LgpToc::entry(const QString &filePath, quint16 id) const
276 {
277  foreach(LgpHeaderEntry *entry, entries(id)) {
278  if(filePath.compare(entry->filePath(), Qt::CaseInsensitive) == 0) {
279  return entry;
280  }
281  }
282 
283  return NULL; // file not found
284 }
285 
286 bool LgpToc::removeEntry(const QString &filePath)
287 {
288  qint32 v = lookupValue(filePath);
289  if(v < 0) {
290  return false; // invalid file name
291  }
292 
293  LgpHeaderEntry *e = entry(filePath);
294  if(e == NULL) {
295  return false; // file not found
296  }
297 
298  bool ok = _header.remove(v, e) > 0;
299 
300  delete e;
301 
302  return ok;
303 }
304 
305 bool LgpToc::isNameValid(const QString &filePath)
306 {
307  return lookupValue(filePath) >= 0;
308 }
309 
310 bool LgpToc::renameEntry(const QString &filePath, const QString &newFilePath)
311 {
312  // Get file
313 
314  qint32 v = lookupValue(filePath);
315  if(v < 0) {
316  qWarning() << "LgpToc::renameEntry invalid filename" << filePath;
317  return false; // invalid file name
318  }
319 
320  LgpHeaderEntry *e = entry(filePath, v);
321  if(e == NULL) {
322  qWarning() << "LgpToc::renameEntry file not found" << filePath;
323  return false; // file not found
324  }
325 
326  // Get new file
327 
328  qint32 newV = lookupValue(newFilePath);
329  if(newV < 0) {
330  qWarning() << "LgpToc::renameEntry invalid new filename" << newFilePath;
331  return false; // invalid file name
332  }
333 
334  if(entry(newFilePath, newV) != NULL) {
335  qWarning() << "LgpToc::renameEntry new file exists" << newFilePath;
336  return false; // file found
337  }
338 
339  // Move file
340 
341  if(_header.remove(v, e) <= 0) {
342  qWarning() << "LgpToc::renameEntry cannot remove entry";
343  return false;
344  }
345 
346  e->setFilePath(newFilePath);
347  _header.insert(newV, e);
348 
349  return true;
350 }
351 
352 bool LgpToc::contains(const QString &filePath) const
353 {
354  return entry(filePath) != NULL;
355 }
356 
358 {
359  qDeleteAll(_header);
360 
361  _header.clear();
362 }
363 
364 bool LgpToc::isEmpty() const
365 {
366  return _header.isEmpty();
367 }
368 
369 int LgpToc::size() const
370 {
371  return _header.size();
372 }
373 
374 QList<const LgpHeaderEntry *> LgpToc::filesSortedByPosition() const
375 {
376  QMultiMap<quint32, const LgpHeaderEntry *> ret;
377 
378  foreach(const LgpHeaderEntry *entry, _header) {
379  ret.insert(entry->filePosition(), entry);
380  }
381 
382  return ret.values();
383 }
384 
386 {
387  if(this != &other) {
388  clear();
389  foreach(LgpHeaderEntry *headerEntry, other.table()) {
390  addEntry(new LgpHeaderEntry(*headerEntry));
391  }
392  }
393 
394  return *this;
395 }
396 
397 qint32 LgpToc::lookupValue(const QString &filePath)
398 {
399  int index = filePath.lastIndexOf('/');
400 
401  if(index != -1) {
402  index++;
403  } else {
404  index = 0;
405  }
406 
407  if(filePath.size() < index + 2) {
408  return -1;
409  }
410 
411  char c1 = lookupValue(filePath.at(index));
412 
413  if(c1 > LOOKUP_VALUE_MAX) {
414  return -1;
415  }
416 
417  char c2 = lookupValue(filePath.at(index + 1));
418 
419  if(c2 > LOOKUP_VALUE_MAX) {
420  return -1;
421  }
422 
423  return c1 * LOOKUP_VALUE_MAX + c2 + 1;
424 }
425 
426 quint8 LgpToc::lookupValue(const QChar &qc)
427 {
428  char c = qc.toLower().toLatin1();
429 
430  if(c == '.') {
431  return 255;
432  }
433 
434  if(c >= '0' && c <= '9') {
435  c += 'a' - '0';
436  }
437 
438  if(c == '_') c = 'k';
439  if(c == '-') c = 'l';
440 
441  return c - 'a';
442 }
bool removeEntry(const QString &filePath)
Definition: Lgp_p.cpp:286
LgpToc()
Definition: Lgp_p.cpp:218
void clear()
Definition: Lgp_p.cpp:357
qint64 readData(char *data, qint64 maxSize)
Definition: Lgp_p.cpp:186
void setFileDir(const QString &fileDir)
Definition: Lgp_p.cpp:80
const QMultiHash< quint16, LgpHeaderEntry * > & table() const
Definition: Lgp_p.cpp:265
LgpToc & operator=(const LgpToc &other)
Definition: Lgp_p.cpp:385
void setFileName(const QString &fileName)
Definition: Lgp_p.cpp:71
qint64 writeData(const char *data, qint64 maxSize)
You cannot write more than the initial file size.
Definition: Lgp_p.cpp:201
void setModifiedFile(QIODevice *io)
Definition: Lgp_p.cpp:137
static bool isNameValid(const QString &filePath)
Definition: Lgp_p.cpp:305
quint32 filePosition() const
Definition: Lgp_p.cpp:58
QList< LgpHeaderEntry * > entries(quint16 id) const
Definition: Lgp_p.cpp:260
Definition: Lgp_p.h:70
qint64 size() const
Definition: Lgp_p.cpp:181
QString _fileName
Definition: Lgp_p.h:91
QFile * _lgp
Definition: Lgp.h:52
#define LOOKUP_VALUE_MAX
Definition: Lgp_p.h:31
bool open(OpenMode mode)
Definition: Lgp_p.cpp:173
bool _hasFileSize
Definition: Lgp_p.h:95
void setFilePosition(quint32 filePosition)
Definition: Lgp_p.cpp:101
LgpIO(QIODevice *lgp, const LgpHeaderEntry *header, QObject *parent=0)
Definition: Lgp_p.cpp:168
bool addEntry(LgpHeaderEntry *entry)
Definition: Lgp_p.cpp:234
QIODevice * modifiedFile(QIODevice *lgp)
Definition: Lgp_p.cpp:122
bool renameEntry(const QString &filePath, const QString &newFilePath)
Definition: Lgp_p.cpp:310
quint32 _fileSize
Definition: Lgp_p.h:94
bool hasEntries(quint16 id) const
Definition: Lgp_p.cpp:270
const QString & fileName() const
Returns the current file name (without the directory).
Definition: Lgp.cpp:122
int size() const
Definition: Lgp_p.cpp:369
QIODevice * _io
Definition: Lgp_p.h:96
void setFileSize(quint32 fileSize)
Definition: Lgp_p.cpp:106
bool isEmpty() const
Definition: Lgp_p.cpp:364
bool canReadLine() const
Definition: Lgp_p.cpp:213
quint32 _filePosition
Definition: Lgp_p.h:93
QString filePath() const
Definition: Lgp_p.cpp:51
QIODevice * _newIO
Definition: Lgp_p.h:97
const LgpHeaderEntry * _header
Definition: Lgp_p.h:112
LgpHeaderEntry(const QString &fileName, quint32 filePosition)
Definition: Lgp_p.cpp:25
QString filePath() const
Returns the current full file path (dir + name).
Definition: Lgp.cpp:140
qint64 fileSize() const
Definition: Lgp_p.cpp:63
const QString & fileDir() const
Definition: Lgp_p.cpp:46
Definition: Lgp_p.h:100
QIODevice * _lgp
Definition: Lgp_p.h:111
const QString & fileName() const
Definition: Lgp_p.cpp:41
void setFile(QIODevice *io)
Definition: Lgp_p.cpp:132
virtual ~LgpToc()
Definition: Lgp_p.cpp:229
Definition: Lgp_p.h:117
QList< const LgpHeaderEntry * > filesSortedByPosition() const
Definition: Lgp_p.cpp:374
virtual ~LgpHeaderEntry()
Definition: Lgp_p.cpp:31
static qint32 lookupValue(const QString &filePath)
Definition: Lgp_p.cpp:397
void setFilePath(const QString &filePath)
Definition: Lgp_p.cpp:89
bool contains(const QString &filePath) const
Definition: Lgp_p.cpp:352
QIODevice * createFile(QIODevice *lgp)
Definition: Lgp_p.cpp:142
QIODevice * file(QIODevice *lgp)
Definition: Lgp_p.cpp:112
QString _fileDir
Definition: Lgp_p.h:92
LgpHeaderEntry * entry(const QString &filePath) const
Definition: Lgp_p.cpp:250