ff7tk  0.02
Toolkit for making FF7 Tools
Lgp.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.h"
24 #include "Lgp_p.h"
25 #include "../utils/QLockedFile.h"
26 
30 LgpIterator::LgpIterator(LgpToc *toc, QFile *lgp) :
31  it(toc->table()), _lgp(lgp)
32 {
33 }
34 
36  it(lgp._files->table()), _lgp(lgp.archiveIO())
37 {
38 }
39 
46 {
47  return it.hasNext();
48 }
49 
56 {
57  return it.hasPrevious();
58 }
59 
67 {
68  it.next();
69 }
70 
78 {
79  it.previous();
80 }
81 
87 {
88  it.toBack();
89 }
90 
96 {
97  it.toFront();
98 }
99 
104 QIODevice *LgpIterator::file()
105 {
106  return it.value()->file(_lgp);
107 }
108 
114 {
115  return it.value()->modifiedFile(_lgp);
116 }
117 
122 const QString &LgpIterator::fileName() const
123 {
124  return it.value()->fileName();
125 }
126 
131 const QString &LgpIterator::fileDir() const
132 {
133  return it.value()->fileDir();
134 }
135 
140 QString LgpIterator::filePath() const
141 {
142  return it.value()->filePath();
143 }
144 
149  Archive(new QLockedFile()), _files(new LgpToc), _error(NoError)
150 {
151 }
152 
156 Lgp::Lgp(const QString &name) :
157  Archive(new QLockedFile(name)), _files(new LgpToc), _error(NoError)
158 {
159 }
160 
164 Lgp::Lgp(QFile *device) :
165  Archive(device), _files(new LgpToc), _error(NoError)
166 {
167 }
168 
173 {
174  delete _files;
175 }
176 
181 {
182  _companyName.clear();
183  _files->clear();
184  _productName.clear();
185 }
186 
190 QStringList Lgp::fileList() const
191 {
192  QStringList ret;
193 
194  if(_files->isEmpty()) {
195  return ret;
196  }
197 
198  foreach(const LgpHeaderEntry *entry, _files->filesSortedByPosition()) {
199  ret.append(entry->filePath());
200  }
201 
202  return ret;
203 }
204 
208 int Lgp::fileCount() const
209 {
210  return _files->size();
211 }
212 
218 {
219  return LgpIterator(_files, archiveIO());
220 }
221 
226 bool Lgp::fileExists(const QString &filePath) const
227 {
228  return headerEntry(filePath) != NULL;// need to open the header
229 }
230 
235 QIODevice *Lgp::file(const QString &filePath)
236 {
237  LgpHeaderEntry *entry = headerEntry(filePath);// need to open the header
238  if(entry == NULL) return NULL;
239 
240  return entry->file(archiveIO());
241 }
242 
247 QIODevice *Lgp::modifiedFile(const QString &filePath)
248 {
249  LgpHeaderEntry *entry = headerEntry(filePath);// need to open the header
250  if(entry == NULL) return NULL;
251 
252  return entry->modifiedFile(archiveIO());
253 }
254 
261 bool Lgp::setFile(const QString &filePath, QIODevice *data)
262 {
263  LgpHeaderEntry *entry = headerEntry(filePath);// need to open the header
264  if(entry == NULL) return false;
265 
266  entry->setModifiedFile(data);
267 
268  return true;
269 }
270 
277 bool Lgp::addFile(const QString &filePath, QIODevice *data)
278 {
279  LgpHeaderEntry *entry = headerEntry(filePath);// need to open the header
280  if(entry != NULL) return false;
281 
282  entry = new LgpHeaderEntry(filePath, archiveIO()->size());
283  entry->setModifiedFile(data);
284 
285  bool ret = _files->addEntry(entry);
286 
287  if(!ret) {
288  delete entry;
289  }
290 
291  return ret;
292 }
293 
298 bool Lgp::removeFile(const QString &filePath)
299 {
300  return _files->removeEntry(filePath);
301 }
302 
307 bool Lgp::isNameValid(const QString &filePath) const
308 {
309  return LgpToc::isNameValid(filePath);
310 }
311 
316 bool Lgp::renameFile(const QString &filePath, const QString &newFilePath)
317 {
318  return _files->renameEntry(filePath, newFilePath);
319 }
320 
322 {
323  if(!isOpen()) {
324  qWarning() << "Lgp::companyName: The device is not open for reading";
325  return false;
326  }
327 
328  if(!archiveIO()->reset()) {
329  return false;
330  }
331  QByteArray companyData = archiveIO()->read(LGP_COMPANY_NAME_SIZE);
332  if(companyData.size() != LGP_COMPANY_NAME_SIZE) {
333  return false;
334  }
335  const char *data = companyData.constData();
336  const char *last = data + LGP_COMPANY_NAME_SIZE;
337  while(*data == '\0' && data < last) {
338  data++;
339  }
340  _companyName = QByteArray(data, (int)(last - data));
341 
342  return true;
343 }
344 
350 const QString &Lgp::companyName()
351 {
352  if(_companyName.isNull()) {
353  openCompanyName();
354  }
355  return _companyName;
356 }
357 
362 void Lgp::setCompanyName(const QString &companyName)
363 {
364  _companyName = companyName.left(LGP_COMPANY_NAME_SIZE);
365 }
366 
368 {
369  if(!isOpen()) {
370  qWarning() << "Lgp::companyName: The device is not open for reading";
371  return false;
372  }
373 
374  if(!archiveIO()->seek(archiveIO()->size() - LGP_PRODUCT_NAME_SIZE)) {
375  return false;
376  }
378 
379  return true;
380 }
381 
387 const QString &Lgp::productName()
388 {
389  if(_productName.isNull()) {
390  openProductName();
391  }
392  return _productName;
393 }
394 
399 void Lgp::setProductName(const QString &productName)
400 {
401  _productName = productName.left(LGP_PRODUCT_NAME_SIZE);
402 }
403 
404 LgpHeaderEntry *Lgp::headerEntry(const QString &filePath) const
405 {
406  return _files->entry(filePath);
407 }
408 
410 {
411  if(!archiveIO()->exists()) {
412  return true; // Create the file
413  }
414 
415  if(!isOpen()) {
416  qWarning() << "Lgp::openHeader: The device is not open for reading";
418  return false;
419  }
420 
421  if(!archiveIO()->seek(LGP_COMPANY_NAME_SIZE)) {
423  return false;
424  }
425 
426  qint32 fileCount;
427 
428  if(archiveIO()->read((char *)&fileCount, 4) != 4) {
430  return false;
431  }
432 
433  if(fileCount < 0) {
435  return false;
436  }
437 
438  if(fileCount == 0) {
439  return true;
440  }
441 
442  const qint32 sizeToc = fileCount * 27;
443  QByteArray headerData = archiveIO()->read(sizeToc);
444 
445  if(headerData.size() != sizeToc) {
447  return false;
448  }
449 
450  const char *headerConstData = headerData.constData();
451  QList<LgpHeaderEntry *> tocEntries;
452  QList<quint16> headerConflict;
453  bool hasConflict = false;
454 
455  for(qint32 cur=0; cur<sizeToc; cur += 27) {
456  quint32 filePos;
457  quint16 conflict;
458  memcpy(&filePos, headerConstData + cur + 20, 4);
459  memcpy(&conflict, headerConstData + cur + 25, 2);
460  tocEntries.append(new LgpHeaderEntry(
461  headerData.mid(cur, 20),
462  filePos));
463  headerConflict.append(conflict);
464  if(conflict != 0 && !hasConflict) {
465  hasConflict = true;
466  }
467  }
468 
469  /* Resolve conflicts */
470 
471  QList< QList<LgpConflictEntry> > conflicts;
472 
473  if(hasConflict) {
474 
475  // Lookup table ignored
476  if(!archiveIO()->seek(archiveIO()->pos() + LOOKUP_TABLE_ENTRIES * 4)) {
478  return false;
479  }
480 
481  // Open conflicts
482  quint16 conflictCount;
483 
484  if(archiveIO()->read((char *)&conflictCount, 2) != 2) {
486  return false;
487  }
488 
489  for(qint32 i=0; i<conflictCount; ++i) {
490  quint16 conflictEntryCount;
491 
492  // Open conflict entries
493  if(archiveIO()->read((char *)&conflictEntryCount, 2) != 2) {
495  return false;
496  }
497 
498  const qint32 sizeConflicData = conflictEntryCount * 130;
499  QByteArray conflictData = archiveIO()->read(sizeConflicData);
500 
501  if(conflictData.size() != sizeConflicData) {
503  return false;
504  }
505 
506  if(sizeConflicData < 0) {
508  return false;
509  }
510 
511  const char *conflictConstData = conflictData.constData();
512  QList<LgpConflictEntry> conflictEntries;
513 
514  for(qint32 cur=0; cur<sizeConflicData; cur += 130) {
515  LgpConflictEntry conflictEntry(conflictData.mid(cur, 128));
516 
517  memcpy(&conflictEntry.tocIndex, conflictConstData + cur + 128, 2);
518 
519  conflictEntries.append(conflictEntry);
520  }
521 
522  conflicts.append(conflictEntries);
523  }
524 
525  }
526 
527  /* Populate _files */
528 
529  int headerEntryID = 0;
530 
531  _files->clear(); // This will delete entries
532 
533  foreach(LgpHeaderEntry *entry, tocEntries) {
534  if(!_files->addEntry(entry)) {
535  qWarning() << "Invalid toc name" << entry->fileName();
536  delete entry;
537  continue;
538  }
539 
540  // Set fileDir
541  if(hasConflict) {
542  const quint16 &conflict = headerConflict.at(headerEntryID);
543 
544  if(conflict != 0) {
545  const quint16 conflictID = conflict - 1;
546  bool resolved = false;
547 
548  if(conflictID < conflicts.size()) {
549  const QList<LgpConflictEntry> &conflictEntries = conflicts.at(conflictID);
550 
551  foreach(const LgpConflictEntry &conflictEntry, conflictEntries) {
552  if(conflictEntry.tocIndex == headerEntryID) {
553  entry->setFileDir(conflictEntry.fileDir);
554  resolved = true;
555  break;
556  }
557  }
558  }
559 
560  if(!resolved) {
561  qWarning() << "Unresolved conflict for" << entry->fileName();
562  }
563  }
564  ++headerEntryID;
565  }
566  }
567 
568  return true;
569 }
570 
578 bool Lgp::pack(const QString &destination, ArchiveObserver *observer)
579 {
580  const int nbFiles = _files->size();
581  int fileId;
582 
583  // Range (0 to max) for the progression indicator
584  if(observer) {
585  observer->setObserverMaximum(nbFiles);
586  fileId = 0;
587  }
588 
589  QString destPath = destination;
590 
591  if(destination.isEmpty()) {
592  QFileInfo fileInfo(*archiveIO());
593  destPath = fileInfo.absoluteFilePath();
594  }
595 
596  // Temporary file (same dir as destination)
597  QFile temp(destPath + ".temp");
598  if(!temp.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
599  setError(OpenError, temp.errorString());
600  return false;
601  }
602 
603  // Writes the company name ( SQUARESOFT)
604  if(temp.write(companyName().toLatin1().rightJustified(LGP_COMPANY_NAME_SIZE, '\0', true)) != LGP_COMPANY_NAME_SIZE) {
605  temp.remove();
606  setError(WriteError, temp.errorString());
607  return false;
608  }
609 
610  // Writes the file count
611  if(temp.write((char *)&nbFiles, 4) != 4) {
612  temp.remove();
613  setError(WriteError, temp.errorString());
614  return false;
615  }
616 
617  const quint32 posLookupTable = 16 + nbFiles * 27;
618 
619  // We write data first, and toc in second
620  if(!temp.resize(posLookupTable)) {
621  temp.remove();
622  setError(ResizeError, temp.errorString());
623  return false;
624  }
625  if(!temp.seek(posLookupTable)) {
626  temp.remove();
627  setError(PositionError, temp.errorString());
628  return false;
629  }
630 
631  // Lookup Table + conflicts
632  LgpLookupTableEntry lookupTable[LOOKUP_TABLE_ENTRIES];
633  QHash<const LgpHeaderEntry *, LgpTocEntry> tocEntries;
634  int tocIndex = 0;
635 
636  for(int i=0; i<LOOKUP_TABLE_ENTRIES; ++i) {
637  // toc index initialization
638  foreach(const LgpHeaderEntry *headerEntry, _files->entries(i)) {
639  tocEntries.insert(headerEntry, LgpTocEntry(tocIndex++));
640  }
641  }
642 
643  QList< QList<LgpConflictEntry> > conflicts;
644 
645  for(int i=0; i<LOOKUP_TABLE_ENTRIES; ++i) {
646  QList<LgpHeaderEntry *> headerEntries = _files->entries(i);
647 
648  // Build list conflicts
649  foreach(const LgpHeaderEntry *headerEntry, headerEntries) {
650  LgpTocEntry &tocEntry = tocEntries[headerEntry];
651 
652  if(tocEntry.conflict == 0) {
653  QList<LgpConflictEntry> conflictEntries;
654 
655  foreach(const LgpHeaderEntry *headerEntry2, headerEntries) {
656  if(headerEntry != headerEntry2 &&
657  headerEntry->fileName().compare(headerEntry2->fileName(),
658  Qt::CaseInsensitive) == 0) {
659  if(conflictEntries.isEmpty()) {
660  tocEntry.conflict = conflicts.size() + 1;
661 
662  conflictEntries.append(LgpConflictEntry(headerEntry->fileDir(),
663  tocEntry.tocIndex));
664  }
665 
666  LgpTocEntry &tocEntry2 = tocEntries[headerEntry2];
667 
668  tocEntry2.conflict = conflicts.size() + 1;
669 
670  conflictEntries.append(LgpConflictEntry(headerEntry2->fileDir(),
671  tocEntry2.tocIndex));
672  }
673  }
674 
675  if(!conflictEntries.isEmpty()) {
676  conflicts.append(conflictEntries);
677  }
678  }
679  }
680 
681  // Build lookup table
682  lookupTable[i].tocOffset = headerEntries.isEmpty()
683  ? 0 : tocEntries.value(headerEntries.first()).tocIndex + 1;
684  lookupTable[i].fileCount = headerEntries.size();
685  }
686 
687  // Write Lookup Table
688  if(temp.write((char *)lookupTable, sizeof(lookupTable)) != sizeof(lookupTable)) {
689  temp.remove();
690  setError(WriteError, temp.errorString());
691  return false;
692  }
693 
694  // Write conflicts
695  QByteArray conflictsData;
696  const quint16 conflictCount = conflicts.size();
697  conflictsData.append((char *)&conflictCount, 2);
698 
699  foreach(const QList<LgpConflictEntry> &conflict, conflicts) {
700  quint16 conflictEntryCount = conflict.size();
701  conflictsData.append((char *)&conflictEntryCount, 2);
702 
703  foreach(const LgpConflictEntry &conflictEntry, conflict) {
704  conflictsData.append(conflictEntry.fileDir.toLatin1().leftJustified(128, '\0', true));
705  conflictsData.append((char *)&conflictEntry.tocIndex, 2);
706  }
707  }
708 
709  if(temp.write(conflictsData) != conflictsData.size()) {
710  temp.remove();
711  setError(WriteError, temp.errorString());
712  return false;
713  }
714 
715  LgpToc newToc;
716 
717  // Write files
718  foreach(const LgpHeaderEntry *lgpEntry, _files->filesSortedByPosition()) {
719  // Cancels if requested
720  if(observer && observer->observerWasCanceled()) {
721  temp.remove();
723  return false;
724  }
725 
726  // Infos for the current file
727  const QString &path = lgpEntry->filePath();
728 
729  // Notify the progression
730  if(observer) observer->setObserverValue(fileId++);
731 
732  // Changes the header info
733  LgpHeaderEntry *newEntry = new LgpHeaderEntry(*lgpEntry);
734  newEntry->setFilePosition(temp.pos());
735  newEntry->setFile(0);
736  newEntry->setModifiedFile(0);
737  newToc.addEntry(newEntry);
738 
739  // Writes the file
740  QIODevice *io = modifiedFile(path);
741  if(io == NULL) {
742  temp.remove();
743  setError(FileNotFoundError, QT_TRANSLATE_NOOP(Lgp, QString("File '%1' not found")
744  .arg(path).toLatin1().data()));
745  return false;
746  }
747  if(!io->open(QIODevice::ReadOnly)) {
748  temp.remove();
749  setError(OpenError, temp.errorString());
750  return false;
751  }
752  // File: writes the name
753  if(temp.write(lgpEntry->fileName().toLatin1().leftJustified(20, '\0', true)) != 20) {
754  temp.remove();
755  setError(WriteError, temp.errorString());
756  return false;
757  }
758  // File: writes the size
759  const QByteArray data = io->readAll();
760  io->close();
761  const qint64 size = data.size();
762  if(temp.write((char *)&size, 4) != 4) {
763  temp.remove();
764  setError(WriteError, temp.errorString());
765  return false;
766  }
767  // File: writes data
768  if(temp.write(data) != size) {
769  temp.remove();
770  setError(WriteError, temp.errorString());
771  return false;
772  }
773  }
774 
775  // Writes the product name (FINAL FANTASY7)
776  if(temp.write(productName().toLatin1().leftJustified(LGP_PRODUCT_NAME_SIZE, '\0', true)) != LGP_PRODUCT_NAME_SIZE) {
777  temp.remove();
778  setError(WriteError, temp.errorString());
779  return false;
780  }
781 
782  if(observer) observer->setObserverValue(fileId);
783 
784  // Go back to the header
785  if(!temp.seek(16)) {
786  temp.remove();
787  setError(PositionError, temp.errorString());
788  return false;
789  }
790 
791  // Header: TOC
792  QByteArray tocData;
793  for(int i=0; i<LOOKUP_TABLE_ENTRIES; ++i) {
794  foreach(const LgpHeaderEntry *headerEntry, newToc.entries(i)) {
795  tocData.append(headerEntry->fileName().toLower().toLatin1().leftJustified(20, '\0', true));
796  quint32 filePos = headerEntry->filePosition();
797  tocData.append((char *)&filePos, 4);
798  tocData.append('\x0e');
799  quint16 conflict = tocEntries.value(headerEntry).conflict;
800  tocData.append((char *)&conflict, 2);
801  }
802  }
803 
804  if(temp.write(tocData) != tocData.size()) {
805  temp.remove();
806  setError(WriteError, temp.errorString());
807  return false;
808  }
809 
810  if(observer) {
811  // Infinite...
812  observer->setObserverValue(-1);
813  // Cancel if requested (last chance)
814  if(observer->observerWasCanceled()) {
815  temp.remove();
817  return false;
818  }
819  }
820 
821  archiveIO()->close();
822 
823  // Remove destination file
824  if(QFile::exists(destPath)) {
825  QFile destFile(destPath);
826  if(!destFile.remove()) {
827  temp.remove();
828  setError(RemoveError, destFile.errorString());
829  return false;
830  }
831  }
832  // Move temp file to destination
833  if(!temp.rename(destPath)) {
834  temp.remove();
835  setError(RenameError, temp.errorString());
836  return false;
837  }
838 
839  // Now the archive is located in "destination"
840  setFileName(destPath);
841 
842  *_files = newToc;
843  setError(NoError);
844 
845  return true;
846 }
847 
853 {
854  return _error;
855 }
856 
858 {
859  _error = error;
860  setErrorString(errorString);
861 }
862 
868 {
869  setError(NoError);
870 }
#define LGP_COMPANY_NAME_SIZE
Definition: Lgp_p.h:28
bool openCompanyName()
Definition: Lgp.cpp:321
bool removeEntry(const QString &filePath)
Definition: Lgp_p.cpp:286
void clear()
Definition: Lgp_p.cpp:357
LgpToc * _files
Definition: Lgp.h:107
QIODevice * modifiedFile(const QString &filePath)
Returns the data, modified by setData if modified, for the file named filePath.
Definition: Lgp.cpp:247
void next()
Advances the iterator by one position.
Definition: Lgp.cpp:66
void setFileDir(const QString &fileDir)
Definition: Lgp_p.cpp:80
virtual ~Lgp()
Destroys the lgp archive object, closing it if necessary.
Definition: Lgp.cpp:172
int fileCount() const
Returns the number of files in the archive, or -1 if there is an error.
Definition: Lgp.cpp:208
QStringList fileList() const
Returns a list of file paths sorted by file position.
Definition: Lgp.cpp:190
void setCompanyName(const QString &companyName)
Change the company name.
Definition: Lgp.cpp:362
void setModifiedFile(QIODevice *io)
Definition: Lgp_p.cpp:137
QFile * archiveIO() const
Definition: Archive.h:83
LgpHeaderEntry * headerEntry(const QString &filePath) const
Definition: Lgp.cpp:404
quint16 tocIndex
Definition: Lgp_p.h:58
static bool isNameValid(const QString &filePath)
Definition: Lgp_p.cpp:305
bool openHeader()
Definition: Lgp.cpp:409
bool isNameValid(const QString &filePath) const
Check if the filePath is a valid name.
Definition: Lgp.cpp:307
Definition: Lgp_p.h:52
void setFileName(const QString &fileName)
Sets the name of the file.
Definition: Archive.cpp:169
bool hasPrevious() const
Returns true if there is at least one item behind the iterator, i.e.
Definition: Lgp.cpp:55
void clear()
Clears the contents of the lgp.
Definition: Lgp.cpp:180
bool fileExists(const QString &filePath) const
Returns true if the file named filePath exists; otherwise false.
Definition: Lgp.cpp:226
quint32 filePosition() const
Definition: Lgp_p.cpp:58
QList< LgpHeaderEntry * > entries(quint16 id) const
Definition: Lgp_p.cpp:260
LgpError _error
Definition: Lgp.h:109
void toBack()
Moves the iterator to the back of the container (after the last item).
Definition: Lgp.cpp:86
quint16 conflict
Definition: Lgp_p.h:66
Definition: Lgp_p.h:70
void setProductName(const QString &productName)
Change the product name.
Definition: Lgp.cpp:399
const QString & companyName()
Returns the company name (like "SQUARESOFT") or a null string if there is an error.
Definition: Lgp.cpp:350
QFile * _lgp
Definition: Lgp.h:52
QString errorString() const
Returns the last error message.
Definition: Archive.cpp:178
#define LOOKUP_TABLE_ENTRIES
Definition: Lgp_p.h:32
bool renameFile(const QString &filePath, const QString &newFilePath)
Rename the file named filePath by newFilePath.
Definition: Lgp.cpp:316
void setFilePosition(quint32 filePosition)
Definition: Lgp_p.cpp:101
#define LGP_PRODUCT_NAME_SIZE
Definition: Lgp_p.h:29
QString fileDir
Definition: Lgp_p.h:57
LgpIterator iterator()
Returns an iterator to iterate over the files.
Definition: Lgp.cpp:217
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
virtual void setObserverMaximum(unsigned int max)=0
bool pack(const QString &destination=QString(), ArchiveObserver *observer=NULL)
Save the lgp into destination (or overwrite the current archive if destination is empty)...
Definition: Lgp.cpp:578
QString _productName
Definition: Lgp.h:108
void toFront()
Moves the iterator to the front of the container (before the first item).
Definition: Lgp.cpp:95
const QString & fileName() const
Returns the current file name (without the directory).
Definition: Lgp.cpp:122
bool removeFile(const QString &filePath)
Remove the file named filePath.
Definition: Lgp.cpp:298
int size() const
Definition: Lgp_p.cpp:369
QHashIterator< quint16, LgpHeaderEntry * > it
Definition: Lgp.h:51
QIODevice * modifiedFile()
Returns the current modified file.
Definition: Lgp.cpp:113
const QString & productName()
Returns the product name (like "FINAL FANTASY7") or a null string if there is an error.
Definition: Lgp.cpp:387
bool isEmpty() const
Definition: Lgp_p.cpp:364
LgpError error() const
Returns the last error status.
Definition: Lgp.cpp:852
LgpError
Definition: Lgp.h:59
bool setFile(const QString &filePath, QIODevice *data)
Change the data for the file named filePath.
Definition: Lgp.cpp:261
LgpIterator(const Lgp &lgp)
Definition: Lgp.cpp:35
QString filePath() const
Definition: Lgp_p.cpp:51
friend class LgpIterator
Definition: Lgp.h:57
virtual void setObserverValue(int value)=0
Definition: Lgp.h:55
const QString & fileDir() const
Returns the current file directory (without the file name).
Definition: Lgp.cpp:131
virtual bool observerWasCanceled() const =0
bool openProductName()
Definition: Lgp.cpp:367
The Archive class is a device list in a file system or an archive file.
Definition: Archive.h:31
QIODevice * file()
Returns the current file.
Definition: Lgp.cpp:104
QString filePath() const
Returns the current full file path (dir + name).
Definition: Lgp.cpp:140
QIODevice * file(const QString &filePath)
Returns the data for the file named filePath.
Definition: Lgp.cpp:235
void previous()
Moves the iterator back by one position.
Definition: Lgp.cpp:77
Definition: Lgp_p.h:61
quint16 tocIndex
Definition: Lgp_p.h:67
const QString & fileDir() const
Definition: Lgp_p.cpp:46
const QString & fileName() const
Definition: Lgp_p.cpp:41
void setFile(QIODevice *io)
Definition: Lgp_p.cpp:132
Definition: Lgp_p.h:117
QList< const LgpHeaderEntry * > filesSortedByPosition() const
Definition: Lgp_p.cpp:374
void unsetError()
Sets the file&#39;s error to Lgp::NoError.
Definition: Lgp.cpp:867
Lgp()
Constructs a new empty lgp archive.
Definition: Lgp.cpp:148
QString _companyName
Definition: Lgp.h:106
QIODevice * file(QIODevice *lgp)
Definition: Lgp_p.cpp:112
void setError(LgpError error, const QString &errorString=QString())
Definition: Lgp.cpp:857
LgpHeaderEntry * entry(const QString &filePath) const
Definition: Lgp_p.cpp:250
bool hasNext() const
Returns true if there is at least one item ahead of the iterator, i.e.
Definition: Lgp.cpp:45
bool addFile(const QString &filePath, QIODevice *data)
Add a new file named filePath with data.
Definition: Lgp.cpp:277
void setErrorString(const QString &errorString)
Definition: Archive.h:79
virtual bool isOpen() const
Returns true if the archive is open; returns false otherwise.
Definition: Archive.cpp:140