blob: 9e804860a9afc8c88d1e61689397a329fa79e378 [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>
19#include <time.h>
20
21#include "common.h"
22
23void usage(void);
24int benchmark(void);
25int compress(char *infile, char *outfile, char *algoname);
26
27const char *usage_text = "cbfs-compression-tool benchmark\n"
28 " runs benchmarks for all implemented algorithms\n"
29 "cbfs-compression-tool compress inFile outFile algo\n"
30 " compresses inFile with algo and stores in outFile\n"
31 "\n"
32 "'compress' file format:\n"
33 " 4 bytes little endian: algorithm ID (as used in CBFS)\n"
34 " 4 bytes little endian: uncompressed size\n"
35 " ...: compressed data stream\n";
36
37void usage()
38{
39 puts(usage_text);
40}
41
42int benchmark()
43{
44 const int bufsize = 10*1024*1024;
45 char *data = malloc(bufsize);
46 if (!data) {
47 fprintf(stderr, "out of memory\n");
48 return 1;
49 }
50 char *compressed_data = malloc(bufsize);
51 if (!compressed_data) {
52 fprintf(stderr, "out of memory\n");
53 return 1;
54 }
55 int i, l = strlen(usage_text) + 1;
56 for (i = 0; i + l < bufsize; i += l) {
57 memcpy(data + i, usage_text, l);
58 }
59 memset(data + i, 0, bufsize - i);
60 const struct typedesc_t *algo;
61 for (algo = &types_cbfs_compression[0]; algo->name != NULL; algo++) {
62 int outsize = bufsize;
63 printf("measuring '%s'\n", algo->name);
64 comp_func_ptr comp = compression_function(algo->type);
65 if (comp == NULL) {
66 printf("no handler associated with algorithm\n");
67 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,
81 t_e.tv_sec - t_s.tv_sec);
82 }
83 return 0;
84}
85
86int compress(char *infile, char *outfile, char *algoname)
87{
88 int err = 1;
89 FILE *fin = NULL;
90 FILE *fout = NULL;
91 void *indata = NULL;
92
93 const struct typedesc_t *algo = &types_cbfs_compression[0];
94 while (algo->name != NULL) {
95 if (strcmp(algo->name, algoname) == 0) break;
96 algo++;
97 }
98 if (algo->name == NULL) {
99 fprintf(stderr, "algo '%s' is not supported.\n", algoname);
100 }
101
102 comp_func_ptr comp = compression_function(algo->type);
103 if (comp == NULL) {
104 printf("no handler associated with algorithm\n");
105 return 1;
106 }
107
108 fin = fopen(infile, "rb");
109 if (!fin) {
110 fprintf(stderr, "could not open '%s'\n", infile);
111 return 1;
112 }
113 fout = fopen(outfile, "wb");
114 if (!fout) {
115 fprintf(stderr, "could not open '%s' for writing\n", outfile);
116 goto out;
117 }
118
119 if (fseek(fin, 0, SEEK_END) != 0) {
120 fprintf(stderr, "could not seek in input\n");
121 goto out;
122 }
123 long insize = ftell(fin);
124 if (insize < 0) {
125 fprintf(stderr, "could not determine input size\n");
126 goto out;
127 }
128 rewind(fin);
129
130 indata = malloc(insize);
131 if (!indata) {
132 fprintf(stderr, "out of memory\n");
133 goto out;
134 }
135
136 void *outdata = malloc(insize);
137 if (!outdata) {
138 fprintf(stderr, "out of memory\n");
139 goto out;
140 }
141 int outsize;
142
143 int remsize = insize;
144 while (remsize > 0) {
145 int readsz = fread(indata, 1, remsize, fin);
146 if (readsz < 0) {
147 fprintf(stderr, "failed to read input with %d bytes left\n", remsize);
148 goto out;
149 }
150 remsize -= readsz;
151 }
152
Patrick Georgib46c4ec2017-01-23 09:35:44 +0100153 if (comp(indata, insize, outdata, &outsize) == -1) {
154 outsize = insize;
155 free(outdata);
156 outdata = indata;
157 algo = &types_cbfs_compression[0];
158 }
Patrick Georgic88d16b2017-01-11 15:26:58 +0100159
160 char header[8];
161 header[0] = algo->type & 0xff;
162 header[1] = (algo->type >> 8) & 0xff;
163 header[2] = (algo->type >> 16) & 0xff;
164 header[3] = (algo->type >> 24) & 0xff;
165 header[4] = insize & 0xff;
166 header[5] = (insize >> 8) & 0xff;
167 header[6] = (insize >> 16) & 0xff;
168 header[7] = (insize >> 24) & 0xff;
169 if (fwrite(header, 8, 1, fout) != 1) {
170 fprintf(stderr, "failed writing header\n");
171 goto out;
172 }
173 if (fwrite(outdata, outsize, 1, fout) != 1) {
174 fprintf(stderr, "failed writing compressed data\n");
175 goto out;
176 }
177
178 err = 0;
179out:
180 if (fin) fclose(fin);
181 if (fout) fclose(fout);
182 if (indata) free(indata);
183 return err;
184}
185
186int main(int argc, char **argv)
187{
188 if ((argc == 2) && (strcmp(argv[1], "benchmark") == 0))
189 return benchmark();
190 if ((argc == 5) && (strcmp(argv[1], "compress") == 0))
191 return compress(argv[2], argv[3], argv[4]);
192 usage();
193 return 1;
194}