1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker extern "C" {
18*288bf522SAndroid Build Coastguard Worker #include <fec.h>
19*288bf522SAndroid Build Coastguard Worker }
20*288bf522SAndroid Build Coastguard Worker
21*288bf522SAndroid Build Coastguard Worker #undef NDEBUG
22*288bf522SAndroid Build Coastguard Worker
23*288bf522SAndroid Build Coastguard Worker #include <assert.h>
24*288bf522SAndroid Build Coastguard Worker #include <errno.h>
25*288bf522SAndroid Build Coastguard Worker #include <getopt.h>
26*288bf522SAndroid Build Coastguard Worker #include <fcntl.h>
27*288bf522SAndroid Build Coastguard Worker #include <pthread.h>
28*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
29*288bf522SAndroid Build Coastguard Worker #include <string.h>
30*288bf522SAndroid Build Coastguard Worker
31*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
32*288bf522SAndroid Build Coastguard Worker #include "image.h"
33*288bf522SAndroid Build Coastguard Worker
34*288bf522SAndroid Build Coastguard Worker enum {
35*288bf522SAndroid Build Coastguard Worker MODE_ENCODE,
36*288bf522SAndroid Build Coastguard Worker MODE_DECODE,
37*288bf522SAndroid Build Coastguard Worker MODE_PRINTSIZE,
38*288bf522SAndroid Build Coastguard Worker MODE_GETECCSTART,
39*288bf522SAndroid Build Coastguard Worker MODE_GETVERITYSTART
40*288bf522SAndroid Build Coastguard Worker };
41*288bf522SAndroid Build Coastguard Worker
encode_rs(struct image_proc_ctx * ctx)42*288bf522SAndroid Build Coastguard Worker static void encode_rs(struct image_proc_ctx *ctx)
43*288bf522SAndroid Build Coastguard Worker {
44*288bf522SAndroid Build Coastguard Worker struct image *fcx = ctx->ctx;
45*288bf522SAndroid Build Coastguard Worker int j;
46*288bf522SAndroid Build Coastguard Worker uint8_t data[fcx->rs_n];
47*288bf522SAndroid Build Coastguard Worker uint64_t i;
48*288bf522SAndroid Build Coastguard Worker
49*288bf522SAndroid Build Coastguard Worker for (i = ctx->start; i < ctx->end; i += fcx->rs_n) {
50*288bf522SAndroid Build Coastguard Worker for (j = 0; j < fcx->rs_n; ++j) {
51*288bf522SAndroid Build Coastguard Worker data[j] = image_get_interleaved_byte(i + j, fcx);
52*288bf522SAndroid Build Coastguard Worker }
53*288bf522SAndroid Build Coastguard Worker
54*288bf522SAndroid Build Coastguard Worker encode_rs_char(ctx->rs, data, &fcx->fec[ctx->fec_pos]);
55*288bf522SAndroid Build Coastguard Worker ctx->fec_pos += fcx->roots;
56*288bf522SAndroid Build Coastguard Worker }
57*288bf522SAndroid Build Coastguard Worker }
58*288bf522SAndroid Build Coastguard Worker
decode_rs(struct image_proc_ctx * ctx)59*288bf522SAndroid Build Coastguard Worker static void decode_rs(struct image_proc_ctx *ctx)
60*288bf522SAndroid Build Coastguard Worker {
61*288bf522SAndroid Build Coastguard Worker struct image *fcx = ctx->ctx;
62*288bf522SAndroid Build Coastguard Worker int j, rv;
63*288bf522SAndroid Build Coastguard Worker uint8_t data[fcx->rs_n + fcx->roots];
64*288bf522SAndroid Build Coastguard Worker uint64_t i;
65*288bf522SAndroid Build Coastguard Worker
66*288bf522SAndroid Build Coastguard Worker assert(sizeof(data) == FEC_RSM);
67*288bf522SAndroid Build Coastguard Worker
68*288bf522SAndroid Build Coastguard Worker for (i = ctx->start; i < ctx->end; i += fcx->rs_n) {
69*288bf522SAndroid Build Coastguard Worker for (j = 0; j < fcx->rs_n; ++j) {
70*288bf522SAndroid Build Coastguard Worker data[j] = image_get_interleaved_byte(i + j, fcx);
71*288bf522SAndroid Build Coastguard Worker }
72*288bf522SAndroid Build Coastguard Worker
73*288bf522SAndroid Build Coastguard Worker memcpy(&data[fcx->rs_n], &fcx->fec[ctx->fec_pos], fcx->roots);
74*288bf522SAndroid Build Coastguard Worker rv = decode_rs_char(ctx->rs, data, nullptr, 0);
75*288bf522SAndroid Build Coastguard Worker
76*288bf522SAndroid Build Coastguard Worker if (rv < 0) {
77*288bf522SAndroid Build Coastguard Worker FATAL("failed to recover [%" PRIu64 ", %" PRIu64 ")\n",
78*288bf522SAndroid Build Coastguard Worker i, i + fcx->rs_n);
79*288bf522SAndroid Build Coastguard Worker } else if (rv > 0) {
80*288bf522SAndroid Build Coastguard Worker /* copy corrected data to output */
81*288bf522SAndroid Build Coastguard Worker for (j = 0; j < fcx->rs_n; ++j) {
82*288bf522SAndroid Build Coastguard Worker image_set_interleaved_byte(i + j, fcx, data[j]);
83*288bf522SAndroid Build Coastguard Worker }
84*288bf522SAndroid Build Coastguard Worker
85*288bf522SAndroid Build Coastguard Worker ctx->rv += rv;
86*288bf522SAndroid Build Coastguard Worker }
87*288bf522SAndroid Build Coastguard Worker
88*288bf522SAndroid Build Coastguard Worker ctx->fec_pos += fcx->roots;
89*288bf522SAndroid Build Coastguard Worker }
90*288bf522SAndroid Build Coastguard Worker }
91*288bf522SAndroid Build Coastguard Worker
usage()92*288bf522SAndroid Build Coastguard Worker static int usage()
93*288bf522SAndroid Build Coastguard Worker {
94*288bf522SAndroid Build Coastguard Worker printf("fec: a tool for encoding and decoding files using RS(255, N).\n"
95*288bf522SAndroid Build Coastguard Worker "\n"
96*288bf522SAndroid Build Coastguard Worker "usage: fec <mode> [ <options> ] [ <data> <fec> [ <output> ] ]\n"
97*288bf522SAndroid Build Coastguard Worker "mode:\n"
98*288bf522SAndroid Build Coastguard Worker " -e --encode encode (default)\n"
99*288bf522SAndroid Build Coastguard Worker " -d --decode decode\n"
100*288bf522SAndroid Build Coastguard Worker " -s, --print-fec-size=<data size> print FEC size\n"
101*288bf522SAndroid Build Coastguard Worker " -E, --get-ecc-start=data print ECC offset in data\n"
102*288bf522SAndroid Build Coastguard Worker " -V, --get-verity-start=data print verity offset\n"
103*288bf522SAndroid Build Coastguard Worker "options:\n"
104*288bf522SAndroid Build Coastguard Worker " -h show this help\n"
105*288bf522SAndroid Build Coastguard Worker " -v enable verbose logging\n"
106*288bf522SAndroid Build Coastguard Worker " -r, --roots=<bytes> number of parity bytes\n"
107*288bf522SAndroid Build Coastguard Worker " -j, --threads=<threads> number of threads to use\n"
108*288bf522SAndroid Build Coastguard Worker " -S treat data as a sparse file\n"
109*288bf522SAndroid Build Coastguard Worker "encoding options:\n"
110*288bf522SAndroid Build Coastguard Worker " -p, --padding=<bytes> add padding after ECC data\n"
111*288bf522SAndroid Build Coastguard Worker "decoding options:\n"
112*288bf522SAndroid Build Coastguard Worker " -i, --inplace correct <data> in place\n"
113*288bf522SAndroid Build Coastguard Worker );
114*288bf522SAndroid Build Coastguard Worker
115*288bf522SAndroid Build Coastguard Worker return 1;
116*288bf522SAndroid Build Coastguard Worker }
117*288bf522SAndroid Build Coastguard Worker
parse_arg(const char * arg,const char * name,uint64_t maxval)118*288bf522SAndroid Build Coastguard Worker static uint64_t parse_arg(const char *arg, const char *name, uint64_t maxval)
119*288bf522SAndroid Build Coastguard Worker {
120*288bf522SAndroid Build Coastguard Worker char* endptr;
121*288bf522SAndroid Build Coastguard Worker errno = 0;
122*288bf522SAndroid Build Coastguard Worker
123*288bf522SAndroid Build Coastguard Worker unsigned long long int value = strtoull(arg, &endptr, 0);
124*288bf522SAndroid Build Coastguard Worker
125*288bf522SAndroid Build Coastguard Worker if (arg[0] == '\0' || *endptr != '\0' ||
126*288bf522SAndroid Build Coastguard Worker (errno == ERANGE && value == ULLONG_MAX)) {
127*288bf522SAndroid Build Coastguard Worker FATAL("invalid value of %s\n", name);
128*288bf522SAndroid Build Coastguard Worker }
129*288bf522SAndroid Build Coastguard Worker if (value > maxval) {
130*288bf522SAndroid Build Coastguard Worker FATAL("value of roots too large (max. %" PRIu64 ")\n", maxval);
131*288bf522SAndroid Build Coastguard Worker }
132*288bf522SAndroid Build Coastguard Worker
133*288bf522SAndroid Build Coastguard Worker return (uint64_t)value;
134*288bf522SAndroid Build Coastguard Worker }
135*288bf522SAndroid Build Coastguard Worker
print_size(image & ctx)136*288bf522SAndroid Build Coastguard Worker static int print_size(image& ctx)
137*288bf522SAndroid Build Coastguard Worker {
138*288bf522SAndroid Build Coastguard Worker /* output size including header */
139*288bf522SAndroid Build Coastguard Worker printf("%" PRIu64 "\n", fec_ecc_get_size(ctx.inp_size, ctx.roots));
140*288bf522SAndroid Build Coastguard Worker return 0;
141*288bf522SAndroid Build Coastguard Worker }
142*288bf522SAndroid Build Coastguard Worker
get_start(int mode,const std::string & filename)143*288bf522SAndroid Build Coastguard Worker static int get_start(int mode, const std::string& filename)
144*288bf522SAndroid Build Coastguard Worker {
145*288bf522SAndroid Build Coastguard Worker fec::io fh(filename, O_RDONLY, FEC_VERITY_DISABLE);
146*288bf522SAndroid Build Coastguard Worker
147*288bf522SAndroid Build Coastguard Worker if (!fh) {
148*288bf522SAndroid Build Coastguard Worker FATAL("failed to open input\n");
149*288bf522SAndroid Build Coastguard Worker }
150*288bf522SAndroid Build Coastguard Worker
151*288bf522SAndroid Build Coastguard Worker if (mode == MODE_GETECCSTART) {
152*288bf522SAndroid Build Coastguard Worker fec_ecc_metadata data;
153*288bf522SAndroid Build Coastguard Worker
154*288bf522SAndroid Build Coastguard Worker if (!fh.get_ecc_metadata(data)) {
155*288bf522SAndroid Build Coastguard Worker FATAL("no ecc data\n");
156*288bf522SAndroid Build Coastguard Worker }
157*288bf522SAndroid Build Coastguard Worker
158*288bf522SAndroid Build Coastguard Worker printf("%" PRIu64 "\n", data.start);
159*288bf522SAndroid Build Coastguard Worker } else {
160*288bf522SAndroid Build Coastguard Worker fec_verity_metadata data;
161*288bf522SAndroid Build Coastguard Worker
162*288bf522SAndroid Build Coastguard Worker if (!fh.get_verity_metadata(data)) {
163*288bf522SAndroid Build Coastguard Worker FATAL("no verity data\n");
164*288bf522SAndroid Build Coastguard Worker }
165*288bf522SAndroid Build Coastguard Worker
166*288bf522SAndroid Build Coastguard Worker printf("%" PRIu64 "\n", data.data_size);
167*288bf522SAndroid Build Coastguard Worker }
168*288bf522SAndroid Build Coastguard Worker
169*288bf522SAndroid Build Coastguard Worker return 0;
170*288bf522SAndroid Build Coastguard Worker }
171*288bf522SAndroid Build Coastguard Worker
encode(image & ctx,const std::vector<std::string> & inp_filenames,const std::string & fec_filename)172*288bf522SAndroid Build Coastguard Worker static int encode(image& ctx, const std::vector<std::string>& inp_filenames,
173*288bf522SAndroid Build Coastguard Worker const std::string& fec_filename)
174*288bf522SAndroid Build Coastguard Worker {
175*288bf522SAndroid Build Coastguard Worker if (ctx.inplace) {
176*288bf522SAndroid Build Coastguard Worker FATAL("invalid parameters: inplace can only used when decoding\n");
177*288bf522SAndroid Build Coastguard Worker }
178*288bf522SAndroid Build Coastguard Worker
179*288bf522SAndroid Build Coastguard Worker if (!image_load(inp_filenames, &ctx)) {
180*288bf522SAndroid Build Coastguard Worker FATAL("failed to read input\n");
181*288bf522SAndroid Build Coastguard Worker }
182*288bf522SAndroid Build Coastguard Worker
183*288bf522SAndroid Build Coastguard Worker if (!image_ecc_new(fec_filename, &ctx)) {
184*288bf522SAndroid Build Coastguard Worker FATAL("failed to allocate ecc\n");
185*288bf522SAndroid Build Coastguard Worker }
186*288bf522SAndroid Build Coastguard Worker
187*288bf522SAndroid Build Coastguard Worker INFO("encoding RS(255, %d) to '%s' for input files:\n", ctx.rs_n,
188*288bf522SAndroid Build Coastguard Worker fec_filename.c_str());
189*288bf522SAndroid Build Coastguard Worker
190*288bf522SAndroid Build Coastguard Worker size_t n = 1;
191*288bf522SAndroid Build Coastguard Worker
192*288bf522SAndroid Build Coastguard Worker for (const auto& fn : inp_filenames) {
193*288bf522SAndroid Build Coastguard Worker INFO("\t%zu: '%s'\n", n++, fn.c_str());
194*288bf522SAndroid Build Coastguard Worker }
195*288bf522SAndroid Build Coastguard Worker
196*288bf522SAndroid Build Coastguard Worker if (ctx.verbose) {
197*288bf522SAndroid Build Coastguard Worker INFO("\traw fec size: %u\n", ctx.fec_size);
198*288bf522SAndroid Build Coastguard Worker INFO("\tblocks: %" PRIu64 "\n", ctx.blocks);
199*288bf522SAndroid Build Coastguard Worker INFO("\trounds: %" PRIu64 "\n", ctx.rounds);
200*288bf522SAndroid Build Coastguard Worker }
201*288bf522SAndroid Build Coastguard Worker
202*288bf522SAndroid Build Coastguard Worker if (!image_process(encode_rs, &ctx)) {
203*288bf522SAndroid Build Coastguard Worker FATAL("failed to process input\n");
204*288bf522SAndroid Build Coastguard Worker }
205*288bf522SAndroid Build Coastguard Worker
206*288bf522SAndroid Build Coastguard Worker if (!image_ecc_save(&ctx)) {
207*288bf522SAndroid Build Coastguard Worker FATAL("failed to write output\n");
208*288bf522SAndroid Build Coastguard Worker }
209*288bf522SAndroid Build Coastguard Worker
210*288bf522SAndroid Build Coastguard Worker image_free(&ctx);
211*288bf522SAndroid Build Coastguard Worker return 0;
212*288bf522SAndroid Build Coastguard Worker }
213*288bf522SAndroid Build Coastguard Worker
decode(image & ctx,const std::vector<std::string> & inp_filenames,const std::string & fec_filename,std::string & out_filename)214*288bf522SAndroid Build Coastguard Worker static int decode(image& ctx, const std::vector<std::string>& inp_filenames,
215*288bf522SAndroid Build Coastguard Worker const std::string& fec_filename, std::string& out_filename)
216*288bf522SAndroid Build Coastguard Worker {
217*288bf522SAndroid Build Coastguard Worker const std::string& inp_filename = inp_filenames.front();
218*288bf522SAndroid Build Coastguard Worker
219*288bf522SAndroid Build Coastguard Worker if (ctx.inplace && ctx.sparse) {
220*288bf522SAndroid Build Coastguard Worker FATAL("invalid parameters: inplace cannot be used with sparse "
221*288bf522SAndroid Build Coastguard Worker "files\n");
222*288bf522SAndroid Build Coastguard Worker }
223*288bf522SAndroid Build Coastguard Worker
224*288bf522SAndroid Build Coastguard Worker if (ctx.padding) {
225*288bf522SAndroid Build Coastguard Worker FATAL("invalid parameters: padding is only relevant when encoding\n");
226*288bf522SAndroid Build Coastguard Worker }
227*288bf522SAndroid Build Coastguard Worker
228*288bf522SAndroid Build Coastguard Worker if (!image_ecc_load(fec_filename, &ctx) ||
229*288bf522SAndroid Build Coastguard Worker !image_load(inp_filenames, &ctx)) {
230*288bf522SAndroid Build Coastguard Worker FATAL("failed to read input\n");
231*288bf522SAndroid Build Coastguard Worker }
232*288bf522SAndroid Build Coastguard Worker
233*288bf522SAndroid Build Coastguard Worker if (ctx.inplace) {
234*288bf522SAndroid Build Coastguard Worker INFO("correcting '%s' using RS(255, %d) from '%s'\n",
235*288bf522SAndroid Build Coastguard Worker inp_filename.c_str(), ctx.rs_n, fec_filename.c_str());
236*288bf522SAndroid Build Coastguard Worker
237*288bf522SAndroid Build Coastguard Worker out_filename = inp_filename;
238*288bf522SAndroid Build Coastguard Worker } else {
239*288bf522SAndroid Build Coastguard Worker INFO("decoding '%s' to '%s' using RS(255, %d) from '%s'\n",
240*288bf522SAndroid Build Coastguard Worker inp_filename.c_str(),
241*288bf522SAndroid Build Coastguard Worker out_filename.empty() ? out_filename.c_str() : "<none>", ctx.rs_n,
242*288bf522SAndroid Build Coastguard Worker fec_filename.c_str());
243*288bf522SAndroid Build Coastguard Worker }
244*288bf522SAndroid Build Coastguard Worker
245*288bf522SAndroid Build Coastguard Worker if (ctx.verbose) {
246*288bf522SAndroid Build Coastguard Worker INFO("\traw fec size: %u\n", ctx.fec_size);
247*288bf522SAndroid Build Coastguard Worker INFO("\tblocks: %" PRIu64 "\n", ctx.blocks);
248*288bf522SAndroid Build Coastguard Worker INFO("\trounds: %" PRIu64 "\n", ctx.rounds);
249*288bf522SAndroid Build Coastguard Worker }
250*288bf522SAndroid Build Coastguard Worker
251*288bf522SAndroid Build Coastguard Worker if (!image_process(decode_rs, &ctx)) {
252*288bf522SAndroid Build Coastguard Worker FATAL("failed to process input\n");
253*288bf522SAndroid Build Coastguard Worker }
254*288bf522SAndroid Build Coastguard Worker
255*288bf522SAndroid Build Coastguard Worker if (ctx.rv) {
256*288bf522SAndroid Build Coastguard Worker INFO("corrected %" PRIu64 " errors\n", ctx.rv);
257*288bf522SAndroid Build Coastguard Worker } else {
258*288bf522SAndroid Build Coastguard Worker INFO("no errors found\n");
259*288bf522SAndroid Build Coastguard Worker }
260*288bf522SAndroid Build Coastguard Worker
261*288bf522SAndroid Build Coastguard Worker if (!out_filename.empty() && !image_save(out_filename, &ctx)) {
262*288bf522SAndroid Build Coastguard Worker FATAL("failed to write output\n");
263*288bf522SAndroid Build Coastguard Worker }
264*288bf522SAndroid Build Coastguard Worker
265*288bf522SAndroid Build Coastguard Worker image_free(&ctx);
266*288bf522SAndroid Build Coastguard Worker return 0;
267*288bf522SAndroid Build Coastguard Worker }
268*288bf522SAndroid Build Coastguard Worker
main(int argc,char ** argv)269*288bf522SAndroid Build Coastguard Worker int main(int argc, char **argv)
270*288bf522SAndroid Build Coastguard Worker {
271*288bf522SAndroid Build Coastguard Worker std::string fec_filename;
272*288bf522SAndroid Build Coastguard Worker std::string out_filename;
273*288bf522SAndroid Build Coastguard Worker std::vector<std::string> inp_filenames;
274*288bf522SAndroid Build Coastguard Worker int mode = MODE_ENCODE;
275*288bf522SAndroid Build Coastguard Worker image ctx;
276*288bf522SAndroid Build Coastguard Worker
277*288bf522SAndroid Build Coastguard Worker image_init(&ctx);
278*288bf522SAndroid Build Coastguard Worker ctx.roots = FEC_DEFAULT_ROOTS;
279*288bf522SAndroid Build Coastguard Worker
280*288bf522SAndroid Build Coastguard Worker while (1) {
281*288bf522SAndroid Build Coastguard Worker const static struct option long_options[] = {
282*288bf522SAndroid Build Coastguard Worker {"help", no_argument, nullptr, 'h'},
283*288bf522SAndroid Build Coastguard Worker {"encode", no_argument, nullptr, 'e'},
284*288bf522SAndroid Build Coastguard Worker {"decode", no_argument, nullptr, 'd'},
285*288bf522SAndroid Build Coastguard Worker {"sparse", no_argument, nullptr, 'S'},
286*288bf522SAndroid Build Coastguard Worker {"roots", required_argument, nullptr, 'r'},
287*288bf522SAndroid Build Coastguard Worker {"inplace", no_argument, nullptr, 'i'},
288*288bf522SAndroid Build Coastguard Worker {"threads", required_argument, nullptr, 'j'},
289*288bf522SAndroid Build Coastguard Worker {"print-fec-size", required_argument, nullptr, 's'},
290*288bf522SAndroid Build Coastguard Worker {"get-ecc-start", required_argument, nullptr, 'E'},
291*288bf522SAndroid Build Coastguard Worker {"get-verity-start", required_argument, nullptr, 'V'},
292*288bf522SAndroid Build Coastguard Worker {"padding", required_argument, nullptr, 'p'},
293*288bf522SAndroid Build Coastguard Worker {"verbose", no_argument, nullptr, 'v'},
294*288bf522SAndroid Build Coastguard Worker {nullptr, 0, nullptr, 0}
295*288bf522SAndroid Build Coastguard Worker };
296*288bf522SAndroid Build Coastguard Worker int c = getopt_long(argc, argv, "hedSr:ij:s:E:V:p:v", long_options, nullptr);
297*288bf522SAndroid Build Coastguard Worker if (c < 0) {
298*288bf522SAndroid Build Coastguard Worker break;
299*288bf522SAndroid Build Coastguard Worker }
300*288bf522SAndroid Build Coastguard Worker
301*288bf522SAndroid Build Coastguard Worker switch (c) {
302*288bf522SAndroid Build Coastguard Worker case 'h':
303*288bf522SAndroid Build Coastguard Worker return usage();
304*288bf522SAndroid Build Coastguard Worker case 'S':
305*288bf522SAndroid Build Coastguard Worker ctx.sparse = true;
306*288bf522SAndroid Build Coastguard Worker break;
307*288bf522SAndroid Build Coastguard Worker case 'e':
308*288bf522SAndroid Build Coastguard Worker if (mode != MODE_ENCODE) {
309*288bf522SAndroid Build Coastguard Worker return usage();
310*288bf522SAndroid Build Coastguard Worker }
311*288bf522SAndroid Build Coastguard Worker break;
312*288bf522SAndroid Build Coastguard Worker case 'd':
313*288bf522SAndroid Build Coastguard Worker if (mode != MODE_ENCODE) {
314*288bf522SAndroid Build Coastguard Worker return usage();
315*288bf522SAndroid Build Coastguard Worker }
316*288bf522SAndroid Build Coastguard Worker mode = MODE_DECODE;
317*288bf522SAndroid Build Coastguard Worker break;
318*288bf522SAndroid Build Coastguard Worker case 'r':
319*288bf522SAndroid Build Coastguard Worker ctx.roots = (int)parse_arg(optarg, "roots", FEC_RSM);
320*288bf522SAndroid Build Coastguard Worker break;
321*288bf522SAndroid Build Coastguard Worker case 'i':
322*288bf522SAndroid Build Coastguard Worker ctx.inplace = true;
323*288bf522SAndroid Build Coastguard Worker break;
324*288bf522SAndroid Build Coastguard Worker case 'j':
325*288bf522SAndroid Build Coastguard Worker ctx.threads = (int)parse_arg(optarg, "threads", IMAGE_MAX_THREADS);
326*288bf522SAndroid Build Coastguard Worker break;
327*288bf522SAndroid Build Coastguard Worker case 's':
328*288bf522SAndroid Build Coastguard Worker if (mode != MODE_ENCODE) {
329*288bf522SAndroid Build Coastguard Worker return usage();
330*288bf522SAndroid Build Coastguard Worker }
331*288bf522SAndroid Build Coastguard Worker mode = MODE_PRINTSIZE;
332*288bf522SAndroid Build Coastguard Worker ctx.inp_size = parse_arg(optarg, "print-fec-size", UINT64_MAX);
333*288bf522SAndroid Build Coastguard Worker break;
334*288bf522SAndroid Build Coastguard Worker case 'E':
335*288bf522SAndroid Build Coastguard Worker if (mode != MODE_ENCODE) {
336*288bf522SAndroid Build Coastguard Worker return usage();
337*288bf522SAndroid Build Coastguard Worker }
338*288bf522SAndroid Build Coastguard Worker mode = MODE_GETECCSTART;
339*288bf522SAndroid Build Coastguard Worker inp_filenames.push_back(optarg);
340*288bf522SAndroid Build Coastguard Worker break;
341*288bf522SAndroid Build Coastguard Worker case 'V':
342*288bf522SAndroid Build Coastguard Worker if (mode != MODE_ENCODE) {
343*288bf522SAndroid Build Coastguard Worker return usage();
344*288bf522SAndroid Build Coastguard Worker }
345*288bf522SAndroid Build Coastguard Worker mode = MODE_GETVERITYSTART;
346*288bf522SAndroid Build Coastguard Worker inp_filenames.push_back(optarg);
347*288bf522SAndroid Build Coastguard Worker break;
348*288bf522SAndroid Build Coastguard Worker case 'p':
349*288bf522SAndroid Build Coastguard Worker ctx.padding = (uint32_t)parse_arg(optarg, "padding", UINT32_MAX);
350*288bf522SAndroid Build Coastguard Worker if (ctx.padding % FEC_BLOCKSIZE) {
351*288bf522SAndroid Build Coastguard Worker FATAL("padding must be multiple of %u\n", FEC_BLOCKSIZE);
352*288bf522SAndroid Build Coastguard Worker }
353*288bf522SAndroid Build Coastguard Worker break;
354*288bf522SAndroid Build Coastguard Worker case 'v':
355*288bf522SAndroid Build Coastguard Worker ctx.verbose = true;
356*288bf522SAndroid Build Coastguard Worker break;
357*288bf522SAndroid Build Coastguard Worker case '?':
358*288bf522SAndroid Build Coastguard Worker return usage();
359*288bf522SAndroid Build Coastguard Worker default:
360*288bf522SAndroid Build Coastguard Worker abort();
361*288bf522SAndroid Build Coastguard Worker }
362*288bf522SAndroid Build Coastguard Worker }
363*288bf522SAndroid Build Coastguard Worker
364*288bf522SAndroid Build Coastguard Worker argc -= optind;
365*288bf522SAndroid Build Coastguard Worker argv += optind;
366*288bf522SAndroid Build Coastguard Worker
367*288bf522SAndroid Build Coastguard Worker assert(ctx.roots > 0 && ctx.roots < FEC_RSM);
368*288bf522SAndroid Build Coastguard Worker
369*288bf522SAndroid Build Coastguard Worker /* check for input / output parameters */
370*288bf522SAndroid Build Coastguard Worker if (mode == MODE_ENCODE) {
371*288bf522SAndroid Build Coastguard Worker /* allow multiple input files */
372*288bf522SAndroid Build Coastguard Worker for (int i = 0; i < (argc - 1); ++i) {
373*288bf522SAndroid Build Coastguard Worker inp_filenames.push_back(argv[i]);
374*288bf522SAndroid Build Coastguard Worker }
375*288bf522SAndroid Build Coastguard Worker
376*288bf522SAndroid Build Coastguard Worker if (inp_filenames.empty()) {
377*288bf522SAndroid Build Coastguard Worker return usage();
378*288bf522SAndroid Build Coastguard Worker }
379*288bf522SAndroid Build Coastguard Worker
380*288bf522SAndroid Build Coastguard Worker /* the last one is the output file */
381*288bf522SAndroid Build Coastguard Worker fec_filename = argv[argc - 1];
382*288bf522SAndroid Build Coastguard Worker } else if (mode == MODE_DECODE) {
383*288bf522SAndroid Build Coastguard Worker if (argc < 2 || argc > 3) {
384*288bf522SAndroid Build Coastguard Worker return usage();
385*288bf522SAndroid Build Coastguard Worker } else if (argc == 3) {
386*288bf522SAndroid Build Coastguard Worker if (ctx.inplace) {
387*288bf522SAndroid Build Coastguard Worker return usage();
388*288bf522SAndroid Build Coastguard Worker }
389*288bf522SAndroid Build Coastguard Worker out_filename = argv[2];
390*288bf522SAndroid Build Coastguard Worker }
391*288bf522SAndroid Build Coastguard Worker
392*288bf522SAndroid Build Coastguard Worker inp_filenames.push_back(argv[0]);
393*288bf522SAndroid Build Coastguard Worker fec_filename = argv[1];
394*288bf522SAndroid Build Coastguard Worker }
395*288bf522SAndroid Build Coastguard Worker
396*288bf522SAndroid Build Coastguard Worker switch (mode) {
397*288bf522SAndroid Build Coastguard Worker case MODE_PRINTSIZE:
398*288bf522SAndroid Build Coastguard Worker return print_size(ctx);
399*288bf522SAndroid Build Coastguard Worker case MODE_GETECCSTART:
400*288bf522SAndroid Build Coastguard Worker case MODE_GETVERITYSTART:
401*288bf522SAndroid Build Coastguard Worker return get_start(mode, inp_filenames.front());
402*288bf522SAndroid Build Coastguard Worker case MODE_ENCODE:
403*288bf522SAndroid Build Coastguard Worker return encode(ctx, inp_filenames, fec_filename);
404*288bf522SAndroid Build Coastguard Worker case MODE_DECODE:
405*288bf522SAndroid Build Coastguard Worker return decode(ctx, inp_filenames, fec_filename, out_filename);
406*288bf522SAndroid Build Coastguard Worker default:
407*288bf522SAndroid Build Coastguard Worker abort();
408*288bf522SAndroid Build Coastguard Worker }
409*288bf522SAndroid Build Coastguard Worker
410*288bf522SAndroid Build Coastguard Worker return 1;
411*288bf522SAndroid Build Coastguard Worker }
412