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 // C++ Standard Library
27 #include <QCoreApplication>
28 
29 // STL
30 #include <iostream>
31 #include <unistd.h>
32 
33 // LibArchive
34 #include "libarchiveqt.h"
35 
36 /* To pretty print file sizes */
formatSize(qint64 num)37 QString formatSize( qint64 num ) {
38 
39 	QString total;
40 	const qint64 kb = 1024;
41 	const qint64 mb = 1024 * kb;
42 	const qint64 gb = 1024 * mb;
43 	const qint64 tb = 1024 * gb;
44 
45 	if ( num >= tb )      total = QString( "%1 TiB" ).arg( QString::number( qreal( num ) / tb, 'f', 3 ) );
46 	else if ( num >= gb ) total = QString( "%1 GiB" ).arg( QString::number( qreal( num ) / gb, 'f', 2 ) );
47 	else if ( num >= mb ) total = QString( "%1 MiB" ).arg( QString::number( qreal( num ) / mb, 'f', 1 ) );
48 	else if ( num >= kb ) total = QString( "%1 KiB" ).arg( QString::number( qreal( num ) / kb,'f',1 ) );
49 	else                  total = QString( "%1 byte%2" ).arg( num ).arg( num > 1 ? "s": "" );
50 
51 	return total;
52 };
53 
54 /* Pretty print the usage */
printUsage(const char * exec)55 void printUsage( const char *exec ) {
56 
57 	std::cout << "Archiver v2.0.4\n" << std::endl;
58 
59 	std::cout << "Usage:\n\t" << exec << " -c archive.xxx file1 file2 file3 ..." << std::endl;
60 	std::cout << "\t" << exec << " -d archive.xxx output_dir" << std::endl;
61 	std::cout << "\t" << exec << " -m archive.xxx member_name output_dir" << std::endl;
62 	std::cout << "\t" << exec << " -l archive.xxx" << std::endl;
63 };
64 
main(int argc,char ** argv)65 int main( int argc, char** argv ) {
66 
67 	/* Init the QApplication instance */
68 	QCoreApplication app( argc, argv);
69 
70 	/*
71 		*
72 		* We need three arguments at minimum
73 		* 	1. The program name (argv[ 0 ]) => Always existing
74 		* 	2. The switch: one of c, d, m or l: Tells the program what to do
75 		* 	3. The archive name to operate on (list or decompress)
76 		*	In case we are compressing or extracting a member, an additional argument is necessary
77 		*
78 	*/
79 	if ( argc < 3 ) {
80 
81 		printUsage( argv[ 0 ] );
82 		return 1;
83 	}
84 
85 	/* Print help text or usage */
86 	else if ( ( argc == 2 ) and ( strcmp( argv[ 1 ], "-h" ) == 0 ) ) {
87 
88 		printUsage( argv[ 0 ] );
89 		return 0;
90 	}
91 
92 	/* Print help text or usage */
93 	else if ( ( argc == 2 ) and ( strcmp( argv[ 1 ], "--help" ) == 0 ) ) {
94 
95 		printUsage( argv[ 0 ] );
96 		return 0;
97 	}
98 
99 	/* Switch c, but no input files mentioned */
100 	else if ( ( argc == 3 ) and ( strcmp( argv[ 1 ], "-c" ) == 0 ) ) {
101 
102 		printUsage( argv[ 0 ] );
103 
104 		std::cout << "\nArchiver: ERROR: No input files specified." << std::endl;
105 		return 1;
106 	}
107 
108 	/* Switch m, but no member name mentioned */
109 	else if ( ( argc < 4 ) and ( strcmp( argv[ 1 ], "-m" ) == 0 ) ) {
110 
111 		printUsage( argv[ 0 ] );
112 
113 		std::cout << "\nArchiver: ERROR: No member name specified." << std::endl;
114 		return 1;
115 	}
116 
117 	/* Excess arguments */
118 	else if ( ( argc > 3 ) and ( strcmp( argv[ 1 ], "-l" ) == 0 ) )  {
119 
120 		printUsage( argv[ 0 ] );
121 
122 		std::cout << "\nArchiver: ERROR: Too many files specified" << std::endl;
123 		return 1;
124 	}
125 
126 	/* No switch mentioned */
127 	else if ( ( argc >= 3 ) and strcmp( argv[ 1 ], "-c" ) and strcmp( argv[ 1 ], "-d" ) and strcmp( argv[ 1 ], "-l" ) and strcmp( argv[ 1 ], "-m" ) ) {
128 
129 		printUsage( argv[ 0 ] );
130 
131 		std::cout << "\nArchiver: ERROR: You need to specify one of -c, -d, -m or -l" << std::endl;
132 		return 1;
133 	}
134 
135 	/* Compress the input files argv[3+] into archive argv[2] */
136 	else if ( strcmp( argv[ 1 ], "-c" ) == 0 ) {
137 
138 		// Write archive code
139 		LibArchiveQt *arc = new LibArchiveQt( argv[ 2 ] );
140 
141 		arc->updateInputFiles( app.arguments().mid( 3 ), LibArchiveQt::RelativeToCurrent );
142 		arc->createArchive();
143 		arc->waitForFinished();
144 
145 		return 0;
146 	}
147 
148 	/* Decompress the archive argv[2] optionally to argv[3] */
149 	else if ( strcmp( argv[ 1 ], "-d" ) == 0 ) {
150 
151 		// Read archive code
152 		LibArchiveQt *arc = new LibArchiveQt( argv[ 2 ] );
153 
154 		if ( argc >= 4 )
155 			arc->setDestination( argv[ 3 ] );
156 
157 		arc->extractArchive();
158 		arc->waitForFinished();
159 
160 		return 0;
161 	}
162 
163 	/* Decompress the member argv[3] optionally to argv[4] from archive argv[2] */
164 	else if ( strcmp( argv[ 1 ], "-m" ) == 0 ) {
165 
166 		// Read archive code
167 		LibArchiveQt *arc = new LibArchiveQt( argv[ 2 ] );
168 
169 		if ( argc == 5 ) {
170 			arc->setDestination( argv[ 3 ] );
171 			arc->extractMember( argv[ 4 ] );
172 		}
173 		else {
174 			arc->extractMember( argv[ 3 ] );
175 		}
176 
177 		arc->waitForFinished();
178 		return 0;
179 	}
180 
181 	/* List archive argv[2] */
182 	else if ( strcmp( argv[ 1 ], "-l" ) == 0 ) {
183 
184 		// List archive code
185 		LibArchiveQt *arc = new LibArchiveQt( argv[ 2 ] );
186 
187 		int length = 0;
188 		Q_FOREACH( ArchiveEntry *ae, arc->listArchive() )
189 			length = ( ae->name.length() > length ? ae->name.length() : length );
190 
191 		Q_FOREACH( ArchiveEntry *ae, arc->listArchive() ) {
192 			if ( ae->type == AE_IFREG )
193 				qDebug() << ae->name.rightJustified( length + 10 ).toLocal8Bit().data() << "  " << formatSize( ae->size ).toLocal8Bit().data();
194 
195 			else
196 				qDebug() << ae->name.rightJustified( length + 10 ).toLocal8Bit().data();
197 		}
198 
199 		arc->waitForFinished();
200 
201 		return 0;
202 	}
203 
204 	/* Print help text */
205 	else {
206 
207 		printUsage( argv[ 0 ] );
208 		return 0;
209 	}
210 };
211