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.