FFSM++  1.1.0
French Forest Sector Model ++
UnzipPrivate Class Reference

#include <unzip_p.h>

Public Member Functions

 UnzipPrivate ()
 
UnZip::ErrorCode openArchive (QIODevice *device)
 
UnZip::ErrorCode seekToCentralDirectory ()
 
UnZip::ErrorCode parseCentralDirectoryRecord ()
 
UnZip::ErrorCode parseLocalHeaderRecord (const QString &path, ZipEntryP &entry)
 
void closeArchive ()
 
UnZip::ErrorCode extractFile (const QString &path, ZipEntryP &entry, const QDir &dir, UnZip::ExtractionOptions options)
 
UnZip::ErrorCode extractFile (const QString &path, ZipEntryP &entry, QIODevice *device, UnZip::ExtractionOptions options)
 
UnZip::ErrorCode testPassword (quint32 *keys, const QString &file, const ZipEntryP &header)
 
bool testKeys (const ZipEntryP &header, quint32 *keys)
 
bool createDirectory (const QString &path)
 
void decryptBytes (quint32 *keys, char *buffer, qint64 read)
 
quint32 getULong (const unsigned char *data, quint32 offset) const
 
quint64 getULLong (const unsigned char *data, quint32 offset) const
 
quint16 getUShort (const unsigned char *data, quint32 offset) const
 
int decryptByte (quint32 key2) const
 
void updateKeys (quint32 *keys, int c) const
 
void initKeys (const QString &pwd, quint32 *keys) const
 
QDateTime convertDateTime (const unsigned char date[2], const unsigned char time[2]) const
 

Public Attributes

QString password
 
bool skipAllEncrypted
 
QMap< QString, ZipEntryP * > * headers
 
QIODevice * device
 
char buffer1 [UNZIP_READ_BUFFER]
 
char buffer2 [UNZIP_READ_BUFFER]
 
unsigned char * uBuffer
 
const quint32 * crcTable
 
quint32 cdOffset
 
quint32 eocdOffset
 
quint16 cdEntryCount
 
quint16 unsupportedEntryCount
 
QString comment
 

Detailed Description

Definition at line 51 of file unzip_p.h.

Constructor & Destructor Documentation

Definition at line 485 of file unzip.cpp.

486 {
487  skipAllEncrypted = false;
488  headers = 0;
489  device = 0;
490 
491  uBuffer = (unsigned char*) buffer1;
492  crcTable = (quint32*) get_crc_table();
493 
494  cdOffset = eocdOffset = 0;
495  cdEntryCount = 0;
497 }
bool skipAllEncrypted
Definition: unzip_p.h:59
char buffer1[UNZIP_READ_BUFFER]
Definition: unzip_p.h:65
quint16 cdEntryCount
Definition: unzip_p.h:77
QMap< QString, ZipEntryP * > * headers
Definition: unzip_p.h:61
quint32 eocdOffset
Definition: unzip_p.h:74
quint16 unsupportedEntryCount
Definition: unzip_p.h:80
quint32 cdOffset
Definition: unzip_p.h:72
QIODevice * device
Definition: unzip_p.h:63
const quint32 * crcTable
Definition: unzip_p.h:69
unsigned char * uBuffer
Definition: unzip_p.h:68

Member Function Documentation

void closeArchive ( )

Definition at line 948 of file unzip.cpp.

Referenced by UnZip::closeArchive().

949 {
950  if (device == 0)
951  return;
952 
953  skipAllEncrypted = false;
954 
955  if (headers != 0)
956  {
957  qDeleteAll(*headers);
958  delete headers;
959  headers = 0;
960  }
961 
962  delete device; device = 0;
963 
964  cdOffset = eocdOffset = 0;
965  cdEntryCount = 0;
967 
968  comment.clear();
969 }
bool skipAllEncrypted
Definition: unzip_p.h:59
quint16 cdEntryCount
Definition: unzip_p.h:77
QString comment
Definition: unzip_p.h:82
QMap< QString, ZipEntryP * > * headers
Definition: unzip_p.h:61
quint32 eocdOffset
Definition: unzip_p.h:74
quint16 unsupportedEntryCount
Definition: unzip_p.h:80
quint32 cdOffset
Definition: unzip_p.h:72
QIODevice * device
Definition: unzip_p.h:63

Here is the caller graph for this function:

QDateTime convertDateTime ( const unsigned char  date[2],
const unsigned char  time[2] 
) const
inline

Definition at line 1345 of file unzip.cpp.

Referenced by UnZip::entryList().

1346 {
1347  QDateTime dt;
1348 
1349  // Usual PKZip low-byte to high-byte order
1350 
1351  // Date: 7 bits = years from 1980, 4 bits = month, 5 bits = day
1352  quint16 year = (date[1] >> 1) & 127;
1353  quint16 month = ((date[1] << 3) & 14) | ((date[0] >> 5) & 7);
1354  quint16 day = date[0] & 31;
1355 
1356  // Time: 5 bits hour, 6 bits minutes, 5 bits seconds with a 2sec precision
1357  quint16 hour = (time[1] >> 3) & 31;
1358  quint16 minutes = ((time[1] << 3) & 56) | ((time[0] >> 5) & 7);
1359  quint16 seconds = (time[0] & 31) * 2;
1360 
1361  dt.setDate(QDate(1980 + year, month, day));
1362  dt.setTime(QTime(hour, minutes, seconds));
1363  return dt;
1364 }

