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

http://github.com/tomahawk-player/tomahawk · C++ · 428 lines · 372 code · 32 blank · 24 comment · 61 complexity · 5c93b119b334321a8d942d7541f1582e 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 "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. p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(),
  241. p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
  242. info.extraLocal.constData(), info.extraLocal.length(),
  243. info.extraGlobal.constData(), info.extraGlobal.length(),
  244. p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
  245. method, level, (int)raw,
  246. windowBits, memLevel, strategy,
  247. password, (uLong)crc));
  248. if(p->zipError==UNZ_OK) {
  249. p->writePos=0;
  250. setOpenMode(mode);
  251. p->raw=raw;
  252. if(raw) {
  253. p->crc=crc;
  254. p->uncompressedSize=info.uncompressedSize;
  255. }
  256. return true;
  257. } else
  258. return false;
  259. }
  260. qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
  261. return false;
  262. }
  263. bool QuaZipFile::isSequential()const
  264. {
  265. return true;
  266. }
  267. qint64 QuaZipFile::pos()const
  268. {
  269. if(p->zip==NULL) {
  270. qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
  271. return -1;
  272. }
  273. if(!isOpen()) {
  274. qWarning("QuaZipFile::pos(): file is not open");
  275. return -1;
  276. }
  277. if(openMode()&ReadOnly)
  278. return unztell(p->zip->getUnzFile());
  279. else
  280. return p->writePos;
  281. }
  282. bool QuaZipFile::atEnd()const
  283. {
  284. if(p->zip==NULL) {
  285. qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
  286. return false;
  287. }
  288. if(!isOpen()) {
  289. qWarning("QuaZipFile::atEnd(): file is not open");
  290. return false;
  291. }
  292. if(openMode()&ReadOnly)
  293. return unzeof(p->zip->getUnzFile())==1;
  294. else
  295. return true;
  296. }
  297. qint64 QuaZipFile::size()const
  298. {
  299. if(!isOpen()) {
  300. qWarning("QuaZipFile::atEnd(): file is not open");
  301. return -1;
  302. }
  303. if(openMode()&ReadOnly)
  304. return p->raw?csize():usize();
  305. else
  306. return p->writePos;
  307. }
  308. qint64 QuaZipFile::csize()const
  309. {
  310. unz_file_info info_z;
  311. p->setZipError(UNZ_OK);
  312. if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
  313. p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
  314. if(p->zipError!=UNZ_OK)
  315. return -1;
  316. return info_z.compressed_size;
  317. }
  318. qint64 QuaZipFile::usize()const
  319. {
  320. unz_file_info info_z;
  321. p->setZipError(UNZ_OK);
  322. if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
  323. p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
  324. if(p->zipError!=UNZ_OK)
  325. return -1;
  326. return info_z.uncompressed_size;
  327. }
  328. bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
  329. {
  330. if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
  331. p->zip->getCurrentFileInfo(info);
  332. p->setZipError(p->zip->getZipError());
  333. return p->zipError==UNZ_OK;
  334. }
  335. void QuaZipFile::close()
  336. {
  337. p->resetZipError();
  338. if(p->zip==NULL||!p->zip->isOpen()) return;
  339. if(!isOpen()) {
  340. qWarning("QuaZipFile::close(): file isn't open");
  341. return;
  342. }
  343. if(openMode()&ReadOnly)
  344. p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
  345. else if(openMode()&WriteOnly)
  346. if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc));
  347. else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
  348. else {
  349. qWarning("Wrong open mode: %d", (int)openMode());
  350. return;
  351. }
  352. if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
  353. else return;
  354. if(p->internal) {
  355. p->zip->close();
  356. p->setZipError(p->zip->getZipError());
  357. }
  358. }
  359. qint64 QuaZipFile::readData(char *data, qint64 maxSize)
  360. {
  361. p->setZipError(UNZ_OK);
  362. qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
  363. if(bytesRead<0) p->setZipError((int)bytesRead);
  364. return bytesRead;
  365. }
  366. qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
  367. {
  368. p->setZipError(ZIP_OK);
  369. p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
  370. if(p->zipError!=ZIP_OK) return -1;
  371. else {
  372. p->writePos+=maxSize;
  373. return maxSize;
  374. }
  375. }
  376. QString QuaZipFile::getFileName() const
  377. {
  378. return p->fileName;
  379. }
  380. QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
  381. {
  382. return p->caseSensitivity;
  383. }
  384. bool QuaZipFile::isRaw() const
  385. {
  386. return p->raw;
  387. }
  388. int QuaZipFile::getZipError() const
  389. {
  390. return p->zipError;
  391. }