]> git.zerfleddert.de Git - proxmark3-svn/blame - client/fpga_compress.c
add options show
[proxmark3-svn] / client / fpga_compress.c
CommitLineData
e6153040 1//-----------------------------------------------------------------------------
2// This code is licensed to you under the terms of the GNU GPL, version 2 or,
3// at your option, any later version. See the LICENSE.txt file for the text of
4// the license.
5//-----------------------------------------------------------------------------
8e074056 6// Compression tool for FPGA config files. Compress several *.bit files at
7// compile time. Decompression is done at run time (see fpgaloader.c).
8// This uses the zlib library tuned to this specific case. The small file sizes
9// allow to use "insane" parameters for optimum compression ratio.
e6153040 10//-----------------------------------------------------------------------------
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
f3919878 15#include <stdint.h>
fb228974 16#include <stdbool.h>
f3919878 17#include "zlib.h"
e6153040 18
19#define MAX(a,b) ((a)>(b)?(a):(b))
20
f3919878 21// zlib configuration
015520dc
JB
22#define COMPRESS_LEVEL 9 // use best possible compression
23#define COMPRESS_WINDOW_BITS 15 // default = max = 15 for a window of 2^15 = 32KBytes
24#define COMPRESS_MEM_LEVEL 9 // determines the amount of memory allocated during compression. Default = 8.
fb228974 25/* COMPRESS_STRATEGY can be
26 Z_DEFAULT_STRATEGY (the default),
27 Z_FILTERED (more huffmann, less string matching),
28 Z_HUFFMAN_ONLY (huffman only, no string matching)
29 Z_RLE (distances limited to one)
30 Z_FIXED (prevents the use of dynamic Huffman codes)
ad8a18e6
JB
31*/
32
015520dc 33#define COMPRESS_STRATEGY Z_DEFAULT_STRATEGY
fb228974 34// zlib tuning parameters:
015520dc
JB
35#define COMPRESS_GOOD_LENGTH 258
36#define COMPRESS_MAX_LAZY 258
37#define COMPRESS_MAX_NICE_LENGTH 258
38#define COMPRESS_MAX_CHAIN 8192
fb228974 39
015520dc 40#define FPGA_INTERLEAVE_SIZE 288 // (the FPGA's internal config frame size is 288 bits. Interleaving with 288 bytes should give best compression)
7f9e4c25 41#define FPGA_CONFIG_SIZE 42336L // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE
42#define HARDNESTED_TABLE_SIZE (sizeof(uint32_t) * ((1L<<19)+1))
e6153040 43
8e074056 44static void usage(void)
e6153040 45{
36b1cdd1
OM
46 fprintf(stdout, "Usage: fpga_compress <infile1> <infile2> ... <infile_n> <outfile>\n");
47 fprintf(stdout, " Combine n FPGA bitstream files and compress them into one.\n\n");
48 fprintf(stdout, " fpga_compress -d <infile> <outfile>");
49 fprintf(stdout, " Decompress <infile>. Write result to <outfile>");
50 fprintf(stdout, " fpga_compress -t <infile> <outfile>");
51 fprintf(stdout, " Compress hardnested table <infile>. Write result to <outfile>");
e6153040 52}
53
54
f3919878 55static voidpf fpga_deflate_malloc(voidpf opaque, uInt items, uInt size)
e6153040 56{
f3919878 57 return malloc(items*size);
e6153040 58}
e6153040 59
f3919878 60
61static void fpga_deflate_free(voidpf opaque, voidpf address)
e6153040 62{
f3919878 63 return free(address);
64}
e6153040 65
f3919878 66
fb228974 67static bool all_feof(FILE *infile[], uint8_t num_infiles)
68{
69 for (uint16_t i = 0; i < num_infiles; i++) {
70 if (!feof(infile[i])) {
71 return false;
72 }
73 }
74
75 return true;
76}
77
78
7f9e4c25 79int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile, bool hardnested_mode)
e6153040 80{
fb228974 81 uint8_t *fpga_config;
82 uint32_t i;
ad8a18e6
JB
83 int32_t ret;
84 uint8_t c;
f3919878 85 z_stream compressed_fpga_stream;
fb228974 86
7f9e4c25 87 if (hardnested_mode) {
88 fpga_config = malloc(num_infiles * HARDNESTED_TABLE_SIZE);
89 } else {
90 fpga_config = malloc(num_infiles * FPGA_CONFIG_SIZE);
91 }
8e074056 92 // read the input files. Interleave them into fpga_config[]
e6153040 93 i = 0;
fb228974 94 do {
7b242c1c 95
7f9e4c25 96 if (i >= num_infiles * (hardnested_mode?HARDNESTED_TABLE_SIZE:FPGA_CONFIG_SIZE)) {
97 if (hardnested_mode) {
98 fprintf(stderr, "Input file too big (> %lu bytes). This is probably not a hardnested bitflip state table.\n", HARDNESTED_TABLE_SIZE);
99 } else {
100 fprintf(stderr, "Input files too big (total > %lu bytes). These are probably not PM3 FPGA config files.\n", num_infiles*FPGA_CONFIG_SIZE);
101 }
7b242c1c 102 for(uint16_t j = 0; j < num_infiles; j++) {
103 fclose(infile[j]);
104 }
38d618ba 105 free(fpga_config);
7b242c1c 106 return(EXIT_FAILURE);
107 }
108
fb228974 109 for(uint16_t j = 0; j < num_infiles; j++) {
110 for(uint16_t k = 0; k < FPGA_INTERLEAVE_SIZE; k++) {
111 c = fgetc(infile[j]);
0fa01ec7 112 if (!feof(infile[j])) {
113 fpga_config[i++] = c;
114 } else if (num_infiles > 1) {
115 fpga_config[i++] = '\0';
116 }
fb228974 117 }
118 }
119
fb228974 120 } while (!all_feof(infile, num_infiles));
e6153040 121
f3919878 122 // initialize zlib structures
123 compressed_fpga_stream.next_in = fpga_config;
124 compressed_fpga_stream.avail_in = i;
125 compressed_fpga_stream.zalloc = fpga_deflate_malloc;
126 compressed_fpga_stream.zfree = fpga_deflate_free;
38d618ba 127 compressed_fpga_stream.opaque = Z_NULL;
fb228974 128 ret = deflateInit2(&compressed_fpga_stream,
129 COMPRESS_LEVEL,
130 Z_DEFLATED,
131 COMPRESS_WINDOW_BITS,
132 COMPRESS_MEM_LEVEL,
133 COMPRESS_STRATEGY);
134
f3919878 135 // estimate the size of the compressed output
ad8a18e6 136 uint32_t outsize_max = deflateBound(&compressed_fpga_stream, compressed_fpga_stream.avail_in);
f3919878 137 uint8_t *outbuf = malloc(outsize_max);
138 compressed_fpga_stream.next_out = outbuf;
139 compressed_fpga_stream.avail_out = outsize_max;
ad8a18e6 140
fb228974 141 if (ret == Z_OK) {
142 ret = deflateTune(&compressed_fpga_stream,
143 COMPRESS_GOOD_LENGTH,
144 COMPRESS_MAX_LAZY,
145 COMPRESS_MAX_NICE_LENGTH,
146 COMPRESS_MAX_CHAIN);
147 }
148
f3919878 149 if (ret == Z_OK) {
150 ret = deflate(&compressed_fpga_stream, Z_FINISH);
e6153040 151 }
e6153040 152
36b1cdd1 153 fprintf(stdout, "compressed %u input bytes to %lu output bytes\n", i, compressed_fpga_stream.total_out);
f3919878 154
155 if (ret != Z_STREAM_END) {
ad8a18e6 156 fprintf(stderr, "Error in deflate(): %i %s\n", ret, compressed_fpga_stream.msg);
f3919878 157 free(outbuf);
158 deflateEnd(&compressed_fpga_stream);
fb228974 159 for(uint16_t j = 0; j < num_infiles; j++) {
160 fclose(infile[j]);
161 }
f3919878 162 fclose(outfile);
fb228974 163 free(infile);
164 free(fpga_config);
7b242c1c 165 return(EXIT_FAILURE);
f3919878 166 }
e6153040 167
f3919878 168 for (i = 0; i < compressed_fpga_stream.total_out; i++) {
169 fputc(outbuf[i], outfile);
170 }
171
172 free(outbuf);
173 deflateEnd(&compressed_fpga_stream);
fb228974 174 for(uint16_t j = 0; j < num_infiles; j++) {
175 fclose(infile[j]);
176 }
e6153040 177 fclose(outfile);
fb228974 178 free(infile);
179 free(fpga_config);
180
7b242c1c 181 return(EXIT_SUCCESS);
f3919878 182
e6153040 183}
184
185
4b3f6d79 186int zlib_decompress(FILE *infile, FILE *outfile)
187{
188 #define DECOMPRESS_BUF_SIZE 1024
189 uint8_t outbuf[DECOMPRESS_BUF_SIZE];
190 uint8_t inbuf[DECOMPRESS_BUF_SIZE];
ad8a18e6 191 int32_t ret;
4b3f6d79 192
193 z_stream compressed_fpga_stream;
8e074056 194
4b3f6d79 195 // initialize zlib structures
196 compressed_fpga_stream.next_in = inbuf;
197 compressed_fpga_stream.avail_in = 0;
198 compressed_fpga_stream.next_out = outbuf;
199 compressed_fpga_stream.avail_out = DECOMPRESS_BUF_SIZE;
200 compressed_fpga_stream.zalloc = fpga_deflate_malloc;
201 compressed_fpga_stream.zfree = fpga_deflate_free;
38d618ba 202 compressed_fpga_stream.opaque = Z_NULL;
4b3f6d79 203
204 ret = inflateInit2(&compressed_fpga_stream, 0);
205
206 do {
207 if (compressed_fpga_stream.avail_in == 0) {
208 compressed_fpga_stream.next_in = inbuf;
209 uint16_t i = 0;
210 do {
ad8a18e6 211 int32_t c = fgetc(infile);
4b3f6d79 212 if (!feof(infile)) {
38d618ba 213 inbuf[i++] = c & 0xFF;
4b3f6d79 214 compressed_fpga_stream.avail_in++;
215 } else {
216 break;
217 }
218 } while (i < DECOMPRESS_BUF_SIZE);
219 }
220
221 ret = inflate(&compressed_fpga_stream, Z_SYNC_FLUSH);
222
223 if (ret != Z_OK && ret != Z_STREAM_END) {
224 break;
225 }
226
227 if (compressed_fpga_stream.avail_out == 0) {
228 for (uint16_t i = 0; i < DECOMPRESS_BUF_SIZE; i++) {
229 fputc(outbuf[i], outfile);
230 }
231 compressed_fpga_stream.avail_out = DECOMPRESS_BUF_SIZE;
232 compressed_fpga_stream.next_out = outbuf;
233 }
234 } while (ret == Z_OK);
235
236 if (ret == Z_STREAM_END) { // reached end of input
237 uint16_t i = 0;
238 while (compressed_fpga_stream.avail_out < DECOMPRESS_BUF_SIZE) {
239 fputc(outbuf[i++], outfile);
240 compressed_fpga_stream.avail_out++;
241 }
242 fclose(outfile);
243 fclose(infile);
7b242c1c 244 return(EXIT_SUCCESS);
4b3f6d79 245 } else {
ad8a18e6 246 fprintf(stderr, "Error. Inflate() returned error %i, %s", ret, compressed_fpga_stream.msg);
4b3f6d79 247 fclose(outfile);
248 fclose(infile);
7b242c1c 249 return(EXIT_FAILURE);
4b3f6d79 250 }
251
252}
253
f3919878 254
e6153040 255int main(int argc, char **argv)
256{
fb228974 257 FILE **infiles;
258 FILE *outfile;
e6153040 259
fb228974 260 if (argc == 1 || argc == 2) {
8e074056 261 usage();
7b242c1c 262 return(EXIT_FAILURE);
fb228974 263 }
264
ad8a18e6 265 if (!strcmp(argv[1], "-d")) { // Decompress
7f9e4c25 266
4b3f6d79 267 infiles = calloc(1, sizeof(FILE*));
268 if (argc != 4) {
8e074056 269 usage();
7b242c1c 270 return(EXIT_FAILURE);
4b3f6d79 271 }
272 infiles[0] = fopen(argv[2], "rb");
273 if (infiles[0] == NULL) {
274 fprintf(stderr, "Error. Cannot open input file %s", argv[2]);
7b242c1c 275 return(EXIT_FAILURE);
4b3f6d79 276 }
277 outfile = fopen(argv[3], "wb");
278 if (outfile == NULL) {
279 fprintf(stderr, "Error. Cannot open output file %s", argv[3]);
7b242c1c 280 return(EXIT_FAILURE);
4b3f6d79 281 }
282 return zlib_decompress(infiles[0], outfile);
4b3f6d79 283
ad8a18e6 284 } else { // Compress
8e074056 285
7f9e4c25 286 bool hardnested_mode = false;
287 int num_input_files = 0;
288 if (!strcmp(argv[1], "-t")) { // hardnested table
289 if (argc != 4) {
290 usage();
291 return(EXIT_FAILURE);
292 }
293 hardnested_mode = true;
294 num_input_files = 1;
295 } else {
296 num_input_files = argc-2;
297 }
298 infiles = calloc(num_input_files, sizeof(FILE*));
299 for (uint16_t i = 0; i < num_input_files; i++) {
300 infiles[i] = fopen(argv[i+hardnested_mode?2:1], "rb");
8e074056 301 if (infiles[i] == NULL) {
7f9e4c25 302 fprintf(stderr, "Error. Cannot open input file %s", argv[i+hardnested_mode?2:1]);
7b242c1c 303 return(EXIT_FAILURE);
8e074056 304 }
305 }
306 outfile = fopen(argv[argc-1], "wb");
307 if (outfile == NULL) {
308 fprintf(stderr, "Error. Cannot open output file %s", argv[argc-1]);
7b242c1c 309 return(EXIT_FAILURE);
e6153040 310 }
7f9e4c25 311 return zlib_compress(infiles, num_input_files, outfile, hardnested_mode);
fb228974 312 }
e6153040 313}
Impressum, Datenschutz