Here is the caller graph for this function:

bool createDirectory ( const QString &  path)

Definition at line 1195 of file unzip.cpp.

1196 {
1197  QDir d(path);
1198  if (!d.exists())
1199  {
1200  int sep = path.lastIndexOf("/");
1201  if (sep <= 0) return true;
1202 
1203  if (!createDirectory(path.left(sep)))
1204  return false;
1205 
1206  if (!d.mkdir(path))
1207  {
1208  qDebug() << QString("Unable to create directory: %1").arg(path);
1209  return false;
1210  }
1211  }
1212 
1213  return true;
1214 }
bool createDirectory(const QString &path)
Definition: unzip.cpp:1195
int decryptByte ( quint32  key2) const
inline

Definition at line 1257 of file unzip.cpp.

1258 {
1259  quint16 temp = ((quint16)(key2) & 0xffff) | 2;
1260  return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
1261 }
void decryptBytes ( quint32 *  keys,
char *  buffer,
qint64  read 
)
inline

Definition at line 1336 of file unzip.cpp.

1337 {
1338  for (int i=0; i<(int)read; ++i)
1339  updateKeys(keys, buffer[i] ^= decryptByte(keys[2]));
1340 }
void updateKeys(quint32 *keys, int c) const
Definition: unzip.cpp:1266
int decryptByte(quint32 key2) const
Definition: unzip.cpp:1257
UnZip::ErrorCode extractFile ( const QString &  path,
ZipEntryP entry,
const QDir &  dir,
UnZip::ExtractionOptions  options 
)
Todo:
Set creation/last_modified date/time

Definition at line 972 of file unzip.cpp.

Referenced by UnZip::extractAll(), and UnZip::extractFile().

973 {
974  QString name(path);
975  QString dirname;
976  QString directory;
977 
978  int pos = name.lastIndexOf('/');
979 
980  // This entry is for a directory
981  if (pos == name.length() - 1)
982  {
983  if (options.testFlag(UnZip::SkipPaths))
984  return UnZip::Ok;
985 
986  directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(name));
987  if (!createDirectory(directory))
988  {
989  qDebug() << QString("Unable to create directory: %1").arg(directory);
990  return UnZip::CreateDirFailed;
991  }
992 
993  return UnZip::Ok;
994  }
995 
996  // Extract path from entry
997  if (pos > 0)
998  {
999  // get directory part
1000  dirname = name.left(pos);
1001  if (options.testFlag(UnZip::SkipPaths))
1002  {
1003  directory = dir.absolutePath();
1004  }
1005  else
1006  {
1007  directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(dirname));
1008  if (!createDirectory(directory))
1009  {
1010  qDebug() << QString("Unable to create directory: %1").arg(directory);
1011  return UnZip::CreateDirFailed;
1012  }
1013  }
1014  name = name.right(name.length() - pos - 1);
1015  } else directory = dir.absolutePath();
1016 
1017  name = QString("%1/%2").arg(directory).arg(name);
1018 
1019  QFile outFile(name);
1020 
1021  if (!outFile.open(QIODevice::WriteOnly))
1022  {
1023  qDebug() << QString("Unable to open %1 for writing").arg(name);
1024  return UnZip::OpenFailed;
1025  }
1026 
1027  //! \todo Set creation/last_modified date/time
1028 
1029  UnZip::ErrorCode ec = extractFile(path, entry, &outFile, options);
1030 
1031  outFile.close();
1032 
1033  if (ec != UnZip::Ok)
1034  {
1035  if (!outFile.remove())
1036  qDebug() << QString("Unable to remove corrupted file: %1").arg(name);
1037  }
1038 
1039  return ec;
1040 }
ErrorCode
Definition: unzip.h:48
bool createDirectory(const QString &path)
Definition: unzip.cpp:1195
Ignores paths and extracts all the files to the same directory.
Definition: unzip.h:75
UnZip::ErrorCode extractFile(const QString &path, ZipEntryP &entry, const QDir &dir, UnZip::ExtractionOptions options)
Definition: unzip.cpp:972

Here is the call graph for this function:

Here is the caller graph for this function:

UnZip::ErrorCode extractFile ( const QString &  path,
ZipEntryP entry,
QIODevice *  device,
UnZip::ExtractionOptions  options 
)

Encryption header size

Definition at line 1043 of file unzip.cpp.

