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
28using BPackageKit::BHPKG::BPackageReader;
29using BPackageKit::BHPKG::BPackageWriter;
30using BPackageKit::BHPKG::BPackageWriterListener;
31using BPackageKit::BHPKG::BPackageWriterParameters;
32
33
34static BPositionIO*
35create_stdio(bool isInput)
36{
37	BFdIO* dataIO = new BFdIO(isInput ? 0 : 1, false);
38	return new BDataPositionIOWrapper(dataIO);
39}
40
41
42int
43command_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 = parse_compression_argument(NULL);
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:hz:qv",
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 'z':
83				compression = parse_compression_argument(optarg);
84				break;
85
86			case 'q':
87				quiet = true;
88				break;
89
90			case 'v':
91				verbose = true;
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	if (compressionLevel == 0)
127		compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE;
128	writerParameters.SetCompression(compression);
129	writerParameters.SetCompressionLevel(compressionLevel);
130
131	PackageWriterListener listener(verbose, quiet);
132	BPackageWriter packageWriter(&listener);
133	if (strcmp(outputPackageFileName, "-") == 0) {
134		if (compressionLevel != 0) {
135			fprintf(stderr, "Error: Writing to stdout is supported only with "
136				"compression level 0.\n");
137			return 1;
138		}
139
140		error = packageWriter.Init(create_stdio(false), true,
141			&writerParameters);
142	} else
143		error = packageWriter.Init(outputPackageFileName, &writerParameters);
144	if (error != B_OK)
145		return 1;
146
147	error = packageWriter.Recompress(inputFile);
148	if (error != B_OK)
149		return 1;
150
151	if (verbose)
152		printf("\nsuccessfully wrote package '%s'\n", outputPackageFileName);
153
154	return 0;
155}
156