xref: /haiku/src/tests/kits/support/compression_test.cpp (revision 6eafb4b041ad79cb936b2041fdb9c56b1209cc10)
1 /*
2  * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <errno.h>
8 #include <getopt.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include <File.h>
14 
15 #include <ZlibCompressionAlgorithm.h>
16 
17 
18 extern const char* __progname;
19 const char* kCommandName = __progname;
20 
21 
22 enum CompressionType {
23 	ZlibCompression,
24 	GzipCompression,
25 };
26 
27 
28 static const char* kUsage =
29 	"Usage: %s <options> <input file> <output file>\n"
30 	"Compresses or decompresses (option -d) a file.\n"
31 	"\n"
32 	"Options:\n"
33 	"  -0 ... -9\n"
34 	"      Use compression level 0 ... 9. 0 means no, 9 best compression.\n"
35 	"      Defaults to 9.\n"
36 	"  -d, --decompress\n"
37 	"      Decompress the input file (default is compress).\n"
38 	"  -f <format>\n"
39 	"      Specify the compression format: \"zlib\" (default), or \"gzip\"\n"
40 	"  -h, --help\n"
41 	"      Print this usage info.\n"
42 	"  -i, --input-stream\n"
43 	"      Use the input stream API (default is output stream API).\n"
44 ;
45 
46 
47 static void
48 print_usage_and_exit(bool error)
49 {
50     fprintf(error ? stderr : stdout, kUsage, kCommandName);
51     exit(error ? 1 : 0);
52 }
53 
54 
55 int
56 main(int argc, const char* const* argv)
57 {
58 	int compressionLevel = B_ZLIB_COMPRESSION_DEFAULT;
59 	bool compress = true;
60 	bool useInputStream = true;
61 	CompressionType compressionType = ZlibCompression;
62 
63 	while (true) {
64 		static struct option sLongOptions[] = {
65 			{ "decompress", no_argument, 0, 'd' },
66 			{ "help", no_argument, 0, 'h' },
67 			{ "input-stream", no_argument, 0, 'i' },
68 			{ 0, 0, 0, 0 }
69 		};
70 
71 		opterr = 0; // don't print errors
72 		int c = getopt_long(argc, (char**)argv, "+0123456789df:hi",
73 			sLongOptions, NULL);
74 		if (c == -1)
75 			break;
76 
77 		switch (c) {
78 			case '0':
79 			case '1':
80 			case '2':
81 			case '3':
82 			case '4':
83 			case '5':
84 			case '6':
85 			case '7':
86 			case '8':
87 			case '9':
88 				compressionLevel = c - '0';
89 				break;
90 
91 			case 'h':
92 				print_usage_and_exit(false);
93 				break;
94 
95 			case 'd':
96 				compress = false;
97 				break;
98 
99 			case 'f':
100 				if (strcmp(optarg, "zlib") == 0) {
101 					compressionType = ZlibCompression;
102 				} else if (strcmp(optarg, "gzip") == 0) {
103 					compressionType = GzipCompression;
104 				} else {
105 					fprintf(stderr, "Error: Unsupported compression type "
106 						"\"%s\"\n", optarg);
107 					return 1;
108 				}
109 				break;
110 
111 			case 'i':
112 				useInputStream = true;
113 				break;
114 
115 			default:
116 				print_usage_and_exit(true);
117 				break;
118 		}
119 	}
120 
121 	// The remaining arguments are input and output file.
122 	if (optind + 2 != argc)
123 		print_usage_and_exit(true);
124 
125 	const char* inputFilePath = argv[optind++];
126 	const char* outputFilePath = argv[optind++];
127 
128 	// open input file
129 	BFile inputFile;
130 	status_t error = inputFile.SetTo(inputFilePath, B_READ_ONLY);
131 	if (error != B_OK) {
132 		fprintf(stderr, "Error: Failed to open \"%s\": %s\n", inputFilePath,
133 			strerror(errno));
134 		return 1;
135 	}
136 
137 	// open output file
138 	BFile outputFile;
139 	error = outputFile.SetTo(outputFilePath,
140 		B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
141 	if (error != B_OK) {
142 		fprintf(stderr, "Error: Failed to open \"%s\": %s\n", outputFilePath,
143 			strerror(errno));
144 		return 1;
145 	}
146 
147 	// create compression algorithm and parameters
148 	BCompressionAlgorithm* compressionAlgorithm;
149 	BCompressionParameters* compressionParameters;
150 	BDecompressionParameters* decompressionParameters;
151 	switch (compressionType) {
152 		case ZlibCompression:
153 		case GzipCompression:
154 		{
155 			compressionAlgorithm = new BZlibCompressionAlgorithm;
156 			BZlibCompressionParameters* zlibCompressionParameters
157 				= new BZlibCompressionParameters(compressionLevel);
158 			zlibCompressionParameters->SetGzipFormat(
159 				compressionType == GzipCompression);
160 			compressionParameters = zlibCompressionParameters;
161 			decompressionParameters = new BZlibDecompressionParameters;
162 			break;
163 		}
164 	}
165 
166 	if (useInputStream) {
167 		// create input stream
168 		BDataIO* inputStream;
169 		if (compress) {
170 			error = compressionAlgorithm->CreateCompressingInputStream(
171 				&inputFile, compressionParameters, inputStream);
172 		} else {
173 			error = compressionAlgorithm->CreateDecompressingInputStream(
174 				&inputFile, decompressionParameters, inputStream);
175 		}
176 
177 		if (error != B_OK) {
178 			fprintf(stderr, "Error: Failed to create input stream: %s\n",
179 				strerror(error));
180 			return 1;
181 		}
182 
183 		// processing loop
184 		for (;;) {
185 			uint8 buffer[64 * 1024];
186 			ssize_t bytesRead = inputStream->Read(buffer, sizeof(buffer));
187 			if (bytesRead < 0) {
188 				fprintf(stderr, "Error: Failed to read from input stream: %s\n",
189 					strerror(bytesRead));
190 				return 1;
191 			}
192 			if (bytesRead == 0)
193 				break;
194 
195 			error = outputFile.WriteExactly(buffer, bytesRead);
196 			if (error != B_OK) {
197 				fprintf(stderr, "Error: Failed to write to output file: %s\n",
198 					strerror(error));
199 				return 1;
200 			}
201 		}
202 	} else {
203 		// create output stream
204 		BDataIO* outputStream;
205 		if (compress) {
206 			error = compressionAlgorithm->CreateCompressingOutputStream(
207 				&outputFile, compressionParameters, outputStream);
208 		} else {
209 			error = compressionAlgorithm->CreateDecompressingOutputStream(
210 				&outputFile, decompressionParameters, outputStream);
211 		}
212 
213 		if (error != B_OK) {
214 			fprintf(stderr, "Error: Failed to create output stream: %s\n",
215 				strerror(error));
216 			return 1;
217 		}
218 
219 		// processing loop
220 		for (;;) {
221 			uint8 buffer[64 * 1024];
222 			ssize_t bytesRead = inputFile.Read(buffer, sizeof(buffer));
223 			if (bytesRead < 0) {
224 				fprintf(stderr, "Error: Failed to read from input file: %s\n",
225 					strerror(bytesRead));
226 				return 1;
227 			}
228 			if (bytesRead == 0)
229 				break;
230 
231 			error = outputStream->WriteExactly(buffer, bytesRead);
232 			if (error != B_OK) {
233 				fprintf(stderr, "Error: Failed to write to output stream: %s\n",
234 					strerror(error));
235 				return 1;
236 			}
237 		}
238 
239 		// flush the output stream
240 		error = outputStream->Flush();
241 		if (error != B_OK) {
242 			fprintf(stderr, "Error: Failed to flush output stream: %s\n",
243 				strerror(error));
244 			return 1;
245 		}
246 	}
247 
248 	return 0;
249 }
250