12 #define DEF_WINDOW_SZ2 11 13 #define DEF_LOOKAHEAD_SZ2 4 14 #define DEF_DECODER_INPUT_BUFFER_SIZE 256 15 #define DEF_BUFFER_SIZE (64 * 1024) 18 #define LOG(...) fprintf(stderr, __VA_ARGS__) 30 fprintf(stderr,
"heatshrink version %u.%u.%u by %s\n",
32 fprintf(stderr,
"Home page: %s\n\n",
url);
35 " heatshrink [-h] [-e|-d] [-v] [-w SIZE] [-l BITS] [IN_FILE] [OUT_FILE]\n" 37 "heatshrink compresses or uncompresses byte streams using LZSS, and is\n" 38 "designed especially for embedded, low-memory, and/or hard real-time\n" 42 " -e encode (compress, default)\n" 43 " -d decode (uncompress)\n" 44 " -v verbose (print input & output sizes, compression ratio, etc.)\n" 46 " -w SIZE Base-2 log of LZSS sliding window size\n" 48 " A larger value allows searches a larger history of the data for repeated\n" 49 " patterns, potentially compressing more effectively, but will use\n" 50 " more memory and processing time.\n" 51 " Recommended default: -w 8 (embedded systems), -w 10 (elsewhere)\n" 53 " -l BITS Number of bits used for back-reference lengths\n" 55 " A larger value allows longer substitutions, but since all\n" 56 " back-references must use -w + -l bits, larger -w or -l can be\n" 57 " counterproductive if most patterns are small and/or local.\n" 58 " Recommended default: -l 4\n" 60 " If IN_FILE or OUT_FILE are unspecified, they will default to\n" 61 " \"-\" for standard input and standard output, respectively.\n");
91 static void die(
char *msg) {
92 fprintf(stderr,
"%s\n", msg);
101 io =
malloc(
sizeof(*io) + buf_sz);
103 memset(io, 0,
sizeof(*io) + buf_sz);
109 if (0 ==
strcmp(
"-", fname)) {
110 io->
fd = STDIN_FILENO;
112 io->
fd = open(fname, O_RDONLY);
115 if (0 ==
strcmp(
"-", fname)) {
116 io->
fd = STDOUT_FILENO;
118 io->
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC , 0644);
134 LOG(
"@ read %zd\n", size);
135 if (buf ==
NULL) {
return -1; }
136 if (size > io->
size) {
137 printf(
"size %zd, io->size %zd\n", size, io->
size);
156 if (read_sz < 0) { err(1,
"read"); }
157 io->
total += read_sz;
159 if (close(io->
fd) < 0) { err(1,
"close"); }
164 return io->
fill > size ? size : io->
fill;
170 LOG(
"@ drop %zd\n", size);
171 if (io->
read + size <= io->fill) {
186 LOG(
"@ sink %zd\n", size);
187 if (size > io->
size) {
return -1; }
191 ssize_t written = write(io->
fd, io->
buf, io->
fill);
192 LOG(
"@ flushing %zd, wrote %zd\n", io->
fill, written);
193 io->
total += written;
194 if (written == -1) { err(1,
"write"); }
195 memmove(io->
buf, &io->
buf[written], io->
fill - written);
206 ssize_t written = write(io->
fd, io->
buf, io->
fill);
207 io->
total += written;
208 LOG(
"@ close: flushing %zd, wrote %zd\n", io->
fill, written);
209 if (written == -1) { err(1,
"write"); }
225 uint8_t *data,
size_t data_sz) {
226 size_t out_sz = 4096;
227 uint8_t out_buf[out_sz];
228 memset(out_buf, 0, out_sz);
240 if (sres < 0) {
die(
"sink"); }
246 if (pres < 0) {
die(
"poll"); }
250 if (poll_sz == 0 && data_sz == 0) {
252 if (fres < 0) {
die(
"finish"); }
255 }
while (sunk < data_sz);
261 size_t window_sz = 1 << window_sz2;
263 if (hse ==
NULL) {
die(
"failed to init encoder: bad settings"); }
269 uint8_t *input =
NULL;
272 printf(
"handle read failure\n");
275 if (read_sz < 0) {
die(
"read"); }
283 if (read_sz == -1) { err(1,
"read"); }
291 uint8_t *data,
size_t data_sz) {
295 size_t out_sz = 4096;
296 uint8_t out_buf[out_sz];
297 memset(out_buf, 0, out_sz);
307 if (sres < 0) {
die(
"sink"); }
313 if (pres < 0) {
die(
"poll"); }
317 if (data_sz == 0 && poll_sz == 0) {
319 if (fres < 0) {
die(
"finish"); }
322 }
while (sunk < data_sz);
329 size_t window_sz = 1 << window_sz2;
333 if (hsd ==
NULL) {
die(
"failed to init decoder"); }
343 uint8_t *input =
NULL;
346 printf(
"handle read failure\n");
351 if (fres < 0) {
die(
"finish"); }
353 }
else if (read_sz < 0) {
360 if (read_sz == -1) { err(1,
"read"); }
370 fprintf(cfg->
out->
fd == STDOUT_FILENO ? stderr : stdout,
371 "%s %0.2f %%\t %zd -> %zd (-w %u -l %u)\n",
372 cfg->
in_fname, 100.0 - (100.0 * outb) / inb, inb, outb,
387 while ((a = getopt(argc, argv,
"hedi:w:l:v")) != -1) {
419 if (argc > 0) { cfg->
out_fname = argv[0]; }
422 int main(
int argc,
char **argv) {
424 memset(&cfg, 0,
sizeof(cfg));
429 printf(
"Refusing to overwrite file '%s' with itself.\n", cfg.
in_fname);
434 if (cfg.
in ==
NULL) {
die(
"Failed to open input file for read"); }
436 if (cfg.
out ==
NULL) {
die(
"Failed to open output file for write"); }
static const int version_major
HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd, uint8_t *out_buf, size_t out_buf_size, size_t *output_size)
#define HEATSHRINK_AUTHOR
static void handle_close(io_handle *io)
heatshrink_decoder * heatshrink_decoder_alloc(uint16_t input_buffer_size, uint8_t window_sz2, uint8_t lookahead_sz2)
#define HEATSHRINK_VERSION_PATCH
static const char author[]
#define DEF_LOOKAHEAD_SZ2
size_t decoder_input_buffer_size
static void report(config *cfg)
void heatshrink_decoder_free(heatshrink_decoder *hsd)
heatshrink_encoder * heatshrink_encoder_alloc(uint8_t window_sz2, uint8_t lookahead_sz2)
HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd)
#define DEF_DECODER_INPUT_BUFFER_SIZE
static int handle_drop(io_handle *io, size_t size)
static void close_and_report(config *cfg)
static heatshrink_decoder hsd
void heatshrink_encoder_free(heatshrink_encoder *hse)
static const int version_patch
int main(int argc, char **argv)
static io_handle * handle_open(char *fname, IO_mode m, size_t buf_sz)
HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse)
HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd, uint8_t *in_buf, size_t size, size_t *input_size)
HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse, uint8_t *out_buf, size_t out_buf_size, size_t *output_size)
HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, uint8_t *in_buf, size_t size, size_t *input_size)
static int decode(config *cfg)
static const int version_minor
static void proc_args(config *cfg, int argc, char **argv)
static void die(char *msg)
static ssize_t handle_sink(io_handle *io, size_t size, uint8_t *input)
#define HEATSHRINK_VERSION_MINOR
#define HEATSHRINK_VERSION_MAJOR
static int encoder_sink_read(config *cfg, heatshrink_encoder *hse, uint8_t *data, size_t data_sz)
static int decoder_sink_read(config *cfg, heatshrink_decoder *hsd, uint8_t *data, size_t data_sz)
static heatshrink_encoder hse
static int encode(config *cfg)
static ssize_t handle_read(io_handle *io, size_t size, uint8_t **buf)