bzip2: port bzip2 1.0.4 to busybox. note: bzip2 code resides
[platform/upstream/busybox.git] / archival / bzip2.c
1 /*
2  * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
3  *
4  * This file uses bzip2 library code which is written
5  * by Julian Seward <jseward@bzip.org>.
6  * See README and LICENSE files in bz/ directory for more information
7  * about bzip2 library code.
8  */
9
10 #include "libbb.h"
11
12 /* This buys 6% speed for nearly 4k code */
13 /*#define FAST_GROUP6 1*/
14
15 #include "bz/bzlib.h"
16
17 #include "bz/bzlib_private.h"
18
19 #include "bz/blocksort.c"
20 #include "bz/bzlib.c"
21 #include "bz/compress.c"
22 #include "bz/crctable.c"
23 #include "bz/huffman.c"
24 #include "bz/randtable.c"
25
26 /* No point in being shy and having very small buffer here.
27  * bzip2 internal buffers are much bigger anyway, hundreds of kbytes.
28  * If iobuf is several pages long, malloc() may use mmap,
29  * making iobuf is page aligned and thus (maybe) have one memcpy less
30  * if kernel is clever enough.
31  */
32 enum {
33         IOBUF_SIZE = 8 * 1024
34 };
35
36 /* Returns:
37  * <0 on write errors (examine errno),
38  * >0 on short writes (errno == 0)
39  * 0  no error (entire input consume, gimme more)
40  * on "impossible" errors (internal bzip2 compressor bug) dies
41  */
42 static
43 ssize_t bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, void *wbuf)
44 {
45         int n, n2, ret;
46
47         /* if (len == 0) return 0; */
48
49         strm->avail_in = rlen;
50         strm->next_in  = rbuf;
51         while (1) {
52                 strm->avail_out = IOBUF_SIZE;
53                 strm->next_out = wbuf;
54
55                 ret = BZ2_bzCompress(strm, BZ_RUN);
56                 if (ret != BZ_RUN_OK)
57                         bb_error_msg_and_die("internal error %d", ret);
58
59                 n = IOBUF_SIZE - strm->avail_out;
60                 if (n) {
61                         /* short reads must have errno == 0 */
62                         errno = 0;
63                         n2 = full_write(STDOUT_FILENO, wbuf, n);
64                         if (n2 != n)
65                                 return n2 ? n2 : 1;
66                 }
67
68                 if (strm->avail_in == 0)
69                         return 0;
70         }
71 }
72
73
74 /*---------------------------------------------------*/
75 static
76 USE_DESKTOP(long long) int bz_write_tail(bz_stream *strm, void *wbuf)
77 {
78         int n, n2, ret;
79         USE_DESKTOP(long long) int total;
80
81         total = -1;
82         while (1) {
83                 strm->avail_out = IOBUF_SIZE;
84                 strm->next_out = wbuf;
85
86                 ret = BZ2_bzCompress(strm, BZ_FINISH);
87                 if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
88                         bb_error_msg_and_die("internal error %d", ret);
89
90                 n = IOBUF_SIZE - strm->avail_out;
91                 if (n) {
92                         n2 = full_write(STDOUT_FILENO, wbuf, n);
93                         if (n2 != n)
94                                 goto err;
95                 }
96
97                 if (ret == BZ_STREAM_END)
98                         break;
99         }
100
101         total = 0 USE_DESKTOP( + strm->total_out );
102  err:
103         BZ2_bzCompressEnd(strm);
104         return total;
105 }
106
107
108 static
109 USE_DESKTOP(long long) int compressStream(void)
110 {
111         USE_DESKTOP(long long) int total;
112         ssize_t count;
113         bz_stream bzs; /* it's small */
114 #define strm (&bzs)
115         char *iobuf;
116 #define rbuf iobuf
117 #define wbuf (iobuf + IOBUF_SIZE)
118
119         iobuf = xmalloc(2 * IOBUF_SIZE);
120
121         BZ2_bzCompressInit(strm, 9 /*blockSize100k*/);
122
123         while (1) {
124                 count = full_read(STDIN_FILENO, rbuf, IOBUF_SIZE);
125                 if (count < 0)
126                         bb_perror_msg("read error");
127                 if (count <= 0)
128                         break;
129                 count = bz_write(strm, rbuf, count, wbuf);
130                 if (count) {
131                         bb_perror_msg(count < 0 ? "write error" : "short write");
132                         break;
133                 }
134         }
135
136         total = bz_write_tail(strm, wbuf);
137         free(iobuf);
138         /* we had no error _only_ if count == 0 */
139         return count == 0 ? total : -1;
140 }
141
142 static
143 char* make_new_name_bzip2(char *filename)
144 {
145         return xasprintf("%s.bz2", filename);
146 }
147
148 int bzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
149 int bzip2_main(int argc, char **argv)
150 {
151         unsigned opt;
152
153         /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
154         opt = getopt32(argv, "cfv" USE_BUNZIP2("d") "q123456789" );
155 #if ENABLE_BUNZIP2 /* bunzip2_main may not be visible... */
156         if (opt & 0x8) // -d
157                 return bunzip2_main(argc, argv);
158 #endif
159         option_mask32 &= 0x7; /* ignore -q, -0..9 */
160         //if (opt & 0x1) // -c
161         //if (opt & 0x2) // -f
162         //if (opt & 0x4) // -v
163         argv += optind;
164
165         return bbunpack(argv, make_new_name_bzip2, compressStream);
166 }