1044 {
1045  Q_UNUSED(options);
1046  Q_ASSERT(dev != 0);
1047 
1048  if (!entry.lhEntryChecked)
1049  {
1050  UnZip::ErrorCode ec = parseLocalHeaderRecord(path, entry);
1051  entry.lhEntryChecked = true;
1052 
1053  if (ec != UnZip::Ok)
1054  return ec;
1055  }
1056 
1057  if (!device->seek(entry.dataOffset))
1058  return UnZip::SeekFailed;
1059 
1060  // Encryption keys
1061  quint32 keys[3];
1062 
1063  if (entry.isEncrypted())
1064  {
1065  UnZip::ErrorCode e = testPassword(keys, path, entry);
1066  if (e != UnZip::Ok)
1067  {
1068  qDebug() << QString("Unable to decrypt %1").arg(path);
1069  return e;
1070  }//! Encryption header size
1071  entry.szComp -= UNZIP_LOCAL_ENC_HEADER_SIZE; // remove encryption header size
1072  }
1073 
1074  if (entry.szComp == 0)
1075  {
1076  if (entry.crc != 0)
1077  return UnZip::Corrupted;
1078 
1079  return UnZip::Ok;
1080  }
1081 
1082  uInt rep = entry.szComp / UNZIP_READ_BUFFER;
1083  uInt rem = entry.szComp % UNZIP_READ_BUFFER;
1084  uInt cur = 0;
1085 
1086  // extract data
1087  qint64 read;
1088  quint64 tot = 0;
1089 
1090  quint32 myCRC = crc32(0L, Z_NULL, 0);
1091 
1092  if (entry.compMethod == 0)
1093  {
1094  while ( (read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem)) > 0 )
1095  {
1096  if (entry.isEncrypted())
1097  decryptBytes(keys, buffer1, read);
1098 
1099  myCRC = crc32(myCRC, uBuffer, read);
1100 
1101  if (dev->write(buffer1, read) != read)
1102  return UnZip::WriteFailed;
1103 
1104  cur++;
1105  tot += read;
1106 
1107  if (tot == entry.szComp)
1108  break;
1109  }
1110 
1111  if (read < 0)
1112  return UnZip::ReadFailed;
1113  }
1114  else if (entry.compMethod == 8)
1115  {
1116  /* Allocate inflate state */
1117  z_stream zstr;
1118  zstr.zalloc = Z_NULL;
1119  zstr.zfree = Z_NULL;
1120  zstr.opaque = Z_NULL;
1121  zstr.next_in = Z_NULL;
1122  zstr.avail_in = 0;
1123 
1124  int zret;
1125 
1126  // Use inflateInit2 with negative windowBits to get raw decompression
1127  if ( (zret = inflateInit2_(&zstr, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream))) != Z_OK )
1128  return UnZip::ZlibError;
1129 
1130  int szDecomp;
1131 
1132  // Decompress until deflate stream ends or end of file
1133  do
1134  {
1135  read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem);
1136  if (read == 0)
1137  break;
1138  if (read < 0)
1139  {
1140  (void)inflateEnd(&zstr);
1141  return UnZip::ReadFailed;
1142  }
1143 
1144  if (entry.isEncrypted())
1145  decryptBytes(keys, buffer1, read);
1146 
1147  cur++;
1148  tot += read;
1149 
1150  zstr.avail_in = (uInt) read;
1151  zstr.next_in = (Bytef*) buffer1;
1152 
1153 
1154  // Run inflate() on input until output buffer not full
1155  do {
1156  zstr.avail_out = UNZIP_READ_BUFFER;
1157  zstr.next_out = (Bytef*) buffer2;;
1158 
1159  zret = inflate(&zstr, Z_NO_FLUSH);
1160 
1161  switch (zret) {
1162  case Z_NEED_DICT:
1163  case Z_DATA_ERROR:
1164  case Z_MEM_ERROR:
1165  inflateEnd(&zstr);
1166  return UnZip::WriteFailed;
1167  default:
1168  ;
1169  }
1170 
1171  szDecomp = UNZIP_READ_BUFFER - zstr.avail_out;
1172  if (dev->write(buffer2, szDecomp) != szDecomp)
1173  {
1174  inflateEnd(&zstr);
1175  return UnZip::ZlibError;
1176  }
1177 
1178  myCRC = crc32(myCRC, (const Bytef*) buffer2, szDecomp);
1179 
1180  } while (zstr.avail_out == 0);
1181 
1182  }
1183  while (zret != Z_STREAM_END);
1184 
1185  inflateEnd(&zstr);
1186  }
1187 
1188  if (myCRC != entry.crc)
1189  return UnZip::Corrupted;
1190 
1191  return UnZip::Ok;
1192 }
UnZip::ErrorCode testPassword(quint32 *keys, const QString &file, const ZipEntryP &header)
Definition: unzip.cpp:1298
quint16 compMethod
Definition: zipentry_p.h:64
ErrorCode
Definition: unzip.h:48
bool isEncrypted() const
Definition: zipentry_p.h:74
UnZip::ErrorCode parseLocalHeaderRecord(const QString &path, ZipEntryP &entry)
Definition: unzip.cpp:574
char buffer1[UNZIP_READ_BUFFER]
Definition: unzip_p.h:65
#define UNZIP_READ_BUFFER
Definition: unzip_p.h:49
#define UNZIP_LOCAL_ENC_HEADER_SIZE
Local header entry encryption header size.
Definition: unzip.cpp:87
bool lhEntryChecked
Definition: zipentry_p.h:72
QIODevice * device
Definition: unzip_p.h:63
void decryptBytes(quint32 *keys, char *buffer, qint64 read)
Definition: unzip.cpp:1336
char buffer2[UNZIP_READ_BUFFER]
Definition: unzip_p.h:66
unsigned char * uBuffer
Definition: unzip_p.h:68
quint32 dataOffset
Definition: zipentry_p.h:62
quint32 szComp
Definition: zipentry_p.h:68
quint32 crc
Definition: zipentry_p.h:67

