Show reading progress.
[dorian] / model / extractzip.cpp
1 #include <QDebug>
2 #include <QFile>
3 #include <QDir>
4
5 #include "extractzip.h"
6 #include "unzip/unzip.h"
7
8 #define WRITEBUFFERSIZE (8192)
9 #define MAXFILENAME (256)
10
11 int doExtractCurrentFile(unzFile uf)
12 {
13     char fileNameInZip[MAXFILENAME];
14     char *fileNameWithoutPath;
15     char *p;
16     int err = UNZ_OK;
17     QFile *f = 0;
18     QDir dir;
19     void *buf;
20     uInt bufSize;
21     bool ret = true;
22     unz_file_info64 fileInfo;
23
24     err = unzGetCurrentFileInfo64(uf, &fileInfo, fileNameInZip,
25                                   sizeof(fileNameInZip), NULL, 0, NULL, 0);
26     if (err != UNZ_OK) {
27         qDebug() << "doExtractCurrentFile: Error" << err
28                 << "in unzGetCurrentFileInfo";
29         return err;
30     }
31
32     bufSize = WRITEBUFFERSIZE;
33     buf = (void *)malloc(bufSize);
34     if (buf == NULL) {
35         qDebug() << "doExtractCurrentFile: Error allocating memory";
36         return UNZ_INTERNALERROR;
37     }
38
39     p = fileNameWithoutPath = fileNameInZip;
40     while ((*p) != '\0') {
41         if (((*p) == '/') || ((*p) == '\\')) {
42             fileNameWithoutPath = p+1;
43         }
44         p++;
45     }
46
47     if ((*fileNameWithoutPath) == '\0') {
48         dir.mkdir(fileNameInZip);
49     }
50     else {
51         const char *writeFileName;
52         int skip = 0;
53
54         writeFileName = fileNameInZip;
55
56         err = unzOpenCurrentFilePassword(uf, 0);
57         if (err != UNZ_OK) {
58             qDebug() << "doExtractCurrentFile: Error" << err
59                     << "in unzOpenCurrentFilePassword";
60             ret = false;
61         }
62
63         if ((skip == 0) && (err == UNZ_OK)) {
64             f = new QFile(writeFileName);
65             ret = f->open(QIODevice::WriteOnly);
66
67             /* some zipfile don't contain directory alone before file */
68             if (!ret && (fileNameWithoutPath != (char *)fileNameInZip))
69             {
70                 char c = *(fileNameWithoutPath-1);
71                 *(fileNameWithoutPath - 1) = '\0';
72                 dir.mkpath(writeFileName);
73                 *(fileNameWithoutPath - 1) = c;
74                 delete f;
75                 f = new QFile(writeFileName);
76                 ret = f->open(QIODevice::WriteOnly);
77             }
78
79             if (!ret) {
80                 qDebug() << "doExtractCurrentFile: Error opening"
81                         << writeFileName;
82             }
83         }
84
85         if (ret) {
86             do {
87                 err = unzReadCurrentFile(uf, buf, bufSize);
88                 if (err < 0) {
89                     qDebug() << "doExtractCurrentFile: Error" << err
90                             << "in unzReadCurrentFile";
91                     break;
92                 }
93                 if (err > 0) {
94                     if (f->write((char *)buf, err) != err) {
95                         qDebug() << "doExtractCurrentFile:"
96                                 << "Error in writing extracted file";
97                         err = UNZ_ERRNO;
98                         break;
99                     }
100                 }
101             }
102             while (err > 0);
103
104             f->close();
105         }
106
107         if (err== UNZ_OK) {
108             err = unzCloseCurrentFile(uf);
109             if (err != UNZ_OK) {
110                 qDebug() << "doExtractCurrentFile: Error" << err
111                        << "with zipfile in unzCloseCurrentFile";
112             }
113         }
114         else {
115             unzCloseCurrentFile(uf); /* don't lose the error */
116         }
117     }
118
119     delete f;
120     free(buf);
121     return err;
122 }
123
124 bool doExtract(unzFile uf)
125 {
126     uLong i;
127     unz_global_info64 gi;
128     int err;
129
130     err = unzGetGlobalInfo64(uf,&gi);
131     if (err != UNZ_OK) {
132         qDebug() << "doExtract: Error" << err << "in unzGetGlobalInfo";
133         return false;
134     }
135
136     for (i = 0; i < gi.number_entry; i++) {
137         if (doExtractCurrentFile(uf) != UNZ_OK) {
138             return false;
139         }
140         if ((i + 1) < gi.number_entry) {
141             err = unzGoToNextFile(uf);
142             if (err != UNZ_OK) {
143                 qDebug() << "doExtract: Error" << err << "in unzGoToNextFile";
144                 return false;
145             }
146         }
147     }
148
149     return true;
150 }
151
152 bool extractZip(const QString &zipFile)
153 {
154     unzFile uf;
155     bool ret = false;
156
157     uf = unzOpen64(zipFile.toUtf8().constData());
158     if (uf) {
159         ret = doExtract(uf);
160         unzClose(uf);
161     }
162     return ret;
163 }