Fix forward navigation control on Linux.
[dorian] / model / extractzip.cpp
1 #include <QFile>
2 #include <QDir>
3 #include <QDebug>
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, const QStringList &excludedExtensions)
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         QString name(fileNameInZip);
52         for (int i = 0; i < excludedExtensions.length(); i++) {
53             if (name.endsWith(excludedExtensions[i], Qt::CaseInsensitive)) {
54                 qDebug() << "extractCurrentFile: Skipping" << name;
55                 free(buf);
56                 return UNZ_OK;
57             }
58         }
59         qDebug() << "extractCurrentFile: Extracting" << name;
60
61         const char *writeFileName;
62         int skip = 0;
63
64         writeFileName = fileNameInZip;
65
66         err = unzOpenCurrentFilePassword(uf, 0);
67         if (err != UNZ_OK) {
68             qDebug() << "doExtractCurrentFile: Error" << err
69                     << "in unzOpenCurrentFilePassword";
70             ret = false;
71         }
72
73         if ((skip == 0) && (err == UNZ_OK)) {
74             f = new QFile(writeFileName);
75             ret = f->open(QIODevice::WriteOnly);
76
77             /* some zipfile don't contain directory alone before file */
78             if (!ret && (fileNameWithoutPath != (char *)fileNameInZip))
79             {
80                 char c = *(fileNameWithoutPath-1);
81                 *(fileNameWithoutPath - 1) = '\0';
82                 dir.mkpath(writeFileName);
83                 *(fileNameWithoutPath - 1) = c;
84                 delete f;
85                 f = new QFile(writeFileName);
86                 ret = f->open(QIODevice::WriteOnly);
87             }
88
89             if (!ret) {
90                 qDebug() << "doExtractCurrentFile: Error opening"
91                         << writeFileName;
92             }
93         }
94
95         if (ret) {
96             do {
97                 err = unzReadCurrentFile(uf, buf, bufSize);
98                 if (err < 0) {
99                     qDebug() << "doExtractCurrentFile: Error" << err
100                             << "in unzReadCurrentFile";
101                     break;
102                 }
103                 if (err > 0) {
104                     if (f->write((char *)buf, err) != err) {
105                         qDebug() << "doExtractCurrentFile:"
106                                 << "Error in writing extracted file";
107                         err = UNZ_ERRNO;
108                         break;
109                     }
110                 }
111             }
112             while (err > 0);
113
114             f->close();
115         }
116
117         if (err == UNZ_OK) {
118             err = unzCloseCurrentFile(uf);
119             if (err != UNZ_OK) {
120                 qDebug() << "doExtractCurrentFile: Error" << err
121                        << "with zipfile in unzCloseCurrentFile";
122             }
123         }
124         else {
125             unzCloseCurrentFile(uf); /* don't lose the error */
126         }
127     }
128
129     delete f;
130     free(buf);
131     return err;
132 }
133
134 bool doExtract(unzFile uf, const QStringList &excludedExtensions)
135 {
136     uLong i;
137     unz_global_info64 gi;
138     int err;
139
140     err = unzGetGlobalInfo64(uf, &gi);
141     if (err != UNZ_OK) {
142         qDebug() << "doExtract: Error" << err << "in unzGetGlobalInfo";
143         return false;
144     }
145
146     for (i = 0; i < gi.number_entry; i++) {
147         if (doExtractCurrentFile(uf, excludedExtensions) != UNZ_OK) {
148             return false;
149         }
150         if ((i + 1) < gi.number_entry) {
151             err = unzGoToNextFile(uf);
152             if (err != UNZ_OK) {
153                 qDebug() << "doExtract: Error" << err << "in unzGoToNextFile";
154                 return false;
155             }
156         }
157     }
158
159     return true;
160 }
161
162 bool extractZip(const QString &zipFile, const QStringList &excludedExtensions)
163 {
164     unzFile uf;
165     bool ret = false;
166
167     uf = unzOpen64(zipFile.toUtf8().constData());
168     if (uf) {
169         ret = doExtract(uf, excludedExtensions);
170         unzClose(uf);
171     }
172     return ret;
173 }