native.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) Refs
---
native.c (5227B)
---
1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdarg.h>
6 #include <unistd.h>
7 #include <errno.h>
8
9 #include <vxa/vxa.h>
10 #include <vxa/codec.h>
11
12 #include "bzlib.h"
13
14
15 #define BUFSIZE (64*1024)
16
17 char vxacodec_name[] = "bzip2";
18
19
20 // Defined in dzlib-bin.c, generated from dzlib by bin2c.pl
21 extern const uint8_t vxa_dbz2_data[];
22 extern const int vxa_dbz2_length;
23
24
25 void bz_internal_error (int errcode)
26 {
27 fprintf(stderr, "Internal bzip2 error: %d", errcode);
28 abort();
29 }
30
31 // Translate a bzlib return code into a VXA return code
32 static int xlrc(vxaio *io, int bzrc)
33 {
34 switch (bzrc) {
35 case BZ_OK:
36 case BZ_RUN_OK:
37 case BZ_FLUSH_OK:
38 case BZ_FINISH_OK:
39 return VXA_RC_OK;
40 case BZ_STREAM_END:
41 return vxa_error(io, VXA_RC_EOF, "end of file");
42 case BZ_MEM_ERROR:
43 return vxa_error(io, VXA_RC_NO_MEMORY,
44 "out of memory in bzlib");
45 default:
46 return vxa_error(io, VXA_RC_UNKNOWN,
47 "unknown bzip2 error (%d)", bzrc);
48 }
49 }
50
51 int vxacodec_init(struct vxacodec *c, struct vxaio *io)
52 {
53 c->decoder = vxa_dbz2_data;
54 c->decodersize = vxa_dbz2_length;
55 }
56
57 int vxacodec_encode(struct vxacodec *c, struct vxaio *io)
58 {
59 io->method = VXA_M_BZIP2;
60
61 bz_stream bzs;
62 memset(&bzs, 0, sizeof(bzs));
63
64 // Allocate input and output data buffers
65 char *iobuf = malloc(BUFSIZE*2);
66 if (iobuf == NULL) {
67 return vxa_error(io, VXA_RC_NO_MEMORY,
68 "No memory for bzip2 I/O buffers");
69 }
70 char *inbuf = iobuf;
71 char *outbuf = iobuf + BUFSIZE;
72
73 // Initialize the bzip2 compressor
74 int bzrc = BZ2_bzCompressInit(&bzs, 9, 0, 0);
75 if (bzrc != BZ_OK) {
76 enderr:
77 free(iobuf);
78 return xlrc(io, bzrc);
79 }
80
81 // Read and compress the input stream
82 ssize_t inlen;
83 while ((inlen = io->readf(io, inbuf, BUFSIZE)) > 0) {
84
85 // Compress this input block
86 bzs.next_in = inbuf;
87 bzs.avail_in = inlen;
88 do {
89 bzs.next_out = outbuf;
90 bzs.avail_out = BUFSIZE;
91 bzrc = BZ2_bzCompress(&bzs, BZ_RUN);
92 if (bzrc != BZ_RUN_OK) {
93 bzerr:
94 BZ2_bzCompressEnd(&bzs);
95 free(iobuf);
96 return xlrc(io, bzrc);
97 }
98
99 // Write any output the decompressor produced
100 ssize_t outlen = io->writef(io, outbuf,
101 BUFSIZE - bzs.avail_out);
102 if (outlen < 0)
103 goto ioerr;
104
105 // Continue decompressing the input block until done
106 } while (bzs.avail_in > 0);
107 }
108 if (inlen < 0) {
109 ioerr:
110 BZ2_bzCompressEnd(&bzs);
111 free(iobuf);
112 return io->errcode;
113 }
114
115 // Flush the output
116 bzs.avail_in = 0;
117 int done = 0;
118 do {
119 bzs.next_out = outbuf;
120 bzs.avail_out = BUFSIZE;
121 bzrc = BZ2_bzCompress(&bzs, BZ_FINISH);
122 if (bzrc == BZ_STREAM_END)
123 done = 1;
124 else if (bzrc != BZ_FINISH_OK)
125 goto bzerr;
126
127 // Write compressor output
128 ssize_t outlen = io->writef(io, outbuf,
129 BUFSIZE - bzs.avail_out);
130 if (outlen < 0)
131 goto ioerr;
132
133 } while (!done);
134
135 bzrc = BZ2_bzCompressEnd(&bzs);
136 if (bzrc != BZ_OK)
137 goto enderr;
138
139 return 0;
140 }
141
142 int vxacodec_decode(struct vxacodec *c, struct vxaio *io)
143 {
144 if (io->method != VXA_M_BZIP2)
145 return vxa_error(io, VXA_RC_WRONG_FORMAT,
146 "bzip2: unsupported method code %08x",
147 io->method);
148
149 bz_stream bzs;
150 memset(&bzs, 0, sizeof(bzs));
151
152 // Allocate input and output data buffers
153 char *iobuf = malloc(BUFSIZE*2);
154 if (iobuf == NULL) {
155 return vxa_error(io, VXA_RC_NO_MEMORY,
156 "No memory for bzip2 I/O buffers");
157 }
158 char *inbuf = iobuf;
159 char *outbuf = iobuf + BUFSIZE;
160
161 // Initialize the bzip2 decompressor
162 int bzrc;
163 if ((bzrc = BZ2_bzDecompressInit(&bzs, 0, 0)) != BZ_OK) {
164 enderr:
165 free(iobuf);
166 return xlrc(io, bzrc);
167 }
168
169 // Decompress the input stream
170 int done = 0;
171 do {
172 // Read a block of input data
173 ssize_t inlen = io->readf(io, inbuf, BUFSIZE);
174 if (inlen == 0)
175 vxa_error(io, VXA_RC_CORRUPT_DATA,
176 "bzip2-compressed input data truncated");
177 if (inlen < 0) {
178 ioerr:
179 BZ2_bzDecompressEnd(&bzs);
180 free(iobuf);
181 return io->errcode;
182 }
183
184 // Decompress this input block
185 bzs.next_in = inbuf;
186 bzs.avail_in = inlen;
187 do {
188 bzs.next_out = outbuf;
189 bzs.avail_out = BUFSIZE;
190 bzrc = BZ2_bzDecompress(&bzs);
191 if (bzrc == BZ_STREAM_END)
192 done = 1;
193 else if (bzrc != BZ_OK) {
194 bzerr:
195 BZ2_bzDecompressEnd(&bzs);
196 free(iobuf);
197 return xlrc(io, bzrc);
198 }
199
200 // Write any output the decompressor produced
201 ssize_t outlen = io->writef(io, outbuf,
202 BUFSIZE - bzs.avail_out);
203 if (outlen < 0)
204 goto ioerr;
205
206 // Continue decompressing the input block until done
207 } while (bzs.avail_in > 0 && !done);
208 } while (!done);
209
210 if ((bzrc = BZ2_bzDecompressEnd(&bzs)) != BZ_OK)
211 goto enderr;
212
213 free(iobuf);
214
215 return VXA_RC_OK;
216 }
217
218 int vxacodec_recognize(struct vxacodec *c, struct vxaio *io,
219 const void *header, size_t size)
220 {
221 const uint8_t *inp = header;
222
223 // See if the initial data provided looks like a GZIP file.
224 if (size >= 10 &&
225 inp[0] == 'B' && // BZIP2 header
226 inp[1] == 'Z' &&
227 inp[2] == 'h' &&
228 inp[3] >= '1' && inp[3] <= '9' &&
229 inp[4] == 0x31 && // Block header
230 inp[5] == 0x41 &&
231 inp[6] == 0x59 &&
232 inp[7] == 0x26 &&
233 inp[8] == 0x53 &&
234 inp[9] == 0x59) {
235 io->method = VXA_M_BZIP2;
236 return vxa_error(io, VXA_RC_COMPRESSED,
237 "input already compressed in bzip2 format");
238 }
239
240 // Format not recognized, but we could try compressing it anyway...
241 return VXA_RC_OK;
242 }
243