129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen/*
229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * Copyright (C) 2015 The Android Open Source Project
329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen *
429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * Licensed under the Apache License, Version 2.0 (the "License");
529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * you may not use this file except in compliance with the License.
629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * You may obtain a copy of the License at
729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen *
829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen *      http://www.apache.org/licenses/LICENSE-2.0
929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen *
1029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * Unless required by applicable law or agreed to in writing, software
1129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * distributed under the License is distributed on an "AS IS" BASIS,
1229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * See the License for the specific language governing permissions and
1429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * limitations under the License.
1529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen */
1629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
1729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenextern "C" {
1829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    #include <fec.h>
1929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
2029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
2129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#undef NDEBUG
2229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
2329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <assert.h>
2429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <errno.h>
2529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <getopt.h>
2629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <fcntl.h>
2729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <pthread.h>
2829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <stdbool.h>
2929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <stdlib.h>
3029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <string.h>
31f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen
3266dd09e8e2407082ce93bf0784de641298131912Elliott Hughes#include <android-base/file.h>
3329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include "image.h"
3429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
3529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenenum {
3629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    MODE_ENCODE,
3729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    MODE_DECODE,
3829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    MODE_PRINTSIZE,
3929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    MODE_GETECCSTART,
4029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    MODE_GETVERITYSTART
4129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen};
4229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
4329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenstatic void encode_rs(struct image_proc_ctx *ctx)
4429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
4529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    struct image *fcx = ctx->ctx;
4629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    int j;
4729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    uint8_t data[fcx->rs_n];
4829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    uint64_t i;
4929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
5029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    for (i = ctx->start; i < ctx->end; i += fcx->rs_n) {
5129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        for (j = 0; j < fcx->rs_n; ++j) {
5229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            data[j] = image_get_interleaved_byte(i + j, fcx);
5329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        }
5429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
5529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        encode_rs_char(ctx->rs, data, &fcx->fec[ctx->fec_pos]);
5629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        ctx->fec_pos += fcx->roots;
5729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
5829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
5929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
6029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenstatic void decode_rs(struct image_proc_ctx *ctx)
6129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
6229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    struct image *fcx = ctx->ctx;
6329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    int j, rv;
6429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    uint8_t data[fcx->rs_n + fcx->roots];
6529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    uint64_t i;
6629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
6729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    assert(sizeof(data) == FEC_RSM);
6829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
6929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    for (i = ctx->start; i < ctx->end; i += fcx->rs_n) {
7029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        for (j = 0; j < fcx->rs_n; ++j) {
7129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            data[j] = image_get_interleaved_byte(i + j, fcx);
7229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        }
7329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
7429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        memcpy(&data[fcx->rs_n], &fcx->fec[ctx->fec_pos], fcx->roots);
7529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        rv = decode_rs_char(ctx->rs, data, NULL, 0);
7629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
7729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        if (rv < 0) {
7829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            FATAL("failed to recover [%" PRIu64 ", %" PRIu64 ")\n",
7929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen                i, i + fcx->rs_n);
8029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        } else if (rv > 0) {
8129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            /* copy corrected data to output */
8229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            for (j = 0; j < fcx->rs_n; ++j) {
8329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen                image_set_interleaved_byte(i + j, fcx, data[j]);
8429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            }
8529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
8629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            ctx->rv += rv;
8729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        }
8829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
8929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        ctx->fec_pos += fcx->roots;
9029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
9129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
9229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
9329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenstatic int usage()
9429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
9529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    printf("fec: a tool for encoding and decoding files using RS(255, N).\n"
9629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "\n"
9729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "usage: fec <mode> [ <options> ] [ <data> <fec> [ <output> ] ]\n"
9829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "mode:\n"
9929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -e  --encode                      encode (default)\n"
10029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -d  --decode                      decode\n"
10129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -s, --print-fec-size=<data size>  print FEC size\n"
10229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -E, --get-ecc-start=data          print ECC offset in data\n"
10329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -V, --get-verity-start=data       print verity offset\n"
10429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "options:\n"
10529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -h                                show this help\n"
10629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -v                                enable verbose logging\n"
10729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -r, --roots=<bytes>               number of parity bytes\n"
10829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -m, --mmap                        use memory mapping\n"
10929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -j, --threads=<threads>           number of threads to use\n"
11029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -S                                treat data as a sparse file\n"
11129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "decoding options:\n"
11229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen           "  -i, --inplace                     correct <data> in place\n"
11329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        );
11429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
11529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    return 1;
11629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
11729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
11829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenstatic uint64_t parse_arg(const char *arg, const char *name, uint64_t maxval)
11929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
12029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    char* endptr;
12129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    errno = 0;
12229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
12329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    unsigned long long int value = strtoull(arg, &endptr, 0);
12429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
12529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (arg[0] == '\0' || *endptr != '\0' ||
12629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            (errno == ERANGE && value == ULLONG_MAX)) {
12729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("invalid value of %s\n", name);
12829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
12929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (value > maxval) {
13029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("value of roots too large (max. %" PRIu64 ")\n", maxval);
13129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
13229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
13329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    return (uint64_t)value;
13429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
13529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
13629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenstatic int print_size(image& ctx)
13729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
13829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    /* output size including header */
13929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    printf("%" PRIu64 "\n", fec_ecc_get_size(ctx.inp_size, ctx.roots));
14029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    return 0;
14129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
14229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
143f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanenstatic int get_start(int mode, const std::string& filename)
14429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
14529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    fec::io fh(filename, O_RDONLY, FEC_VERITY_DISABLE);
14629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
14729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (!fh) {
14829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("failed to open input\n");
14929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
15029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
15129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (mode == MODE_GETECCSTART) {
15229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        fec_ecc_metadata data;
15329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
15429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        if (!fh.get_ecc_metadata(data)) {
15529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            FATAL("no ecc data\n");
15629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        }
15729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
1584b71c1b3ab941a3edb258e55eb25dcf5fc013d49Sami Tolvanen        printf("%" PRIu64 "\n", data.start);
15929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    } else {
16029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        fec_verity_metadata data;
16129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
16229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        if (!fh.get_verity_metadata(data)) {
16329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            FATAL("no verity data\n");
16429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        }
16529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
16629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        printf("%" PRIu64 "\n", data.data_size);
16729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
16829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
16929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    return 0;
17029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
17129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
172f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanenstatic int encode(image& ctx, const std::vector<std::string>& inp_filenames,
173f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        const std::string& fec_filename)
17429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
17529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (ctx.inplace) {
17629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("invalid parameters: inplace can only used when decoding\n");
17729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
17829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
179f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    if (!image_load(inp_filenames, &ctx, false)) {
18029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("failed to read input\n");
18129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
18229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
18329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (!image_ecc_new(fec_filename, &ctx)) {
18429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("failed to allocate ecc\n");
18529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
18629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
187f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    INFO("encoding RS(255, %d) to '%s' for input files:\n", ctx.rs_n,
188f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        fec_filename.c_str());
189f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen
190f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    size_t n = 1;
191f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen
192f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    for (auto fn : inp_filenames) {
193f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        INFO("\t%zu: '%s'\n", n++, fn.c_str());
194f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    }
19529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
19629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (ctx.verbose) {
19729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("\traw fec size: %u\n", ctx.fec_size);
19829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("\tblocks: %" PRIu64 "\n", ctx.blocks);
19929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("\trounds: %" PRIu64 "\n", ctx.rounds);
20029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
20129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
20229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (!image_process(encode_rs, &ctx)) {
20329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("failed to process input\n");
20429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
20529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
20629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (!image_ecc_save(&ctx)) {
20729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("failed to write output\n");
20829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
20929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
21029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    image_free(&ctx);
21129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    return 0;
21229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
21329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
214f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanenstatic int decode(image& ctx, const std::vector<std::string>& inp_filenames,
215f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        const std::string& fec_filename, std::string& out_filename)
21629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
217f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    const std::string& inp_filename = inp_filenames.front();
218f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen
21929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (ctx.inplace && ctx.sparse) {
22029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("invalid parameters: inplace cannot be used with sparse "
22129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            "files\n");
22229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
22329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
22429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (!image_ecc_load(fec_filename, &ctx) ||
225f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            !image_load(inp_filenames, &ctx, !out_filename.empty())) {
22629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("failed to read input\n");
22729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
22829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
22929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (ctx.inplace) {
230f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        INFO("correcting '%s' using RS(255, %d) from '%s'\n",
231f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            inp_filename.c_str(), ctx.rs_n, fec_filename.c_str());
23229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
23329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        out_filename = inp_filename;
23429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    } else {
23529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("decoding '%s' to '%s' using RS(255, %d) from '%s'\n",
236f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            inp_filename.c_str(),
237f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            out_filename.empty() ? out_filename.c_str() : "<none>", ctx.rs_n,
238f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            fec_filename.c_str());
23929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
24029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
24129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (ctx.verbose) {
24229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("\traw fec size: %u\n", ctx.fec_size);
24329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("\tblocks: %" PRIu64 "\n", ctx.blocks);
24429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("\trounds: %" PRIu64 "\n", ctx.rounds);
24529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
24629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
24729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (!image_process(decode_rs, &ctx)) {
24829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("failed to process input\n");
24929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
25029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
25129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    if (ctx.rv) {
25229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("corrected %" PRIu64 " errors\n", ctx.rv);
25329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    } else {
25429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        INFO("no errors found\n");
25529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
25629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
257f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    if (!out_filename.empty() && !image_save(out_filename, &ctx)) {
25829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        FATAL("failed to write output\n");
25929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
26029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
26129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    image_free(&ctx);
26229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    return 0;
26329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
26429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
26529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenint main(int argc, char **argv)
26629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{
267f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    std::string fec_filename;
268f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    std::string out_filename;
269f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    std::vector<std::string> inp_filenames;
27029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    int mode = MODE_ENCODE;
27129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    image ctx;
27229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
27329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    image_init(&ctx);
27429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    ctx.roots = FEC_DEFAULT_ROOTS;
27529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
27629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    while (1) {
27729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        const static struct option long_options[] = {
27829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"help", no_argument, 0, 'h'},
27929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"encode", no_argument, 0, 'e'},
28029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"decode", no_argument, 0, 'd'},
28129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"sparse", no_argument, 0, 'S'},
28229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"roots", required_argument, 0, 'r'},
28329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"inplace", no_argument, 0, 'i'},
28429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"mmap", no_argument, 0, 'm'},
28529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"threads", required_argument, 0, 'j'},
28629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"print-fec-size", required_argument, 0, 's'},
28729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"get-ecc-start", required_argument, 0, 'E'},
28829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"get-verity-start", required_argument, 0, 'V'},
28929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {"verbose", no_argument, 0, 'v'},
29029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            {NULL, 0, 0, 0}
29129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        };
29229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        int c = getopt_long(argc, argv, "hedSr:imj:s:E:V:v", long_options, NULL);
29329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        if (c < 0) {
29429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
29529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        }
29629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
29729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        switch (c) {
29829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'h':
29929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            return usage();
30029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'S':
30129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            ctx.sparse = true;
30229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
30329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'e':
30429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            if (mode != MODE_ENCODE) {
30529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen                return usage();
30629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            }
30729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
30829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'd':
30929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            if (mode != MODE_ENCODE) {
31029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen                return usage();
31129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            }
31229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            mode = MODE_DECODE;
31329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
31429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'r':
31529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            ctx.roots = (int)parse_arg(optarg, "roots", FEC_RSM);
31629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
31729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'i':
31829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            ctx.inplace = true;
31929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
32029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'm':
32129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            ctx.mmap = true;
32229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
32329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'j':
32429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            ctx.threads = (int)parse_arg(optarg, "threads", IMAGE_MAX_THREADS);
32529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
32629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 's':
32729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            if (mode != MODE_ENCODE) {
32829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen                return usage();
32929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            }
33029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            mode = MODE_PRINTSIZE;
33129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            ctx.inp_size = parse_arg(optarg, "print-fec-size", UINT64_MAX);
33229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
33329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'E':
33429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            if (mode != MODE_ENCODE) {
33529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen                return usage();
33629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            }
33729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            mode = MODE_GETECCSTART;
338f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            inp_filenames.push_back(optarg);
33929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
34029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'V':
34129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            if (mode != MODE_ENCODE) {
34229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen                return usage();
34329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            }
34429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            mode = MODE_GETVERITYSTART;
345f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            inp_filenames.push_back(optarg);
34629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
34729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case 'v':
34829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            ctx.verbose = true;
34929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            break;
35029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        case '?':
35129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            return usage();
35229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        default:
35329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            abort();
35429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        }
35529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
35629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
35729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    argc -= optind;
35829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    argv += optind;
35929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
36029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    assert(ctx.roots > 0 && ctx.roots < FEC_RSM);
36129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
36229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    /* check for input / output parameters */
363f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    if (mode == MODE_ENCODE) {
364f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        /* allow multiple input files */
365f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        for (int i = 0; i < (argc - 1); ++i) {
366f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            inp_filenames.push_back(argv[i]);
367f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        }
368f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen
369f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        if (inp_filenames.empty()) {
370f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            return usage();
371f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        }
372f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen
373f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        /* the last one is the output file */
374f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        fec_filename = argv[argc - 1];
375f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen    } else if (mode == MODE_DECODE) {
37629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        if (argc < 2 || argc > 3) {
37729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            return usage();
37829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        } else if (argc == 3) {
379f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen            if (ctx.inplace) {
38029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen                return usage();
38129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            }
38229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen            out_filename = argv[2];
38329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        }
38429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
385f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        inp_filenames.push_back(argv[0]);
38629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        fec_filename = argv[1];
38729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
38829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
38929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    switch (mode) {
39029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    case MODE_PRINTSIZE:
39129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        return print_size(ctx);
39229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    case MODE_GETECCSTART:
39329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    case MODE_GETVERITYSTART:
394f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        return get_start(mode, inp_filenames.front());
39529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    case MODE_ENCODE:
396f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        return encode(ctx, inp_filenames, fec_filename);
39729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    case MODE_DECODE:
398f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen        return decode(ctx, inp_filenames, fec_filename, out_filename);
39929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    default:
40029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen        abort();
40129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    }
40229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen
40329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen    return 1;
40429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen}
405