xref: /haiku/src/bin/package/command_recompress.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
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 <fcntl.h>
9 #include <getopt.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include <File.h>
16 
17 #include <package/hpkg/HPKGDefs.h>
18 #include <package/hpkg/PackageReader.h>
19 #include <package/hpkg/PackageWriter.h>
20 
21 #include <DataPositionIOWrapper.h>
22 #include <FdIO.h>
23 
24 #include "package.h"
25 #include "PackageWriterListener.h"
26 
27 
28 using BPackageKit::BHPKG::BPackageReader;
29 using BPackageKit::BHPKG::BPackageWriter;
30 using BPackageKit::BHPKG::BPackageWriterListener;
31 using BPackageKit::BHPKG::BPackageWriterParameters;
32 
33 
34 static BPositionIO*
35 create_stdio(bool isInput)
36 {
37 	BFdIO* dataIO = new BFdIO(isInput ? 0 : 1, false);
38 	return new BDataPositionIOWrapper(dataIO);
39 }
40 
41 
42 int
43 command_recompress(int argc, const char* const* argv)
44 {
45 	bool quiet = false;
46 	bool verbose = false;
47 	int32 compressionLevel = BPackageKit::BHPKG::B_HPKG_COMPRESSION_LEVEL_BEST;
48 	int32 compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_ZLIB;
49 
50 	while (true) {
51 		static struct option sLongOptions[] = {
52 			{ "help", no_argument, 0, 'h' },
53 			{ "quiet", no_argument, 0, 'q' },
54 			{ "verbose", no_argument, 0, 'v' },
55 			{ 0, 0, 0, 0 }
56 		};
57 
58 		opterr = 0; // don't print errors
59 		int c = getopt_long(argc, (char**)argv, "+0123456789:hqvz",
60 			sLongOptions, NULL);
61 		if (c == -1)
62 			break;
63 
64 		switch (c) {
65 			case '0':
66 			case '1':
67 			case '2':
68 			case '3':
69 			case '4':
70 			case '5':
71 			case '6':
72 			case '7':
73 			case '8':
74 			case '9':
75 				compressionLevel = c - '0';
76 				break;
77 
78 			case 'h':
79 				print_usage_and_exit(false);
80 				break;
81 
82 			case 'q':
83 				quiet = true;
84 				break;
85 
86 			case 'v':
87 				verbose = true;
88 				break;
89 
90 			case 'z':
91 				compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_ZSTD;
92 				break;
93 
94 			default:
95 				print_usage_and_exit(true);
96 				break;
97 		}
98 	}
99 
100 	// The remaining arguments are the input package file and the output
101 	// package file, i.e. two more arguments.
102 	if (argc - optind != 2)
103 		print_usage_and_exit(true);
104 
105 	const char* inputPackageFileName = argv[optind++];
106 	const char* outputPackageFileName = argv[optind++];
107 
108 	// open the input package
109 	status_t error = B_OK;
110 	BPositionIO* inputFile;
111 	if (strcmp(inputPackageFileName, "-") == 0) {
112 		inputFile = create_stdio(true);
113 	} else {
114 		BFile* inputFileFile = new BFile;
115 		error = inputFileFile->SetTo(inputPackageFileName, O_RDONLY);
116 		if (error != B_OK) {
117 			fprintf(stderr, "Error: Failed to open input file \"%s\": %s\n",
118 				inputPackageFileName, strerror(error));
119 			return 1;
120 		}
121 		inputFile = inputFileFile;
122 	}
123 
124 	// write the output package
125 	BPackageWriterParameters writerParameters;
126 	writerParameters.SetCompressionLevel(compressionLevel);
127 	if (compressionLevel == 0) {
128 		writerParameters.SetCompression(
129 			BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE);
130 	}
131 
132 	if (compressionLevel == 0)
133 		compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE;
134 	writerParameters.SetCompression(compression);
135 
136 	PackageWriterListener listener(verbose, quiet);
137 	BPackageWriter packageWriter(&listener);
138 	if (strcmp(outputPackageFileName, "-") == 0) {
139 		if (compressionLevel != 0) {
140 			fprintf(stderr, "Error: Writing to stdout is supported only with "
141 				"compression level 0.\n");
142 			return 1;
143 		}
144 
145 		error = packageWriter.Init(create_stdio(false), true,
146 			&writerParameters);
147 	} else
148 		error = packageWriter.Init(outputPackageFileName, &writerParameters);
149 	if (error != B_OK)
150 		return 1;
151 
152 	error = packageWriter.Recompress(inputFile);
153 	if (error != B_OK)
154 		return 1;
155 
156 	if (verbose)
157 		printf("\nsuccessfully wrote package '%s'\n", outputPackageFileName);
158 
159 	return 0;
160 }
161