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