Here is the call graph for this function:

quint64 getULLong ( const unsigned char *  data,
quint32  offset 
) const
inline

Definition at line 1232 of file unzip.cpp.

1233 {
1234  quint64 res = (quint64) data[offset];
1235  res |= (((quint64)data[offset+1]) << 8);
1236  res |= (((quint64)data[offset+2]) << 16);
1237  res |= (((quint64)data[offset+3]) << 24);
1238  res |= (((quint64)data[offset+1]) << 32);
1239  res |= (((quint64)data[offset+2]) << 40);
1240  res |= (((quint64)data[offset+3]) << 48);
1241  res |= (((quint64)data[offset+3]) << 56);
1242 
1243  return res;
1244 }
quint32 getULong ( const unsigned char *  data,
quint32  offset 
) const
inline

Definition at line 1219 of file unzip.cpp.

1220 {
1221  quint32 res = (quint32) data[offset];
1222  res |= (((quint32)data[offset+1]) << 8);
1223  res |= (((quint32)data[offset+2]) << 16);
1224  res |= (((quint32)data[offset+3]) << 24);
1225 
1226  return res;
1227 }
quint16 getUShort ( const unsigned char *  data,
quint32  offset 
) const
inline

Definition at line 1249 of file unzip.cpp.

1250 {
1251  return (quint16) data[offset] | (((quint16)data[offset+1]) << 8);
1252 }
void initKeys ( const QString &  pwd,
quint32 *  keys 
) const
inline

Definition at line 1278 of file unzip.cpp.

1279 {
1280  keys[0] = 305419896L;
1281  keys[1] = 591751049L;
1282  keys[2] = 878082192L;
1283 
1284  //QByteArray pwdBytes = pwd.toAscii(); // Qt4
1285  QByteArray pwdBytes = pwd.toLatin1(); // Qt5
1286  int sz = pwdBytes.size();
1287  const char* ascii = pwdBytes.data();
1288 
1289  for (int i=0; i<sz; ++i)
1290  updateKeys(keys, (int)ascii[i]);
1291 }
void updateKeys(quint32 *keys, int c) const
Definition: unzip.cpp:1266
UnZip::ErrorCode openArchive ( QIODevice *  device)
Todo:
Ignore CD entry count? CD may be corrupted.

Definition at line 500 of file unzip.cpp.

Referenced by UnZip::openArchive().

501 {
502  Q_ASSERT(dev != 0);
503 
504  if (device != 0)
505  closeArchive();
506 
507  device = dev;
508 
509  if (!(device->isOpen() || device->open(QIODevice::ReadOnly)))
510  {
511  delete device;
512  device = 0;
513 
514  qDebug() << "Unable to open device for reading";
515  return UnZip::OpenFailed;
516  }
517 
518  UnZip::ErrorCode ec;
519 
520  ec = seekToCentralDirectory();
521  if (ec != UnZip::Ok)
522  {
523  closeArchive();
524  return ec;
525  }
526 
527  //! \todo Ignore CD entry count? CD may be corrupted.
528  if (cdEntryCount == 0)
529  {
530  return UnZip::Ok;
531  }
532 
533  bool continueParsing = true;
534 
535  while (continueParsing)
536  {
537  if (device->read(buffer1, 4) != 4)
539 
540  if (! (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x01 && buffer1[3] == 0x02) )
541  break;
542 
543  if ( (ec = parseCentralDirectoryRecord()) != UnZip::Ok )
544  break;
545  }
546 
547  if (ec != UnZip::Ok)
548  closeArchive();
549 
550  return ec;
551 }
ErrorCode
Definition: unzip.h:48
char buffer1[UNZIP_READ_BUFFER]
Definition: unzip_p.h:65
quint16 cdEntryCount
Definition: unzip_p.h:77
#define UNZIP_CHECK_FOR_VALID_DATA
Checks if some file has been already extracted.
Definition: unzip.cpp:139
QIODevice * device
Definition: unzip_p.h:63
UnZip::ErrorCode seekToCentralDirectory()
Definition: unzip.cpp:713
UnZip::ErrorCode parseCentralDirectoryRecord()
Definition: unzip.cpp:837
void closeArchive()
Definition: unzip.cpp:948

Here is the call graph for this function:

Here is the caller graph for this function:

UnZip::ErrorCode parseCentralDirectoryRecord ( )

Definition at line 837 of file unzip.cpp.

