blob: 028893c35f5e01ef282a3c332a537ce39baf8021 [file] [log] [blame]
Patrick Georgic88d16b2017-01-11 15:26:58 +01001/*
2 * cbfs-compression-tool, CLI utility for dealing with CBFS compressed data
3 *
4 * Copyright (C) 2017 Google, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
Felix Helde8305132018-07-25 13:00:04 +020019#include <strings.h>
Patrick Georgic88d16b2017-01-11 15:26:58 +010020#include <time.h>
21
22#include "common.h"
23
Patrick Georgic88d16b2017-01-11 15:26:58 +010024const char *usage_text = "cbfs-compression-tool benchmark\n"
25 " runs benchmarks for all implemented algorithms\n"
26 "cbfs-compression-tool compress inFile outFile algo\n"
27 " compresses inFile with algo and stores in outFile\n"
28 "\n"
29 "'compress' file format:\n"
30 " 4 bytes little endian: algorithm ID (as used in CBFS)\n"
31 " 4 bytes little endian: uncompressed size\n"
32 " ...: compressed data stream\n";
33
Julius Werner88f4e082018-05-15 17:30:20 -070034static void usage(void)
Patrick Georgic88d16b2017-01-11 15:26:58 +010035{
36 puts(usage_text);
37}
38
Julius Werner88f4e082018-05-15 17:30:20 -070039static int benchmark(void)
Patrick Georgic88d16b2017-01-11 15:26:58 +010040{
41 const int bufsize = 10*1024*1024;
42 char *data = malloc(bufsize);
43 if (!data) {
44 fprintf(stderr, "out of memory\n");
45 return 1;
46 }
47 char *compressed_data = malloc(bufsize);
48 if (!compressed_data) {
Patrick Georgidce629b2017-01-13 13:30:54 +010049 free(data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010050 fprintf(stderr, "out of memory\n");
51 return 1;
52 }
53 int i, l = strlen(usage_text) + 1;
54 for (i = 0; i + l < bufsize; i += l) {
55 memcpy(data + i, usage_text, l);
56 }
57 memset(data + i, 0, bufsize - i);
58 const struct typedesc_t *algo;
59 for (algo = &types_cbfs_compression[0]; algo->name != NULL; algo++) {
60 int outsize = bufsize;
61 printf("measuring '%s'\n", algo->name);
62 comp_func_ptr comp = compression_function(algo->type);
63 if (comp == NULL) {
64 printf("no handler associated with algorithm\n");
Patrick Georgidce629b2017-01-13 13:30:54 +010065 free(data);
66 free(compressed_data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010067 return 1;
68 }
69
70 struct timespec t_s, t_e;
71 clock_gettime(CLOCK_MONOTONIC, &t_s);
72
73 if (comp(data, bufsize, compressed_data, &outsize)) {
74 printf("compression failed");
75 return 1;
76 }
77
78 clock_gettime(CLOCK_MONOTONIC, &t_e);
79 printf("compressing %d bytes to %d took %ld seconds\n",
80 bufsize, outsize,
Mike Frysingera8ca0322017-05-24 22:28:57 -040081 (long)(t_e.tv_sec - t_s.tv_sec));
Patrick Georgic88d16b2017-01-11 15:26:58 +010082 }
Patrick Georgidce629b2017-01-13 13:30:54 +010083 free(data);
84 free(compressed_data);
Patrick Georgic88d16b2017-01-11 15:26:58 +010085 return 0;
86}
87
Julius Werner88f4e082018-05-15 17:30:20 -070088static int compress(char *infile, char *outfile, char *algoname,
89 int write_header)
Patrick Georgic88d16b2017-01-11 15:26:58 +010090{
91 int err = 1;
92 FILE *fin = NULL;
93 FILE *fout = NULL;
94 void *indata = NULL;
95
96 const struct typedesc_t *algo = &types_cbfs_compression[0];
97 while (algo->name != NULL) {
Julius Werneree878852018-05-18 17:56:23 -070098 if (strcasecmp(algo->name, algoname) == 0) break;
Patrick Georgic88d16b2017-01-11 15:26:58 +010099 algo++;
100 }
101 if (algo->name == NULL) {
102 fprintf(stderr, "algo '%s' is not supported.\n", algoname);
Julius Werneree878852018-05-18 17:56:23 -0700103 return 1;
Patrick Georgic88d16b2017-01-11 15:26:58 +0100104 }
105
106 comp_func_ptr comp = compression_function(algo->type);
107 if (comp == NULL) {
108 printf("no handler associated with algorithm\n");
109 return 1;
110 }
111
112 fin = fopen(infile, "rb");
113 if (!fin) {
114 fprintf(stderr, "could not open '%s'\n", infile);
115 return 1;
116 }
117 fout = fopen(outfile, "wb");
118 if (!fout) {
119 fprintf(stderr, "could not open '%s' for writing\n", outfile);
120 goto out;
121 }
122
123 if (fseek(fin, 0, SEEK_END) != 0) {
124 fprintf(stderr, "could not seek in input\n");
125 goto out;
126 }
127 long insize = ftell(fin);
128 if (insize < 0) {
129 fprintf(stderr, "could not determine input size\n");
130 goto out;
131 }
132 rewind(fin);
133
134 indata = malloc(insize);
135 if (!indata) {
136 fprintf(stderr, "out of memory\n");
137 goto out;
138 }
139
140 void *outdata = malloc(insize);
141 if (!outdata) {
142 fprintf(stderr, "out of memory\n");
143 goto out;
144 }
145 int outsize;
146
147 int remsize = insize;
148 while (remsize > 0) {
149 int readsz = fread(indata, 1, remsize, fin);
150 if (readsz < 0) {
151 fprintf(stderr, "failed to read input with %d bytes left\n", remsize);
152 goto out;
153 }
154 remsize -= readsz;
155 }
156
Patrick Georgib46c4ec2017-01-23 09:35:44 +0100157 if (comp(indata, insize, outdata, &outsize) == -1) {
158 outsize = insize;
159 free(outdata);
160 outdata = indata;
161 algo = &types_cbfs_compression[0];
162 }
Patrick Georgic88d16b2017-01-11 15:26:58 +0100163
Julius Werner88f4e082018-05-15 17:30:20 -0700164 if (write_header) {
165 char header[8];
166 header[0] = algo->type & 0xff;
167 header[1] = (algo->type >> 8) & 0xff;
168 header[2] = (algo->type >> 16) & 0xff;
169 header[3] = (algo->type >> 24) & 0xff;
170 header[4] = insize & 0xff;
171 header[5] = (insize >> 8) & 0xff;
172 header[6] = (insize >> 16) & 0xff;
173 header[7] = (insize >> 24) & 0xff;
174 if (fwrite(header, 8, 1, fout) != 1) {
175 fprintf(stderr, "failed writing header\n");
176 goto out;
177 }
Patrick Georgic88d16b2017-01-11 15:26:58 +0100178 }
179 if (fwrite(outdata, outsize, 1, fout) != 1) {
180 fprintf(stderr, "failed writing compressed data\n");
181 goto out;
182 }
183
184 err = 0;
185out:
186 if (fin) fclose(fin);
187 if (fout) fclose(fout);
188 if (indata) free(indata);
189 return err;
190}
191
192int main(int argc, char **argv)
193{
194 if ((argc == 2) && (strcmp(argv[1], "benchmark") == 0))
195 return benchmark();
196 if ((argc == 5) && (strcmp(argv[1], "compress") == 0))
Julius Werner88f4e082018-05-15 17:30:20 -0700197 return compress(argv[2], argv[3], argv[4], 1);
198 if ((argc == 5) && (strcmp(argv[1], "rawcompress") == 0))
199 return compress(argv[2], argv[3], argv[4], 0);
Patrick Georgic88d16b2017-01-11 15:26:58 +0100200 usage();
201 return 1;
202}