/src/libtomahawk/thirdparty/quazip/quazip/quazip.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 427 lines · 370 code · 33 blank · 24 comment · 49 complexity · 2cdfe96a7ba2f1486b77ca1582759672 MD5 · raw file

  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 <QFile>
  19. #include "quazip.h"
  20. class QuaZipPrivate {
  21. friend class QuaZip;
  22. private:
  23. QTextCodec *fileNameCodec, *commentCodec;
  24. QString zipName;
  25. QIODevice *ioDevice;
  26. QString comment;
  27. QuaZip::Mode mode;
  28. union {
  29. unzFile unzFile_f;
  30. zipFile zipFile_f;
  31. };
  32. bool hasCurrentFile_f;
  33. int zipError;
  34. inline QuaZipPrivate():
  35. fileNameCodec(QTextCodec::codecForLocale()),
  36. commentCodec(QTextCodec::codecForLocale()),
  37. ioDevice(NULL),
  38. mode(QuaZip::mdNotOpen),
  39. hasCurrentFile_f(false),
  40. zipError(UNZ_OK) {}
  41. inline QuaZipPrivate(const QString &zipName):
  42. fileNameCodec(QTextCodec::codecForLocale()),
  43. commentCodec(QTextCodec::codecForLocale()),
  44. zipName(zipName),
  45. ioDevice(NULL),
  46. mode(QuaZip::mdNotOpen),
  47. hasCurrentFile_f(false),
  48. zipError(UNZ_OK) {}
  49. inline QuaZipPrivate(QIODevice *ioDevice):
  50. fileNameCodec(QTextCodec::codecForLocale()),
  51. commentCodec(QTextCodec::codecForLocale()),
  52. ioDevice(ioDevice),
  53. mode(QuaZip::mdNotOpen),
  54. hasCurrentFile_f(false),
  55. zipError(UNZ_OK) {}
  56. };
  57. QuaZip::QuaZip():
  58. p(new QuaZipPrivate())
  59. {
  60. }
  61. QuaZip::QuaZip(const QString& zipName):
  62. p(new QuaZipPrivate(zipName))
  63. {
  64. }
  65. QuaZip::QuaZip(QIODevice *ioDevice):
  66. p(new QuaZipPrivate(ioDevice))
  67. {
  68. }
  69. QuaZip::~QuaZip()
  70. {
  71. if(isOpen())
  72. close();
  73. delete p;
  74. }
  75. bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi)
  76. {
  77. p->zipError=UNZ_OK;
  78. if(isOpen()) {
  79. qWarning("QuaZip::open(): ZIP already opened");
  80. return false;
  81. }
  82. QIODevice *ioDevice = p->ioDevice;
  83. if (ioDevice == NULL) {
  84. if (p->zipName.isEmpty()) {
  85. qWarning("QuaZip::open(): set either ZIP file name or IO device first");
  86. return false;
  87. } else {
  88. ioDevice = new QFile(p->zipName);
  89. }
  90. }
  91. switch(mode) {
  92. case mdUnzip:
  93. p->unzFile_f=unzOpen2(ioDevice, ioApi);
  94. if(p->unzFile_f!=NULL) {
  95. p->mode=mode;
  96. p->ioDevice = ioDevice;
  97. return true;
  98. } else {
  99. p->zipError=UNZ_OPENERROR;
  100. if (!p->zipName.isEmpty())
  101. delete ioDevice;
  102. return false;
  103. }
  104. case mdCreate:
  105. case mdAppend:
  106. case mdAdd:
  107. p->zipFile_f=zipOpen2(ioDevice,
  108. mode==mdCreate?APPEND_STATUS_CREATE:
  109. mode==mdAppend?APPEND_STATUS_CREATEAFTER:
  110. APPEND_STATUS_ADDINZIP,
  111. NULL,
  112. ioApi);
  113. if(p->zipFile_f!=NULL) {
  114. p->mode=mode;
  115. p->ioDevice = ioDevice;
  116. return true;
  117. } else {
  118. p->zipError=UNZ_OPENERROR;
  119. if (!p->zipName.isEmpty())
  120. delete ioDevice;
  121. return false;
  122. }
  123. default:
  124. qWarning("QuaZip::open(): unknown mode: %d", (int)mode);
  125. if (!p->zipName.isEmpty())
  126. delete ioDevice;
  127. return false;
  128. break;
  129. }
  130. }
  131. void QuaZip::close()
  132. {
  133. p->zipError=UNZ_OK;
  134. switch(p->mode) {
  135. case mdNotOpen:
  136. qWarning("QuaZip::close(): ZIP is not open");
  137. return;
  138. case mdUnzip:
  139. p->zipError=unzClose(p->unzFile_f);
  140. break;
  141. case mdCreate:
  142. case mdAppend:
  143. case mdAdd:
  144. p->zipError=zipClose(p->zipFile_f, p->commentCodec->fromUnicode(p->comment).constData());
  145. break;
  146. default:
  147. qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode);
  148. return;
  149. }
  150. // opened by name, need to delete the internal IO device
  151. if (!p->zipName.isEmpty())
  152. delete p->ioDevice;
  153. if(p->zipError==UNZ_OK)
  154. p->mode=mdNotOpen;
  155. }
  156. void QuaZip::setZipName(const QString& zipName)
  157. {
  158. if(isOpen()) {
  159. qWarning("QuaZip::setZipName(): ZIP is already open!");
  160. return;
  161. }
  162. p->zipName=zipName;
  163. p->ioDevice = NULL;
  164. }
  165. void QuaZip::setIoDevice(QIODevice *ioDevice)
  166. {
  167. if(isOpen()) {
  168. qWarning("QuaZip::setIoDevice(): ZIP is already open!");
  169. return;
  170. }
  171. p->ioDevice = ioDevice;
  172. p->zipName = QString();
  173. }
  174. int QuaZip::getEntriesCount()const
  175. {
  176. QuaZip *fakeThis=(QuaZip*)this; // non-const
  177. fakeThis->p->zipError=UNZ_OK;
  178. if(p->mode!=mdUnzip) {
  179. qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode");
  180. return -1;
  181. }
  182. unz_global_info globalInfo;
  183. if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK)
  184. return p->zipError;
  185. return (int)globalInfo.number_entry;
  186. }
  187. QString QuaZip::getComment()const
  188. {
  189. QuaZip *fakeThis=(QuaZip*)this; // non-const
  190. fakeThis->p->zipError=UNZ_OK;
  191. if(p->mode!=mdUnzip) {
  192. qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode");
  193. return QString();
  194. }
  195. unz_global_info globalInfo;
  196. QByteArray comment;
  197. if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK)
  198. return QString();
  199. comment.resize(globalInfo.size_comment);
  200. if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0)
  201. return QString();
  202. fakeThis->p->zipError = UNZ_OK;
  203. return p->commentCodec->toUnicode(comment);
  204. }
  205. bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs)
  206. {
  207. p->zipError=UNZ_OK;
  208. if(p->mode!=mdUnzip) {
  209. qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode");
  210. return false;
  211. }
  212. if(fileName.isEmpty()) {
  213. p->hasCurrentFile_f=false;
  214. return true;
  215. }
  216. // Unicode-aware reimplementation of the unzLocateFile function
  217. if(p->unzFile_f==NULL) {
  218. p->zipError=UNZ_PARAMERROR;
  219. return false;
  220. }
  221. if(fileName.length()>MAX_FILE_NAME_LENGTH) {
  222. p->zipError=UNZ_PARAMERROR;
  223. return false;
  224. }
  225. bool sens;
  226. if(cs==csDefault) {
  227. #ifdef Q_WS_WIN
  228. sens=false;
  229. #else
  230. sens=true;
  231. #endif
  232. } else sens=cs==csSensitive;
  233. QString lower, current;
  234. if(!sens) lower=fileName.toLower();
  235. p->hasCurrentFile_f=false;
  236. for(bool more=goToFirstFile(); more; more=goToNextFile()) {
  237. current=getCurrentFileName();
  238. if(current.isEmpty()) return false;
  239. if(sens) {
  240. if(current==fileName) break;
  241. } else {
  242. if(current.toLower()==lower) break;
  243. }
  244. }
  245. return p->hasCurrentFile_f;
  246. }
  247. bool QuaZip::goToFirstFile()
  248. {
  249. p->zipError=UNZ_OK;
  250. if(p->mode!=mdUnzip) {
  251. qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode");
  252. return false;
  253. }
  254. p->zipError=unzGoToFirstFile(p->unzFile_f);
  255. p->hasCurrentFile_f=p->zipError==UNZ_OK;
  256. return p->hasCurrentFile_f;
  257. }
  258. bool QuaZip::goToNextFile()
  259. {
  260. p->zipError=UNZ_OK;
  261. if(p->mode!=mdUnzip) {
  262. qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode");
  263. return false;
  264. }
  265. p->zipError=unzGoToNextFile(p->unzFile_f);
  266. p->hasCurrentFile_f=p->zipError==UNZ_OK;
  267. if(p->zipError==UNZ_END_OF_LIST_OF_FILE)
  268. p->zipError=UNZ_OK;
  269. return p->hasCurrentFile_f;
  270. }
  271. bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const
  272. {
  273. QuaZip *fakeThis=(QuaZip*)this; // non-const
  274. fakeThis->p->zipError=UNZ_OK;
  275. if(p->mode!=mdUnzip) {
  276. qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode");
  277. return false;
  278. }
  279. unz_file_info info_z;
  280. QByteArray fileName;
  281. QByteArray extra;
  282. QByteArray comment;
  283. if(info==NULL) return false;
  284. if(!isOpen()||!hasCurrentFile()) return false;
  285. if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK)
  286. return false;
  287. fileName.resize(info_z.size_filename);
  288. extra.resize(info_z.size_file_extra);
  289. comment.resize(info_z.size_file_comment);
  290. if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL,
  291. fileName.data(), fileName.size(),
  292. extra.data(), extra.size(),
  293. comment.data(), comment.size()))!=UNZ_OK)
  294. return false;
  295. info->versionCreated=info_z.version;
  296. info->versionNeeded=info_z.version_needed;
  297. info->flags=info_z.flag;
  298. info->method=info_z.compression_method;
  299. info->crc=info_z.crc;
  300. info->compressedSize=info_z.compressed_size;
  301. info->uncompressedSize=info_z.uncompressed_size;
  302. info->diskNumberStart=info_z.disk_num_start;
  303. info->internalAttr=info_z.internal_fa;
  304. info->externalAttr=info_z.external_fa;
  305. info->name=p->fileNameCodec->toUnicode(fileName);
  306. info->comment=p->commentCodec->toUnicode(comment);
  307. info->extra=extra;
  308. info->dateTime=QDateTime(
  309. QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday),
  310. QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec));
  311. return true;
  312. }
  313. QString QuaZip::getCurrentFileName()const
  314. {
  315. QuaZip *fakeThis=(QuaZip*)this; // non-const
  316. fakeThis->p->zipError=UNZ_OK;
  317. if(p->mode!=mdUnzip) {
  318. qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode");
  319. return QString();
  320. }
  321. if(!isOpen()||!hasCurrentFile()) return QString();
  322. QByteArray fileName(MAX_FILE_NAME_LENGTH, 0);
  323. if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL, fileName.data(), fileName.size(),
  324. NULL, 0, NULL, 0))!=UNZ_OK)
  325. return QString();
  326. return p->fileNameCodec->toUnicode(fileName.constData());
  327. }
  328. void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec)
  329. {
  330. p->fileNameCodec=fileNameCodec;
  331. }
  332. void QuaZip::setFileNameCodec(const char *fileNameCodecName)
  333. {
  334. p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName);
  335. }
  336. QTextCodec *QuaZip::getFileNameCodec()const
  337. {
  338. return p->fileNameCodec;
  339. }
  340. void QuaZip::setCommentCodec(QTextCodec *commentCodec)
  341. {
  342. p->commentCodec=commentCodec;
  343. }
  344. void QuaZip::setCommentCodec(const char *commentCodecName)
  345. {
  346. p->commentCodec=QTextCodec::codecForName(commentCodecName);
  347. }
  348. QTextCodec *QuaZip::getCommentCodec()const
  349. {
  350. return p->commentCodec;
  351. }
  352. QString QuaZip::getZipName() const
  353. {
  354. return p->zipName;
  355. }
  356. QIODevice *QuaZip::getIoDevice() const
  357. {
  358. if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice
  359. return NULL;
  360. return p->ioDevice;
  361. }
  362. QuaZip::Mode QuaZip::getMode()const
  363. {
  364. return p->mode;
  365. }
  366. bool QuaZip::isOpen()const
  367. {
  368. return p->mode!=mdNotOpen;
  369. }
  370. int QuaZip::getZipError() const
  371. {
  372. return p->zipError;
  373. }
  374. void QuaZip::setComment(const QString& comment)
  375. {
  376. p->comment=comment;
  377. }
  378. bool QuaZip::hasCurrentFile()const
  379. {
  380. return p->hasCurrentFile_f;
  381. }
  382. unzFile QuaZip::getUnzFile()
  383. {
  384. return p->unzFile_f;
  385. }
  386. zipFile QuaZip::getZipFile()
  387. {
  388. return p->zipFile_f;
  389. }