blob: 3ea87ad4491bc962b6c8655a41eb6808c43ffd54 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* cbfs-compression-tool, CLI utility for dealing with CBFS compressed data */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Patrick Georgic88d16b2017-01-11 15:26:58 +01003
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
Felix Helde8305132018-07-25 13:00:04 +02007#include <strings.h>
Patrick Georgic88d16b2017-01-11 15:26:58 +01008#include <time.h>
9
10#include "common.h"
11
Patrick Georgic88d16b2017-01-11 15:26:58 +010012const char *usage_text = "cbfs-compression-tool benchmark\n"
13 " runs benchmarks for all implemented algorithms\n"
14 "cbfs-compression-tool compress inFile outFile algo\n"
15 " compresses inFile with algo and stores in outFile\n"
16 "\n"
17 "'compress' file format:\n"
18 " 4 bytes little endian: algorithm ID (as used in CBFS)\n"
19 " 4 bytes little endian: uncompressed size\n"
20 " ...: compressed data stream\n";
21
Julius Werner88f4e082018-05-15 17:30:20 -070022static void usage(void)
Patrick Georgic88d16b2017-01-11 15:26:58 +010023{
24 puts(usage_text);
25}
26
Julius Werner88f4e082018-05-15 17:30:20 -070027static int benchmark(void)
Patrick Georgic88d16b2017-01-11 15:26:58 +010028{
29 const int bufsize = 10*1024*1024;
30 char *data = malloc(bufsize);
31 if (!data) {
32 fprintf(stderr, "out of memory\n");
33 return 1;
34 }
35 char *compressed_data = malloc(bufsize);
36 if (!compressed_data) {
Patrick Georgidce629b2017-01-13 13:30:54 +010037 free(data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010038 fprintf(stderr, "out of memory\n");
39 return 1;
40 }
41 int i, l = strlen(usage_text) + 1;
42 for (i = 0; i + l < bufsize; i += l) {
43 memcpy(data + i, usage_text, l);
44 }
45 memset(data + i, 0, bufsize - i);
46 const struct typedesc_t *algo;
47 for (algo = &types_cbfs_compression[0]; algo->name != NULL; algo++) {
48 int outsize = bufsize;
49 printf("measuring '%s'\n", algo->name);
50 comp_func_ptr comp = compression_function(algo->type);
51 if (comp == NULL) {
52 printf("no handler associated with algorithm\n");
Patrick Georgidce629b2017-01-13 13:30:54 +010053 free(data);
54 free(compressed_data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010055 return 1;
56 }
57
58 struct timespec t_s, t_e;
59 clock_gettime(CLOCK_MONOTONIC, &t_s);
60
61 if (comp(data, bufsize, compressed_data, &outsize)) {
62 printf("compression failed");
63 return 1;
64 }
65
66 clock_gettime(CLOCK_MONOTONIC, &t_e);
67 printf("compressing %d bytes to %d took %ld seconds\n",
68 bufsize, outsize,
Mike Frysingera8ca0322017-05-24 22:28:57 -040069 (long)(t_e.tv_sec - t_s.tv_sec));
Patrick Georgic88d16b2017-01-11 15:26:58 +010070 }
Patrick Georgidce629b2017-01-13 13:30:54 +010071 free(data);
72 free(compressed_data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010073 return 0;
74}
75
Julius Werner88f4e082018-05-15 17:30:20 -070076static int compress(char *infile, char *outfile, char *algoname,
77 int write_header)
Patrick Georgic88d16b2017-01-11 15:26:58 +010078{
79 int err = 1;
80 FILE *fin = NULL;
81 FILE *fout = NULL;
82 void *indata = NULL;
83
84 const struct typedesc_t *algo = &types_cbfs_compression[0];
85 while (algo->name != NULL) {
Julius Werneree878852018-05-18 17:56:23 -070086 if (strcasecmp(algo->name, algoname) == 0) break;
Patrick Georgic88d16b2017-01-11 15:26:58 +010087 algo++;
88 }
89 if (algo->name == NULL) {
90 fprintf(stderr, "algo '%s' is not supported.\n", algoname);
Julius Werneree878852018-05-18 17:56:23 -070091 return 1;
Patrick Georgic88d16b2017-01-11 15:26:58 +010092 }
93
94 comp_func_ptr comp = compression_function(algo->type);
95 if (comp == NULL) {
96 printf("no handler associated with algorithm\n");
97 return 1;
98 }
99
100 fin = fopen(infile, "rb");
101 if (!fin) {
102 fprintf(stderr, "could not open '%s'\n", infile);
103 return 1;
104 }
105 fout = fopen(outfile, "wb");
106 if (!fout) {
107 fprintf(stderr, "could not open '%s' for writing\n", outfile);
108 goto out;
109 }
110
111 if (fseek(fin, 0, SEEK_END) != 0) {
112 fprintf(stderr, "could not seek in input\n");
113 goto out;
114 }
115 long insize = ftell(fin);
116 if (insize < 0) {
117 fprintf(stderr, "could not determine input size\n");
118 goto out;
119 }
120 rewind(fin);
121
122 indata = malloc(insize);
123 if (!indata) {
124 fprintf(stderr, "out of memory\n");
125 goto out;
126 }
127
128 void *outdata = malloc(insize);
129 if (!outdata) {
130 fprintf(stderr, "out of memory\n");
131 goto out;
132 }
133 int outsize;
134
135 int remsize = insize;
136 while (remsize > 0) {
137 int readsz = fread(indata, 1, remsize, fin);
138 if (readsz < 0) {
139 fprintf(stderr, "failed to read input with %d bytes left\n", remsize);
140 goto out;
141 }
142 remsize -= readsz;
143 }
144
Patrick Georgib46c4ec2017-01-23 09:35:44 +0100145 if (comp(indata, insize, outdata, &outsize) == -1) {
146 outsize = insize;
147 free(outdata);
148 outdata = indata;
149 algo = &types_cbfs_compression[0];
150 }
Patrick Georgic88d16b2017-01-11 15:26:58 +0100151
Julius Werner88f4e082018-05-15 17:30:20 -0700152 if (write_header) {
153 char header[8];
154 header[0] = algo->type & 0xff;
155 header[1] = (algo->type >> 8) & 0xff;
156 header[2] = (algo->type >> 16) & 0xff;
157 header[3] = (algo->type >> 24) & 0xff;
158 header[4] = insize & 0xff;
159 header[5] = (insize >> 8) & 0xff;
160 header[6] = (insize >> 16) & 0xff;
161 header[7] = (insize >> 24) & 0xff;
162 if (fwrite(header, 8, 1, fout) != 1) {
163 fprintf(stderr, "failed writing header\n");
164 goto out;
165 }
Patrick Georgic88d16b2017-01-11 15:26:58 +0100166 }
167 if (fwrite(outdata, outsize, 1, fout) != 1) {
168 fprintf(stderr, "failed writing compressed data\n");
169 goto out;
170 }
171
172 err = 0;
173out:
174 if (fin) fclose(fin);
175 if (fout) fclose(fout);
176 if (indata) free(indata);
177 return err;
178}
179
180int main(int argc, char **argv)
181{
182 if ((argc == 2) && (strcmp(argv[1], "benchmark") == 0))
183 return benchmark();
184 if ((argc == 5) && (strcmp(argv[1], "compress") == 0))
Julius Werner88f4e082018-05-15 17:30:20 -0700185 return compress(argv[2], argv[3], argv[4], 1);
186 if ((argc == 5) && (strcmp(argv[1], "rawcompress") == 0))
187 return compress(argv[2], argv[3], argv[4], 0);
Patrick Georgic88d16b2017-01-11 15:26:58 +0100188 usage();
189 return 1;
190}