838 {
839  // Read CD record
841  return UnZip::ReadFailed;
842 
843  bool skipEntry = false;
844 
845  // Get compression type so we can skip non compatible algorithms
846  quint16 compMethod = getUShort(uBuffer, UNZIP_CD_OFF_CMETHOD);
847 
848  // Get variable size fields length so we can skip the whole record
849  // if necessary
850  quint16 szName = getUShort(uBuffer, UNZIP_CD_OFF_NAMELEN);
851  quint16 szExtra = getUShort(uBuffer, UNZIP_CD_OFF_XLEN);
852  quint16 szComment = getUShort(uBuffer, UNZIP_CD_OFF_COMMLEN);
853 
854  quint32 skipLength = szName + szExtra + szComment;
855 
857 
858  if ((compMethod != 0) && (compMethod != 8))
859  {
860  qDebug() << "Unsupported compression method. Skipping file.";
861  skipEntry = true;
862  }
863 
864  // Header parsing may be a problem if version is bigger than UNZIP_VERSION
865  if (!skipEntry && buffer1[UNZIP_CD_OFF_VERSION] > UNZIP_VERSION)
866  {
867  qDebug() << "Unsupported PKZip version. Skipping file.";
868  skipEntry = true;
869  }
870 
871  if (!skipEntry && szName == 0)
872  {
873  qDebug() << "Skipping file with no name.";
874  skipEntry = true;
875  }
876 
877  if (!skipEntry && device->read(buffer2, szName) != szName)
878  {
879  ec = UnZip::ReadFailed;
880  skipEntry = true;
881  }
882 
883  if (skipEntry)
884  {
885  if (ec == UnZip::Ok)
886  {
887  if (!device->seek( device->pos() + skipLength ))
888  ec = UnZip::SeekFailed;
889 
891  }
892 
893  return ec;
894  }
895 
896  //QString filename = QString::fromAscii(buffer2, szName); // Qt4
897  QString filename = QString::fromLatin1(buffer2, szName); // Qt5
898 
899  ZipEntryP* h = new ZipEntryP;
900  h->compMethod = compMethod;
901 
903  h->gpFlag[1] = buffer1[UNZIP_CD_OFF_GPFLAG + 1];
904 
906  h->modTime[1] = buffer1[UNZIP_CD_OFF_MODT + 1];
907 
909  h->modDate[1] = buffer1[UNZIP_CD_OFF_MODD + 1];
910 
914 
915  // Skip extra field (if any)
916  if (szExtra != 0)
917  {
918  if (!device->seek( device->pos() + szExtra ))
919  {
920  delete h;
921  return UnZip::SeekFailed;
922  }
923  }
924 
925  // Read comment field (if any)
926  if (szComment != 0)
927  {
928  if (device->read(buffer2, szComment) != szComment)
929  {
930  delete h;
931  return UnZip::ReadFailed;
932  }
933 
934  //h->comment = QString::fromAscii(buffer2, szComment); // Qt4
935  h->comment = QString::fromLatin1(buffer2, szComment); // Qt5
936  }
937 
939 
940  if (headers == 0)
941  headers = new QMap<QString, ZipEntryP*>();
942  headers->insert(filename, h);
943 
944  return UnZip::Ok;
945 }
quint16 getUShort(const unsigned char *data, quint32 offset) const
Definition: unzip.cpp:1249
#define UNZIP_CD_OFF_CSIZE
Definition: unzip.cpp:96
quint16 compMethod
Definition: zipentry_p.h:64
ErrorCode
Definition: unzip.h:48
unsigned char modTime[2]
Definition: zipentry_p.h:65
quint32 lhOffset
Definition: zipentry_p.h:61
#define UNZIP_CD_OFF_CMETHOD
Definition: unzip.cpp:92
#define UNZIP_CD_OFF_LHOFFSET
Definition: unzip.cpp:101
char buffer1[UNZIP_READ_BUFFER]
Definition: unzip_p.h:65
#define UNZIP_CD_OFF_MODT
Definition: unzip.cpp:93
QMap< QString, ZipEntryP * > * headers
Definition: unzip_p.h:61
#define UNZIP_CD_ENTRY_SIZE_NS
Central Directory file entry size (excluding signature, excluding variable length fields) ...
Definition: unzip.cpp:81
quint16 unsupportedEntryCount
Definition: unzip_p.h:80
#define UNZIP_VERSION
Definition: unzip.cpp:131
QString comment
Definition: zipentry_p.h:70
QIODevice * device
Definition: unzip_p.h:63
#define UNZIP_CD_OFF_COMMLEN
Definition: unzip.cpp:100
#define UNZIP_CD_OFF_XLEN
Definition: unzip.cpp:99
#define UNZIP_CD_OFF_CRC32
Definition: unzip.cpp:95
#define UNZIP_CD_OFF_GPFLAG
Definition: unzip.cpp:91
#define UNZIP_CD_OFF_VERSION
Definition: unzip.cpp:90
unsigned char gpFlag[2]
Definition: zipentry_p.h:63
char buffer2[UNZIP_READ_BUFFER]
Definition: unzip_p.h:66
quint32 szUncomp
Definition: zipentry_p.h:69
#define UNZIP_CD_OFF_NAMELEN
Definition: unzip.cpp:98
#define UNZIP_CD_OFF_MODD
Definition: unzip.cpp:94
unsigned char * uBuffer
Definition: unzip_p.h:68
unsigned char modDate[2]
Definition: zipentry_p.h:66
#define UNZIP_CD_OFF_USIZE
Definition: unzip.cpp:97
quint32 getULong(const unsigned char *data, quint32 offset) const
Definition: unzip.cpp:1219
quint32 szComp
Definition: zipentry_p.h:68
quint32 crc
Definition: zipentry_p.h:67
UnZip::ErrorCode parseLocalHeaderRecord ( const QString &  path,
ZipEntryP entry 
)

