25 #include "../utils/QLockedFile.h"    31     it(toc->table()), _lgp(lgp)
    36     it(lgp._files->table()), 
_lgp(lgp.archiveIO())
    57     return it.hasPrevious();
   106     return it.value()->file(
_lgp);
   115     return it.value()->modifiedFile(
_lgp);
   124     return it.value()->fileName();
   133     return it.value()->fileDir();
   142     return it.value()->filePath();
   238     if(entry == NULL) 
return NULL;
   250     if(entry == NULL) 
return NULL;
   264     if(entry == NULL) 
return false;
   280     if(entry != NULL) 
return false;
   324         qWarning() << 
"Lgp::companyName: The device is not open for reading";
   335     const char *data = companyData.constData();
   337     while(*data == 
'\0' && data < last) {
   370         qWarning() << 
"Lgp::companyName: The device is not open for reading";
   416         qWarning() << 
"Lgp::openHeader: The device is not open for reading";
   428     if(
archiveIO()->read((
char *)&fileCount, 4) != 4) {
   442     const qint32 sizeToc = fileCount * 27;
   443     QByteArray headerData = 
archiveIO()->read(sizeToc);
   445     if(headerData.size() != sizeToc) {
   450     const char *headerConstData = headerData.constData();
   451     QList<LgpHeaderEntry *> tocEntries;
   452     QList<quint16> headerConflict;
   453     bool hasConflict = 
false;
   455     for(qint32 cur=0; cur<sizeToc; cur += 27) {
   458         memcpy(&filePos, headerConstData + cur + 20, 4);
   459         memcpy(&conflict, headerConstData + cur + 25, 2);
   461                               headerData.mid(cur, 20),
   463         headerConflict.append(conflict);
   464         if(conflict != 0 && !hasConflict) {
   471     QList< QList<LgpConflictEntry> > conflicts;
   482         quint16 conflictCount;
   484         if(
archiveIO()->read((
char *)&conflictCount, 2) != 2) {
   489         for(qint32 i=0; i<conflictCount; ++i) {
   490             quint16 conflictEntryCount;
   493             if(
archiveIO()->read((
char *)&conflictEntryCount, 2) != 2) {
   498             const qint32 sizeConflicData = conflictEntryCount * 130;
   499             QByteArray conflictData = 
archiveIO()->read(sizeConflicData);
   501             if(conflictData.size() != sizeConflicData) {
   506             if(sizeConflicData < 0) {
   511             const char *conflictConstData = conflictData.constData();
   512             QList<LgpConflictEntry> conflictEntries;
   514             for(qint32 cur=0; cur<sizeConflicData; cur += 130) {
   517                 memcpy(&conflictEntry.tocIndex, conflictConstData + cur + 128, 2);
   519                 conflictEntries.append(conflictEntry);
   522             conflicts.append(conflictEntries);
   529     int headerEntryID = 0;
   535             qWarning() << 
"Invalid toc name" << entry->
fileName();
   542             const quint16 &conflict = headerConflict.at(headerEntryID);
   545                 const quint16 conflictID = conflict - 1;
   546                 bool resolved = 
false;
   548                 if(conflictID < conflicts.size()) {
   549                     const QList<LgpConflictEntry> &conflictEntries = conflicts.at(conflictID);
   552                         if(conflictEntry.
tocIndex == headerEntryID) {
   561                     qWarning() << 
"Unresolved conflict for" << entry->
fileName();
   589     QString destPath = destination;
   591     if(destination.isEmpty()) {
   593         destPath = fileInfo.absoluteFilePath();
   597     QFile temp(destPath + 
".temp");
   598     if(!temp.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
   611     if(temp.write((
char *)&nbFiles, 4) != 4) {
   617     const quint32 posLookupTable = 16 + nbFiles * 27;
   620     if(!temp.resize(posLookupTable)) {
   625     if(!temp.seek(posLookupTable)) {
   633     QHash<const LgpHeaderEntry *, LgpTocEntry> tocEntries;
   639             tocEntries.insert(headerEntry, 
LgpTocEntry(tocIndex++));
   643     QList< QList<LgpConflictEntry> > conflicts;
   653                 QList<LgpConflictEntry> conflictEntries;
   656                     if(headerEntry != headerEntry2 &&
   658                                                             Qt::CaseInsensitive) == 0) {
   659                         if(conflictEntries.isEmpty()) {
   660                             tocEntry.
conflict = conflicts.size() + 1;
   668                         tocEntry2.
conflict = conflicts.size() + 1;
   675                 if(!conflictEntries.isEmpty()) {
   676                     conflicts.append(conflictEntries);
   682         lookupTable[i].tocOffset = headerEntries.isEmpty()
   683                 ? 0 : tocEntries.value(headerEntries.first()).tocIndex + 1;
   684         lookupTable[i].fileCount = headerEntries.size();
   688     if(temp.write((
char *)lookupTable, 
sizeof(lookupTable)) != 
sizeof(lookupTable)) {
   695     QByteArray conflictsData;
   696     const quint16 conflictCount = conflicts.size();
   697     conflictsData.append((
char *)&conflictCount, 2);
   699     foreach(
const QList<LgpConflictEntry> &conflict, conflicts) {
   700         quint16 conflictEntryCount = conflict.size();
   701         conflictsData.append((
char *)&conflictEntryCount, 2);
   704             conflictsData.append(conflictEntry.
fileDir.toLatin1().leftJustified(128, 
'\0', 
true));
   705             conflictsData.append((
char *)&conflictEntry.
tocIndex, 2);
   709     if(temp.write(conflictsData) != conflictsData.size()) {
   727         const QString &path = lgpEntry->
filePath();
   744                                                           .arg(path).toLatin1().data()));
   747         if(!io->open(QIODevice::ReadOnly)) {
   753         if(temp.write(lgpEntry->
fileName().toLatin1().leftJustified(20, 
'\0', 
true)) != 20) {
   759         const QByteArray data = io->readAll();
   761         const qint64 size = data.size();
   762         if(temp.write((
char *)&size, 4) != 4) {
   768         if(temp.write(data) != size) {
   795             tocData.append(headerEntry->
fileName().toLower().toLatin1().leftJustified(20, 
'\0', 
true));
   797             tocData.append((
char *)&filePos, 4);
   798             tocData.append(
'\x0e');
   799             quint16 conflict = tocEntries.value(headerEntry).conflict;
   800             tocData.append((
char *)&conflict, 2);
   804     if(temp.write(tocData) != tocData.size()) {
   824     if(QFile::exists(destPath)) {
   825         QFile destFile(destPath);
   826         if(!destFile.remove()) {
   833     if(!temp.rename(destPath)) {
 #define LGP_COMPANY_NAME_SIZE
 
bool removeEntry(const QString &filePath)
 
QIODevice * modifiedFile(const QString &filePath)
Returns the data, modified by setData if modified, for the file named filePath. 
 
void next()
Advances the iterator by one position. 
 
virtual ~Lgp()
Destroys the lgp archive object, closing it if necessary. 
 
int fileCount() const 
Returns the number of files in the archive, or -1 if there is an error. 
 
QStringList fileList() const 
Returns a list of file paths sorted by file position. 
 
void setCompanyName(const QString &companyName)
Change the company name. 
 
QFile * archiveIO() const 
 
LgpHeaderEntry * headerEntry(const QString &filePath) const 
 
static bool isNameValid(const QString &filePath)
 
bool isNameValid(const QString &filePath) const 
Check if the filePath is a valid name. 
 
void setFileName(const QString &fileName)
Sets the name of the file. 
 
bool hasPrevious() const 
Returns true if there is at least one item behind the iterator, i.e. 
 
void clear()
Clears the contents of the lgp. 
 
bool fileExists(const QString &filePath) const 
Returns true if the file named filePath exists; otherwise false. 
 
QList< LgpHeaderEntry * > entries(quint16 id) const 
 
void toBack()
Moves the iterator to the back of the container (after the last item). 
 
void setProductName(const QString &productName)
Change the product name. 
 
const QString & companyName()
Returns the company name (like "SQUARESOFT") or a null string if there is an error. 
 
QString errorString() const 
Returns the last error message. 
 
#define LOOKUP_TABLE_ENTRIES
 
bool renameFile(const QString &filePath, const QString &newFilePath)
Rename the file named filePath by newFilePath. 
 
#define LGP_PRODUCT_NAME_SIZE
 
LgpIterator iterator()
Returns an iterator to iterate over the files. 
 
bool addEntry(LgpHeaderEntry *entry)
 
bool renameEntry(const QString &filePath, const QString &newFilePath)
 
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)...
 
void toFront()
Moves the iterator to the front of the container (before the first item). 
 
const QString & fileName() const 
Returns the current file name (without the directory). 
 
bool removeFile(const QString &filePath)
Remove the file named filePath. 
 
QHashIterator< quint16, LgpHeaderEntry * > it
 
QIODevice * modifiedFile()
Returns the current modified file. 
 
const QString & productName()
Returns the product name (like "FINAL FANTASY7") or a null string if there is an error. 
 
LgpError error() const 
Returns the last error status. 
 
bool setFile(const QString &filePath, QIODevice *data)
Change the data for the file named filePath. 
 
LgpIterator(const Lgp &lgp)
 
virtual void setObserverValue(int value)=0
 
const QString & fileDir() const 
Returns the current file directory (without the file name). 
 
virtual bool observerWasCanceled() const =0
 
The Archive class is a device list in a file system or an archive file. 
 
QIODevice * file()
Returns the current file. 
 
QString filePath() const 
Returns the current full file path (dir + name). 
 
QIODevice * file(const QString &filePath)
Returns the data for the file named filePath. 
 
void previous()
Moves the iterator back by one position. 
 
QList< const LgpHeaderEntry * > filesSortedByPosition() const 
 
void unsetError()
Sets the file's error to Lgp::NoError. 
 
Lgp()
Constructs a new empty lgp archive. 
 
void setError(LgpError error, const QString &errorString=QString())
 
LgpHeaderEntry * entry(const QString &filePath) const 
 
bool hasNext() const 
Returns true if there is at least one item ahead of the iterator, i.e. 
 
bool addFile(const QString &filePath, QIODevice *data)
Add a new file named filePath with data. 
 
void setErrorString(const QString &errorString)
 
virtual bool isOpen() const 
Returns true if the archive is open; returns false otherwise.