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