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