]> pd.if.org Git - zpackage/blob - lib/uncompress.c
create combined single header for jsw library
[zpackage] / lib / uncompress.c
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <assert.h>
10
11 #include <sys/mman.h>
12
13 #include "lzma.h"
14
15 void uncompresslzma(void *buf, size_t bufsize, FILE *out) {
16         lzma_stream s = LZMA_STREAM_INIT;
17         lzma_stream *strm;
18         
19         uint8_t outbuf[BUFSIZ];
20
21         int ret;
22
23         strm = &s;
24
25         ret = lzma_stream_decoder(strm, UINT64_MAX, 0);
26         /* The only reasonable error here is LZMA_MEM_ERROR. */
27         if (ret != LZMA_OK) {
28                 fprintf(stderr, "%s", ret == LZMA_MEM_ERROR ? strerror(ENOMEM)
29                                 : "Internal error (bug)");
30                 exit(EXIT_FAILURE);
31         }
32
33         strm->avail_in = bufsize;
34         strm->next_in = buf;
35         strm->avail_out = BUFSIZ;
36         strm->next_out = outbuf;
37
38         lzma_action action = LZMA_RUN;
39
40         while (1) {
41                 ret = lzma_code(strm, action);
42
43                 // Write and check write error before checking decoder error.
44                 // This way as much data as possible gets written to output
45                 // even if decoder detected an error.
46                 if (strm->avail_out == 0 || ret != LZMA_OK) {
47                         const size_t write_size = BUFSIZ - strm->avail_out;
48
49                         if (fwrite(outbuf, 1, write_size, out) != write_size) {
50                                 // Wouldn't be a surprise if writing to stderr
51                                 // would fail too but at least try to show an
52                                 // error message.
53                                 fprintf(stderr, "Cannot write to output file stream: "
54                                                 "%s", strerror(errno));
55                                 exit(EXIT_FAILURE);
56                         }
57
58                         strm->next_out = outbuf;
59                         strm->avail_out = BUFSIZ;
60                 }
61
62                 if (ret != LZMA_OK) {
63                         if (ret == LZMA_STREAM_END) {
64                                 // lzma_stream_decoder() already guarantees
65                                 // that there's no trailing garbage.
66                                 assert(strm->avail_in == 0);
67                                 //assert(action == LZMA_FINISH);
68                                 return;
69                         }
70
71                         const char *msg;
72                         switch (ret) {
73                                 case LZMA_MEM_ERROR:
74                                         msg = strerror(ENOMEM);
75                                         break;
76
77                                 case LZMA_FORMAT_ERROR:
78                                         msg = "File format not recognized";
79                                         break;
80
81                                 case LZMA_OPTIONS_ERROR:
82                                         // FIXME: Better message?
83                                         msg = "Unsupported compression options";
84                                         break;
85
86                                 case LZMA_DATA_ERROR:
87                                         msg = "File is corrupt";
88                                         break;
89
90                                 case LZMA_BUF_ERROR:
91                                         msg = "Unexpected end of input";
92                                         break;
93
94                                 default:
95                                         msg = "Internal error (bug)";
96                                         break;
97                         }
98
99                         fprintf(stderr, "xz: %s\n", msg);
100                         exit(EXIT_FAILURE);
101                 }
102         }
103 }