blob: fabb7efa83c663d504305210e70d0bbf6b52af93 [file] [log] [blame]
Tianjie Xu1f1cdb22017-11-20 11:05:55 -08001#include "bsdiff/bsdiff_arguments.h"
2
3#include <getopt.h>
4
5#include <algorithm>
6#include <iostream>
7
8#include "brotli/encode.h"
9
10using std::endl;
11using std::string;
12
13namespace {
14
15// The name in string for the compression algorithms.
16constexpr char kNoCompressionString[] = "nocompression";
17constexpr char kBZ2String[] = "bz2";
18constexpr char kBrotliString[] = "brotli";
19
20// The name in string for the bsdiff format.
21constexpr char kLegacyString[] = "legacy";
22constexpr char kBsdf2String[] = "bsdf2";
23constexpr char kBsdiff40String[] = "bsdiff40";
24
25const struct option OPTIONS[] = {
26 {"format", required_argument, nullptr, 0},
27 {"type", required_argument, nullptr, 0},
28 {"quality", required_argument, nullptr, 0},
29 {nullptr, 0, nullptr, 0},
30};
31
32const uint32_t kBrotliDefaultQuality = BROTLI_MAX_QUALITY;
33
34} // namespace
35
36namespace bsdiff {
37
38bool BsdiffArguments::IsValid() const {
39 if (format_ == BsdiffFormat::kLegacy) {
40 return (compressor_type_ == CompressorType::kBZ2);
41 } else if (format_ == BsdiffFormat::kBsdf2) {
42 if (compressor_type_ == CompressorType::kBZ2) {
43 return true;
44 }
45 if (compressor_type_ == CompressorType::kBrotli) {
46 return (compression_quality_ >= BROTLI_MIN_QUALITY &&
47 compression_quality_ <= BROTLI_MAX_QUALITY);
48 }
49 }
50 return false;
51}
52
53bool BsdiffArguments::ParseCommandLine(int argc, char** argv) {
54 int opt;
55 int option_index;
56 while ((opt = getopt_long(argc, argv, "", OPTIONS, &option_index)) != -1) {
57 if (opt != 0) {
58 return false;
59 }
60
61 std::string name = OPTIONS[option_index].name;
62 if (name == "format") {
63 if (!ParseBsdiffFormat(optarg, &format_)) {
64 return false;
65 }
66 } else if (name == "type") {
67 if (!ParseCompressorType(optarg, &compressor_type_)) {
68 return false;
69 }
70 } else if (name == "quality") {
71 if (!ParseQuality(optarg, &compression_quality_)) {
72 return false;
73 }
74 } else {
75 std::cerr << "Unrecognized options: " << name << endl;
76 return false;
77 }
78 }
79
80 // If quality is uninitialized for brotli, set it to default value.
81 if (format_ == BsdiffFormat::kBsdf2 &&
82 compressor_type_ == CompressorType::kBrotli &&
83 compression_quality_ == -1) {
84 compression_quality_ = kBrotliDefaultQuality;
85 } else if (compressor_type_ != CompressorType::kBrotli &&
86 compression_quality_ != -1) {
87 std::cerr << "Warning: Compression quality is only used in the brotli"
88 " compressor." << endl;
89 }
90
91 return true;
92}
93
94bool BsdiffArguments::ParseCompressorType(const string& str,
95 CompressorType* type) {
96 string type_string = str;
97 std::transform(type_string.begin(), type_string.end(), type_string.begin(),
98 ::tolower);
99 if (type_string == kNoCompressionString) {
100 *type = CompressorType::kNoCompression;
101 return true;
102 } else if (type_string == kBZ2String) {
103 *type = CompressorType::kBZ2;
104 return true;
105 } else if (type_string == kBrotliString) {
106 *type = CompressorType::kBrotli;
107 return true;
108 }
109 std::cerr << "Failed to parse compressor type in " << str << endl;
110 return false;
111}
112
113bool BsdiffArguments::ParseBsdiffFormat(const string& str,
114 BsdiffFormat* format) {
115 string format_string = str;
116 std::transform(format_string.begin(), format_string.end(),
117 format_string.begin(), ::tolower);
118 if (format_string == kLegacyString || format_string == kBsdiff40String) {
119 *format = BsdiffFormat::kLegacy;
120 return true;
121 } else if (format_string == kBsdf2String) {
122 *format = BsdiffFormat::kBsdf2;
123 return true;
124 }
125 std::cerr << "Failed to parse bsdiff format in " << str << endl;
126 return false;
127}
128
129bool BsdiffArguments::ParseQuality(const string& str, int* quality) {
130 errno = 0;
131 char* end;
132 const char* s = str.c_str();
133 long result = strtol(s, &end, 10);
134 if (errno != 0 || s == end || *end != '\0') {
135 return false;
136 }
137
138 if (result < BROTLI_MIN_QUALITY || result > BROTLI_MAX_QUALITY) {
139 std::cerr << "Compression quality out of range " << str << endl;
140 return false;
141 }
142
143 *quality = result;
144 return true;
145}
146
147} // namespace bsdiff