blob: 5745093165fd6366c547073d9dfdb941ceda523b [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
Julius Wernerd4775652020-03-13 16:43:34 -070010#include "cbfs.h"
Patrick Georgic88d16b2017-01-11 15:26:58 +010011#include "common.h"
12
Patrick Georgic88d16b2017-01-11 15:26:58 +010013const char *usage_text = "cbfs-compression-tool benchmark\n"
14 " runs benchmarks for all implemented algorithms\n"
15 "cbfs-compression-tool compress inFile outFile algo\n"
16 " compresses inFile with algo and stores in outFile\n"
17 "\n"
18 "'compress' file format:\n"
19 " 4 bytes little endian: algorithm ID (as used in CBFS)\n"
20 " 4 bytes little endian: uncompressed size\n"
21 " ...: compressed data stream\n";
22
Julius Werner88f4e082018-05-15 17:30:20 -070023static void usage(void)
Patrick Georgic88d16b2017-01-11 15:26:58 +010024{
25 puts(usage_text);
26}
27
Julius Werner88f4e082018-05-15 17:30:20 -070028static int benchmark(void)
Patrick Georgic88d16b2017-01-11 15:26:58 +010029{
30 const int bufsize = 10*1024*1024;
31 char *data = malloc(bufsize);
32 if (!data) {
33 fprintf(stderr, "out of memory\n");
34 return 1;
35 }
36 char *compressed_data = malloc(bufsize);
37 if (!compressed_data) {
Patrick Georgidce629b2017-01-13 13:30:54 +010038 free(data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010039 fprintf(stderr, "out of memory\n");
40 return 1;
41 }
42 int i, l = strlen(usage_text) + 1;
43 for (i = 0; i + l < bufsize; i += l) {
44 memcpy(data + i, usage_text, l);
45 }
46 memset(data + i, 0, bufsize - i);
47 const struct typedesc_t *algo;
48 for (algo = &types_cbfs_compression[0]; algo->name != NULL; algo++) {
49 int outsize = bufsize;
50 printf("measuring '%s'\n", algo->name);
51 comp_func_ptr comp = compression_function(algo->type);
52 if (comp == NULL) {
53 printf("no handler associated with algorithm\n");
Patrick Georgidce629b2017-01-13 13:30:54 +010054 free(data);
55 free(compressed_data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010056 return 1;
57 }
58
59 struct timespec t_s, t_e;
60 clock_gettime(CLOCK_MONOTONIC, &t_s);
61
62 if (comp(data, bufsize, compressed_data, &outsize)) {
63 printf("compression failed");
64 return 1;
65 }
66
67 clock_gettime(CLOCK_MONOTONIC, &t_e);
68 printf("compressing %d bytes to %d took %ld seconds\n",
69 bufsize, outsize,
Mike Frysingera8ca0322017-05-24 22:28:57 -040070 (long)(t_e.tv_sec - t_s.tv_sec));
Patrick Georgic88d16b2017-01-11 15:26:58 +010071 }
Patrick Georgidce629b2017-01-13 13:30:54 +010072 free(data);
73 free(compressed_data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010074 return 0;
75}
76
Julius Werner88f4e082018-05-15 17:30:20 -070077static int compress(char *infile, char *outfile, char *algoname,
78 int write_header)
Patrick Georgic88d16b2017-01-11 15:26:58 +010079{
80 int err = 1;
81 FILE *fin = NULL;
82 FILE *fout = NULL;
83 void *indata = NULL;
84
85 const struct typedesc_t *algo = &types_cbfs_compression[0];
86 while (algo->name != NULL) {
Julius Werneree878852018-05-18 17:56:23 -070087 if (strcasecmp(algo->name, algoname) == 0) break;
Patrick Georgic88d16b2017-01-11 15:26:58 +010088 algo++;
89 }
90 if (algo->name == NULL) {
91 fprintf(stderr, "algo '%s' is not supported.\n", algoname);
Julius Werneree878852018-05-18 17:56:23 -070092 return 1;
Patrick Georgic88d16b2017-01-11 15:26:58 +010093 }
94
95 comp_func_ptr comp = compression_function(algo->type);
96 if (comp == NULL) {
97 printf("no handler associated with algorithm\n");
98 return 1;
99 }
100
101 fin = fopen(infile, "rb");
102 if (!fin) {
103 fprintf(stderr, "could not open '%s'\n", infile);
104 return 1;
105 }
106 fout = fopen(outfile, "wb");
107 if (!fout) {
108 fprintf(stderr, "could not open '%s' for writing\n", outfile);
109 goto out;
110 }
111
112 if (fseek(fin, 0, SEEK_END) != 0) {
113 fprintf(stderr, "could not seek in input\n");
114 goto out;
115 }
116 long insize = ftell(fin);
117 if (insize < 0) {
118 fprintf(stderr, "could not determine input size\n");
119 goto out;
120 }
121 rewind(fin);
122
123 indata = malloc(insize);
124 if (!indata) {
125 fprintf(stderr, "out of memory\n");
126 goto out;
127 }
128
129 void *outdata = malloc(insize);
130 if (!outdata) {
131 fprintf(stderr, "out of memory\n");
132 goto out;
133 }
134 int outsize;
135
136 int remsize = insize;
137 while (remsize > 0) {
138 int readsz = fread(indata, 1, remsize, fin);
139 if (readsz < 0) {
140 fprintf(stderr, "failed to read input with %d bytes left\n", remsize);
141 goto out;
142 }
143 remsize -= readsz;
144 }
145
Patrick Georgib46c4ec2017-01-23 09:35:44 +0100146 if (comp(indata, insize, outdata, &outsize) == -1) {
147 outsize = insize;
148 free(outdata);
149 outdata = indata;
150 algo = &types_cbfs_compression[0];
151 }
Patrick Georgic88d16b2017-01-11 15:26:58 +0100152
Julius Werner88f4e082018-05-15 17:30:20 -0700153 if (write_header) {
154 char header[8];
155 header[0] = algo->type & 0xff;
156 header[1] = (algo->type >> 8) & 0xff;
157 header[2] = (algo->type >> 16) & 0xff;
158 header[3] = (algo->type >> 24) & 0xff;
159 header[4] = insize & 0xff;
160 header[5] = (insize >> 8) & 0xff;
161 header[6] = (insize >> 16) & 0xff;
162 header[7] = (insize >> 24) & 0xff;
163 if (fwrite(header, 8, 1, fout) != 1) {
164 fprintf(stderr, "failed writing header\n");
165 goto out;
166 }
Patrick Georgic88d16b2017-01-11 15:26:58 +0100167 }
168 if (fwrite(outdata, outsize, 1, fout) != 1) {
169 fprintf(stderr, "failed writing compressed data\n");
170 goto out;
171 }
172
173 err = 0;
174out:
175 if (fin) fclose(fin);
176 if (fout) fclose(fout);
177 if (indata) free(indata);
178 return err;
179}
180
181int main(int argc, char **argv)
182{
183 if ((argc == 2) && (strcmp(argv[1], "benchmark") == 0))
184 return benchmark();
185 if ((argc == 5) && (strcmp(argv[1], "compress") == 0))
Julius Werner88f4e082018-05-15 17:30:20 -0700186 return compress(argv[2], argv[3], argv[4], 1);
187 if ((argc == 5) && (strcmp(argv[1], "rawcompress") == 0))
188 return compress(argv[2], argv[3], argv[4], 0);
Patrick Georgic88d16b2017-01-11 15:26:58 +0100189 usage();
190 return 1;
191}