1 /*
2 	*
3 	* Copyright 2018 Britanicus <marcusbritanicus@gmail.com>
4 	*
5 
6 	*
7 	* This program is free software: you can redistribute it and/or modify
8 	* it under the terms of the GNU Lesser General Public License as published by
9 	* the Free Software Foundation, either version 3 of the License, or
10 	* (at your option) any later version.
11 	*
12 
13 	*
14 	* This program is distributed in the hope that it will be useful,
15 	* but WITHOUT ANY WARRANTY; without even the implied warranty of
16 	* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 	* GNU Lesser General Public License for more details.
18 	*
19 
20 	*
21 	* You should have received a copy of the GNU Lesser General Public License
22 	* along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 	*
24 */
25 
26 #include "Global.hpp"
27 #include "libarchiveqt.h"
28 
29 #include "LibLzma.hpp"
30 #include "LibLzma2.hpp"
31 #include "LibBZip2.hpp"
32 #include "LibGZip.hpp"
33 
34 extern "C" {
35 	#include "lz4dec.h"
36 }
37 
38 // SystemWide Headers
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <assert.h>
43 #include <libgen.h>
44 
isDir(QString path)45 inline static bool isDir( QString path ) {
46 
47 	struct stat statbuf;
48 	if ( stat( path.toLocal8Bit().data(), &statbuf ) == 0 )
49 
50 		if ( S_ISDIR( statbuf.st_mode ) )
51 			return true;
52 
53 		else
54 			return false;
55 
56 	else
57 		return false;
58 };
59 
recDirWalk(QString path)60 inline static QStringList recDirWalk( QString path ) {
61 
62 	QStringList fileList;
63 
64 	if ( not isDir( path ) )
65 		return fileList;
66 
67 	QDirIterator it( path, QDir::AllEntries | QDir::System | QDir::NoDotAndDotDot | QDir::Hidden, QDirIterator::Subdirectories );
68 	while ( it.hasNext() ) {
69 		it.next();
70 		if ( it.fileInfo().isFile() )
71 			fileList.append( it.fileInfo().filePath() );
72 	}
73 
74 	return fileList;
75 };
76 
dirName(QString path)77 inline static QString dirName( QString path ) {
78 
79 	while( path.contains( "//" ) )
80 		path = path.replace( "//", "/" );
81 
82 	if ( path.endsWith( "/" ) )
83 		path.chop( 1 );
84 
85 	char *dupPath = strdup( path.toLocal8Bit().constData() );
86 	QString dirPth = QString( dirname( dupPath ) ) + "/";
87 	free( dupPath );
88 
89 	return ( dirPth == "//" ? "/" : dirPth );
90 };
91 
baseName(QString path)92 inline static QString baseName( QString path ) {
93 
94 	while( path.contains( "//" ) )
95 		path = path.replace( "//", "/" );
96 
97 	if ( path.endsWith( "/" ) )
98 		path.chop( 1 );
99 
100 	char *dupPath = strdup( path.toLocal8Bit().constData() );
101 	QString basePth = QString( basename( dupPath ) );
102 	free( dupPath );
103 
104 	return basePth;
105 };
106 
exists(QString path)107 inline static bool exists( QString path ) {
108 
109 	return not access( path.toLocal8Bit().constData(), F_OK );
110 }
111 
mkpath(QString path,mode_t mode)112 inline static int mkpath( QString path, mode_t mode ) {
113 
114 	/* Root always exists */
115 	if ( path == "/" )
116 		return 0;
117 
118 	/* If the directory exists, thats okay for us */
119 	if ( exists( path ) )
120 		return 0;
121 
122 	/* If the path is absolute, remove the leading '/' */
123 	if ( path.startsWith( '/' ) )
124 		path.remove( 0, 1 );
125 
126 	mkpath( dirName( path ), mode );
127 
128 	return mkdir( path.toLocal8Bit().constData(), mode );
129 };
130 
longestPath(QStringList & dirs)131 inline static QString longestPath( QStringList &dirs ) {
132 
133 	QStringList paths;
134 	Q_FOREACH( QString file, dirs )
135 		paths << QFileInfo( file ).absoluteFilePath();
136 
137 	/* Get shortest path: Shortest path is the one with least number of '/' */
138 	QString shortest = paths.at( 0 );
139 	int count = 10240;
140 	Q_FOREACH( QString path, paths ) {
141 		if ( path.count( "/" ) < count ) {
142 			count = path.count( "/" );
143 			shortest = path;
144 		}
145 	}
146 
147 	/* Remove the trailing '/' */
148 	if ( shortest.endsWith( "/" ) )
149 		shortest.chop( 1 );
150 
151 	QFileInfo sDir( shortest );
152  	while ( paths.filter( sDir.absoluteFilePath() ).count() != paths.count() ) {
153 		if ( sDir.absoluteFilePath() == "/" )
154 			break;
155 
156 		sDir = QFileInfo( sDir.absolutePath() );
157 	}
158 
159 	return sDir.absoluteFilePath();
160 };
161 
LibArchiveQt(QString archive)162 LibArchiveQt::LibArchiveQt( QString archive ) {
163 
164 	readDone = false;
165 	isRunning = false;
166 	mJob = NoJob;
167 	extractedMember = QString();
168 	mExitStatus = 0;				// 0 - Good, 1 - Bad
169 
170 	archiveName = QDir( archive ).absolutePath();
171 
172 	setFilterFormat( mimeDb.mimeTypeForFile( archiveName ) );
173 };
174 
suffix(QString archiveName)175 QString LibArchiveQt::suffix( QString archiveName ) {
176 
177 	QMimeType mType = mimeDb.mimeTypeForFile( archiveName );
178 
179 	if ( mType == mimeDb.mimeTypeForFile( "file.cpio" ) )
180 		return ".cpio";
181 
182 	else if ( mType == mimeDb.mimeTypeForFile( "file.shar" ) )
183 		return ".shar";
184 
185 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar" ) )
186 		return ".tar";
187 
188 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.gz" ) )
189 		return ( archiveName.endsWith( ".tar.gz" ) ? ".tar.gz" : ".tgz" );
190 
191 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.grz" ) )
192 		return ( archiveName.endsWith( ".tar.grz" ) ? ".tar.grz" : ".tgrz" );
193 
194 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.xz" ) )
195 		return ( archiveName.endsWith( ".tar.xz" ) ? ".tar.xz" : ".txz" );
196 
197 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lzo" ) )
198 		return ( archiveName.endsWith( ".tar.lzo" ) ? ".tar.lzo" : ".tlzo" );
199 
200 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lzma" ) )
201 		return ( archiveName.endsWith( ".tar.lzma" ) ? ".tar.lzma" : ".tlzma" );
202 
203 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lz" ) )
204 		return ( archiveName.endsWith( ".tar.lz" ) ? ".tar.lz" : ".tlz" );
205 
206 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lrz" ) )
207 		return ( archiveName.endsWith( ".tar.lrz" ) ? ".tar.lrz" : ".tlrz" );
208 
209 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lz4" ) )
210 		return ( archiveName.endsWith( ".tar.lz4" ) ? ".tar.lz4" : ".tlzo4" );
211 
212 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.bz2" ) )
213 		return ( archiveName.endsWith( ".tar.bz2" ) ? ".tar.bz2" : ".tbz2" );
214 
215 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.Z" ) )
216 		return ( archiveName.endsWith( ".tar.Z" ) ? ".tar.Z" : ".tZ" );
217 
218 	else if ( mType == mimeDb.mimeTypeForFile( "file.iso" ) )
219 		return ".iso";
220 
221 	else if ( mType == mimeDb.mimeTypeForFile( "file.zip" ) )
222 		return ".zip";
223 
224 	else if ( mType == mimeDb.mimeTypeForFile( "file.ar" ) )
225 		return ".ar";
226 
227 	else if ( mType == mimeDb.mimeTypeForFile( "file.xar" ) )
228 		return ".xar";
229 
230 	else if ( mType == mimeDb.mimeTypeForFile( "file.7z" ) )
231 		return ".7z";
232 
233 	else if ( mType == mimeDb.mimeTypeForFile( "file.lz" ) )
234 		return ".lz";
235 
236 	else if ( mType == mimeDb.mimeTypeForFile( "file.lz4" ) )
237 		return ".lz4";
238 
239 	else if ( mType == mimeDb.mimeTypeForFile( "file.uu" ) )
240 		return ".uu";
241 
242 	else if ( mType == mimeDb.mimeTypeForFile( "file.lzo" ) )
243 		return ".lzo";
244 
245 	else if ( mType == mimeDb.mimeTypeForFile( "file.gz" ) )
246 		return ".gz";
247 
248 	else if ( mType == mimeDb.mimeTypeForFile( "file.bz2" ) )
249 		return ".bz2";
250 
251 	else if ( mType == mimeDb.mimeTypeForFile( "file.lzma" ) )
252 		return ".lzma";
253 
254 	else if ( mType == mimeDb.mimeTypeForFile( "file.xz" ) )
255 		return ".xz";
256 
257 	return "";
258 };
259 
supportedFormats()260 QStringList LibArchiveQt::supportedFormats() {
261 
262 	QStringList supported;
263 
264 	supported << mimeDb.mimeTypeForFile( "file.cpio" ).name();
265 	supported << mimeDb.mimeTypeForFile( "file.shar" ).name();
266 	supported << mimeDb.mimeTypeForFile( "file.tar" ).name();
267 	supported << mimeDb.mimeTypeForFile( "file.tar.gz" ).name();
268 	supported << mimeDb.mimeTypeForFile( "file.tar.grz" ).name();
269 	supported << mimeDb.mimeTypeForFile( "file.tar.xz" ).name();
270 	supported << mimeDb.mimeTypeForFile( "file.tar.lzma" ).name();
271 	supported << mimeDb.mimeTypeForFile( "file.tar.lz4" ).name();
272 	supported << mimeDb.mimeTypeForFile( "file.tar.bz2" ).name();
273 	supported << mimeDb.mimeTypeForFile( "file.tar.Z" ).name();
274 	supported << mimeDb.mimeTypeForFile( "file.iso" ).name();
275 	supported << mimeDb.mimeTypeForFile( "file.zip" ).name();
276 	supported << mimeDb.mimeTypeForFile( "file.ar" ).name();
277 	supported << mimeDb.mimeTypeForFile( "file.xar" ).name();
278 	supported << mimeDb.mimeTypeForFile( "file.7z" ).name();
279 	supported << mimeDb.mimeTypeForFile( "file.lz" ).name();
280 	supported << mimeDb.mimeTypeForFile( "file.lz4" ).name();
281 	supported << mimeDb.mimeTypeForFile( "file.uu" ).name();
282 	supported << mimeDb.mimeTypeForFile( "file.lzo" ).name();
283 	supported << mimeDb.mimeTypeForFile( "file.gz" ).name();
284 	supported << mimeDb.mimeTypeForFile( "file.bz2" ).name();
285 	supported << mimeDb.mimeTypeForFile( "file.lzma" ).name();
286 	supported << mimeDb.mimeTypeForFile( "file.xz" ).name();
287 
288 	QString binary;
289 
290 	#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
291 	QStringList exeLocs = QString::fromLocal8Bit( qgetenv( "PATH" ) ).split( ":", Qt::SkipEmptyParts );
292 	#else
293 	QStringList exeLocs = QString::fromLocal8Bit( qgetenv( "PATH" ) ).split( ":", QString::SkipEmptyParts );
294 	#endif
295 
296 	QString lzop = mimeDb.mimeTypeForFile( "file.lzo" ).name();
297 	QString lzip = mimeDb.mimeTypeForFile( "file.lz" ).name();
298 	QString lrzip = mimeDb.mimeTypeForFile( "file.lrz" ).name();
299 
300 	Q_FOREACH( QString loc, exeLocs ) {
301 		if ( exists( loc + "/lzip" ) and not supported.contains( lzip ) )
302 			supported << lzip;
303 
304 		if ( exists( loc + "/lzop" ) and not supported.contains( lzop ) )
305 			supported << lzop;
306 
307 		if ( exists( loc + "/lrzip" ) and not supported.contains( lrzip ) )
308 			supported << lrzip;
309 	}
310 
311 	return supported;
312 };
313 
createArchive()314 void LibArchiveQt::createArchive() {
315 
316 	mJob = CreateArchive;
317 	isRunning = true;
318 
319 	start();
320 };
321 
extractArchive()322 void LibArchiveQt::extractArchive() {
323 
324 	mJob = ExtractArchive;
325 	isRunning = true;
326 
327 	start();
328 };
329 
extractMember(QString memberName)330 void LibArchiveQt::extractMember( QString memberName ) {
331 
332 	extractedMember = memberName;
333 	mJob = ExtractMember;
334 	isRunning = true;
335 
336 	start();
337 };
338 
listArchive()339 ArchiveEntries LibArchiveQt::listArchive() {
340 
341 	if ( readDone )
342 		return memberList;
343 
344 	memberList.clear();
345 
346 	struct archive *a;
347 	struct archive_entry *entry;
348 	int r;
349 
350 	// Source Archive
351 	a = archive_read_new();
352 	archive_read_support_format_all( a );
353 	archive_read_support_format_raw( a );
354 	archive_read_support_filter_all( a );
355 
356 	if ( ( r = archive_read_open_filename( a, archiveName.toUtf8().data(), 10240 ) ) ) {
357 		qDebug() << "[Error]" << archive_error_string( a );
358 		readDone = true;
359 		return ArchiveEntries();
360 	}
361 
362 	while ( true ) {
363 		r = archive_read_next_header( a, &entry );
364 
365 		if ( r == ARCHIVE_EOF )
366 			break;
367 
368 		if ( r < ARCHIVE_OK )
369 			qDebug() << archive_error_string( a );
370 
371 		ArchiveEntry *ae = new ArchiveEntry;
372 		ae->name = archive_entry_pathname( entry );
373 		ae->size = archive_entry_size( entry );
374 		ae->type = archive_entry_filetype( entry );
375 		memcpy( &ae->info, archive_entry_stat( entry ), sizeof( struct stat ) );
376 
377 		memberList << ae;
378 	}
379 
380 	archive_read_close( a );
381 	archive_read_free( a );
382 
383 	readDone = true;
384 
385 	return memberList;
386 };
387 
exitStatus()388 int LibArchiveQt::exitStatus() {
389 
390 	return mExitStatus;
391 };
392 
updateInputFiles(QStringList inFiles,LibArchiveQt::InputFileMode inMode)393 void LibArchiveQt::updateInputFiles( QStringList inFiles, LibArchiveQt::InputFileMode inMode ) {
394 
395 	if ( not inFiles.count() )
396 		return;
397 
398 	/* First get the absolute filenames */
399 	Q_FOREACH( QString file, inFiles ) {
400 		if ( isDir( file ) )
401 			updateInputFiles( recDirWalk( file ), inMode );
402 
403 		else {
404 			QFileInfo info( file );
405 			switch ( inMode ) {
406 				case AbsolutePath: {
407 					inputList.insert( info.absoluteFilePath(), info.absoluteFilePath() );
408 					break;
409 				}
410 
411 				case RelativeToRoot: {
412 					inputList.insert( info.absoluteFilePath(), QDir::root().relativeFilePath( info.absoluteFilePath() ) );
413 					break;
414 				}
415 
416 				case RelativeToHome: {
417 					QString relPath = QDir::home().relativeFilePath( info.absoluteFilePath() );
418 					while ( relPath.startsWith( "../" ) )
419 						relPath.remove( 0, 3 );
420 
421 					inputList.insert( info.absoluteFilePath(), relPath );
422 					break;
423 				}
424 
425 				case RelativeToCurrent: {
426 					QString relPath = QDir::current().relativeFilePath( info.absoluteFilePath() );
427 					while ( relPath.startsWith( "../" ) )
428 						relPath.remove( 0, 3 );
429 
430 					inputList.insert( info.absoluteFilePath(), relPath );
431 					break;
432 				}
433 
434 				case RelativeToWorkDir: {
435 					/* If @src is empty, set it to root */
436 					src = ( src.isEmpty() ? "/" : src );
437 
438 					QString relPath = QDir( src ).relativeFilePath( info.absoluteFilePath() );
439 					while ( relPath.startsWith( "../" ) )
440 						relPath.remove( 0, 3 );
441 
442 					inputList.insert( info.absoluteFilePath(), relPath );
443 					break;
444 				}
445 
446 				case CommonRelativePath: {
447 					QString common;
448 					if ( inFiles.count() == 1 )
449 						common = dirName( inFiles.at( 0 ) );
450 
451 					else
452 						common = longestPath( inFiles );
453 
454 					QString relPath = QDir( common ).relativeFilePath( info.absoluteFilePath() );
455 					while ( relPath.startsWith( "../" ) )
456 						relPath.remove( 0, 3 );
457 
458 					inputList.insert( info.absoluteFilePath(), relPath );
459 					break;
460 				}
461 
462 				default: {
463 					QString relPath = QDir::current().relativeFilePath( info.absoluteFilePath() );
464 					while ( relPath.startsWith( "../" ) )
465 						relPath.remove( 0, 3 );
466 
467 					inputList.insert( info.absoluteFilePath(), relPath );
468 					break;
469 				}
470 			}
471 		}
472 	}
473 };
474 
setWorkingDir(QString wDir)475 void LibArchiveQt::setWorkingDir( QString wDir ) {
476 
477 	src = QString( wDir );
478 };
479 
setDestination(QString path)480 void LibArchiveQt::setDestination( QString path ) {
481 
482 	/*
483 		*
484 		* @p path will be a absolute.
485 		* So QDir we construct will be home path
486 		*
487 	*/
488 
489 	dest = QString( path );
490 	if ( not QFileInfo( QDir( dest ).absolutePath() ).exists() )
491 		mkpath( path, 0755 );
492 
493 	qDebug() << "Extracting to:" << dest;
494 };
495 
waitForFinished()496 void LibArchiveQt::waitForFinished() {
497 
498 	if ( not isRunning )
499 		return;
500 
501 	QEventLoop eventLoop;
502 	#if QT_VERSION >= 0x050000
503 		connect(this, &LibArchiveQt::jobFailed, &eventLoop, &QEventLoop::quit);
504 		connect(this, &LibArchiveQt::jobComplete, &eventLoop, &QEventLoop::quit);
505 	#else
506 		connect(this, SIGNAL( jobFailed() ), &eventLoop, SLOT( quit() ) );
507 		connect(this, SIGNAL( jobComplete() ), &eventLoop, SLOT( quit() ) );
508 	#endif
509 
510 	eventLoop.exec();
511 };
512 
run()513 void LibArchiveQt::run() {
514 
515 	switch( mJob ) {
516 		case CreateArchive: {
517 			if ( doCreateArchive() ) {
518 				mExitStatus = 0;
519 				emit jobComplete();
520 			}
521 
522 			else {
523 				mExitStatus = 1;
524 				emit jobFailed();
525 			}
526 
527 			isRunning = false;
528 			return;
529 		}
530 
531 		case ExtractArchive: {
532 			if ( doExtractArchive() ) {
533 				mExitStatus = 0;
534 				emit jobComplete();
535 			}
536 
537 			else {
538 				mExitStatus = 1;
539 				emit jobFailed();
540 			}
541 
542 			isRunning = false;
543 			return;
544 		}
545 
546 		case ExtractMember: {
547 			if ( doExtractMember( extractedMember ) ) {
548 				mExitStatus = 0;
549 				emit jobComplete();
550 			}
551 
552 			else {
553 				mExitStatus = 1;
554 				emit jobFailed();
555 			}
556 
557 			isRunning = false;
558 			return;
559 		}
560 
561 		case ListArchive: {
562 			/* Nothing to run in the thread */
563 			return;
564 		}
565 	}
566 };
567 
doCreateArchive()568 bool LibArchiveQt::doCreateArchive() {
569 
570 	struct archive *a;
571 	struct archive_entry *entry;
572 	struct stat st;
573 	char buff[ 8192 ];
574 	int len;
575 	int fd;
576 	int r = ARCHIVE_OK;
577 	int errors = 0;
578 	int processed = 0;
579 
580 	/* Prepare the workingDir */
581 	if ( src.isEmpty() )
582 		src = "/";
583 
584 	a = archive_write_new();
585 
586 	// Depend on the format provided by the user
587 	r |= archive_write_set_format( a, mArchiveFormat );
588 	r |= archive_write_add_filter( a, mArchiveFilter );
589 	if ( r < ARCHIVE_OK ) {
590 		qDebug() << "Cannot use the input filter/format.";
591 		return false;
592 	}
593 
594 	r = archive_write_open_filename( a, archiveName.toUtf8().data() );
595 	if ( r < ARCHIVE_OK ) {
596 		qDebug() << "Unable to write file for writing.";
597 		return false;
598 	}
599 
600 	Q_FOREACH( QString file, inputList.keys() ) {
601 		char *filename = new char[ file.count() + 1 ];
602 		strcpy( filename, file.toUtf8().data() );
603 
604 		if ( stat( filename, &st ) != 0 ) {
605 			errors++;
606 			printf( "[Error %d]: %s: %s\n", errno, strerror( errno ), filename );
607 			continue;
608 		}
609 
610 		char *arcPath = new char[ file.count() + 1 ];
611 		strcpy( arcPath, inputList.value( file ).toUtf8().data() );
612 
613 		entry = archive_entry_new();
614 		archive_entry_set_pathname( entry, arcPath );
615 		archive_entry_set_size( entry, st.st_size );
616 		archive_entry_set_filetype( entry, st.st_mode );
617 		archive_entry_set_perm( entry, st.st_mode );
618 
619 		archive_write_header( a, entry );
620 
621 		// Perform the write
622 		fd = open( filename, O_RDONLY );
623 		len = read( fd, buff, sizeof( buff ) );
624 		while ( len > 0 ) {
625 			archive_write_data( a, buff, len );
626 			len = read( fd, buff, sizeof( buff ) );
627 		}
628 		close( fd );
629 		archive_entry_free( entry );
630 
631 		processed++;
632 
633 		emit progress( processed * 100 / inputList.count() );
634 		qApp->processEvents();
635 	}
636 
637 	archive_write_close( a );
638 	archive_write_free( a );
639 
640 	return ( errors ? false : true );
641 };
642 
doExtractArchive()643 bool LibArchiveQt::doExtractArchive() {
644 
645 	if ( archiveType == None )
646 		return false;
647 
648 	// Change to the target directory
649 	char srcDir[ 10240 ] = { 0 };
650 	getcwd( srcDir, 10240 );
651 
652 	if ( not dest.isEmpty() ) {
653 		int ret = chdir( dest.toUtf8().data() );
654 		if ( ret )
655 			qDebug() << "chdir() failed:" << errno;
656 	}
657 
658 	if ( archiveType == Single ) {
659 		QMimeType mType = mimeDb.mimeTypeForFile( archiveName );
660 
661 		if ( mType == mimeDb.mimeTypeForFile( "file.lz" ) ) {
662 			/* LZip Extractor */
663 
664 			QString lzip;
665 
666 			#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
667 			QStringList exeLocs = QString::fromLocal8Bit( qgetenv( "PATH" ) ).split( ":", Qt::SkipEmptyParts );
668 			#else
669 			QStringList exeLocs = QString::fromLocal8Bit( qgetenv( "PATH" ) ).split( ":", QString::SkipEmptyParts );
670 			#endif
671 
672 			Q_FOREACH( QString loc, exeLocs ) {
673 				if ( exists( loc + "/lzip" ) ) {
674 					lzip = loc + "/lzip";
675 					break;
676 				}
677 			}
678 
679 			if  ( not lzip.count() ) {
680 				qDebug() << "External program lzip not found.";
681 				return false;
682 			}
683 
684 			struct archive *a;
685 			struct archive *ext;
686 			struct archive_entry *entry;
687 			int flags;
688 
689 			int r = ARCHIVE_OK;
690 
691 			/* Select which attributes we want to restore. */
692 			flags = ARCHIVE_EXTRACT_TIME;
693 			flags |= ARCHIVE_EXTRACT_PERM;
694 			flags |= ARCHIVE_EXTRACT_ACL;
695 			flags |= ARCHIVE_EXTRACT_FFLAGS;
696 
697 			// Source Archive
698 			a = archive_read_new();
699 			r |= archive_read_support_format_raw( a );
700 			r |= archive_read_support_filter_program( a, QString( lzip + " -d" ).toLocal8Bit().data() );
701 
702 			if ( r < ARCHIVE_OK ) {
703 				qDebug() << "Cannot use the input filter/format.";
704 				return false;
705 			}
706 
707 			// Structure to write files to disk
708 			ext = archive_write_disk_new();
709 			archive_write_disk_set_options( ext, flags );
710 			archive_write_disk_set_standard_lookup( ext );
711 
712 			if ( ( r = archive_read_open_filename( a, archiveName.toLocal8Bit().data(), 10240 ) ) ) {
713 				qDebug() << "Unable to read archive:" << archive_error_string( a );
714 				return false;
715 			}
716 
717 			while ( true ) {
718 				r = archive_read_next_header( a, &entry );
719 				if ( r == ARCHIVE_EOF ) {
720 					qDebug() << "EOF";
721 					break;
722 				}
723 
724 				if ( r < ARCHIVE_OK )
725 					fprintf( stderr, "%s\n", archive_error_string( a ) );
726 
727 				if ( r < ARCHIVE_WARN ) {
728 					fprintf( stderr, "%s\n", archive_error_string( a ) );
729 					return false;
730 				}
731 
732 				r = archive_write_header( ext, entry );
733 				if ( r < ARCHIVE_OK )
734 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
735 
736 				else if ( archive_entry_size( entry ) == 0 ) {
737 					r = copyData( a, ext );
738 					if ( r < ARCHIVE_OK )
739 						fprintf( stderr, "%s\n", archive_error_string( ext ) );
740 
741 					if ( r < ARCHIVE_WARN )
742 						return false;
743 				}
744 
745 				r = archive_write_finish_entry( ext );
746 				if ( r < ARCHIVE_OK )
747 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
748 
749 				if ( r < ARCHIVE_WARN )
750 					return true;
751 			}
752 
753 			archive_read_close( a );
754 			archive_read_free( a );
755 
756 			archive_write_close( ext );
757 			archive_write_free( ext );
758 
759 			return true;
760 		}
761 
762 		else if ( mType == mimeDb.mimeTypeForFile( "file.uu" ) ) {
763 			/* UUEncode Extractor */
764 
765 			return false;
766 		}
767 
768 		else if ( mType == mimeDb.mimeTypeForFile( "file.lrz" ) ) {
769 			/* lrzip Extractor */
770 
771 			QString lrzip;
772 
773 			#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
774 			QStringList exeLocs = QString::fromLocal8Bit( qgetenv( "PATH" ) ).split( ":", Qt::SkipEmptyParts );
775 			#else
776 			QStringList exeLocs = QString::fromLocal8Bit( qgetenv( "PATH" ) ).split( ":", QString::SkipEmptyParts );
777 			#endif
778 			Q_FOREACH( QString loc, exeLocs ) {
779 				if ( exists( loc + "/lrzip" ) ) {
780 					lrzip = loc + "/lrzip";
781 					break;
782 				}
783 			}
784 
785 			if  ( not lrzip.count() ) {
786 				qDebug() << "External program lrzip not found.";
787 				return false;
788 			}
789 
790 			struct archive *a;
791 			struct archive *ext;
792 			struct archive_entry *entry;
793 			int flags;
794 
795 			int r = ARCHIVE_OK;
796 
797 			/* Select which attributes we want to restore. */
798 			flags = ARCHIVE_EXTRACT_TIME;
799 			flags |= ARCHIVE_EXTRACT_PERM;
800 			flags |= ARCHIVE_EXTRACT_ACL;
801 			flags |= ARCHIVE_EXTRACT_FFLAGS;
802 
803 			// Source Archive
804 			a = archive_read_new();
805 			r |= archive_read_support_format_raw( a );
806 			r |= archive_read_support_filter_program( a, QString( lrzip + " -d" ).toLocal8Bit().data() );
807 
808 			if ( r < ARCHIVE_OK )
809 				qDebug() << "Cannot use the input filter/format.";
810 
811 			// Structure to write files to disk
812 			ext = archive_write_disk_new();
813 			archive_write_disk_set_options( ext, flags );
814 			archive_write_disk_set_standard_lookup( ext );
815 
816 			if ( ( r = archive_read_open_filename( a, archiveName.toLocal8Bit().data(), 10240 ) ) ) {
817 				qDebug() << "Unable to read archive:" << archive_error_string( a );
818 				return false;
819 			}
820 
821 			while ( true ) {
822 				r = archive_read_next_header( a, &entry );
823 				if ( r == ARCHIVE_EOF ) {
824 					qDebug() << "EOF";
825 					break;
826 				}
827 
828 				if ( r < ARCHIVE_OK )
829 					fprintf( stderr, "%s\n", archive_error_string( a ) );
830 
831 				if ( r < ARCHIVE_WARN ) {
832 					fprintf( stderr, "%s\n", archive_error_string( a ) );
833 					return false;
834 				}
835 
836 				r = archive_write_header( ext, entry );
837 				if ( r < ARCHIVE_OK )
838 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
839 
840 				else if ( archive_entry_size( entry ) == 0 ) {
841 					r = copyData( a, ext );
842 					if ( r < ARCHIVE_OK )
843 						fprintf( stderr, "%s\n", archive_error_string( ext ) );
844 
845 					if ( r < ARCHIVE_WARN )
846 						return false;
847 				}
848 
849 				r = archive_write_finish_entry( ext );
850 				if ( r < ARCHIVE_OK )
851 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
852 
853 				if ( r < ARCHIVE_WARN )
854 					return true;
855 			}
856 
857 			archive_read_close( a );
858 			archive_read_free( a );
859 
860 			archive_write_close( ext );
861 			archive_write_free( ext );
862 
863 			return true;
864 		}
865 
866 		else if ( mType == mimeDb.mimeTypeForFile( "file.lzo" ) ) {
867 			/* LZop Extractor */
868 
869 			QString lzop;
870 
871 			#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
872 			QStringList exeLocs = QString::fromLocal8Bit( qgetenv( "PATH" ) ).split( ":", Qt::SkipEmptyParts );
873 			#else
874 			QStringList exeLocs = QString::fromLocal8Bit( qgetenv( "PATH" ) ).split( ":", QString::SkipEmptyParts );
875 			#endif
876 			Q_FOREACH( QString loc, exeLocs ) {
877 				if ( exists( loc + "/lzop" ) ) {
878 					lzop = loc + "/lzop";
879 					break;
880 				}
881 			}
882 
883 			if  ( not lzop.count() ) {
884 				qDebug() << "External program lzop not found.";
885 				return false;
886 			}
887 
888 			struct archive *a;
889 			struct archive *ext;
890 			struct archive_entry *entry;
891 			int flags;
892 
893 			int r = ARCHIVE_OK;
894 
895 			/* Select which attributes we want to restore. */
896 			flags = ARCHIVE_EXTRACT_TIME;
897 			flags |= ARCHIVE_EXTRACT_PERM;
898 			flags |= ARCHIVE_EXTRACT_ACL;
899 			flags |= ARCHIVE_EXTRACT_FFLAGS;
900 
901 			// Source Archive
902 			a = archive_read_new();
903 			r |= archive_read_support_format_raw( a );
904 			r |= archive_read_support_filter_program( a, QString( lzop + " -d" ).toLocal8Bit().data() );
905 
906 			if ( r < ARCHIVE_OK )
907 				qDebug() << "Cannot use the input filter/format.";
908 
909 			// Structure to write files to disk
910 			ext = archive_write_disk_new();
911 			archive_write_disk_set_options( ext, flags );
912 			archive_write_disk_set_standard_lookup( ext );
913 
914 			if ( ( r = archive_read_open_filename( a, archiveName.toLocal8Bit().data(), 10240 ) ) ) {
915 				qDebug() << "Unable to read archive:" << archive_error_string( a );
916 				return false;
917 			}
918 
919 			while ( true ) {
920 				r = archive_read_next_header( a, &entry );
921 				if ( r == ARCHIVE_EOF ) {
922 					qDebug() << "EOF";
923 					break;
924 				}
925 
926 				if ( r < ARCHIVE_OK )
927 					fprintf( stderr, "%s\n", archive_error_string( a ) );
928 
929 				if ( r < ARCHIVE_WARN ) {
930 					fprintf( stderr, "%s\n", archive_error_string( a ) );
931 					return false;
932 				}
933 
934 				r = archive_write_header( ext, entry );
935 				if ( r < ARCHIVE_OK )
936 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
937 
938 				else if ( archive_entry_size( entry ) == 0 ) {
939 					r = copyData( a, ext );
940 					if ( r < ARCHIVE_OK )
941 						fprintf( stderr, "%s\n", archive_error_string( ext ) );
942 
943 					if ( r < ARCHIVE_WARN )
944 						return false;
945 				}
946 
947 				r = archive_write_finish_entry( ext );
948 				if ( r < ARCHIVE_OK )
949 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
950 
951 				if ( r < ARCHIVE_WARN )
952 					return true;
953 			}
954 
955 			archive_read_close( a );
956 			archive_read_free( a );
957 
958 			archive_write_close( ext );
959 			archive_write_free( ext );
960 
961 			return true;
962 		}
963 
964 		else if ( mType == mimeDb.mimeTypeForFile( "file.lz4" ) ) {
965 			/* LZ4 Extractor */
966 
967 			dest = archiveName;
968 			dest.chop( 4 );
969 
970 			int i = 0;
971 			while ( exists( dest ) ) {
972 				i++;
973 
974 				dest = archiveName;
975 				dest.chop( 3 );
976 
977 				dest = dirName( dest )  + QString( "(%1) - " ).arg( i ) + baseName( dest );
978 			}
979 
980 			unlz4( archiveName.toLocal8Bit().constData(), dest.toLocal8Bit().constData(), NULL );
981 			return true;
982 		}
983 
984 		else if ( mType == mimeDb.mimeTypeForFile( "file.gz" ) ) {
985 			/* GZip Extractor */
986 
987 			dest = archiveName;
988 			dest.chop( 3 );
989 
990 			int i = 0;
991 			while ( exists( dest ) ) {
992 				i++;
993 
994 				dest = archiveName;
995 				dest.chop( 3 );
996 
997 				dest = dirName( dest )  + QString( "(%1) - " ).arg( i ) + baseName( dest );
998 			}
999 
1000 			NBGZip *gzExt = new NBGZip( archiveName, dest );
1001 			return gzExt->extract();
1002 		}
1003 
1004 		else if ( mType == mimeDb.mimeTypeForFile( "file.bz2" ) ) {
1005 			/* BZip2 Extractor */
1006 
1007 			dest = archiveName;
1008 			dest.chop( 3 );
1009 
1010 			int i = 0;
1011 			while ( exists( dest ) ) {
1012 				i++;
1013 
1014 				dest = archiveName;
1015 				dest.chop( 3 );
1016 
1017 				dest = dirName( dest )  + QString( "(%1) - " ).arg( i ) + baseName( dest );
1018 			}
1019 
1020 			NBBZip2 *bz2Ext = new NBBZip2( archiveName, dest );
1021 			return bz2Ext->extract();
1022 		}
1023 
1024 		else if ( mType == mimeDb.mimeTypeForFile( "file.lzma" ) ) {
1025 			/* LZMA Extractor */
1026 
1027 			dest = archiveName;
1028 			dest.chop( 3 );
1029 
1030 			int i = 0;
1031 			while ( exists( dest ) ) {
1032 				i++;
1033 
1034 				dest = archiveName;
1035 				dest.chop( 3 );
1036 
1037 				dest = dirName( dest )  + QString( "(%1) - " ).arg( i ) + baseName( dest );
1038 			}
1039 
1040 			NBLzma *lzmaExt = new NBLzma( archiveName, dest );
1041 			return lzmaExt->extract();
1042 		}
1043 
1044 		else if ( mType == mimeDb.mimeTypeForFile( "file.xz" ) ) {
1045 			/* XZ Extractor */
1046 
1047 			dest = archiveName;
1048 			dest.chop( 3 );
1049 
1050 			int i = 0;
1051 			while ( exists( dest ) ) {
1052 				i++;
1053 
1054 				dest = archiveName;
1055 				dest.chop( 3 );
1056 
1057 				dest = dirName( dest )  + QString( "(%1) - " ).arg( i ) + baseName( dest );
1058 			}
1059 
1060 			NBXz *xzExt = new NBXz( archiveName, dest );
1061 			return xzExt->extract();
1062 		}
1063 
1064 		return false;
1065 	}
1066 
1067 	else {
1068 		/* To show progress we want the number of entries. So list the archive first. */
1069 		/* Then count the number of members. Then clear the memberList */
1070 		listArchive();
1071 		int entryCount = memberList.count();
1072 		memberList.clear();
1073 		readDone = false;
1074 
1075 		struct archive *a;
1076 		struct archive *ext;
1077 		struct archive_entry *entry;
1078 		int flags;
1079 		int r = ARCHIVE_OK;
1080 
1081 		int processedEntries = 0;
1082 
1083 		/* Select which attributes we want to restore. */
1084 		flags = ARCHIVE_EXTRACT_TIME;
1085 		flags |= ARCHIVE_EXTRACT_PERM;
1086 		flags |= ARCHIVE_EXTRACT_ACL;
1087 		flags |= ARCHIVE_EXTRACT_FFLAGS;
1088 
1089 		// Source Archive
1090 		a = archive_read_new();
1091 
1092 		r |= archive_read_support_format_all( a );
1093 		r |= archive_read_support_filter_all( a );
1094 
1095 		if ( ( r |= archive_read_open_filename( a, archiveName.toUtf8().data(), 10240 ) ) < ARCHIVE_OK ) {
1096 			fprintf( stderr, "%s\n", archive_error_string( a ) );
1097 			return false;
1098 		}
1099 
1100 		r = ARCHIVE_OK;
1101 
1102 		// Structure to write files to disk
1103 		ext = archive_write_disk_new();
1104 		r |= archive_write_disk_set_options( ext, flags );
1105 		r |= archive_write_disk_set_standard_lookup( ext );
1106 
1107 		if ( r < ARCHIVE_WARN ) {
1108 			fprintf( stderr, "%s\n", archive_error_string( a ) );
1109 			return false;
1110 		}
1111 
1112 		while ( true ) {
1113 			r = archive_read_next_header( a, &entry );
1114 			if ( r == ARCHIVE_EOF ) {
1115 				break;
1116 			}
1117 
1118 			if ( r < ARCHIVE_OK )
1119 				fprintf( stderr, "%s\n", archive_error_string( a ) );
1120 
1121 			if ( r < ARCHIVE_WARN )
1122 				return 1;
1123 
1124 			r = archive_write_header( ext, entry );
1125 			if ( r < ARCHIVE_OK )
1126 				fprintf( stderr, "%s\n", archive_error_string( ext ) );
1127 
1128 			else if ( archive_entry_size( entry ) > 0 ) {
1129 				r = copyData( a, ext );
1130 				if ( r < ARCHIVE_OK )
1131 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
1132 
1133 				if ( r < ARCHIVE_WARN )
1134 					return 1;
1135 			}
1136 
1137 			processedEntries++;
1138 			emit progress( processedEntries * 100 / entryCount );
1139 
1140 			qApp->processEvents();
1141 
1142 			r = archive_write_finish_entry( ext );
1143 			if ( r < ARCHIVE_OK )
1144 				fprintf( stderr, "%s\n", archive_error_string( ext ) );
1145 
1146 			if ( r < ARCHIVE_WARN )
1147 				return 1;
1148 		}
1149 
1150 		archive_read_close( a );
1151 		archive_read_free( a );
1152 
1153 		archive_write_close( ext );
1154 		archive_write_free( ext );
1155 
1156 		return true;
1157 	}
1158 
1159 	chdir( srcDir );
1160 };
1161 
doExtractMember(QString memberName)1162 bool LibArchiveQt::doExtractMember( QString memberName ) {
1163 
1164 	listArchive();
1165 
1166 	if ( archiveType == Single )
1167 		return doExtractMember( memberName );
1168 
1169 	// Change to the target directory
1170 	char srcDir[ 10240 ] = { 0 };
1171 	getcwd( srcDir, 10240 );
1172 	chdir( dest.toUtf8().data() );
1173 
1174 	struct archive *a;
1175 	struct archive *ext;
1176 	struct archive_entry *entry;
1177 	int flags;
1178 	int r;
1179 
1180 	/* Select which attributes we want to restore. */
1181 	flags = ARCHIVE_EXTRACT_TIME;
1182 	flags |= ARCHIVE_EXTRACT_PERM;
1183 	flags |= ARCHIVE_EXTRACT_ACL;
1184 	flags |= ARCHIVE_EXTRACT_FFLAGS;
1185 
1186 	// Source Archive
1187 	a = archive_read_new();
1188 	archive_read_support_format_all( a );
1189 	archive_read_support_filter_all( a );
1190 
1191 	// Structure to write files to disk
1192 	ext = archive_write_disk_new();
1193 	archive_write_disk_set_options( ext, flags );
1194 	archive_write_disk_set_standard_lookup( ext );
1195 
1196 	r = archive_read_open_filename( a, archiveName.toUtf8().data(), 10240 );
1197 	if ( r != ARCHIVE_OK ) {
1198 		qDebug() << "[ERROR]: Failed to open archive:" << archiveName;
1199 		return true;
1200 	}
1201 
1202 	bool dir = false, found = false;
1203 
1204 	/* Direct member */
1205 	Q_FOREACH( ArchiveEntry *ae, memberList ) {
1206 		if ( ae->name == memberName ) {
1207 			dir = ( ae->type == AE_IFDIR );
1208 			found = true;
1209 			break;
1210 		}
1211 
1212 		if ( ae->name == memberName + "/" ) {
1213 			memberName += "/";
1214 			dir = ( ae->type == AE_IFDIR );
1215 			found = true;
1216 			break;
1217 		}
1218 	}
1219 
1220 	if ( not found ) {
1221 		/* Always check for @memberName + "/" because, all indirect members will be directories */
1222 		memberName += "/";
1223 
1224 		/* Indirect member: ex. debug/ is a member if debug/path/to/file.ext exists */
1225 		Q_FOREACH( ArchiveEntry *ae, memberList ) {
1226 			if ( ae->name.startsWith( memberName ) == 0 ) {
1227 				dir = true;
1228 				found = true;
1229 				break;
1230 			}
1231 		}
1232 	}
1233 
1234 	if ( found ) {
1235 		while ( true ) {
1236 			r = archive_read_next_header( a, &entry );
1237 			if ( r == ARCHIVE_EOF )
1238 				break;
1239 
1240 			if ( r < ARCHIVE_OK )
1241 				fprintf( stderr, "%s\n", archive_error_string( a ) );
1242 
1243 			if ( r < ARCHIVE_WARN )
1244 				return true;
1245 
1246 			QString entryPath = archive_entry_pathname( entry );
1247 
1248 			/* Check if the current entry starts with @memberName */
1249 			if ( entryPath.startsWith( memberName ) ) {
1250 				if ( not dir ) {
1251 					if ( entryPath != memberName )
1252 						continue;
1253 				}
1254 
1255 				r = archive_write_header( ext, entry );
1256 				if ( r < ARCHIVE_OK )
1257 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
1258 
1259 				else if ( archive_entry_size( entry ) > 0 ) {
1260 					r = copyData( a, ext );
1261 					if ( r < ARCHIVE_OK )
1262 						fprintf( stderr, "%s\n", archive_error_string( ext ) );
1263 
1264 					if ( r < ARCHIVE_WARN )
1265 						return false;
1266 				}
1267 
1268 				r = archive_write_finish_entry( ext );
1269 				if ( r < ARCHIVE_OK )
1270 					fprintf( stderr, "%s\n", archive_error_string( ext ) );
1271 
1272 				if ( r < ARCHIVE_WARN )
1273 					return false;
1274 			}
1275 		}
1276 	}
1277 
1278 	else {
1279 
1280 		qDebug() << "[Error]" << "File not found in the archive:" << memberName;
1281 		return false;
1282 	}
1283 
1284 	archive_read_close( a );
1285 	archive_read_free( a );
1286 
1287 	archive_write_close( ext );
1288 	archive_write_free( ext );
1289 
1290 	chdir( srcDir );
1291 
1292 	return true;
1293 };
1294 
copyData(struct archive * ar,struct archive * aw)1295 int LibArchiveQt::copyData( struct archive *ar, struct archive *aw ) {
1296 
1297 	int r;
1298 	const void *buff;
1299 	size_t size;
1300 
1301 	#ifdef __LP64__
1302 		off_t offset;
1303 	#else
1304 		la_int64_t offset;
1305 	#endif
1306 
1307 	while ( true ) {
1308 		r = archive_read_data_block( ar, &buff, &size, &offset );
1309 		if ( r == ARCHIVE_EOF )
1310 			return ( ARCHIVE_OK );
1311 
1312 		if ( r < ARCHIVE_OK )
1313 			return ( r );
1314 
1315 		r = archive_write_data_block( aw, buff, size, offset );
1316 		if ( r < ARCHIVE_OK ) {
1317 			fprintf( stderr, "%s\n", archive_error_string( aw ) );
1318 			return ( r );
1319 		}
1320 	}
1321 };
1322 
setFilterFormat(QMimeType mType)1323 void LibArchiveQt::setFilterFormat( QMimeType mType ) {
1324 
1325 	if ( mType == mimeDb.mimeTypeForFile( "file.cpio" ) ) {
1326 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1327 		mArchiveFormat = ARCHIVE_FORMAT_CPIO;
1328 		archiveType = Container;
1329 	}
1330 
1331 	else if ( mType == mimeDb.mimeTypeForFile( "file.shar" ) ) {
1332 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1333 		mArchiveFormat = ARCHIVE_FORMAT_SHAR;
1334 		archiveType = Container;
1335 	}
1336 
1337 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar" ) ) {
1338 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1339 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1340 		archiveType = Container;
1341 	}
1342 
1343 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.gz" ) ) {
1344 		mArchiveFilter = ARCHIVE_FILTER_GZIP;
1345 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1346 		archiveType = Container;
1347 	}
1348 
1349 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.grz" ) ) {
1350 		mArchiveFilter = ARCHIVE_FILTER_GRZIP;
1351 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1352 		archiveType = Container;
1353 	}
1354 
1355 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.xz" ) ) {
1356 		mArchiveFilter = ARCHIVE_FILTER_XZ;
1357 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1358 		archiveType = Container;
1359 	}
1360 
1361 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lzo" ) ) {
1362 		mArchiveFilter = ARCHIVE_FILTER_LZOP;
1363 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1364 		archiveType = Container;
1365 	}
1366 
1367 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lzma" ) ) {
1368 		mArchiveFilter = ARCHIVE_FILTER_LZMA;
1369 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1370 		archiveType = Container;
1371 	}
1372 
1373 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lz" ) ) {
1374 		mArchiveFilter = ARCHIVE_FILTER_LZIP;
1375 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1376 		archiveType = Container;
1377 	}
1378 
1379 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lrz" ) ) {
1380 		mArchiveFilter = ARCHIVE_FILTER_LRZIP;
1381 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1382 		archiveType = Container;
1383 	}
1384 
1385 	#if ARCHIVE_VERSION_NUMBER > 3001002
1386 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.lz4" ) ) {
1387 		mArchiveFilter = ARCHIVE_FILTER_LZ4;
1388 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1389 		archiveType = Container;
1390 	}
1391 	#endif
1392 
1393 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.bz2" ) ) {
1394 		mArchiveFilter = ARCHIVE_FILTER_BZIP2;
1395 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1396 		archiveType = Container;
1397 	}
1398 
1399 	else if ( mType == mimeDb.mimeTypeForFile( "file.tar.Z" ) ) {
1400 		mArchiveFilter = ARCHIVE_FILTER_COMPRESS;
1401 		mArchiveFormat = ARCHIVE_FORMAT_TAR;
1402 		archiveType = Container;
1403 	}
1404 
1405 	else if ( mType == mimeDb.mimeTypeForFile( "file.iso" ) ) {
1406 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1407 		mArchiveFormat = ARCHIVE_FORMAT_ISO9660;
1408 		archiveType = Container;
1409 	}
1410 
1411 	else if ( mType == mimeDb.mimeTypeForFile( "file.zip" ) ) {
1412 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1413 		mArchiveFormat = ARCHIVE_FORMAT_ZIP;
1414 		archiveType = Container;
1415 	}
1416 
1417 	else if ( mType == mimeDb.mimeTypeForFile( "file.ar" ) ) {
1418 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1419 		mArchiveFormat = ARCHIVE_FORMAT_AR;
1420 		archiveType = Container;
1421 	}
1422 
1423 	else if ( mType == mimeDb.mimeTypeForFile( "file.xar" ) ) {
1424 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1425 		mArchiveFormat = ARCHIVE_FORMAT_XAR;
1426 		archiveType = Container;
1427 	}
1428 
1429 	else if ( mType == mimeDb.mimeTypeForFile( "file.7z" ) ) {
1430 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1431 		mArchiveFormat = ARCHIVE_FORMAT_7ZIP;
1432 		archiveType = Container;
1433 	}
1434 
1435 	else if ( mType == mimeDb.mimeTypeForFile( "file.lz" ) ) {
1436 		mArchiveFilter = ARCHIVE_FILTER_LZIP;
1437 		mArchiveFormat = ARCHIVE_FORMAT_RAW;
1438 		archiveType = Single;
1439 	}
1440 
1441 	#if ARCHIVE_VERSION_NUMBER > 3001002
1442 	else if ( mType == mimeDb.mimeTypeForFile( "file.lz4" ) ) {
1443 		mArchiveFilter = ARCHIVE_FILTER_LZ4;
1444 		mArchiveFormat = ARCHIVE_FORMAT_RAW;
1445 		archiveType = Single;
1446 	}
1447 	#endif
1448 
1449 	else if ( mType == mimeDb.mimeTypeForFile( "file.uu" ) ) {
1450 		mArchiveFilter = ARCHIVE_FILTER_UU;
1451 		mArchiveFormat = ARCHIVE_FORMAT_RAW;
1452 		archiveType = Single;
1453 	}
1454 
1455 	else if ( mType == mimeDb.mimeTypeForFile( "file.lzo" ) ) {
1456 		mArchiveFilter = ARCHIVE_FILTER_LZOP;
1457 		mArchiveFormat = ARCHIVE_FORMAT_RAW;
1458 		archiveType = Single;
1459 	}
1460 
1461 	else if ( mType == mimeDb.mimeTypeForFile( "file.gz" ) ) {
1462 		mArchiveFilter = ARCHIVE_FILTER_GZIP;
1463 		mArchiveFormat = ARCHIVE_FORMAT_RAW;
1464 		archiveType = Single;
1465 	}
1466 
1467 	else if ( mType == mimeDb.mimeTypeForFile( "file.bz2" ) ) {
1468 		mArchiveFilter = ARCHIVE_FILTER_BZIP2;
1469 		mArchiveFormat = ARCHIVE_FORMAT_RAW;
1470 		archiveType = Single;
1471 	}
1472 
1473 	else if ( mType == mimeDb.mimeTypeForFile( "file.lzma" ) ) {
1474 		mArchiveFilter = ARCHIVE_FILTER_LZMA;
1475 		mArchiveFormat = ARCHIVE_FORMAT_RAW;
1476 		archiveType = Single;
1477 	}
1478 
1479 	else if ( mType == mimeDb.mimeTypeForFile( "file.xz" ) ) {
1480 		mArchiveFilter = ARCHIVE_FILTER_XZ;
1481 		mArchiveFormat = ARCHIVE_FORMAT_RAW;
1482 		archiveType = Single;
1483 	}
1484 
1485 	else {
1486 		mArchiveFormat = ARCHIVE_FORMAT_EMPTY;
1487 		mArchiveFilter = ARCHIVE_FILTER_NONE;
1488 		archiveType = None;
1489 	}
1490 };
1491