coreboot-kgpe-d16/util/cbfstool/cbfscomptool.c

191 lines
4.4 KiB
C

/* cbfs-compression-tool, CLI utility for dealing with CBFS compressed data */
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include "common.h"
const char *usage_text = "cbfs-compression-tool benchmark\n"
" runs benchmarks for all implemented algorithms\n"
"cbfs-compression-tool compress inFile outFile algo\n"
" compresses inFile with algo and stores in outFile\n"
"\n"
"'compress' file format:\n"
" 4 bytes little endian: algorithm ID (as used in CBFS)\n"
" 4 bytes little endian: uncompressed size\n"
" ...: compressed data stream\n";
static void usage(void)
{
puts(usage_text);
}
static int benchmark(void)
{
const int bufsize = 10*1024*1024;
char *data = malloc(bufsize);
if (!data) {
fprintf(stderr, "out of memory\n");
return 1;
}
char *compressed_data = malloc(bufsize);
if (!compressed_data) {
free(data);
fprintf(stderr, "out of memory\n");
return 1;
}
int i, l = strlen(usage_text) + 1;
for (i = 0; i + l < bufsize; i += l) {
memcpy(data + i, usage_text, l);
}
memset(data + i, 0, bufsize - i);
const struct typedesc_t *algo;
for (algo = &types_cbfs_compression[0]; algo->name != NULL; algo++) {
int outsize = bufsize;
printf("measuring '%s'\n", algo->name);
comp_func_ptr comp = compression_function(algo->type);
if (comp == NULL) {
printf("no handler associated with algorithm\n");
free(data);
free(compressed_data);
return 1;
}
struct timespec t_s, t_e;
clock_gettime(CLOCK_MONOTONIC, &t_s);
if (comp(data, bufsize, compressed_data, &outsize)) {
printf("compression failed");
return 1;
}
clock_gettime(CLOCK_MONOTONIC, &t_e);
printf("compressing %d bytes to %d took %ld seconds\n",
bufsize, outsize,
(long)(t_e.tv_sec - t_s.tv_sec));
}
free(data);
free(compressed_data);
return 0;
}
static int compress(char *infile, char *outfile, char *algoname,
int write_header)
{
int err = 1;
FILE *fin = NULL;
FILE *fout = NULL;
void *indata = NULL;
const struct typedesc_t *algo = &types_cbfs_compression[0];
while (algo->name != NULL) {
if (strcasecmp(algo->name, algoname) == 0) break;
algo++;
}
if (algo->name == NULL) {
fprintf(stderr, "algo '%s' is not supported.\n", algoname);
return 1;
}
comp_func_ptr comp = compression_function(algo->type);
if (comp == NULL) {
printf("no handler associated with algorithm\n");
return 1;
}
fin = fopen(infile, "rb");
if (!fin) {
fprintf(stderr, "could not open '%s'\n", infile);
return 1;
}
fout = fopen(outfile, "wb");
if (!fout) {
fprintf(stderr, "could not open '%s' for writing\n", outfile);
goto out;
}
if (fseek(fin, 0, SEEK_END) != 0) {
fprintf(stderr, "could not seek in input\n");
goto out;
}
long insize = ftell(fin);
if (insize < 0) {
fprintf(stderr, "could not determine input size\n");
goto out;
}
rewind(fin);
indata = malloc(insize);
if (!indata) {
fprintf(stderr, "out of memory\n");
goto out;
}
void *outdata = malloc(insize);
if (!outdata) {
fprintf(stderr, "out of memory\n");
goto out;
}
int outsize;
int remsize = insize;
while (remsize > 0) {
int readsz = fread(indata, 1, remsize, fin);
if (readsz < 0) {
fprintf(stderr, "failed to read input with %d bytes left\n", remsize);
goto out;
}
remsize -= readsz;
}
if (comp(indata, insize, outdata, &outsize) == -1) {
outsize = insize;
free(outdata);
outdata = indata;
algo = &types_cbfs_compression[0];
}
if (write_header) {
char header[8];
header[0] = algo->type & 0xff;
header[1] = (algo->type >> 8) & 0xff;
header[2] = (algo->type >> 16) & 0xff;
header[3] = (algo->type >> 24) & 0xff;
header[4] = insize & 0xff;
header[5] = (insize >> 8) & 0xff;
header[6] = (insize >> 16) & 0xff;
header[7] = (insize >> 24) & 0xff;
if (fwrite(header, 8, 1, fout) != 1) {
fprintf(stderr, "failed writing header\n");
goto out;
}
}
if (fwrite(outdata, outsize, 1, fout) != 1) {
fprintf(stderr, "failed writing compressed data\n");
goto out;
}
err = 0;
out:
if (fin) fclose(fin);
if (fout) fclose(fout);
if (indata) free(indata);
return err;
}
int main(int argc, char **argv)
{
if ((argc == 2) && (strcmp(argv[1], "benchmark") == 0))
return benchmark();
if ((argc == 5) && (strcmp(argv[1], "compress") == 0))
return compress(argv[2], argv[3], argv[4], 1);
if ((argc == 5) && (strcmp(argv[1], "rawcompress") == 0))
return compress(argv[2], argv[3], argv[4], 0);
usage();
return 1;
}