ff7tk  0.02
Toolkit for making FF7 Tools
IsoArchive.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 #include "IsoArchive.h"
19 
20 IsoFileOrDirectory::IsoFileOrDirectory(const QString &name, quint32 location, quint32 size, qint64 structPosition) :
21  structPosition(structPosition), _name(name), _location(location), _size(size),
22  _newLocation(location), _newSize(size), _paddingAfter(0)
23 {
24 }
25 
27 {
28 }
29 
30 const QString &IsoFileOrDirectory::name() const
31 {
32  return _name;
33 }
34 
36 {
37  return _location;
38 }
39 
41 {
42  return location() + sectorCount();
43 }
44 
45 quint32 IsoFileOrDirectory::size() const
46 {
47  return _size;
48 }
49 
51 {
52  return _size / SECTOR_SIZE_DATA + (int)(_size % SECTOR_SIZE_DATA != 0);
53 }
54 
56 {
57  return _newLocation;
58 }
59 
61 {
62  return _newSize;
63 }
64 
66 {
67  return _newSize / SECTOR_SIZE_DATA + (int)(_newSize % SECTOR_SIZE_DATA != 0);
68 }
69 
70 void IsoFileOrDirectory::setName(const QString &name)
71 {
72  _name = name;
73 }
74 
76 {
78 }
79 
81 {
82  return !isDirectory();
83 }
84 
86 {
87  return _location != _newLocation || _size != _newSize;
88 }
89 
91 {
93  _size = _newSize;
94 }
95 
97 {
98  return _name.isEmpty() || _name == "\x01";
99 }
100 
102 {
103  _paddingAfter = after;
104 }
105 
107 {
108  return _paddingAfter;
109 }
110 
111 IsoDirectory::IsoDirectory(const QString &name, quint32 location, quint32 size, qint64 structPosition) :
112  IsoFileOrDirectory(name, location, size, structPosition)
113 {
114 }
115 
117 {
118  qDeleteAll(_filesAndDirectories);
119 }
120 
122 {
123  return true;
124 }
125 
126 const QMap<QString, IsoFileOrDirectory *> &IsoDirectory::filesAndDirectories() const
127 {
128  return _filesAndDirectories;
129 }
130 
131 QList<IsoFile *> IsoDirectory::files() const
132 {
133  QList<IsoFile *> fs;
134 
135  foreach(IsoFileOrDirectory *fOrD, _filesAndDirectories) {
136  if(fOrD->isFile()) {
137  fs.append(static_cast<IsoFile *>(fOrD));
138  }
139  }
140 
141  return fs;
142 }
143 
144 QList<IsoDirectory *> IsoDirectory::directories() const
145 {
146  QList<IsoDirectory *> ds;
147 
148  foreach(IsoFileOrDirectory *fOrD, _filesAndDirectories) {
149  if(fOrD->isDirectory()) {
150  ds.append(static_cast<IsoDirectory *>(fOrD));
151  }
152  }
153 
154  return ds;
155 }
156 
158 {
159  int index;
160 
161  if((index = path.indexOf("/")) != -1) {
162  IsoFileOrDirectory *fOrD = _filesAndDirectories.value(path.left(index).toUpper(), NULL);
163 
164  if(fOrD == NULL) return NULL;
165 
166  if(fOrD->isDirectory()) {
167  return static_cast<IsoDirectory *>(fOrD)->fileOrDirectory(path.mid(index+1));
168  } else {
169  return NULL;
170  }
171  } else {
172  return _filesAndDirectories.value(path.toUpper(), NULL);
173  }
174 
175 }
176 
177 IsoFile *IsoDirectory::file(const QString &path) const
178 {
179  IsoFileOrDirectory *fOrD = fileOrDirectory(path);
180 
181  if(fOrD == NULL) return NULL;
182 
183  if(fOrD->isDirectory()) {
184  return NULL;
185  }
186 
187  return static_cast<IsoFile *>(fOrD);
188 }
189 
190 IsoDirectory *IsoDirectory::directory(const QString &path) const
191 {
192  IsoFileOrDirectory *fOrD = fileOrDirectory(path);
193 
194  if(fOrD == NULL) return NULL;
195 
196  if(fOrD->isFile()) {
197  return NULL;
198  }
199 
200  return static_cast<IsoDirectory *>(fOrD);
201 }
202 
204 {
205  _filesAndDirectories.insert(fileOrDirectory->name(), fileOrDirectory);
206 }
207 
208 IsoFile::IsoFile(const QString &name, quint32 location, quint32 size, qint64 structPosition, IsoArchiveIO *io) :
209  IsoFileOrDirectory(name, location, size, structPosition),
210  _io(0), _newIO(0), dataChanged(false),
211  _newIOMustBeRemoved(false)
212 {
213  setFile(new IsoFileIO(io, this));
214 }
215 
217 {
218  if (_io) delete _io;
219  cleanNewIO();
220 }
221 
223 {
224  return false;
225 }
226 
227 QByteArray IsoFile::data(quint32 maxSize) const
228 {
229  if(_io->isOpen() || _io->open(QIODevice::ReadOnly)) {
230  _io->reset();
231  return maxSize == 0 ? _io->readAll() : _io->read(maxSize);
232  }
233  return QByteArray();
234 }
235 
236 QByteArray IsoFile::modifiedData(quint32 maxSize) const
237 {
238  if(_newIO && (_newIO->isOpen() || _newIO->open(QIODevice::ReadOnly))) {
239  _newIO->reset();
240  return maxSize == 0 ? _newIO->readAll() : _newIO->read(maxSize);
241  }
242  return data(maxSize);
243 }
244 
245 bool IsoFile::extract(const QString &destination, quint32 maxSize) const
246 {
247 // QTime t;t.start();
248 
249  maxSize = maxSize == 0 ? size() : qMin(maxSize, size());
250  char data[MAX_ISO_READ];
251  qint64 r, totalR=0;
252  QFile ret(destination);
253  if(!ret.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
254  return false;
255  }
256  if(!_io->isOpen() && !_io->open(QIODevice::ReadOnly)) {
257  return false;
258  }
259 
260  while(maxSize-totalR > 0 && (r = _io->read(data, qMin((qint64)MAX_ISO_READ, maxSize-totalR))) > 0) {
261  ret.write(data, r);
262  totalR += r;
263  }
264 
265 // qDebug() << "time" << t.elapsed();
266 
267  return true;
268 }
269 
270 QIODevice *IsoFile::file() const
271 {
272  return _io;
273 }
274 
275 QIODevice *IsoFile::modifiedFile() const
276 {
277  if (_newIO) {
278  return _newIO;
279  }
280  return file();
281 }
282 
283 void IsoFile::setFile(QIODevice *io)
284 {
285  _io = io;
286 }
287 
288 bool IsoFile::setModifiedFile(QIODevice *io)
289 {
290  if(!io->isOpen() && !io->open(QIODevice::ReadOnly)) {
291  return false;
292  }
293 
294  cleanNewIO();
295  _newIO = io;
296  _newSize = _newIO->size();
297  dataChanged = true;
298 
299  return true;
300 }
301 
302 bool IsoFile::setModifiedFile(const QByteArray &data)
303 {
304  QBuffer *io = new QBuffer();
305  io->setData(data);
306  _newIOMustBeRemoved = true;
307 
308  return setModifiedFile(io);
309 }
310 
312 {
313  if (_newIOMustBeRemoved && _newIO) {
314  delete _newIO;
315  _newIOMustBeRemoved = false;
316  }
317  _newIO = 0;
318 }
319 
321 {
323 }
324 
326 {
327  cleanNewIO();
328  dataChanged = false;
330 }
331 
333 {
334 }
335 
337  QFile(name)
338 {
339 }
340 
342 {
343 }
344 
345 bool IsoArchiveIO::open(QIODevice::OpenMode mode)
346 {
347  bool open = QFile::open(mode);
348  if(!open) return false;
349 
350  if(mode.testFlag(QIODevice::Truncate)) {
351  return true;
352  }
353 
354  reset();
355 
356  return true;
357 }
358 
359 qint64 IsoArchiveIO::posIso() const
360 {
361  return isoPos(pos());
362 }
363 
364 bool IsoArchiveIO::seekIso(qint64 off)
365 {
366  return seek(filePos(off));
367 }
368 
369 qint64 IsoArchiveIO::sizeIso() const
370 {
371  return isoPos(size());
372 }
373 
374 qint64 IsoArchiveIO::isoPos(qint64 pos)
375 {
376  qint64 start = (pos % SECTOR_SIZE) - SECTOR_SIZE_HEADER;
377  if(start < 0) {
378  start = 0;
379  } else if(start > SECTOR_SIZE_DATA) {
380  start = SECTOR_SIZE_DATA;
381  }
382 
383  return SECTOR_SIZE_DATA * (pos / SECTOR_SIZE) + start;
384 }
385 
386 qint64 IsoArchiveIO::filePos(qint64 pos)
387 {
389 }
390 
391 qint64 IsoArchiveIO::readIso(char *data, qint64 maxSize)
392 {
393  qint64 read, readTotal = 0, seqLen;
394 
395 // qDebug() << pos() << "seek >> " << seqLen;
396  if(!seekIso(isoPos(pos()))) return 0;
397 
398  seqLen = qMin(SECTOR_SIZE_HEADER + SECTOR_SIZE_DATA - (pos() % SECTOR_SIZE), maxSize);
399  if(seqLen < 0) return 0;
400 
401  while((read = this->read(data, seqLen)) > 0) {
402 // qDebug() << "read" << seqLen << read;
403  data += read;
404  maxSize -= read;
405  readTotal += read;
406  seqLen = qMin((qint64)SECTOR_SIZE_DATA, maxSize);
407 // qDebug() << "seqLen" << seqLen << maxSize << pos();
408  // Si on est à la fin du secteur
409  if(pos() % SECTOR_SIZE >= SECTOR_SIZE_HEADER + SECTOR_SIZE_DATA) {
410  if(!seek(pos() + SECTOR_SIZE_HEADER + SECTOR_SIZE_FOOTER)) break;
411 // qDebug() << "seek >> 304" << pos();
412  }
413  }
414 
415  return read < 0 ? read : readTotal;
416 }
417 
418 QByteArray IsoArchiveIO::readIso(qint64 maxSize)
419 {
420  char *data = new char[maxSize];
421 
422  QByteArray baData(data, readIso(data, maxSize));
423 
424  delete[] data;
425 
426  return baData;
427 }
428 
429 qint64 IsoArchiveIO::writeIso(const char *data, qint64 maxSize)
430 {
431  qint64 write, writeTotal = 0, seqLen;
432 
433 // qDebug() << pos() << "seek >> " << seqLen;
434  if(!seekIso(isoPos(pos()))) return 0;
435 
436  seqLen = qMin(SECTOR_SIZE_HEADER + SECTOR_SIZE_DATA - (pos() % SECTOR_SIZE), maxSize);
437 
438  while((write = this->write(data, seqLen)) > 0) {
439 // qDebug() << "write" << seqLen << write;
440  data += write;
441  maxSize -= write;
442  writeTotal += write;
443  seqLen = qMin((qint64)2048, maxSize);
444 // qDebug() << "seqLen" << seqLen << maxSize << pos();
445  // Si on est à la fin du secteur
447  if(!seek(pos() + SECTOR_SIZE_HEADER + SECTOR_SIZE_FOOTER)) break;
448 // qDebug() << "seek >> 304" << pos();
449  }
450  }
451 
452  return write < 0 ? write : writeTotal;
453 }
454 
455 qint64 IsoArchiveIO::writeIso(const QByteArray &byteArray)
456 {
457  return writeIso(byteArray.constData(), byteArray.size());
458 }
459 
460 QByteArray IsoArchiveIO::sectorHeader(quint32 num)
461 {
462  seek(SECTOR_SIZE * num);
463  return read(SECTOR_SIZE_HEADER);
464 }
465 
466 QByteArray IsoArchiveIO::sectorFooter(quint32 num)
467 {
469  return read(SECTOR_SIZE_FOOTER);
470 }
471 
472 QByteArray IsoArchiveIO::sector(quint32 num, quint16 maxSize)
473 {
474  seek(SECTOR_SIZE * num + SECTOR_SIZE_HEADER);
475  return read(qMin(maxSize, quint16(SECTOR_SIZE_DATA)));
476 }
477 
479 {
480  return pos() / SECTOR_SIZE;
481 }
482 
484 {
485  return size() / SECTOR_SIZE;
486 }
487 
488 quint32 IsoArchiveIO::sectorCountData(quint32 dataSize)
489 {
490  return dataSize / SECTOR_SIZE_DATA;
491 }
492 
493 bool IsoArchiveIO::seekToSector(quint32 num)
494 {
495  return seek(SECTOR_SIZE * num);
496 }
497 
498 bool IsoArchiveIO::writeSector(const QByteArray &data, quint8 type, quint8 mode)
499 {
500  qint64 dataSize = data.size();
501  quint32 sectorCur = currentSector();
502  QByteArray sectorData;
503 
504  Q_ASSERT(pos() % SECTOR_SIZE == 0);
505  Q_ASSERT(dataSize <= SECTOR_SIZE_DATA);
506 
507  // sector header
508  sectorData = buildHeader(sectorCur, type, mode);
509  // data
510  sectorData.append(data);
511  if(dataSize != SECTOR_SIZE_DATA) {
512  sectorData.append(QByteArray(SECTOR_SIZE_DATA - dataSize, '\x00'));
513  }
514  // sector footer
515  sectorData.append(buildFooter(sectorCur));
516 
517  return SECTOR_SIZE == write(sectorData);
518 }
519 
520 IsoFileIO::IsoFileIO(IsoArchiveIO *io, const IsoFile *infos, QObject *parent) :
521  QIODevice(parent), _io(io), _infos(infos)
522 {
523 }
524 
525 bool IsoFileIO::open(OpenMode mode) {
526  if(mode.testFlag(QIODevice::Append)
527  || mode.testFlag(QIODevice::Truncate)
528  || mode.testFlag(QIODevice::WriteOnly)) {
529  return false;
530  }
531  return QIODevice::open(mode);
532 }
533 
534 qint64 IsoFileIO::size() const
535 {
536  return _infos->size();
537 }
538 
539 qint64 IsoFileIO::readData(char *data, qint64 maxSize)
540 {
541  if(_io->seekToSector(_infos->location()) && _io->seekIso(_io->posIso() + pos())) {
542  qint64 size = this->size();
543  if(size < 0) {
544  return -1;
545  }
546  return _io->readIso(data, qMin(maxSize, size - pos()));
547  }
548  return -1;
549 }
550 
551 qint64 IsoFileIO::writeData(const char *data, qint64 maxSize)
552 {
553  Q_UNUSED(data)
554  Q_UNUSED(maxSize)
555  return -1;
556 }
557 
559 {
560  return pos() < size();
561 }
562 
564  _rootDirectory(NULL), _error(Archive::NoError)
565 {
566 }
567 
568 IsoArchive::IsoArchive(const QString &name) :
569  _io(name), _rootDirectory(NULL), _error(Archive::NoError)
570 {
571 }
572 
574 {
575  if(_rootDirectory != NULL) delete _rootDirectory;
576 }
577 
578 bool IsoArchive::open(QIODevice::OpenMode mode)
579 {
580  if(!_io.open(mode)) {
581  return false;
582  }
583 
584  if (mode.testFlag(QIODevice::Truncate)) {
585  return true;
586  }
587 
588  if(!openVolumeDescriptor()) {
589  qWarning() << "IsoArchive::open" << "cannot open volume descriptor";
590  _io.setErrorString("Cannot open volume descriptor");
591  return false;
592  }
593 // qDebug() << volumeDescriptorToString(volume);
594  qint64 size = _io.size();
595  if(size%SECTOR_SIZE != 0 || volume.vd1.volume_space_size != _io.sectorCount() || volume.vd1.id[0] != 'C' || volume.vd1.id[1] != 'D' || volume.vd1.id[2] != '0' || volume.vd1.id[3] != '0' || volume.vd1.id[4] != '1') {
596  qWarning() << "IsoArchive::open error archive size" << (size%SECTOR_SIZE) << volume.vd1.volume_space_size << _io.sectorCount();
597  _io.setErrorString("Archive size error");
598  return false;
599  }
600 
602  qWarning() << "IsoArchive::_open cannot open root directory";
603  _io.setErrorString("Cannot open root directory");
604  return false;
605  }
606 // pathTables1a = pathTable(volume.vd1.type_path_table, volume.vd1.path_table_size);
607 // pathTables1b = pathTable(volume.vd1.opt_type_path_table, volume.vd1.path_table_size);
608 // pathTables2a = pathTable(qFromBigEndian(volume.vd1.type_path_table2), volume.vd1.path_table_size);
609 // pathTables2b = pathTable(qFromBigEndian(volume.vd1.opt_type_path_table2), volume.vd1.path_table_size);
610 
611  /*qDebug() << "PATHTABLE1";
612  foreach(PathTable pt, pathTables1a)
613  qDebug() << pathTableToString(pt);
614  qDebug() << "PATHTABLE2";
615  foreach(PathTable pt, pathTables1b)
616  qDebug() << pathTableToString(pt);
617  qDebug() << "PATHTABLE3";
618  foreach(PathTable pt, pathTables2a)
619  qDebug() << pathTableToString(pt, true);
620  qDebug() << "PATHTABLE4";
621  foreach(PathTable pt, pathTables2b)
622  qDebug() << pathTableToString(pt, true);
623  */
624 
625  return true;
626 }
627 
629 {
630  _io.close();
631  if(_rootDirectory != NULL) {
632  delete _rootDirectory;
633  _rootDirectory = NULL;
634  }
635 }
636 
637 int IsoArchive::findPadding(const QList<IsoFileOrDirectory *> &filesWithPadding, quint32 minSectorCount)
638 {
639  int i=0;
640  foreach(IsoFileOrDirectory *fileOrDir, filesWithPadding) {
641  if(fileOrDir->paddingAfter() >= minSectorCount) {
642  return i;
643  }
644  ++i;
645  }
646 
647  return -1;
648 }
649 
655 bool IsoArchive::reorganizeModifiedFilesAfter(QMap<quint32, const IsoFile *> &writeToTheMain, QList<const IsoFile *> &writeToTheEnd)
656 {
657  Q_UNUSED(writeToTheMain)
658  Q_UNUSED(writeToTheEnd)
659  return true;
660 }
661 
662 bool IsoArchive::pack(IsoArchive *destination, ArchiveObserver *control, IsoDirectory *directory)
663 {
664  IsoArchiveIO *destinationIO = &(destination->_io);
665  QMap<quint32, const IsoFile *> writeToTheMain;
666  QList<const IsoFile *> writeToTheEnd;
667  QList<IsoFileOrDirectory *> filesWithPadding = getIntegrity();
668  IsoFileOrDirectory *lastFileWithPadding = filesWithPadding.isEmpty() ? NULL : filesWithPadding.last();
669  quint32 endOfIso = _io.sectorCount(),
670  sectorCountAtTheEnd = lastFileWithPadding ? (endOfIso - lastFileWithPadding->locationAfter()) : 0,
671  lastPadding = lastFileWithPadding ? lastFileWithPadding->paddingAfter() : 0,
672  endOfFilledIso, endOfFilledIsoAfter;
673 
674  if (lastFileWithPadding && sectorCountAtTheEnd == lastPadding) {
675  endOfFilledIso = lastFileWithPadding->locationAfter();
676  lastFileWithPadding->setPaddingAfter(0);
677  } else {
678  endOfFilledIso = endOfIso;
679  }
680  endOfFilledIsoAfter = endOfFilledIso;
681 
682  if(directory == NULL) {
683  directory = _rootDirectory;
684  if(directory == NULL) {
685  setError(Archive::OpenError, "Not opened to pack");
686  return false;
687  }
688  }
689 
690  foreach(IsoFile *isoFile, getModifiedFiles(directory)) {
691  // Est-ce que les nouvelles données sont plus grandes que les anciennes ? Est-ce qu'on est pas à la fin de l'archive ?
692  if(isoFile->newSectorCount() > isoFile->sectorCount() + isoFile->paddingAfter()
693  && isoFile->location() + isoFile->sectorCount() < _io.sectorCount()) {
694 //#ifdef ISOARCHIVE_DEBUG
695  qWarning() << "File too big" << isoFile->newSectorCount() << isoFile->sectorCount() << (isoFile->newSectorCount() - isoFile->sectorCount()) << isoFile->name();
696 //#endif
697  int index = findPadding(filesWithPadding, isoFile->newSectorCount());
698  if(index >= 0) {
699  IsoFileOrDirectory *fileWithPaddingAfter = filesWithPadding.at(index);
700  isoFile->setLocation(fileWithPaddingAfter->newLocation() + fileWithPaddingAfter->newSectorCount());
701  isoFile->setPaddingAfter(fileWithPaddingAfter->paddingAfter() - isoFile->newSectorCount());
702  fileWithPaddingAfter->setPaddingAfter(0);
703  if (isoFile->paddingAfter() > 0) {
704  filesWithPadding.replace(index, isoFile);
705  } else {
706  filesWithPadding.removeAt(index);
707  }
708  writeToTheMain.insert(isoFile->newLocation(), isoFile);
709 //#ifdef ISOARCHIVE_DEBUG
710  qWarning() << "Found enough space at" << fileWithPaddingAfter->name() << isoFile->newLocation() << "for" << isoFile->name();
711 //#endif
712  } else {
713  writeToTheEnd.append(isoFile);
714  isoFile->setLocation(endOfFilledIsoAfter);
715 //#ifdef ISOARCHIVE_DEBUG
716  qWarning() << "Add file at the end" << isoFile->name() << endOfFilledIsoAfter;
717 //#endif
718  endOfFilledIsoAfter += isoFile->newSectorCount();
719  }
720  } else {
721  if(isoFile->paddingAfter() > isoFile->newSectorCount() - isoFile->sectorCount())
722  isoFile->setPaddingAfter(isoFile->paddingAfter() - (isoFile->newSectorCount() - isoFile->sectorCount()));
723  writeToTheMain.insert(isoFile->newLocation(), isoFile);
724  }
725  }
726 
727  if(!reorganizeModifiedFilesAfter(writeToTheMain, writeToTheEnd)) {
728  return false;
729  }
730 
731  if(control) {
732  control->setObserverMaximum(endOfIso);
733  }
734 
735  destinationIO->reset();
736  _io.reset();
737 
738  foreach(const IsoFile *isoFile, writeToTheMain) {
739  if(control && control->observerWasCanceled()) {
741  return false;
742  }
743 
744  quint32 fileLocation = isoFile->newLocation();
745 
746  // Données avant le fichier
747  if(!copySectors(destinationIO, qint64(fileLocation) - qint64(_io.currentSector()), control)) {
748  return false;
749  }
750 
751 #ifdef ISOARCHIVE_DEBUG
752  if(destinationIO->pos() % SECTOR_SIZE != 0) qWarning() << "destination error 1a" << (destinationIO->pos() % SECTOR_SIZE) << isoFile->name();
753  if(destinationIO->currentSector() != fileLocation) qWarning() << "destination error 1b" << destinationIO->currentSector() << fileLocation << isoFile->name();
754  if(destinationIO->pos() != _io.pos()) qWarning() << "destination error 1c" << destinationIO->pos() << _io.pos() << isoFile->name();
755 #endif
756 
757  // On écrit le même nombre de secteurs que le fichier d'origine
758  if(!destination->writeFile(isoFile->modifiedFile(), isoFile->sectorCount() + isoFile->paddingAfter(), control)) {
759  return false;
760  }
761  _io.seek(destinationIO->pos());
762 
763 #ifdef ISOARCHIVE_DEBUG
764  if(destinationIO->pos() % SECTOR_SIZE != 0) qWarning() << "destination error 2a" << (destinationIO->pos() % SECTOR_SIZE) << isoFile->name();
765  if(destinationIO->currentSector() != _io.currentSector()) qWarning() << "destination error 2b" << destinationIO->currentSector() << _io.currentSector() << isoFile->name();
766  if(destinationIO->pos() != _io.pos()) qWarning() << "destination error 2c" << destinationIO->pos() << _io.pos() << isoFile->name();
767 #endif
768 
769  // Envoi de la position courante à l'output
770  if(control) control->setObserverValue(destinationIO->currentSector());
771  }
772 
773  // Données après les fichiers patchés
774  if(!copySectors(destinationIO, endOfFilledIso - _io.currentSector(), control)) {
775  return false;
776  }
777 
778 #ifdef ISOARCHIVE_DEBUG
779  if(destinationIO->pos() % SECTOR_SIZE != 0) qWarning() << "destination error 3a" << (destinationIO->pos() % SECTOR_SIZE);
780  if(destinationIO->currentSector() != endOfFilledIso) qWarning() << "destination error 3b" << destinationIO->currentSector() << _io.sectorCount();
781  if(destinationIO->pos() != _io.pos()) qWarning() << "destination error 3c" << destinationIO->pos() << _io.pos();
782 #endif
783 
784  // Fichiers trop gros mis à la fin de l'ISO
785  foreach(const IsoFile *isoFile, writeToTheEnd) {
786  if(control && control->observerWasCanceled()) {
788  return false;
789  }
790 #ifdef ISOARCHIVE_DEBUG
791  qWarning() << "Write file at the end" << isoFile->name() << destinationIO->currentSector();
792 #endif
793 
794  if(!destination->writeFile(isoFile->modifiedFile(), 0, control)) {
795  return false;
796  }
797 
798 #ifdef ISOARCHIVE_DEBUG
799  if(destinationIO->pos() % SECTOR_SIZE != 0) qWarning() << "destination error 3a" << (destinationIO->pos() % SECTOR_SIZE) << isoFile->name();
800 #endif
801 
802  // Envoi de la position courante à l'output
803  if(control) control->setObserverValue(destinationIO->currentSector());
804  }
805 
806  if(!copySectors(destinationIO, endOfIso - endOfFilledIso, control, true)) {
807  return false;
808  }
809 
810  // Modifications données
811 
812  if(destinationIO->size() != _io.size()) {
813 #ifdef ISOARCHIVE_DEBUG
814  qDebug() << "size iso !=" << destinationIO->sectorCount() << _io.sectorCount();
815 #endif
816  // volume_space_size (taille totale de l'ISO)
817  destinationIO->seekIso(SECTOR_SIZE_DATA * 16 + 80);// sector 16 : pos 80 size 4+4
818  quint32 volume_space_size = destinationIO->size() / SECTOR_SIZE, volume_space_size2 = qToBigEndian(volume_space_size);
819  destinationIO->write((char *)&volume_space_size, 4);
820  destinationIO->write((char *)&volume_space_size2, 4);
821  }
822 
823  // Update ISO files locations
824  repairLocationSectors(directory, destination);
825 
826  //Debug
827 
828  /* qDebug() << "check headers";
829  for(quint32 i = 0 ; i < destinationIO->sectorCount() ; ++i) {
830  if(control && control->observerWasCanceled()) return false;
831  destinationIO->seek(12 + i*SECTOR_SIZE);
832  if(destinationIO->peek(3) != IsoArchiveIO::int2Header(i)) {
833  qDebug() << "Error header" << i << destinationIO->peek(3).toHex();
834  break;
835  }
836  }
837  qDebug() << "check done"; */
838 
839 #ifdef ISOARCHIVE_DEBUG
840  if(destinationIO->size() % SECTOR_SIZE != 0) qWarning() << "Invalid size" << destinationIO->size();
841 #endif
842 
843  return true;
844 }
845 
846 bool IsoArchive::copySectors(IsoArchiveIO *out, qint64 sectorCount, ArchiveObserver *control, bool repair)
847 {
848  if (sectorCount < 0) {
849  qWarning() << "IsoArchive::copySectors sectorCount < 0" << sectorCount;
851  return false;
852  }
853 
854  Q_ASSERT(out->pos() % SECTOR_SIZE == 0);
855  Q_ASSERT(_io.pos() % SECTOR_SIZE == 0);
856 
857  for(int i = 0 ; i < sectorCount ; ++i) {
858  if(control && control->observerWasCanceled()) {
860  return false;
861  }
862 
863  QByteArray data = _io.read(SECTOR_SIZE);
864  if(data.size() != SECTOR_SIZE) {
865  qWarning() << "IsoArchive::copySectors read error" << data.size() << SECTOR_SIZE;
866  setError(Archive::ReadError, _io.errorString());
867  return false;
868  }
869 
870  if (!repair) {
871  if(out->write(data) != SECTOR_SIZE) {
872  qWarning() << "IsoArchive::copySectors write error" << data.size() << SECTOR_SIZE;
873  setError(Archive::WriteError, out->errorString());
874  return false;
875  }
876  } else {
877  quint8 type, mode;
878  IsoArchiveIO::headerInfos(data, &type, &mode);
879  if(!out->writeSector(data.mid(SECTOR_SIZE_HEADER, SECTOR_SIZE_DATA), type, mode)) {
880  qWarning() << "IsoArchive::copySectors writeSector error";
881  setError(Archive::WriteError, out->errorString());
882  return false;
883  }
884  }
885 
886  // Envoi de la position courante à l'output
887  if(control) control->setObserverValue(out->currentSector());
888  }
889 
890  return true;
891 }
892 
893 bool IsoArchive::writeFile(QIODevice *in, quint32 sectorCount, ArchiveObserver *control)
894 {
895  if(!in->isOpen() || !in->reset()) {
896  setError(Archive::OpenError, in->errorString());
897  return false;
898  }
899 
900  qint64 remainingSize = in->size();
901  const quint32 sectorStart = _io.currentSector();
902 
903  while(remainingSize > 0) {
904  if(control && control->observerWasCanceled()) {
906  return false;
907  }
908 
909  QByteArray sectorData;
910  qint64 toRead;
911  quint8 type;
912  if(remainingSize <= SECTOR_SIZE_DATA) { // Last sector of file
913  toRead = remainingSize;
914  type = 0x89;
915  } else {
916  toRead = SECTOR_SIZE_DATA;
917  type = 0x08;
918  }
919 
920  sectorData = in->read(toRead);
921  if(sectorData.size() != toRead) {
922  setError(Archive::ReadError, in->errorString());
923  return false;
924  }
925 
926  if(!_io.writeSector(sectorData, type)) {
927  setError(Archive::WriteError, _io.errorString());
928  return false;
929  }
930 
931  remainingSize = in->size() - in->pos();
932  }
933 
934  if(sectorCount != 0) {
935  // Write empty sectors
936  while(_io.currentSector() - sectorStart < sectorCount) {
937  if(control && control->observerWasCanceled()) {
939  return false;
940  }
941 
942  if(!_io.writeSector(QByteArray(), 0x20)) {
943  setError(Archive::WriteError, _io.errorString());
944  return false;
945  }
946  }
947  }
948 
949  return true;
950 }
951 
953 {
954  quint32 pos, oldSectorStart, newSectorStart, newSectorStart2, oldSize, newSize, newSize2;
955  QList<IsoDirectory *> dirs;
956 
957  foreach(IsoFileOrDirectory *fileOrDir, directory->filesAndDirectories()) {
958  if(fileOrDir->isModified()) {
959  pos = fileOrDir->structPosition + 2;
960  oldSectorStart = fileOrDir->location();
961  oldSize = fileOrDir->size();
962  newSectorStart = fileOrDir->newLocation();
963  newSize = fileOrDir->newSize();
964 
965  // location_extent
966  if(newSectorStart != oldSectorStart) {
967  newSectorStart2 = qToBigEndian(newSectorStart);
968  newIso->_io.seekIso(pos);
969  newIso->_io.writeIso((char *)&newSectorStart, 4);
970  newIso->_io.writeIso((char *)&newSectorStart2, 4);
971 // qDebug() << "nouvelle position" << fileOrDir->name() << oldSectorStart << newSectorStart;
972  }
973 
974  // data_length
975  if(newSize != oldSize) {
976  newSize2 = qToBigEndian(newSize);
977  newIso->_io.seekIso(pos + 8);
978  newIso->_io.writeIso((char *)&newSize, 4);
979  newIso->_io.writeIso((char *)&newSize2, 4);
980 // qDebug() << "nouvelle taille" << fileOrDir->name() << oldSize << newSize;
981  }
982  }
983 
984  if(fileOrDir->isDirectory()) {
985  dirs.append(static_cast<IsoDirectory *>(fileOrDir));
986  }
987  }
988 
989  foreach(IsoDirectory *d, dirs) {
990  repairLocationSectors(d, newIso);
991  }
992 }
993 
995 {
996  return _rootDirectory;
997 }
998 
999 /*const QList<PathTable> &IsoArchive::getPathTables1a() const
1000 {
1001  return pathTables1a;
1002 }
1003 
1004 const QList<PathTable> &IsoArchive::getPathTables1b() const
1005 {
1006  return pathTables1b;
1007 }
1008 
1009 const QList<PathTable> &IsoArchive::getPathTables2a() const
1010 {
1011  return pathTables2a;
1012 }
1013 
1014 const QList<PathTable> &IsoArchive::getPathTables2b() const
1015 {
1016  return pathTables2b;
1017 }*/
1018 
1020 {
1021 // qDebug() << "sizeof(VolumeDescriptor)" << sizeof(VolumeDescriptor1) << sizeof(VolumeDescriptor2) << sizeof(IsoTime) << sizeof(DirectoryRecord);
1022 
1023  if(!_io.seek(SECTOR_SIZE * (16 + num) + SECTOR_SIZE_HEADER)) {
1024  qWarning() << "1";
1025  return false;
1026  }
1027 // qint64 pos = this->pos();
1028  if(_io.read((char *)&volume.vd1, sizeof(VolumeDescriptor1)) != sizeof(VolumeDescriptor1)) {
1029  qWarning() << "2" << _io.pos();
1030  return false;
1031  }
1032 // qint64 pos2 = this->pos();
1033  if(_io.read((char *)&volume.dr.length_dr, 1) != 1) {
1034  qWarning() << "3";
1035  return false;
1036  }
1037  if(_io.read((char *)&volume.dr.extended_attr_record_length, 1) != 1) {
1038  qWarning() << "4";
1039  return false;
1040  }
1041  if(_io.peek((char *)&volume.dr.drh, sizeof(DirectoryRecordHead)) != sizeof(DirectoryRecordHead)) {
1042  qWarning() << "5";
1043  return false;
1044  }
1045  if(!_io.seek(_io.pos() + 31)) {
1046  qWarning() << "6";
1047  return false;
1048  }
1049  volume.dr.name = _io.read(qMin((int)volume.dr.drh.length_fi, MAX_FILENAME_LENGTH));
1050  if(_io.pos() & 1) {
1051  if(!_io.seek(_io.pos() + 1)) {// padding
1052  qWarning() << "7";
1053  return false;
1054  }
1055  }
1056 // qDebug() << "sizeDirectoryRecord : " << (this->pos() - pos2);
1057  if(_io.read((char *)&volume.vd2, sizeof(VolumeDescriptor2)) != sizeof(VolumeDescriptor2)) {
1058  qWarning() << "8";
1059  return false;
1060  }
1061 
1062 // qDebug() << "size : " << (this->pos() - pos);
1063  return true;
1064 }
1065 
1066 bool IsoArchive::openRootDirectory(quint32 sector, quint32 dataSize)
1067 {
1068  QList<quint32> dirVisisted;
1069  _rootDirectory = _openDirectoryRecord(new IsoDirectory(QString(), sector, dataSize, 0), dirVisisted);
1070  return _rootDirectory != NULL;
1071 }
1072 
1073 IsoDirectory *IsoArchive::_openDirectoryRecord(IsoDirectory *directories, QList<quint32> &dirVisisted)
1074 {
1075  const quint32 sector = directories->location(), dataSize = directories->size();
1076  // anti-loop forever
1077  if(dirVisisted.contains(sector)) return directories;
1078  for(quint32 i=0 ; i<_io.sectorCountData(dataSize) ; ++i)
1079  dirVisisted.append(sector + i);
1080 
1081  if(!_io.seekToSector(sector)) {
1082  goto _openDirectoryRecordError;
1083  }
1084 
1085  {
1086  const quint32 maxPos = _io.posIso() + dataSize;
1087 
1088  while(_io.posIso() < maxPos) {
1089  DirectoryRecord dr;
1090  const qint64 beginPos = _io.posIso();
1091 
1092  if(_io.readIso((char *)&dr.length_dr, 1) != 1) {
1093  qWarning() << "IsoArchive::_openDirectoryRecord cannot read length_dr at" << beginPos;
1094  goto _openDirectoryRecordError;
1095  }
1096 
1097  if(dr.length_dr == 0) {
1098  // Next sector
1100  continue;
1101  }
1102 
1103  if(_io.readIso((char *)&dr.extended_attr_record_length, 1) != 1) {
1104  qWarning() << "IsoArchive::_openDirectoryRecord cannot read extended_attr_record_length at" << beginPos;
1105  goto _openDirectoryRecordError;
1106  }
1107  if(_io.readIso((char *)&dr.drh, sizeof(DirectoryRecordHead)) != sizeof(DirectoryRecordHead)) {
1108  qWarning() << "IsoArchive::_openDirectoryRecord cannot read drh at" << beginPos;
1109  goto _openDirectoryRecordError;
1110  }
1111 
1112  if(dr.drh.length_fi > MAX_FILENAME_LENGTH) {
1113  qWarning() << "IsoArchive::_openDirectoryRecord length filename >" << MAX_FILENAME_LENGTH << dr.drh.length_fi;
1114  goto _openDirectoryRecordError;
1115  }
1116 
1117  if(!_io.seekIso(beginPos + 33)) {
1118  qWarning() << "IsoArchive::_openDirectoryRecord cannot seek to" << beginPos + 33;
1119  goto _openDirectoryRecordError;
1120  }
1121 
1122  dr.name = _io.readIso(dr.drh.length_fi);
1123  int index = dr.name.lastIndexOf(SEPARATOR_2);
1124  //dr.version = dr.name.mid(index+1);
1125  dr.name = dr.name.left(index);
1126  if(!_io.seekIso(beginPos + dr.length_dr)) {
1127  qWarning() << "IsoArchive::_openDirectoryRecord cannot seek to" << beginPos + + dr.length_dr;
1128  goto _openDirectoryRecordError;
1129  }
1130 
1131 // qDebug() << directoryRecordToString(dr) << beginPos;
1132 
1133  if((dr.drh.file_flags >> 1) & 1) { // Directory
1134  directories->add(new IsoDirectory(dr.name, dr.drh.location_extent, dr.drh.data_length, beginPos));
1135  } else {
1136  directories->add(new IsoFile(dr.name, dr.drh.location_extent, dr.drh.data_length, beginPos, &_io));
1137  }
1138  }
1139 
1140  foreach(IsoDirectory *dir, directories->directories()) {
1141  if(!dir->isSpecial()) {
1142 // qDebug() << "IN DIR" << dir->name() << dir->location();
1143  if(!_openDirectoryRecord(dir, dirVisisted)) {
1144  qWarning() << "IsoArchive::_openDirectoryRecord cannot open directory" << dir->name() << dir->location();
1145  goto _openDirectoryRecordError;
1146  }
1147 // qDebug() << "OUT DIR" << dir->name();
1148  }
1149  }
1150 
1151  return directories;
1152  }
1153 _openDirectoryRecordError:
1154  delete directories;
1155  return NULL;
1156 }
1157 
1158 /*QList<PathTable> IsoArchive::pathTable(quint32 sector, quint32 dataSize)
1159 {
1160  QList<PathTable> pathTables;
1161 
1162  if(!_io.seekToSector(sector)) {
1163  return pathTables;
1164  }
1165  const quint32 maxPos = _io.posIso() + dataSize;
1166 
1167  while(_io.posIso() < maxPos) {
1168  PathTable pt;
1169  pt.position = _io.posIso();
1170 
1171  if(_io.readIso((char *)&pt.length_di, 1) != 1
1172  || _io.readIso((char *)&pt.extended_attr_record_length, 1) != 1
1173  || _io.readIso((char *)&pt.location_extent, 4) != 4
1174  || _io.readIso((char *)&pt.parent_directory_number, 2) != 2) {
1175  break;
1176  }
1177  pt.name = _io.readIso(pt.length_di);
1178  if(pt.length_di & 1) {
1179  if(!_io.seekIso(_io.posIso() + 1)) {
1180  break;
1181  }
1182  }
1183 
1184  pathTables.append(pt);
1185  }
1186 
1187  return pathTables;
1188 }*/
1189 
1190 QByteArray IsoArchive::file(const QString &path, quint32 maxSize) const
1191 {
1192  if (_rootDirectory == NULL) {
1193  return QByteArray();
1194  }
1195  IsoFile *file = _rootDirectory->file(path);
1196  if (file == NULL) {
1197  return QByteArray();
1198  }
1199  return file->data(maxSize);
1200 }
1201 
1202 QIODevice *IsoArchive::fileDevice(const QString &path) const
1203 {
1204  if (_rootDirectory == NULL) {
1205  return NULL;
1206  }
1207  IsoFile *file = _rootDirectory->file(path);
1208  if (file == NULL) {
1209  return NULL;
1210  }
1211  return file->file();
1212 }
1213 
1214 QByteArray IsoArchive::modifiedFile(const QString &path, quint32 maxSize) const
1215 {
1216  if (_rootDirectory == NULL) {
1217  return QByteArray();
1218  }
1219  IsoFile *file = _rootDirectory->file(path);
1220  if (file == NULL) {
1221  return QByteArray();
1222  }
1223  return file->modifiedData(maxSize);
1224 }
1225 
1226 QIODevice *IsoArchive::modifiedFileDevice(const QString &path) const
1227 {
1228  if (_rootDirectory == NULL) {
1229  return NULL;
1230  }
1231  IsoFile *file = _rootDirectory->file(path);
1232  if (file == NULL) {
1233  return NULL;
1234  }
1235  return file->modifiedFile();
1236 }
1237 
1238 bool IsoArchive::extract(const QString &path, const QString &destination, quint32 maxSize) const
1239 {
1240  if (_rootDirectory == NULL) {
1241  return false;
1242  }
1243  IsoFile *file = _rootDirectory->file(path);
1244  if (file == NULL) {
1245  return false;
1246  }
1247  return file->extract(destination, maxSize);
1248 }
1249 
1250 bool IsoArchive::extractDir(const QString &path, const QString &destination) const
1251 {
1252  if (_rootDirectory == NULL) {
1253  return false;
1254  }
1255  IsoDirectory *dir = _rootDirectory->directory(path);
1256  if (dir == NULL) {
1257  return false;
1258  }
1259  QDir destDir(destination);
1260  bool error = false;
1261 
1262  foreach (IsoFile *file, dir->files()) {
1263  if (!file->extract(destDir.filePath(file->name()))) {
1264  error = true;
1265  }
1266  }
1267 
1268  return error;
1269 }
1270 
1271 void IsoArchive::extractAll(const QString &destination) const
1272 {
1273  if (_rootDirectory == NULL) {
1274  return;
1275  }
1276  _extractAll(destination, _rootDirectory);
1277 }
1278 
1279 void IsoArchive::_extractAll(const QString &destination, IsoDirectory *directories, QString currentInternalDir) const
1280 {
1281 // QTime t;t.start();
1282 
1283  QDir dir(destination);
1284  QString currentPath = dir.absolutePath().append('/');
1285 // qDebug() << currentPath;
1286  foreach(IsoFileOrDirectory *fileOrDir, directories->filesAndDirectories()) {
1287  QCoreApplication::processEvents();
1288 
1289  if(fileOrDir->isDirectory())// Directory
1290  {
1291  if(!fileOrDir->isSpecial()) {
1292  dir.mkdir(fileOrDir->name());
1293  _extractAll(currentPath + fileOrDir->name(), static_cast<IsoDirectory *>(fileOrDir), currentInternalDir.isEmpty() ? fileOrDir->name() : currentInternalDir + '/' + fileOrDir->name());
1294  }
1295  }
1296  else
1297  {
1298 // qDebug() << fileOrDir->name();
1299  extract(currentInternalDir.isEmpty() ? fileOrDir->name() : currentInternalDir + '/' + fileOrDir->name(), currentPath + fileOrDir->name());
1300  }
1301  }
1302 
1303 // qDebug() << "time" << t.elapsed();
1304 }
1305 
1306 qint32 IsoArchive::diffCountSectors(const QString &path, quint32 newSize) const
1307 {
1308  if(_rootDirectory == NULL) {
1309  return false;
1310  }
1312  if(isoFile == NULL) {
1313  return false;
1314  }
1315 
1316  return _io.sectorCountData(newSize - isoFile->size());
1317 }
1318 
1319 //bool IsoArchive::insert(QString path, QString newISO, QByteArray data)
1320 //{
1321 // QTime t;t.start();
1322 
1323 // IsoFile *isoFile = _rootDirectory->file(path);
1324 // if(isoFile == NULL) {
1325 // return false;
1326 // }
1327 
1328 // seekToFile(isoFile);
1329 
1330 // qDebug() << "time" << t.elapsed();
1331 
1332 // return true;
1333 //}
1334 
1336 {
1337  if(prevFile != NULL) {
1338  prevFile->setPaddingAfter(fileLocation - prevFile->locationAfter());
1339 
1340  if(prevFile->paddingAfter() > 0) {
1341  QByteArray sectorHeaderEmpty("\x00\x00\x20\x00\x00\x00\x20\x00", 8),
1342  sectorHeaderVoid(8, '\0');
1343  int sector;
1344 
1345  for (sector = 0 ; sector < prevFile->paddingAfter() ; ++sector) {
1346  QByteArray sectorHeaderPart = _io.sectorHeader(prevFile->locationAfter() + sector).mid(0x10, 8);
1347  if (sectorHeaderPart != sectorHeaderEmpty
1348  && sectorHeaderPart != sectorHeaderVoid) {
1349  break;
1350  }
1351  }
1352 
1353 #ifdef ISOARCHIVE_DEBUG
1354  if(sector > 0) {
1355  qDebug() << QString("%1 -> %2 (%3 sectors, %4 empty) : padding after %5 (%6 sectors)")
1356  .arg(prevFile->locationAfter())
1357  .arg(fileLocation)
1358  .arg(prevFile->paddingAfter())
1359  .arg(sector)
1360  .arg(prevFile->name())
1361  .arg(prevFile->sectorCount());
1362  }
1363 #endif
1364 
1365  prevFile->setPaddingAfter(sector);
1366 
1367  return true;
1368  }
1369  }
1370 
1371  return false;
1372 }
1373 
1374 QList<IsoFileOrDirectory *> IsoArchive::getIntegrity()
1375 {
1376  QMap<quint32, IsoFileOrDirectory *> files;
1377  QList<IsoFileOrDirectory *> filesWithPadding;
1378 
1379  _getIntegrity(files, _rootDirectory);
1380 
1381  IsoFileOrDirectory *prevFile = NULL;
1382 
1383  QMapIterator<quint32, IsoFileOrDirectory *> i(files);
1384  while (i.hasNext()) {
1385  i.next();
1386  IsoFileOrDirectory *file = i.value();
1387 
1388  if (getIntegritySetPaddingAfter(prevFile, file->location())) {
1389  filesWithPadding.append(prevFile);
1390  }
1391 
1392  prevFile = file;
1393  }
1394 
1395  if (prevFile && getIntegritySetPaddingAfter(prevFile, _io.sectorCount())) {
1396  filesWithPadding.append(prevFile);
1397  }
1398 
1399  return filesWithPadding;
1400 }
1401 
1402 void IsoArchive::_getIntegrity(QMap<quint32, IsoFileOrDirectory *> &files, IsoDirectory *directory) const
1403 {
1404  foreach(IsoFileOrDirectory *fileOrDir, directory->filesAndDirectories()) {
1405  if(!fileOrDir->isSpecial()) {
1406  files.insert(fileOrDir->location(), fileOrDir);
1407 
1408  if(fileOrDir->isDirectory()) {
1409  _getIntegrity(files, static_cast<IsoDirectory *>(fileOrDir));
1410  }
1411  }
1412  }
1413 }
1414 
1415 QMap<quint32, IsoFile *> IsoArchive::getModifiedFiles(IsoDirectory *directory) const
1416 {
1417  QMap<quint32, IsoFile *> ret;
1418  getModifiedFiles(ret, directory);
1419  return ret;
1420 }
1421 
1422 void IsoArchive::getModifiedFiles(QMap<quint32, IsoFile *> &files, IsoDirectory *directory) const
1423 {
1424  foreach(IsoFileOrDirectory *fileOrDir, directory->filesAndDirectories()) {
1425  if(fileOrDir->isDirectory()) {
1426  getModifiedFiles(files, static_cast<IsoDirectory *>(fileOrDir));
1427  } else if(static_cast<IsoFile *>(fileOrDir)->isModified()) {
1428  files.insert(fileOrDir->newLocation(), static_cast<IsoFile *>(fileOrDir));
1429  }
1430  }
1431 }
1432 
1434 {
1435  foreach(IsoFileOrDirectory *fileOrDir, directory->filesAndDirectories()) {
1436  if(fileOrDir->isDirectory()) {
1437  applyModifications(static_cast<IsoDirectory *>(fileOrDir));
1438  }
1439  if(fileOrDir->isModified()) {
1440  fileOrDir->applyModifications();
1441  }
1442  }
1443 }
1444 
1450 {
1451  return _error;
1452 }
1453 
1459 {
1460  _error = error;
1461  _io.setErrorString(errorString);
1462 }
1463 
1464 #ifdef ISOARCHIVE_DEBUG
1465 
1466 QString IsoArchive::isoTimeToString(const IsoTime &time)
1467 {
1468  return QString("%1/%2/%3 %4:%5:%6 (%7ms) [GMT%8]").arg(
1469  QByteArray((char *)time.day, 2),
1470  QByteArray((char *)time.month, 2),
1471  QByteArray((char *)time.year, 4),
1472  QByteArray((char *)time.hour, 2),
1473  QByteArray((char *)time.minute, 2),
1474  QByteArray((char *)time.second, 2),
1475  QByteArray((char *)time.millis, 2),
1476  QString("%1%2").arg(time.GMT >= 0 ? "+" : "").arg(time.GMT));
1477 }
1478 
1479 QString IsoArchive::volumeDescriptorToString(const VolumeDescriptor &vd)
1480 {
1481  QString out;
1482  out.append("struct VolumeDescriptor {\n");
1483  out.append(QString("\t type = %1\n").arg(vd.vd1.type, 2, 16, QChar('0')));
1484  out.append(QString("\t id = %1\n").arg(QString(QByteArray((char *)vd.vd1.id, sizeof(vd.vd1.id)))));
1485  out.append(QString("\t version = %1\n").arg(vd.vd1.version));
1486  if(vd.vd1.type != 0xff) {
1487  out.append(QString("\t system_id = %1\n").arg(QString(QByteArray((char *)vd.vd1.system_id, sizeof(vd.vd1.system_id)))));
1488  out.append(QString("\t volume_id = %1\n").arg(QString(QByteArray((char *)vd.vd1.volume_id, sizeof(vd.vd1.volume_id)))));
1489  out.append(QString("\t volume_space_size = %1\n").arg(vd.vd1.volume_space_size));
1490  out.append(QString("\t volume_space_size2 = %1\n").arg(qFromBigEndian(vd.vd1.volume_space_size2)));
1491  out.append(QString("\t volume_set_size = %1\n").arg(vd.vd1.volume_set_size));
1492  out.append(QString("\t volume_set_size2 = %1\n").arg(qFromBigEndian(vd.vd1.volume_set_size2)));
1493  out.append(QString("\t volume_sequence_number = %1\n").arg(vd.vd1.volume_sequence_number));
1494  out.append(QString("\t volume_sequence_number2 = %1\n").arg(qFromBigEndian(vd.vd1.volume_sequence_number2)));
1495  out.append(QString("\t logical_block_size = %1\n").arg(vd.vd1.logical_block_size));
1496  out.append(QString("\t logical_block_size2 = %1\n").arg(qFromBigEndian(vd.vd1.logical_block_size2)));
1497  out.append(QString("\t path_table_size = %1\n").arg(vd.vd1.path_table_size));
1498  out.append(QString("\t path_table_size2 = %1\n").arg(qFromBigEndian(vd.vd1.path_table_size2)));
1499  out.append(QString("\t type_path_table = %1\n").arg(vd.vd1.type_path_table));
1500  out.append(QString("\t opt_type_path_table = %1\n").arg(vd.vd1.opt_type_path_table));
1501  out.append(QString("\t type_path_table2 = %1\n").arg(qFromBigEndian(vd.vd1.type_path_table2)));
1502  out.append(QString("\t opt_type_path_table2 = %1\n").arg(qFromBigEndian(vd.vd1.opt_type_path_table2)));
1503  out.append("\t ====================\n");
1504  out.append(directoryRecordToString(vd.dr));
1505  out.append("\t ====================\n");
1506  out.append(QString("\t volume_set_id = %1\n").arg(QString(QByteArray((char *)vd.vd2.volume_set_id, sizeof(vd.vd2.volume_set_id)))));
1507  out.append(QString("\t publisher_id = %1\n").arg(QString(QByteArray((char *)vd.vd2.publisher_id, sizeof(vd.vd2.publisher_id)))));
1508  out.append(QString("\t preparer_id = %1\n").arg(QString(QByteArray((char *)vd.vd2.preparer_id, sizeof(vd.vd2.preparer_id)))));
1509  out.append(QString("\t application_id = %1\n").arg(QString(QByteArray((char *)vd.vd2.application_id, sizeof(vd.vd2.application_id)))));
1510  out.append(QString("\t copyright_file_id = %1\n").arg(QString(QByteArray((char *)vd.vd2.copyright_file_id, sizeof(vd.vd2.copyright_file_id)))));
1511  out.append(QString("\t abstract_file_id = %1\n").arg(QString(QByteArray((char *)vd.vd2.abstract_file_id, sizeof(vd.vd2.abstract_file_id)))));
1512  out.append(QString("\t bibliographic_file_id = %1\n").arg(QString(QByteArray((char *)vd.vd2.bibliographic_file_id, sizeof(vd.vd2.bibliographic_file_id)))));
1513  out.append(QString("\t creation_date = %1\n").arg(isoTimeToString(vd.vd2.creation_date)));
1514  out.append(QString("\t file_structure_version = %1\n").arg(vd.vd2.file_structure_version));
1515  out.append(QString("\t application_data = %1\n").arg(QString(QByteArray((char *)vd.vd2.application_data, sizeof(vd.vd2.application_data)).toHex())));
1516  }
1517  out.append("}");
1518 
1519  return out;
1520 }
1521 
1522 QString IsoArchive::directoryRecordToString(const DirectoryRecord &dr)
1523 {
1524  QString out;
1525  out.append("struct DirectoryRecord {\n");
1526  out.append(QString("\t length_dr = %1\n").arg(dr.length_dr));
1527  out.append(QString("\t extended_attr_record_length = %1\n").arg(dr.extended_attr_record_length));
1528  out.append(QString("\t location_extent = %1\n").arg(dr.drh.location_extent));
1529  out.append(QString("\t location_extent2 = %1\n").arg(qFromBigEndian(dr.drh.location_extent2)));
1530  out.append(QString("\t data_length = %1\n").arg(dr.drh.data_length));
1531  out.append(QString("\t data_length2 = %1\n").arg(qFromBigEndian(dr.drh.data_length2)));
1532  out.append(QString("\t %3/%2/%1 %4:%5:%6 [GMT%7]\n").arg(dr.drh.year, 2, 10, QChar('0')).arg(dr.drh.month, 2, 10, QChar('0')).arg(dr.drh.day, 2, 10, QChar('0')).arg(dr.drh.hour, 2, 10, QChar('0')).arg(dr.drh.minute, 2, 10, QChar('0')).arg(dr.drh.second, 2, 10, QChar('0')).arg(QString("%1%2").arg(dr.drh.GMT >= 0 ? "+" : "").arg(dr.drh.GMT)));
1533  out.append(QString("\t file_flags = %1\n").arg(dr.drh.file_flags, 8, 2, QChar('0')));
1534  out.append(QString("\t file_unit_size = %1\n").arg(dr.drh.file_unit_size));
1535  out.append(QString("\t interleave_grap_size = %1\n").arg(dr.drh.interleave_grap_size));
1536  out.append(QString("\t volume_sequence_number = %1\n").arg(dr.drh.volume_sequence_number));
1537  out.append(QString("\t volume_sequence_number2 = %1\n").arg(qFromBigEndian(dr.drh.volume_sequence_number2)));
1538  out.append(QString("\t length_fi = %1\n").arg(dr.drh.length_fi));
1539  out.append(QString("\t name = %1\n").arg(dr.name));
1540  out.append("}");
1541  return out;
1542 }
1543 
1544 QString IsoArchive::pathTableToString(const PathTable &pathTable, bool bigEndian)
1545 {
1546  QString out;
1547  out.append("struct PathTable {\n");
1548  out.append(QString("\t length_di = %1\n").arg(pathTable.length_di));
1549  out.append(QString("\t extended_attr_record_length = %1\n").arg(pathTable.extended_attr_record_length));
1550  out.append(QString("\t location_extent = %1\n").arg(bigEndian ? qFromBigEndian(pathTable.location_extent) : pathTable.location_extent));
1551  out.append(QString("\t parent_directory_number = %1\n").arg(bigEndian ? qFromBigEndian(pathTable.parent_directory_number) : pathTable.parent_directory_number));
1552  out.append(QString("\t name = %1\n").arg(pathTable.name));
1553  out.append("}");
1554  return out;
1555 }
1556 
1557 #endif
bool seekIso(qint64 off)
Definition: IsoArchive.cpp:364
const IsoFile * _infos
Definition: IsoArchive.h:300
quint32 currentSector() const
Definition: IsoArchive.cpp:478
QByteArray sectorFooter(quint32 num)
Definition: IsoArchive.cpp:466
bool setModifiedFile(QIODevice *io)
Definition: IsoArchive.cpp:288
quint32 newLocation() const
Definition: IsoArchive.cpp:55
Archive::ArchiveError _error
Definition: IsoArchive.h:374
quint16 volume_sequence_number2
Definition: IsoArchive.h:104
IsoDirectory * rootDirectory() const
Definition: IsoArchive.cpp:994
char hour[2]
Definition: IsoArchive.h:45
virtual bool isDirectory() const =0
quint32 type_path_table2
Definition: IsoArchive.h:111
qint64 readIso(char *data, qint64 maxSize)
Definition: IsoArchive.cpp:391
virtual bool reorganizeModifiedFilesAfter(QMap< quint32, const IsoFile * > &writeToTheMain, QList< const IsoFile * > &writeToTheEnd)
Used to extend IsoArchive. Called in pack() afer file reorganization.
Definition: IsoArchive.cpp:655
IsoFile(const QString &name, quint32 location, quint32 size, qint64 structPosition, IsoArchiveIO *io)
Definition: IsoArchive.cpp:208
#define MAX_FILENAME_LENGTH
Definition: IsoArchive.h:25
#define SECTOR_SIZE_FOOTER
Definition: IsoArchive.h:31
IsoFile * file(const QString &path) const
Definition: IsoArchive.cpp:177
quint32 location() const
Definition: IsoArchive.cpp:35
quint8 volume_id[32]
Definition: IsoArchive.h:96
virtual ~IsoArchive()
Definition: IsoArchive.cpp:573
VolumeDescriptor2 vd2
Definition: IsoArchive.h:136
void _getIntegrity(QMap< quint32, IsoFileOrDirectory * > &files, IsoDirectory *directory) const
quint8 file_structure_version
Definition: IsoArchive.h:127
IsoDirectory * _openDirectoryRecord(IsoDirectory *directories, QList< quint32 > &dirVisisted)
IsoDirectory * directory(const QString &path) const
Definition: IsoArchive.cpp:190
QList< IsoFileOrDirectory * > getIntegrity()
virtual void close()
Definition: IsoArchive.cpp:628
quint16 volume_sequence_number
Definition: IsoArchive.h:76
quint8 publisher_id[128]
Definition: IsoArchive.h:117
quint8 extended_attr_record_length
Definition: IsoArchive.h:83
static qint64 isoPos(qint64 pos)
Definition: IsoArchive.cpp:374
static int findPadding(const QList< IsoFileOrDirectory * > &filesWithPadding, quint32 minSectorCount)
Definition: IsoArchive.cpp:637
QIODevice * fileDevice(const QString &path) const
quint8 bibliographic_file_id[37]
Definition: IsoArchive.h:122
QMap< QString, IsoFileOrDirectory * > _filesAndDirectories
Definition: IsoArchive.h:208
QString errorString() const
Definition: IsoArchive.h:321
virtual ~IsoDirectory()
Definition: IsoArchive.cpp:116
void setName(const QString &name)
Definition: IsoArchive.cpp:70
void _extractAll(const QString &destination, IsoDirectory *directories, QString currentInternalDir=QString()) const
void setFile(QIODevice *io)
Definition: IsoArchive.cpp:283
quint8 abstract_file_id[37]
Definition: IsoArchive.h:121
char year[4]
Definition: IsoArchive.h:42
static QByteArray buildFooter(quint32 sector)
Definition: IsoArchive.h:251
char minute[2]
Definition: IsoArchive.h:46
quint16 logical_block_size
Definition: IsoArchive.h:105
char second[2]
Definition: IsoArchive.h:47
bool openRootDirectory(quint32 sector, quint32 dataSize=SECTOR_SIZE_DATA)
quint16 volume_sequence_number2
Definition: IsoArchive.h:77
quint8 length_dr
Definition: IsoArchive.h:82
quint16 volume_set_size
Definition: IsoArchive.h:101
qint64 sizeIso() const
Definition: IsoArchive.cpp:369
bool openVolumeDescriptor(quint8 num=0)
#define SECTOR_SIZE_DATA
Definition: IsoArchive.h:30
bool extractDir(const QString &path, const QString &destination) const
quint32 location_extent
Definition: IsoArchive.h:55
quint16 volume_sequence_number
Definition: IsoArchive.h:103
QByteArray modifiedData(quint32 maxSize=0) const
Definition: IsoArchive.cpp:236
quint32 data_length2
Definition: IsoArchive.h:65
quint32 newSize() const
Definition: IsoArchive.cpp:60
bool extract(const QString &destination, quint32 maxSize=0) const
Definition: IsoArchive.cpp:245
quint16 volume_set_size2
Definition: IsoArchive.h:102
qint32 diffCountSectors(const QString &path, quint32 newSize) const
bool isDirectory() const
Definition: IsoArchive.cpp:222
quint32 _newLocation
Definition: IsoArchive.h:166
quint32 location_extent2
Definition: IsoArchive.h:63
quint8 paddingAfter() const
Definition: IsoArchive.cpp:106
quint32 sectorCount() const
Definition: IsoArchive.cpp:50
void cleanNewIO()
Definition: IsoArchive.cpp:311
static qint64 filePos(qint64 pos)
Definition: IsoArchive.cpp:386
quint8 application_data[512]
Definition: IsoArchive.h:129
bool getIntegritySetPaddingAfter(IsoFileOrDirectory *prevFile, quint32 fileLocation)
virtual void applyModifications()
Definition: IsoArchive.cpp:90
#define SEPARATOR_2
Definition: IsoArchive.h:27
bool dataChanged
Definition: IsoArchive.h:190
QByteArray data(quint32 maxSize=0) const
Definition: IsoArchive.cpp:227
bool canReadLine() const
Definition: IsoArchive.cpp:558
const QMap< QString, IsoFileOrDirectory * > & filesAndDirectories() const
Definition: IsoArchive.cpp:126
virtual void setObserverMaximum(unsigned int max)=0
QIODevice * modifiedFile() const
Definition: IsoArchive.cpp:275
quint8 system_id[32]
Definition: IsoArchive.h:95
quint32 type_path_table
Definition: IsoArchive.h:109
quint8 preparer_id[128]
Definition: IsoArchive.h:118
quint8 application_id[128]
Definition: IsoArchive.h:119
virtual bool open(QIODevice::OpenMode mode)
Definition: IsoArchive.cpp:578
quint8 extended_attr_record_length
Definition: IsoArchive.h:54
bool isModified() const
Definition: IsoArchive.cpp:320
quint32 volume_space_size2
Definition: IsoArchive.h:99
bool writeFile(QIODevice *in, quint32 sectorCount=0, ArchiveObserver *control=NULL)
Definition: IsoArchive.cpp:893
qint8 GMT
Definition: IsoArchive.h:49
qint64 readData(char *data, qint64 maxSize)
Definition: IsoArchive.cpp:539
QByteArray modifiedFile(const QString &path, quint32 maxSize=0) const
DirectoryRecordHead drh
Definition: IsoArchive.h:84
void applyModifications()
Definition: IsoArchive.cpp:325
quint32 location_extent
Definition: IsoArchive.h:62
void setError(Archive::ArchiveError error, const QString &errorString=QString())
Sets the file&#39;s error type and text.
IsoDirectory * _rootDirectory
Definition: IsoArchive.h:373
quint32 size() const
Definition: IsoArchive.cpp:45
quint16 parent_directory_number
Definition: IsoArchive.h:56
qint64 size() const
Definition: IsoArchive.cpp:534
quint32 opt_type_path_table
Definition: IsoArchive.h:110
void extractAll(const QString &destination) const
IsoArchiveIO _io
Definition: IsoArchive.h:371
virtual ~IsoFileOrDirectory()
Definition: IsoArchive.cpp:26
bool isSpecial() const
Definition: IsoArchive.cpp:96
bool open(OpenMode mode)
Definition: IsoArchive.cpp:525
quint16 logical_block_size2
Definition: IsoArchive.h:106
quint32 locationAfter() const
Definition: IsoArchive.cpp:40
qint64 writeData(const char *data, qint64 maxSize)
Definition: IsoArchive.cpp:551
quint32 path_table_size2
Definition: IsoArchive.h:108
QIODevice * _newIO
Definition: IsoArchive.h:189
void setLocation(quint32 location)
Definition: IsoArchive.cpp:75
virtual void setObserverValue(int value)=0
QByteArray sectorHeader(quint32 num)
Definition: IsoArchive.cpp:460
const QString & name() const
Definition: IsoArchive.cpp:30
virtual bool observerWasCanceled() const =0
void add(IsoFileOrDirectory *fileOrDirectory)
Definition: IsoArchive.cpp:203
The Archive class is a device list in a file system or an archive file.
Definition: Archive.h:31
QByteArray file(const QString &path, quint32 maxSize=0) const
VolumeDescriptor volume
Definition: IsoArchive.h:372
qint64 posIso() const
Definition: IsoArchive.cpp:359
ArchiveError
Definition: Archive.h:34
quint8 copyright_file_id[37]
Definition: IsoArchive.h:120
Archive::ArchiveError error() const
Returns the last error status.
quint32 sectorCount() const
Definition: IsoArchive.cpp:483
quint32 opt_type_path_table2
Definition: IsoArchive.h:112
qint64 writeIso(const char *data, qint64 maxSize)
Definition: IsoArchive.cpp:429
void setPaddingAfter(quint8 after)
Definition: IsoArchive.cpp:101
IsoTime creation_date
Definition: IsoArchive.h:123
quint8 interleave_grap_size
Definition: IsoArchive.h:75
VolumeDescriptor1 vd1
Definition: IsoArchive.h:134
bool copySectors(IsoArchiveIO *out, qint64 size, ArchiveObserver *control=NULL, bool repair=false)
Definition: IsoArchive.cpp:846
virtual ~IsoArchiveIO()
Definition: IsoArchive.cpp:341
IsoDirectory(const QString &name, quint32 location, quint32 size, qint64 structPosition)
Definition: IsoArchive.cpp:111
bool open(QIODevice::OpenMode mode)
Definition: IsoArchive.cpp:345
bool writeSector(const QByteArray &data, quint8 type, quint8 mode=2)
Definition: IsoArchive.cpp:498
quint8 id[5]
Definition: IsoArchive.h:92
quint8 volume_set_id[128]
Definition: IsoArchive.h:116
#define SECTOR_SIZE_HEADER
Definition: IsoArchive.h:29
DirectoryRecord dr
Definition: IsoArchive.h:135
QByteArray sector(quint32 num, quint16 maxSize=SECTOR_SIZE_DATA)
Definition: IsoArchive.cpp:472
IsoArchiveIO * _io
Definition: IsoArchive.h:299
QIODevice * file() const
Definition: IsoArchive.cpp:270
QList< IsoFile * > files() const
Definition: IsoArchive.cpp:131
bool pack(IsoArchive *destination, ArchiveObserver *control=NULL, IsoDirectory *directory=NULL)
Definition: IsoArchive.cpp:662
char month[2]
Definition: IsoArchive.h:43
QList< IsoDirectory * > directories() const
Definition: IsoArchive.cpp:144
#define SECTOR_SIZE
Definition: IsoArchive.h:28
bool extract(const QString &path, const QString &destination, quint32 maxSize=0) const
char millis[2]
Definition: IsoArchive.h:48
QIODevice * modifiedFileDevice(const QString &path) const
virtual bool isModified() const
Definition: IsoArchive.cpp:85
QString name
Definition: IsoArchive.h:85
QIODevice * _io
Definition: IsoArchive.h:189
IsoFileOrDirectory * fileOrDirectory(const QString &path) const
Definition: IsoArchive.cpp:157
static void headerInfos(const QByteArray &header, quint8 *type, quint8 *mode=NULL)
Definition: IsoArchive.h:256
static void repairLocationSectors(IsoDirectory *directory, IsoArchive *newIso)
Definition: IsoArchive.cpp:952
bool seekToSector(quint32 num)
Definition: IsoArchive.cpp:493
bool _newIOMustBeRemoved
Definition: IsoArchive.h:190
static quint32 sectorCountData(quint32 dataSize)
Definition: IsoArchive.cpp:488
virtual ~IsoFile()
Definition: IsoArchive.cpp:216
bool isDirectory() const
Definition: IsoArchive.cpp:121
void applyModifications(IsoDirectory *directory)
quint32 volume_space_size
Definition: IsoArchive.h:98
quint32 newSectorCount() const
Definition: IsoArchive.cpp:65
bool isFile() const
Definition: IsoArchive.cpp:80
IsoFileOrDirectory(const QString &name, quint32 location, quint32 size, qint64 structPosition)
Definition: IsoArchive.cpp:20
char day[2]
Definition: IsoArchive.h:44
static QByteArray buildHeader(quint32 sector, quint8 type, quint8 mode=2)
Definition: IsoArchive.h:245
quint8 length_di
Definition: IsoArchive.h:53
IsoFileIO(IsoArchiveIO *io, const IsoFile *infos, QObject *parent=0)
Definition: IsoArchive.cpp:520
quint32 path_table_size
Definition: IsoArchive.h:107
QMap< quint32, IsoFile * > getModifiedFiles(IsoDirectory *directory) const
QString name
Definition: IsoArchive.h:57
#define MAX_ISO_READ
Definition: IsoArchive.h:24