quazipfile.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. Copyright (C) 2005-2011 Sergey A. Tachenov
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at
  6. your option) any later version.
  7. This program is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
  10. General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  14. See COPYING file for the full LGPL text.
  15. Original ZIP package is copyrighted by Gilles Vollant, see
  16. quazip/(un)zip.h files for details, basically it's zlib license.
  17. **/
  18. #include "quazipfile.h"
  19. using namespace std;
  20. class QuaZipFilePrivate {
  21. friend class QuaZipFile;
  22. private:
  23. QuaZipFile *q;
  24. QuaZip *zip;
  25. QString fileName;
  26. QuaZip::CaseSensitivity caseSensitivity;
  27. bool raw;
  28. qint64 writePos;
  29. // these two are for writing raw files
  30. ulong uncompressedSize;
  31. quint32 crc;
  32. bool internal;
  33. int zipError;
  34. inline void resetZipError() const {setZipError(UNZ_OK);}
  35. // const, but sets zipError!
  36. void setZipError(int zipError) const;
  37. inline QuaZipFilePrivate(QuaZipFile *q):
  38. q(q), zip(NULL), internal(true), zipError(UNZ_OK) {}
  39. inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName):
  40. q(q), internal(true), zipError(UNZ_OK)
  41. {
  42. zip=new QuaZip(zipName);
  43. }
  44. inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName,
  45. QuaZip::CaseSensitivity cs):
  46. q(q), internal(true), zipError(UNZ_OK)
  47. {
  48. zip=new QuaZip(zipName);
  49. this->fileName=fileName;
  50. this->caseSensitivity=cs;
  51. }
  52. inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip):
  53. q(q), zip(zip), internal(false), zipError(UNZ_OK) {}
  54. inline ~QuaZipFilePrivate()
  55. {
  56. if (internal)
  57. delete zip;
  58. }
  59. };
  60. QuaZipFile::QuaZipFile():
  61. p(new QuaZipFilePrivate(this))
  62. {
  63. }
  64. QuaZipFile::QuaZipFile(QObject *parent):
  65. QIODevice(parent),
  66. p(new QuaZipFilePrivate(this))
  67. {
  68. }
  69. QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
  70. QIODevice(parent),
  71. p(new QuaZipFilePrivate(this, zipName))
  72. {
  73. }
  74. QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
  75. QuaZip::CaseSensitivity cs, QObject *parent):
  76. QIODevice(parent),
  77. p(new QuaZipFilePrivate(this, zipName, fileName, cs))
  78. {
  79. }
  80. QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
  81. QIODevice(parent),
  82. p(new QuaZipFilePrivate(this, zip))
  83. {
  84. }
  85. QuaZipFile::~QuaZipFile()
  86. {
  87. if (isOpen())
  88. close();
  89. delete p;
  90. }
  91. QString QuaZipFile::getZipName() const
  92. {
  93. return p->zip==NULL ? QString() : p->zip->getZipName();
  94. }
  95. QString QuaZipFile::getActualFileName()const
  96. {
  97. p->setZipError(UNZ_OK);
  98. if (p->zip == NULL || (openMode() & WriteOnly))
  99. return QString();
  100. QString name=p->zip->getCurrentFileName();
  101. if(name.isNull())
  102. p->setZipError(p->zip->getZipError());
  103. return name;
  104. }
  105. void QuaZipFile::setZipName(const QString& zipName)
  106. {
  107. if(isOpen()) {
  108. qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
  109. return;
  110. }
  111. if(p->zip!=NULL && p->internal)
  112. delete p->zip;
  113. p->zip=new QuaZip(zipName);
  114. p->internal=true;
  115. }
  116. void QuaZipFile::setZip(QuaZip *zip)
  117. {
  118. if(isOpen()) {
  119. qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
  120. return;
  121. }
  122. if(p->zip!=NULL && p->internal)
  123. delete p->zip;
  124. p->zip=zip;
  125. p->fileName=QString();
  126. p->internal=false;
  127. }
  128. void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
  129. {
  130. if(p->zip==NULL) {
  131. qWarning("QuaZipFile::setFileName(): call setZipName() first");
  132. return;
  133. }
  134. if(!p->internal) {
  135. qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
  136. return;
  137. }
  138. if(isOpen()) {
  139. qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
  140. return;
  141. }
  142. p->fileName=fileName;
  143. p->caseSensitivity=cs;
  144. }
  145. void QuaZipFilePrivate::setZipError(int zipError) const
  146. {
  147. QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
  148. fakeThis->zipError=zipError;
  149. if(zipError==UNZ_OK)
  150. q->setErrorString(QString());
  151. else
  152. q->setErrorString(q->tr("ZIP/UNZIP API error %1").arg(zipError));
  153. }
  154. bool QuaZipFile::open(OpenMode mode)
  155. {
  156. return open(mode, NULL);
  157. }
  158. bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
  159. {
  160. p->resetZipError();
  161. if(isOpen()) {
  162. qWarning("QuaZipFile::open(): already opened");
  163. return false;
  164. }
  165. if(mode&Unbuffered) {
  166. qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
  167. return false;
  168. }
  169. if((mode&ReadOnly)&&!(mode&WriteOnly)) {
  170. if(p->internal) {
  171. if(!p->zip->open(QuaZip::mdUnzip)) {
  172. p->setZipError(p->zip->getZipError());
  173. return false;
  174. }
  175. if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) {
  176. p->setZipError(p->zip->getZipError());
  177. p->zip->close();
  178. return false;
  179. }
  180. } else {
  181. if(p->zip==NULL) {
  182. qWarning("QuaZipFile::open(): zip is NULL");
  183. return false;
  184. }
  185. if(p->zip->getMode()!=QuaZip::mdUnzip) {
  186. qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
  187. (int)mode, (int)p->zip->getMode());
  188. return false;
  189. }
  190. if(!p->zip->hasCurrentFile()) {
  191. qWarning("QuaZipFile::open(): zip does not have current file");
  192. return false;
  193. }
  194. }
  195. p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password));
  196. if(p->zipError==UNZ_OK) {
  197. setOpenMode(mode);
  198. p->raw=raw;
  199. return true;
  200. } else
  201. return false;
  202. }
  203. qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
  204. return false;
  205. }
  206. bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info,
  207. const char *password, quint32 crc,
  208. int method, int level, bool raw,
  209. int windowBits, int memLevel, int strategy)
  210. {
  211. zip_fileinfo info_z;
  212. p->resetZipError();
  213. if(isOpen()) {
  214. qWarning("QuaZipFile::open(): already opened");
  215. return false;
  216. }
  217. if((mode&WriteOnly)&&!(mode&ReadOnly)) {
  218. if(p->internal) {
  219. qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
  220. return false;
  221. }
  222. if(p->zip==NULL) {
  223. qWarning("QuaZipFile::open(): zip is NULL");
  224. return false;
  225. }
  226. if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) {
  227. qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
  228. (int)mode, (int)p->zip->getMode());
  229. return false;
  230. }
  231. info_z.tmz_date.tm_year=info.dateTime.date().year();
  232. info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1;
  233. info_z.tmz_date.tm_mday=info.dateTime.date().day();
  234. info_z.tmz_date.tm_hour=info.dateTime.time().hour();
  235. info_z.tmz_date.tm_min=info.dateTime.time().minute();
  236. info_z.tmz_date.tm_sec=info.dateTime.time().second();
  237. info_z.dosDate = 0;
  238. info_z.internal_fa=(uLong)info.internalAttr;
  239. info_z.external_fa=(uLong)info.externalAttr;
  240. if (!p->zip->isDataDescriptorWritingEnabled())
  241. zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
  242. p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(),
  243. p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
  244. info.extraLocal.constData(), info.extraLocal.length(),
  245. info.extraGlobal.constData(), info.extraGlobal.length(),
  246. p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
  247. method, level, (int)raw,
  248. windowBits, memLevel, strategy,
  249. password, (uLong)crc));
  250. if(p->zipError==UNZ_OK) {
  251. p->writePos=0;
  252. setOpenMode(mode);
  253. p->raw=raw;
  254. if(raw) {
  255. p->crc=crc;
  256. p->uncompressedSize=info.uncompressedSize;
  257. }
  258. return true;
  259. } else
  260. return false;
  261. }
  262. qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
  263. return false;
  264. }
  265. bool QuaZipFile::isSequential()const
  266. {
  267. return true;
  268. }
  269. qint64 QuaZipFile::pos()const
  270. {
  271. if(p->zip==NULL) {
  272. qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
  273. return -1;
  274. }
  275. if(!isOpen()) {
  276. qWarning("QuaZipFile::pos(): file is not open");
  277. return -1;
  278. }
  279. if(openMode()&ReadOnly)
  280. // QIODevice::pos() is broken for sequential devices,
  281. // but thankfully bytesAvailable() returns the number of
  282. // bytes buffered, so we know how far ahead we are.
  283. return unztell(p->zip->getUnzFile()) - QIODevice::bytesAvailable();
  284. else
  285. return p->writePos;
  286. }
  287. bool QuaZipFile::atEnd()const
  288. {
  289. if(p->zip==NULL) {
  290. qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
  291. return false;
  292. }
  293. if(!isOpen()) {
  294. qWarning("QuaZipFile::atEnd(): file is not open");
  295. return false;
  296. }
  297. if(openMode()&ReadOnly)
  298. // the same problem as with pos()
  299. return QIODevice::bytesAvailable() == 0
  300. && unzeof(p->zip->getUnzFile())==1;
  301. else
  302. return true;
  303. }
  304. qint64 QuaZipFile::size()const
  305. {
  306. if(!isOpen()) {
  307. qWarning("QuaZipFile::atEnd(): file is not open");
  308. return -1;
  309. }
  310. if(openMode()&ReadOnly)
  311. return p->raw?csize():usize();
  312. else
  313. return p->writePos;
  314. }
  315. qint64 QuaZipFile::csize()const
  316. {
  317. unz_file_info info_z;
  318. p->setZipError(UNZ_OK);
  319. if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
  320. p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
  321. if(p->zipError!=UNZ_OK)
  322. return -1;
  323. return info_z.compressed_size;
  324. }
  325. qint64 QuaZipFile::usize()const
  326. {
  327. unz_file_info info_z;
  328. p->setZipError(UNZ_OK);
  329. if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
  330. p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
  331. if(p->zipError!=UNZ_OK)
  332. return -1;
  333. return info_z.uncompressed_size;
  334. }
  335. bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
  336. {
  337. if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
  338. p->zip->getCurrentFileInfo(info);
  339. p->setZipError(p->zip->getZipError());
  340. return p->zipError==UNZ_OK;
  341. }
  342. void QuaZipFile::close()
  343. {
  344. p->resetZipError();
  345. if(p->zip==NULL||!p->zip->isOpen()) return;
  346. if(!isOpen()) {
  347. qWarning("QuaZipFile::close(): file isn't open");
  348. return;
  349. }
  350. if(openMode()&ReadOnly)
  351. p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
  352. else if(openMode()&WriteOnly)
  353. if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc));
  354. else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
  355. else {
  356. qWarning("Wrong open mode: %d", (int)openMode());
  357. return;
  358. }
  359. if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
  360. else return;
  361. if(p->internal) {
  362. p->zip->close();
  363. p->setZipError(p->zip->getZipError());
  364. }
  365. }
  366. qint64 QuaZipFile::readData(char *data, qint64 maxSize)
  367. {
  368. p->setZipError(UNZ_OK);
  369. qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
  370. if(bytesRead<0) p->setZipError((int)bytesRead);
  371. return bytesRead;
  372. }
  373. qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
  374. {
  375. p->setZipError(ZIP_OK);
  376. p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
  377. if(p->zipError!=ZIP_OK) return -1;
  378. else {
  379. p->writePos+=maxSize;
  380. return maxSize;
  381. }
  382. }
  383. QString QuaZipFile::getFileName() const
  384. {
  385. return p->fileName;
  386. }
  387. QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
  388. {
  389. return p->caseSensitivity;
  390. }
  391. bool QuaZipFile::isRaw() const
  392. {
  393. return p->raw;
  394. }
  395. int QuaZipFile::getZipError() const
  396. {
  397. return p->zipError;
  398. }
  399. qint64 QuaZipFile::bytesAvailable() const
  400. {
  401. return size() - pos();
  402. }