1 /*
2  *  SPDX-FileCopyrightText: 2002-2013 David Faure <faure@kde.org>
3  *
4  *  SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 
7 #include "kzip.h"
8 #include "kcompressiondevice.h"
9 
10 #include <QCoreApplication>
11 #include <QDebug>
12 #include <QFile>
13 
14 #include <stdio.h>
15 
recursive_print(const KArchiveDirectory * dir,const QString & path)16 void recursive_print(const KArchiveDirectory *dir, const QString &path)
17 {
18     const QStringList lst = dir->entries();
19     for (const QString &it : lst) {
20         const KArchiveEntry *entry = dir->entry(it);
21         printf("mode=%07o %s %s \"%s%s\" size: %lld pos: %lld isdir=%d%s",
22                entry->permissions(),
23                entry->user().toLatin1().constData(),
24                entry->group().toLatin1().constData(),
25                path.toLatin1().constData(),
26                it.toLatin1().constData(),
27                entry->isDirectory() ? 0 : (static_cast<const KArchiveFile *>(entry))->size(),
28                entry->isDirectory() ? 0 : (static_cast<const KArchiveFile *>(entry))->position(),
29                entry->isDirectory(),
30                entry->symLinkTarget().isEmpty() ? "" : QStringLiteral(" symlink: %1").arg(entry->symLinkTarget()).toLatin1().constData());
31 
32         //    if (!entry->isDirectory()) printf("%d", (static_cast<const KArchiveFile *>(entry))->size());
33         printf("\n");
34         if (entry->isDirectory()) {
35             recursive_print(static_cast<const KArchiveDirectory *>(entry), path + it + '/');
36         }
37     }
38 }
39 
recursive_transfer(const KArchiveDirectory * dir,const QString & path,KZip * zip)40 void recursive_transfer(const KArchiveDirectory *dir, const QString &path, KZip *zip)
41 {
42     const QStringList lst = dir->entries();
43     for (const QString &it : lst) {
44         const KArchiveEntry *e = dir->entry(it);
45         qDebug() << "actual file: " << e->name();
46         if (e->isFile()) {
47             Q_ASSERT(e && e->isFile());
48             const KArchiveFile *f = static_cast<const KArchiveFile *>(e);
49             printf("FILE=%s\n", qPrintable(e->name()));
50 
51             QByteArray arr(f->data());
52             printf("SIZE=%i\n", arr.size());
53             QString str(arr);
54             printf("DATA=%s\n", qPrintable(str));
55 
56             if (e->symLinkTarget().isEmpty()) {
57                 zip->writeFile(path + e->name(), arr);
58             } else {
59                 zip->writeSymLink(path + e->name(), e->symLinkTarget());
60             }
61         } else if (e->isDirectory()) {
62             recursive_transfer(static_cast<const KArchiveDirectory *>(e), path + e->name() + '/', zip);
63         }
64     }
65 }
66 
doList(const QString & fileName)67 static int doList(const QString &fileName)
68 {
69     KZip zip(fileName);
70     if (!zip.open(QIODevice::ReadOnly)) {
71         qWarning() << "Could not open" << fileName << "for reading. ZIP file doesn't exist or is invalid:" << zip.errorString();
72         return 1;
73     }
74     const KArchiveDirectory *dir = zip.directory();
75     recursive_print(dir, QString());
76     zip.close();
77     return 0;
78 }
79 
doPrintAll(const QString & fileName)80 static int doPrintAll(const QString &fileName)
81 {
82     KZip zip(fileName);
83     qDebug() << "Opening zip file";
84     if (!zip.open(QIODevice::ReadOnly)) {
85         qWarning() << "Could not open" << fileName << "for reading. ZIP file doesn't exist or is invalid:" << zip.errorString();
86         return 1;
87     }
88     const KArchiveDirectory *dir = zip.directory();
89     qDebug() << "Listing toplevel of zip file";
90     const QStringList lst = dir->entries();
91     for (const QString &it : lst) {
92         const KArchiveEntry *e = dir->entry(it);
93         qDebug() << "Printing" << it;
94         if (e->isFile()) {
95             Q_ASSERT(e && e->isFile());
96             const KArchiveFile *f = static_cast<const KArchiveFile *>(e);
97             const QByteArray data(f->data());
98             printf("SIZE=%i\n", data.size());
99             QString str = QString::fromUtf8(data);
100             printf("DATA=%s\n", qPrintable(str));
101         }
102     }
103     zip.close();
104     return 0;
105 }
106 
doSave(const QString & fileName)107 static int doSave(const QString &fileName)
108 {
109     KZip zip(fileName);
110     if (!zip.open(QIODevice::WriteOnly)) {
111         qWarning() << "Could not open" << fileName << "for writing:" << zip.errorString();
112         return 1;
113     }
114 
115     const QByteArray data = "This is the data for the main file";
116     bool writeOk = zip.writeFile(QStringLiteral("maindoc.txt"), data);
117     if (!writeOk) {
118         qWarning() << "Write error (main file)";
119         return 1;
120     }
121     const QByteArray data2 = "This is the data for the other file";
122     writeOk = zip.writeFile(QStringLiteral("subdir/other.txt"), data2);
123     if (!writeOk) {
124         qWarning() << "Write error (other file)";
125         return 1;
126     }
127     // writeOk = zip.addLocalFile("David.jpg", "picture.jpg");
128     // if (!writeOk) {
129     //    qWarning() << "Write error (picture)";
130     //    return 1;
131     //}
132     return 0;
133 }
134 
doLoad(const QString & fileName)135 static int doLoad(const QString &fileName)
136 {
137     KZip zip(fileName);
138     if (!zip.open(QIODevice::ReadOnly)) {
139         qWarning() << "Could not open" << fileName << "for reading. ZIP file doesn't exist or is invalid:" << zip.errorString();
140         return 1;
141     }
142     const KArchiveDirectory *dir = zip.directory();
143     const KArchiveEntry *mainEntry = dir->entry(QStringLiteral("maindoc.txt"));
144     Q_ASSERT(mainEntry && mainEntry->isFile());
145     const KArchiveFile *mainFile = static_cast<const KArchiveFile *>(mainEntry);
146     qDebug() << "maindoc.txt:" << mainFile->data();
147     return 0;
148 }
149 
doPrint(const QString & fileName,const QString & entryName)150 static int doPrint(const QString &fileName, const QString &entryName)
151 {
152     KZip zip(fileName);
153     if (!zip.open(QIODevice::ReadOnly)) {
154         qWarning() << "Could not open" << fileName << "for reading. ZIP file doesn't exist or is invalid:" << zip.errorString();
155         return 1;
156     }
157     const KArchiveDirectory *dir = zip.directory();
158     const KArchiveEntry *e = dir->entry(entryName);
159     Q_ASSERT(e && e->isFile());
160     const KArchiveFile *f = static_cast<const KArchiveFile *>(e);
161 
162     const QByteArray arr(f->data());
163     printf("SIZE=%i\n", arr.size());
164     QString str = QString::fromUtf8(arr);
165     printf("%s", qPrintable(str));
166     return zip.close() ? 0 : 1 /*error*/;
167 }
168 
doCreate(const QString & archiveName,const QStringList & fileNames)169 static int doCreate(const QString &archiveName, const QStringList &fileNames)
170 {
171     KZip zip(archiveName);
172     if (!zip.open(QIODevice::WriteOnly)) {
173         qWarning() << "Could not open" << archiveName << "for writing:" << zip.errorString();
174         return 1;
175     }
176     for (const QString &fileName : fileNames) {
177         QFile f(fileName);
178         if (!f.open(QIODevice::ReadOnly)) {
179             qWarning() << "Could not open" << fileName << "for reading:" << zip.errorString();
180             return 1;
181         }
182         zip.writeFile(fileName, f.readAll());
183     }
184     return zip.close() ? 0 : 1 /*error*/;
185 }
186 
doUpdate(const QString & archiveName,const QString & fileName)187 static int doUpdate(const QString &archiveName, const QString &fileName)
188 {
189     KZip zip(archiveName);
190     if (!zip.open(QIODevice::ReadWrite)) {
191         qWarning() << "Could not open" << archiveName << "for read/write:" << zip.errorString();
192         return 1;
193     }
194 
195     QFile f(fileName);
196     if (!f.open(QIODevice::ReadOnly)) {
197         qWarning() << "Could not open" << fileName << "for reading:" << zip.errorString();
198         return 1;
199     }
200 
201     zip.writeFile(fileName, f.readAll());
202     return zip.close() ? 0 : 1 /*error*/;
203 }
204 
doTransfer(const QString & sourceFile,const QString & destFile)205 static int doTransfer(const QString &sourceFile, const QString &destFile)
206 {
207     KZip zip1(sourceFile);
208     KZip zip2(destFile);
209     if (!zip1.open(QIODevice::ReadOnly)) {
210         qWarning() << "Could not open" << sourceFile << "for reading. ZIP file doesn't exist or is invalid:" << zip1.errorString();
211         return 1;
212     }
213     if (!zip2.open(QIODevice::WriteOnly)) {
214         qWarning() << "Could not open" << destFile << "for writing:" << zip2.errorString();
215         return 1;
216     }
217     const KArchiveDirectory *dir1 = zip1.directory();
218 
219     recursive_transfer(dir1, QLatin1String(""), &zip2);
220 
221     zip1.close();
222     zip2.close();
223     return 0;
224 }
225 
save(QIODevice * device)226 static bool save(QIODevice *device)
227 {
228     const QByteArray data = "This is some text that will be compressed.\n";
229     const int written = device->write(data);
230     if (written != data.size()) {
231         qWarning() << "Error writing data";
232         return 1;
233     }
234     // success
235     return 0;
236 }
237 
doCompress(const QString & fileName)238 static int doCompress(const QString &fileName)
239 {
240     KCompressionDevice device(fileName, KCompressionDevice::BZip2);
241     if (!device.open(QIODevice::WriteOnly)) {
242         qWarning() << "Could not open" << fileName << "for writing:" << device.errorString();
243         return 1;
244     }
245 
246     return save(&device);
247 }
248 
load(QIODevice * device)249 static bool load(QIODevice *device)
250 {
251     const QByteArray data = device->readAll();
252     printf("%s", data.constData());
253     return true;
254 }
255 
doUncompress(const QString & fileName)256 static int doUncompress(const QString &fileName)
257 {
258     KCompressionDevice device(fileName, KCompressionDevice::BZip2);
259     if (!device.open(QIODevice::ReadOnly)) {
260         qWarning() << "Could not open" << fileName << "for reading:" << device.errorString();
261         return 1;
262     }
263     return load(&device);
264 }
265 
main(int argc,char ** argv)266 int main(int argc, char **argv)
267 {
268     if (argc < 3) {
269         // ###### Note: please consider adding new tests to karchivetest (so that they can be automated)
270         // rather than here (interactive)
271         printf(
272             "\n"
273             " Usage :\n"
274             " ./kziptest list /path/to/existing_file.zip       tests listing an existing zip\n"
275             " ./kziptest print-all file.zip                    prints contents of all files.\n"
276             " ./kziptest print file.zip filename               prints contents of one file.\n"
277             " ./kziptest create file.zip filenames             create a new zip file with these files.\n"
278             " ./kziptest update file.zip filename              update filename in file.zip.\n"
279             " ./kziptest save file.zip                         save file.\n"
280             " ./kziptest load file.zip                         load file.\n"
281             " ./kziptest write file.bz2                        write compressed file.\n"
282             " ./kziptest read file.bz2                         read uncompressed file.\n");
283         return 1;
284     }
285     QCoreApplication app(argc, argv);
286     QString command = argv[1];
287     if (command == QLatin1String("list")) {
288         return doList(QFile::decodeName(argv[2]));
289     } else if (command == QLatin1String("print-all")) {
290         return doPrintAll(QFile::decodeName(argv[2]));
291     } else if (command == QLatin1String("print")) {
292         if (argc != 4) {
293             printf("usage: kziptest print archivename filename");
294             return 1;
295         }
296         return doPrint(QFile::decodeName(argv[2]), argv[3]);
297     } else if (command == QLatin1String("save")) {
298         return doSave(QFile::decodeName(argv[2]));
299     } else if (command == QLatin1String("load")) {
300         return doLoad(QFile::decodeName(argv[2]));
301     } else if (command == QLatin1String("write")) {
302         return doCompress(QFile::decodeName(argv[2]));
303     } else if (command == QLatin1String("read")) {
304         return doUncompress(QFile::decodeName(argv[2]));
305     } else if (command == QLatin1String("create")) {
306         if (argc < 4) {
307             printf("usage: kziptest create archivename filenames");
308             return 1;
309         }
310         const QStringList fileNames = app.arguments().mid(3);
311         return doCreate(QFile::decodeName(argv[2]), fileNames);
312     } else if (command == QLatin1String("update")) {
313         if (argc != 4) {
314             printf("usage: kziptest update archivename filename");
315             return 1;
316         }
317         return doUpdate(QFile::decodeName(argv[2]), QFile::decodeName(argv[3]));
318     } else if (command == QLatin1String("transfer")) {
319         if (argc != 4) {
320             printf("usage: kziptest transfer sourcefile destfile");
321             return 1;
322         }
323         return doTransfer(QFile::decodeName(argv[2]), QFile::decodeName(argv[3]));
324     } else {
325         printf("Unknown command\n");
326     }
327 }
328