Definition at line 574 of file unzip.cpp.

575 {
576  if (!device->seek(entry.lhOffset))
577  return UnZip::SeekFailed;
578 
579  // Test signature
580  if (device->read(buffer1, 4) != 4)
581  return UnZip::ReadFailed;
582 
583  if ((buffer1[0] != 'P') || (buffer1[1] != 'K') || (buffer1[2] != 0x03) || (buffer1[3] != 0x04))
584  return UnZip::InvalidArchive;
585 
587  return UnZip::ReadFailed;
588 
589  /*
590  Check 3rd general purpose bit flag.
591 
592  "bit 3: If this bit is set, the fields crc-32, compressed size
593  and uncompressed size are set to zero in the local
594  header. The correct values are put in the data descriptor
595  immediately following the compressed data."
596  */
597  bool hasDataDescriptor = entry.hasDataDescriptor();
598 
599  bool checkFailed = false;
600 
601  if (!checkFailed)
602  checkFailed = entry.compMethod != getUShort(uBuffer, UNZIP_LH_OFF_CMETHOD);
603  if (!checkFailed)
604  checkFailed = entry.gpFlag[0] != uBuffer[UNZIP_LH_OFF_GPFLAG];
605  if (!checkFailed)
606  checkFailed = entry.gpFlag[1] != uBuffer[UNZIP_LH_OFF_GPFLAG + 1];
607  if (!checkFailed)
608  checkFailed = entry.modTime[0] != uBuffer[UNZIP_LH_OFF_MODT];
609  if (!checkFailed)
610  checkFailed = entry.modTime[1] != uBuffer[UNZIP_LH_OFF_MODT + 1];
611  if (!checkFailed)
612  checkFailed = entry.modDate[0] != uBuffer[UNZIP_LH_OFF_MODD];
613  if (!checkFailed)
614  checkFailed = entry.modDate[1] != uBuffer[UNZIP_LH_OFF_MODD + 1];
615  if (!hasDataDescriptor)
616  {
617  if (!checkFailed)
618  checkFailed = entry.crc != getULong(uBuffer, UNZIP_LH_OFF_CRC32);
619  if (!checkFailed)
620  checkFailed = entry.szComp != getULong(uBuffer, UNZIP_LH_OFF_CSIZE);
621  if (!checkFailed)
622  checkFailed = entry.szUncomp != getULong(uBuffer, UNZIP_LH_OFF_USIZE);
623  }
624 
625  if (checkFailed)
627 
628  // Check filename
629  quint16 szName = getUShort(uBuffer, UNZIP_LH_OFF_NAMELEN);
630  if (szName == 0)
632 
633  if (device->read(buffer2, szName) != szName)
634  return UnZip::ReadFailed;
635 
636  //QString filename = QString::fromAscii(buffer2, szName); // Qt4
637  QString filename = QString::fromLatin1(buffer2, szName); // Qt5
638  if (filename != path)
639  {
640  qDebug() << "Filename in local header mismatches.";
642  }
643 
644  // Skip extra field
645  quint16 szExtra = getUShort(uBuffer, UNZIP_LH_OFF_XLEN);
646  if (szExtra != 0)
647  {
648  if (!device->seek(device->pos() + szExtra))
649  return UnZip::SeekFailed;
650  }
651 
652  entry.dataOffset = device->pos();
653 
654  if (hasDataDescriptor)
655  {
656  /*
657  The data descriptor has this OPTIONAL signature: PK\7\8
658  We try to skip the compressed data relying on the size set in the
659  Central Directory record.
660  */
661  if (!device->seek(device->pos() + entry.szComp))
662  return UnZip::SeekFailed;
663 
664  // Read 4 bytes and check if there is a data descriptor signature
665  if (device->read(buffer2, 4) != 4)
666  return UnZip::ReadFailed;
667 
668  bool hasSignature = buffer2[0] == 'P' && buffer2[1] == 'K' && buffer2[2] == 0x07 && buffer2[3] == 0x08;
669  if (hasSignature)
670  {
671  if (device->read(buffer2, UNZIP_DD_SIZE) != UNZIP_DD_SIZE)
672  return UnZip::ReadFailed;
673  }
674  else
675  {
676  if (device->read(buffer2 + 4, UNZIP_DD_SIZE - 4) != UNZIP_DD_SIZE - 4)
677  return UnZip::ReadFailed;
678  }
679 
680  // DD: crc, compressed size, uncompressed size
681  if (
682  entry.crc != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CRC32) ||
683  entry.szComp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CSIZE) ||
684  entry.szUncomp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_USIZE)
685  )
687  }
688 
689  return UnZip::Ok;
690 }
quint16 getUShort(const unsigned char *data, quint32 offset) const
Definition: unzip.cpp:1249
bool hasDataDescriptor() const
Definition: zipentry_p.h:75
quint16 compMethod
Definition: zipentry_p.h:64
#define UNZIP_LH_OFF_GPFLAG
Definition: unzip.cpp:105
#define UNZIP_DD_OFF_CRC32
Definition: unzip.cpp:116
unsigned char modTime[2]
Definition: zipentry_p.h:65
quint32 lhOffset
Definition: zipentry_p.h:61
char buffer1[UNZIP_READ_BUFFER]
Definition: unzip_p.h:65
#define UNZIP_DD_SIZE
Data descriptor size (excluding signature)
Definition: unzip.cpp:83
#define UNZIP_DD_OFF_USIZE
Definition: unzip.cpp:118
#define UNZIP_LH_OFF_USIZE
Definition: unzip.cpp:111
QIODevice * device
Definition: unzip_p.h:63
#define UNZIP_LOCAL_HEADER_SIZE
Local header size (excluding signature, excluding variable length fields)
Definition: unzip.cpp:79
#define UNZIP_LH_OFF_XLEN
Definition: unzip.cpp:113
#define UNZIP_LH_OFF_CMETHOD
Definition: unzip.cpp:106
#define UNZIP_LH_OFF_MODD
Definition: unzip.cpp:108
#define UNZIP_DD_OFF_CSIZE
Definition: unzip.cpp:117
unsigned char gpFlag[2]
Definition: zipentry_p.h:63
char buffer2[UNZIP_READ_BUFFER]
Definition: unzip_p.h:66
#define UNZIP_LH_OFF_CRC32
Definition: unzip.cpp:109
quint32 szUncomp
Definition: zipentry_p.h:69
unsigned char * uBuffer
Definition: unzip_p.h:68
unsigned char modDate[2]
Definition: zipentry_p.h:66
#define UNZIP_LH_OFF_MODT
Definition: unzip.cpp:107
quint32 dataOffset
Definition: zipentry_p.h:62
#define UNZIP_LH_OFF_NAMELEN
Definition: unzip.cpp:112
quint32 getULong(const unsigned char *data, quint32 offset) const
Definition: unzip.cpp:1219
quint32 szComp
Definition: zipentry_p.h:68
#define UNZIP_LH_OFF_CSIZE
Definition: unzip.cpp:110
quint32 crc
Definition: zipentry_p.h:67

