xref: /aosp_15_r20/external/coreboot/util/cbfstool/cbfscomptool.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* cbfs-compression-tool, CLI utility for dealing with CBFS compressed data */
2 /* SPDX-License-Identifier: GPL-2.0-only */
3 
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <strings.h>
8 #include <time.h>
9 
10 #include "cbfs.h"
11 #include "common.h"
12 
13 const 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 
usage(void)23 static void usage(void)
24 {
25 	puts(usage_text);
26 }
27 
benchmark(void)28 static int benchmark(void)
29 {
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) {
38 		free(data);
39 		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");
54 			free(data);
55 			free(compressed_data);
56 			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,
70 			(long)(t_e.tv_sec - t_s.tv_sec));
71 	}
72 	free(data);
73 	free(compressed_data);
74 	return 0;
75 }
76 
compress(char * infile,char * outfile,char * algoname,int write_header)77 static int compress(char *infile, char *outfile, char *algoname,
78 		    int write_header)
79 {
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) {
87 		if (strcasecmp(algo->name, algoname) == 0) break;
88 		algo++;
89 	}
90 	if (algo->name == NULL) {
91 		fprintf(stderr, "algo '%s' is not supported.\n", algoname);
92 		return 1;
93 	}
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 
146 	if (comp(indata, insize, outdata, &outsize) == -1) {
147 		outsize = insize;
148 		free(outdata);
149 		outdata = indata;
150 		algo = &types_cbfs_compression[0];
151 	}
152 
153 	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 		}
167 	}
168 	if (fwrite(outdata, outsize, 1, fout) != 1) {
169 		fprintf(stderr, "failed writing compressed data\n");
170 		goto out;
171 	}
172 
173 	err = 0;
174 out:
175 	if (fin) fclose(fin);
176 	if (fout) fclose(fout);
177 	if (indata) free(indata);
178 	return err;
179 }
180 
main(int argc,char ** argv)181 int 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))
186 		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);
189 	usage();
190 	return 1;
191 }
192