ff7tk  0.02
Toolkit for making FF7 Tools
IsoArchive.h
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 #ifndef ISOARCHIVE_H
19 #define ISOARCHIVE_H
20 
21 #include <QtCore>
22 #include "Archive.h"
23 
24 #define MAX_ISO_READ 10000
25 #define MAX_FILENAME_LENGTH 207
26 #define SEPARATOR_1 '\x2E' // .
27 #define SEPARATOR_2 '\x3B' // ;
28 #define SECTOR_SIZE 2352
29 #define SECTOR_SIZE_HEADER 24
30 #define SECTOR_SIZE_DATA 2048
31 #define SECTOR_SIZE_FOOTER 280
32 
33 //#define ISOARCHIVE_DEBUG
34 
35 //d-characters : [\w ]
36 //a-characters : [!"%&'\(\)*+,\-\./\w:;<=>? ] (+ SP)
37 
38 class IsoArchiveIO;
39 class IsoFileIO;
40 
41 struct IsoTime {
42  char year[4];
43  char month[2];
44  char day[2];
45  char hour[2];
46  char minute[2];
47  char second[2];
48  char millis[2];
49  qint8 GMT;
50 };
51 
52 struct PathTable {
53  quint8 length_di;
55  quint32 location_extent;
57  QString name;
58  quint32 position;
59 };
60 
62  quint32 location_extent;// little endian //first sector in the directory
63  quint32 location_extent2;// big endian
64  quint32 data_length;// little endian
65  quint32 data_length2;// big endian
66  quint8 year;// since 1900
67  quint8 month;
68  quint8 day;
69  quint8 hour;
70  quint8 minute;
71  quint8 second;
72  qint8 GMT;
73  quint8 file_flags;// Multi-Extent/Reserved/Reserved/Protection/Record/Associated File/Directory/Existence
76  quint16 volume_sequence_number;// little endian
77  quint16 volume_sequence_number2;// big endian
78  quint8 length_fi;
79 };
80 
82  quint8 length_dr;
85  QString name;
86  QString version;
87  // padding;
88 };
89 
91  quint8 type;// 0x01 or 0xff
92  quint8 id[5];// CD001
93  quint8 version;// 1 = international standard
94  quint8 unused1;
95  quint8 system_id[32];
96  quint8 volume_id[32];
97  quint8 unused2[8];
98  quint32 volume_space_size;// little endian // number of sectors
99  quint32 volume_space_size2;// big endian
100  quint8 unused3[32];
101  quint16 volume_set_size;// little endian
102  quint16 volume_set_size2;// big endian
103  quint16 volume_sequence_number;// little endian
104  quint16 volume_sequence_number2;// big endian
105  quint16 logical_block_size;// little endian
106  quint16 logical_block_size2;// big endian
107  quint32 path_table_size;// little endian
108  quint32 path_table_size2;// big endian
109  quint32 type_path_table;// little endian
110  quint32 opt_type_path_table;// little endian
111  quint32 type_path_table2;// big endian
112  quint32 opt_type_path_table2;// big endian
113 };
114 
116  quint8 volume_set_id[128];
117  quint8 publisher_id[128];
118  quint8 preparer_id[128];
119  quint8 application_id[128];
120  quint8 copyright_file_id[37];
121  quint8 abstract_file_id[37];
122  quint8 bibliographic_file_id[37];
128  quint8 unused4;
129  quint8 application_data[512];
130  quint8 unused5[653];
131 };
132 
137 };
138 
140 {
141 public:
142  virtual ~IsoFileOrDirectory();
143  const QString &name() const;
144  quint32 location() const;
145  quint32 locationAfter() const;
146  quint32 size() const;
147  quint32 sectorCount() const;
148  quint32 newLocation() const;
149  quint32 newSize() const;
150  quint32 newSectorCount() const;
151  void setName(const QString &name);
152  void setLocation(quint32 location);
153  virtual bool isDirectory() const=0;
154  bool isFile() const;
155  virtual bool isModified() const;
156  virtual void applyModifications();
157  bool isSpecial() const;
159  void setPaddingAfter(quint8 after);
160  quint8 paddingAfter() const;
161 protected:
162  Q_DISABLE_COPY(IsoFileOrDirectory)
163  IsoFileOrDirectory(const QString &name, quint32 location, quint32 size, qint64 structPosition);
164  QString _name;
165  quint32 _location, _size;
166  quint32 _newLocation, _newSize;
167  quint8 _paddingAfter;
168 };
169 
171 {
172 public:
173  IsoFile(const QString &name, quint32 location, quint32 size, qint64 structPosition, IsoArchiveIO *io);
174  virtual ~IsoFile();
175  bool isDirectory() const;
176  QByteArray data(quint32 maxSize=0) const;
177  QByteArray modifiedData(quint32 maxSize=0) const;
178  bool extract(const QString &destination, quint32 maxSize=0) const;
179  QIODevice *file() const;
180  QIODevice *modifiedFile() const;
181  bool setModifiedFile(QIODevice *io);
182  bool setModifiedFile(const QByteArray &data);
183  bool isModified() const;
184  void applyModifications();
185 private:
186  Q_DISABLE_COPY(IsoFile)
187  void setFile(QIODevice *io);
188  void cleanNewIO();
189  QIODevice *_io, *_newIO;
190  bool dataChanged, _newIOMustBeRemoved;
191 };
192 
194 {
195 public:
196  IsoDirectory(const QString &name, quint32 location, quint32 size, qint64 structPosition);
197  virtual ~IsoDirectory();
198  bool isDirectory() const;
199  const QMap<QString, IsoFileOrDirectory *> &filesAndDirectories() const;
200  QList<IsoFile *> files() const;
201  QList<IsoDirectory *> directories() const;
202  IsoFileOrDirectory *fileOrDirectory(const QString &path) const;
203  IsoFile *file(const QString &path) const;
204  IsoDirectory *directory(const QString &path) const;
205  void add(IsoFileOrDirectory *fileOrDirectory);
206 private:
207  Q_DISABLE_COPY(IsoDirectory)
208  QMap<QString, IsoFileOrDirectory *> _filesAndDirectories;
209 };
210 
211 class IsoArchiveIO : public QFile
212 {
213  friend class IsoArchive;
214 public:
215  IsoArchiveIO();
216  explicit IsoArchiveIO(const QString &name);
217  virtual ~IsoArchiveIO();
218 
219  bool open(QIODevice::OpenMode mode);
220  qint64 posIso() const;
221  bool seekIso(qint64 off);
222  qint64 sizeIso() const;
223 
224  qint64 readIso(char *data, qint64 maxSize);
225  QByteArray readIso(qint64 maxSize);
226 
227  qint64 writeIso(const char *data, qint64 maxSize);
228  qint64 writeIso(const QByteArray &byteArray);
229 
230  static inline QByteArray int2Header(quint32 id) {
231  quint8 h1, h2, h3;
232 
233  if(id < 4350) {
234  h1 = 0;
235  h2 = dec2Hex(id/75 + 2);
236  h3 = dec2Hex(id - 75*(hex2Dec(h2) - 2));
237  } else {
238  h1 = dec2Hex((id + 150) / 4500);
239  h2 = dec2Hex((id + 150 - hex2Dec(h1)*4500) / 75);
240  h3 = dec2Hex(id + 150 - hex2Dec(h1)*4500 - hex2Dec(h2)*75);
241  }
242 
243  return QByteArray().append((char)h1).append((char)h2).append((char)h3);
244  }
245  static inline QByteArray buildHeader(quint32 sector, quint8 type, quint8 mode=2) {
246  return QByteArray("\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00", 12)
247  .append(int2Header(sector)).append((char)mode)
248  .append("\x00\x00", 2).append((char)type).append('\x00')
249  .append("\x00\x00", 2).append((char)type).append('\x00');
250  }
251  static inline QByteArray buildFooter(quint32 sector) {
252  Q_UNUSED(sector)
253  //TODO (if possible): Checksum EDC/ECC (Error Detection Code & Error Correction Code)
254  return QByteArray(SECTOR_SIZE_FOOTER, '\x00');
255  }
256  static inline void headerInfos(const QByteArray &header, quint8 *type, quint8 *mode = NULL) {
257  Q_ASSERT(header.size() != SECTOR_SIZE_HEADER);
258  if (type) {
259  *type = header.at(18);
260  }
261  if (mode) {
262  *mode = header.at(15);
263  }
264  }
265 
266  QByteArray sector(quint32 num, quint16 maxSize=SECTOR_SIZE_DATA);
267  QByteArray sectorHeader(quint32 num);
268  QByteArray sectorFooter(quint32 num);
269  quint32 currentSector() const;
270  quint32 sectorCount() const;
271  static quint32 sectorCountData(quint32 dataSize);
272  bool seekToSector(quint32 num);
273  bool writeSector(const QByteArray &data, quint8 type, quint8 mode=2);
274 private:
275  Q_DISABLE_COPY(IsoArchiveIO)
276  static qint64 isoPos(qint64 pos);
277  static qint64 filePos(qint64 pos);
278 
279  static inline quint8 hex2Dec(quint8 hex) {
280  return 10*(hex/16) + hex%16;
281  }
282  static inline quint8 dec2Hex(quint8 dec) {
283  return 16*(dec/10) + dec%10;
284  }
285 };
286 
287 class IsoFileIO : public QIODevice
288 {
289 public:
290  IsoFileIO(IsoArchiveIO *io, const IsoFile *infos, QObject *parent=0);
291  bool open(OpenMode mode);
292  qint64 size() const;
293  bool canReadLine() const;
294 protected:
295  qint64 readData(char *data, qint64 maxSize);
296  qint64 writeData(const char *data, qint64 maxSize);
297 private:
298  Q_DISABLE_COPY(IsoFileIO)
300  const IsoFile *_infos;
301 };
302 
304 {
305 public:
306  IsoArchive();
307  explicit IsoArchive(const QString &name);
308  virtual ~IsoArchive();
309 
310  virtual bool open(QIODevice::OpenMode mode);
311  inline virtual bool isOpen() const {
312  return _io.isOpen() && _rootDirectory;
313  }
314  virtual void close();
315  inline QString fileName() const {
316  return _io.fileName();
317  }
318  inline void setFileName(const QString &fileName) {
319  _io.setFileName(fileName);
320  }
321  inline QString errorString() const {
322  return _io.errorString();
323  }
324  inline const IsoArchiveIO &io() const {
325  return _io;
326  }
327 
328  bool pack(IsoArchive *destination, ArchiveObserver *control = NULL, IsoDirectory *directory = NULL);
329  void applyModifications(IsoDirectory *directory);
330 
331  QByteArray file(const QString &path, quint32 maxSize=0) const;
332  QIODevice *fileDevice(const QString &path) const;
333  QByteArray modifiedFile(const QString &path, quint32 maxSize=0) const;
334  QIODevice *modifiedFileDevice(const QString &path) const;
335  bool extract(const QString &path, const QString &destination, quint32 maxSize=0) const;
336  bool extractDir(const QString &path, const QString &destination) const;
337  void extractAll(const QString &destination) const;
338  qint32 diffCountSectors(const QString &path, quint32 newSize) const;
339 
340  IsoDirectory *rootDirectory() const;
341 // const QList<PathTable> &getPathTables1a() const;
342 // const QList<PathTable> &getPathTables1b() const;
343 // const QList<PathTable> &getPathTables2a() const;
344 // const QList<PathTable> &getPathTables2b() const;
345  Archive::ArchiveError error() const;
346 protected:
347  virtual bool reorganizeModifiedFilesAfter(QMap<quint32, const IsoFile *> &writeToTheMain, QList<const IsoFile *> &writeToTheEnd);
348  void setError(Archive::ArchiveError error, const QString &errorString = QString());
349 private:
350  Q_DISABLE_COPY(IsoArchive)
351  bool openVolumeDescriptor(quint8 num=0);
352  bool openRootDirectory(quint32 sector, quint32 dataSize=SECTOR_SIZE_DATA);
353  IsoDirectory *_openDirectoryRecord(IsoDirectory *directories, QList<quint32> &dirVisisted);
354 // QList<PathTable> pathTable(quint32 sector, quint32 dataSize=SECTOR_SIZE_DATA);
355 
356  // Returns index of file in "filesWithPadding" who have paddingAfter >= minSectorCount
357  static int findPadding(const QList<IsoFileOrDirectory *> &filesWithPadding, quint32 minSectorCount);
358  // Returns files with padding after
359  QList<IsoFileOrDirectory *> getIntegrity();
360  bool getIntegritySetPaddingAfter(IsoFileOrDirectory *prevFile, quint32 fileLocation);
361 
362  void _extractAll(const QString &destination, IsoDirectory *directories, QString currentInternalDir=QString()) const;
363  void _getIntegrity(QMap<quint32, IsoFileOrDirectory *> &files, IsoDirectory *directory) const;
364  QMap<quint32, IsoFile *> getModifiedFiles(IsoDirectory *directory) const;
365  void getModifiedFiles(QMap<quint32, IsoFile *> &files, IsoDirectory *directory) const;
366  static void repairLocationSectors(IsoDirectory *directory, IsoArchive *newIso);
367 
368  bool writeFile(QIODevice *in, quint32 sectorCount = 0, ArchiveObserver *control = NULL);
369  bool copySectors(IsoArchiveIO *out, qint64 size, ArchiveObserver *control = NULL, bool repair = false);
370 
375 // QList<PathTable> pathTables1a;
376 // QList<PathTable> pathTables1b;
377 // QList<PathTable> pathTables2a;
378 // QList<PathTable> pathTables2b;
379 #ifdef ISOARCHIVE_DEBUG
380  static QString isoTimeToString(const IsoTime &time);
381  static QString volumeDescriptorToString(const VolumeDescriptor &vd);
382  static QString directoryRecordToString(const DirectoryRecord &dr);
383  static QString pathTableToString(const PathTable &pathTable, bool bigEndian=false);
384 #endif
385 };
386 
387 #endif // ISOARCHIVE_H
quint32 position
Definition: IsoArchive.h:58
Archive::ArchiveError _error
Definition: IsoArchive.h:374
quint16 volume_sequence_number2
Definition: IsoArchive.h:104
IsoTime effective_date
Definition: IsoArchive.h:126
static QByteArray int2Header(quint32 id)
Definition: IsoArchive.h:230
char hour[2]
Definition: IsoArchive.h:45
quint32 type_path_table2
Definition: IsoArchive.h:111
#define SECTOR_SIZE_FOOTER
Definition: IsoArchive.h:31
VolumeDescriptor2 vd2
Definition: IsoArchive.h:136
quint8 file_structure_version
Definition: IsoArchive.h:127
quint16 volume_sequence_number
Definition: IsoArchive.h:76
quint8 extended_attr_record_length
Definition: IsoArchive.h:83
QString errorString() const
Definition: IsoArchive.h:321
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
quint8 length_dr
Definition: IsoArchive.h:82
quint16 volume_sequence_number2
Definition: IsoArchive.h:77
quint16 volume_set_size
Definition: IsoArchive.h:101
#define SECTOR_SIZE_DATA
Definition: IsoArchive.h:30
quint32 location_extent
Definition: IsoArchive.h:55
QString version
Definition: IsoArchive.h:86
quint16 volume_sequence_number
Definition: IsoArchive.h:103
quint32 data_length2
Definition: IsoArchive.h:65
quint16 volume_set_size2
Definition: IsoArchive.h:102
quint32 location_extent2
Definition: IsoArchive.h:63
bool dataChanged
Definition: IsoArchive.h:190
quint32 type_path_table
Definition: IsoArchive.h:109
IsoTime modification_date
Definition: IsoArchive.h:124
virtual bool open(QIODevice::OpenMode mode)
Definition: IsoArchive.cpp:578
quint8 extended_attr_record_length
Definition: IsoArchive.h:54
quint32 volume_space_size2
Definition: IsoArchive.h:99
qint8 GMT
Definition: IsoArchive.h:49
DirectoryRecordHead drh
Definition: IsoArchive.h:84
quint32 location_extent
Definition: IsoArchive.h:62
IsoDirectory * _rootDirectory
Definition: IsoArchive.h:373
quint16 parent_directory_number
Definition: IsoArchive.h:56
quint32 opt_type_path_table
Definition: IsoArchive.h:110
IsoArchiveIO _io
Definition: IsoArchive.h:371
quint16 logical_block_size2
Definition: IsoArchive.h:106
quint32 path_table_size2
Definition: IsoArchive.h:108
QIODevice * _newIO
Definition: IsoArchive.h:189
void setFileName(const QString &fileName)
Definition: IsoArchive.h:318
VolumeDescriptor volume
Definition: IsoArchive.h:372
ArchiveError
Definition: Archive.h:34
quint32 opt_type_path_table2
Definition: IsoArchive.h:112
IsoTime creation_date
Definition: IsoArchive.h:123
quint8 interleave_grap_size
Definition: IsoArchive.h:75
VolumeDescriptor1 vd1
Definition: IsoArchive.h:134
const IsoArchiveIO & io() const
Definition: IsoArchive.h:324
IsoTime expiration_date
Definition: IsoArchive.h:125
#define SECTOR_SIZE_HEADER
Definition: IsoArchive.h:29
DirectoryRecord dr
Definition: IsoArchive.h:135
QString fileName() const
Definition: IsoArchive.h:315
char month[2]
Definition: IsoArchive.h:43
char millis[2]
Definition: IsoArchive.h:48
QString name
Definition: IsoArchive.h:85
static void headerInfos(const QByteArray &header, quint8 *type, quint8 *mode=NULL)
Definition: IsoArchive.h:256
quint32 volume_space_size
Definition: IsoArchive.h:98
char day[2]
Definition: IsoArchive.h:44
static QByteArray buildHeader(quint32 sector, quint8 type, quint8 mode=2)
Definition: IsoArchive.h:245
static quint8 dec2Hex(quint8 dec)
Definition: IsoArchive.h:282
quint8 length_di
Definition: IsoArchive.h:53
quint32 path_table_size
Definition: IsoArchive.h:107
static quint8 hex2Dec(quint8 hex)
Definition: IsoArchive.h:279
QString name
Definition: IsoArchive.h:57
virtual bool isOpen() const
Definition: IsoArchive.h:311