Here is the call graph for this function:

UnZip::ErrorCode seekToCentralDirectory ( )

Definition at line 713 of file unzip.cpp.

714 {
715  qint64 length = device->size();
716  qint64 offset = length - UNZIP_EOCD_SIZE;
717 
718  if (length < UNZIP_EOCD_SIZE)
719  return UnZip::InvalidArchive;
720 
721  if (!device->seek( offset ))
722  return UnZip::SeekFailed;
723 
724  if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE)
725  return UnZip::ReadFailed;
726 
727  bool eocdFound = (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x05 && buffer1[3] == 0x06);
728 
729  if (eocdFound)
730  {
731  // Zip file has no comment (the only variable length field in the EOCD record)
732  eocdOffset = offset;
733  }
734  else
735  {
736  qint64 read;
737  char* p = 0;
738 
739  offset -= UNZIP_EOCD_SIZE;
740 
741  if (offset <= 0)
742  return UnZip::InvalidArchive;
743 
744  if (!device->seek( offset ))
745  return UnZip::SeekFailed;
746 
747  while ((read = device->read(buffer1, UNZIP_EOCD_SIZE)) >= 0)
748  {
749  if ( (p = strstr(buffer1, "PK\5\6")) != 0)
750  {
751  // Seek to the start of the EOCD record so we can read it fully
752  // Yes... we could simply read the missing bytes and append them to the buffer
753  // but this is far easier so heck it!
754  device->seek( offset + (p - buffer1) );
755  eocdFound = true;
756  eocdOffset = offset + (p - buffer1);
757 
758  // Read EOCD record
759  if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE)
760  return UnZip::ReadFailed;
761 
762  break;
763  }
764 
765  offset -= UNZIP_EOCD_SIZE;
766  if (offset <= 0)
767  return UnZip::InvalidArchive;
768 
769  if (!device->seek( offset ))
770  return UnZip::SeekFailed;
771  }
772  }
773 
774  if (!eocdFound)
775  return UnZip::InvalidArchive;
776 
777  // Parse EOCD to locate CD offset
778  offset = getULong((const unsigned char*)buffer1, UNZIP_EOCD_OFF_CDOFF + 4);
779 
780  cdOffset = offset;
781 
782  cdEntryCount = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_ENTRIES + 4);
783 
784  quint16 commentLength = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_COMMLEN + 4);
785  if (commentLength != 0)
786  {
787  QByteArray c = device->read(commentLength);
788  if (c.count() != commentLength)
789  return UnZip::ReadFailed;
790 
791  comment = c;
792  }
793 
794  // Seek to the start of the CD record
795  if (!device->seek( cdOffset ))
796  return UnZip::SeekFailed;
797 
798  return UnZip::Ok;
799 }
quint16 getUShort(const unsigned char *data, quint32 offset) const
Definition: unzip.cpp:1249
#define UNZIP_EOCD_OFF_CDOFF
Definition: unzip.cpp:122
char buffer1[UNZIP_READ_BUFFER]
Definition: unzip_p.h:65
quint16 cdEntryCount
Definition: unzip_p.h:77
QString comment
Definition: unzip_p.h:82
quint32 eocdOffset
Definition: unzip_p.h:74
quint32 cdOffset
Definition: unzip_p.h:72
QIODevice * device
Definition: unzip_p.h:63
#define UNZIP_EOCD_OFF_COMMLEN
Definition: unzip.cpp:123
#define UNZIP_EOCD_OFF_ENTRIES
Definition: unzip.cpp:121
#define UNZIP_EOCD_SIZE
End Of Central Directory size (including signature, excluding variable length fields) ...
Definition: unzip.cpp:85
quint32 getULong(const unsigned char *data, quint32 offset) const
Definition: unzip.cpp:1219
bool testKeys ( const ZipEntryP header,
quint32 *  keys 
)

Definition at line 1317 of file unzip.cpp.

1318 {
1319  char lastByte;
1320 
1321  // decrypt encryption header
1322  for (int i=0; i<11; ++i)
1323  updateKeys(keys, lastByte = buffer1[i] ^ decryptByte(keys[2]));
1324  updateKeys(keys, lastByte = buffer1[11] ^ decryptByte(keys[2]));
1325 
1326  // if there is an extended header (bit in the gp flag) buffer[11] is a byte from the file time
1327  // with no extended header we have to check the crc high-order byte
1328  char c = ((header.gpFlag[0] & 0x08) == 8) ? header.modTime[1] : header.crc >> 24;
1329 
1330  return (lastByte == c);
1331 }
unsigned char modTime[2]
Definition: zipentry_p.h:65
char buffer1[UNZIP_READ_BUFFER]
Definition: unzip_p.h:65
void updateKeys(quint32 *keys, int c) const
Definition: unzip.cpp:1266
int decryptByte(quint32 key2) const
Definition: unzip.cpp:1257
unsigned char gpFlag[2]
Definition: zipentry_p.h:63
quint32 crc
Definition: zipentry_p.h:67
UnZip::ErrorCode testPassword ( quint32 *  keys,
const QString &  file,
const ZipEntryP header 
)

Definition at line 1298 of file unzip.cpp.

1299 {
1300  Q_UNUSED(file);
1301 
1302  // read encryption keys
1303  if (device->read(buffer1, 12) != 12)
1304  return UnZip::Corrupted;
1305 
1306  // Replace this code if you want to i.e. call some dialog and ask the user for a password
1307  initKeys(password, keys);
1308  if (testKeys(header, keys))
1309  return UnZip::Ok;
1310 
1311  return UnZip::Skip;
1312 }
bool testKeys(const ZipEntryP &header, quint32 *keys)
Definition: unzip.cpp:1317
char buffer1[UNZIP_READ_BUFFER]
Definition: unzip_p.h:65
QString password
Definition: unzip_p.h:57
void initKeys(const QString &pwd, quint32 *keys) const
Definition: unzip.cpp:1278
QIODevice * device
Definition: unzip_p.h:63
void updateKeys ( quint32 *  keys,
int  c 
) const
inline

Definition at line 1266 of file unzip.cpp.

1267 {
1268  keys[0] = CRC32(keys[0], c);
1269  keys[1] += keys[0] & 0xff;
1270  keys[1] = keys[1] * 134775813L + 1;
1271  keys[2] = CRC32(keys[2], ((int)keys[1]) >> 24);
1272 }
#define CRC32(c, b)
CRC32 routine.
Definition: unzip.cpp:136

Member Data Documentation

char buffer1[UNZIP_READ_BUFFER]

Definition at line 65 of file unzip_p.h.

char buffer2[UNZIP_READ_BUFFER]

Definition at line 66 of file unzip_p.h.

quint16 cdEntryCount

Definition at line 77 of file unzip_p.h.

quint32 cdOffset

Definition at line 72 of file unzip_p.h.

QString comment

Definition at line 82 of file unzip_p.h.

Referenced by UnZip::archiveComment().

const quint32* crcTable

Definition at line 69 of file unzip_p.h.

QIODevice* device

Definition at line 63 of file unzip_p.h.

Referenced by UnZip::archiveComment(), UnZip::extractAll(), and UnZip::isOpen().

quint32 eocdOffset

Definition at line 74 of file unzip_p.h.

QMap<QString,ZipEntryP*>* headers
QString password

Definition at line 57 of file unzip_p.h.

Referenced by UnZip::setPassword().

bool skipAllEncrypted

Definition at line 59 of file unzip_p.h.

Referenced by UnZip::extractAll().

unsigned char* uBuffer

Definition at line 68 of file unzip_p.h.

quint16 unsupportedEntryCount

Definition at line 80 of file unzip_p.h.


The documentation for this class was generated from the following files: