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 (5271B)
---
1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <errno.h>
8
9 #include <vxa/vxa.h>
10 #include <vxa/codec.h>
11
12 #include "zlib.h"
13
14
15 #define BUFSIZE (64*1024)
16
17 char vxacodec_name[] = "zlib";
18
19
20 // Defined in dzlib-bin.c, generated from dzlib by bin2c.pl
21 extern const uint8_t vxa_dzlib_data[];
22 extern const int vxa_dzlib_length;
23
24
25 // Translate a zlib return code into a VXA return code
26 static int xlrc(vxaio *io, z_stream *zs, int zrc)
27 {
28 switch (zrc) {
29 case Z_OK:
30 return VXA_RC_OK;
31 case Z_STREAM_END:
32 return vxa_error(io, VXA_RC_EOF, "end of file");
33 case Z_MEM_ERROR:
34 return vxa_error(io, VXA_RC_NO_MEMORY, "out of memory in zlib");
35 case Z_STREAM_ERROR:
36 return vxa_error(io, VXA_RC_INVALID_ARG,
37 "zlib detected invalid argument");
38 default:
39 if (zs->msg)
40 return vxa_error(io, VXA_RC_UNKNOWN,
41 "zlib error: %s", zs->msg);
42 else
43 return vxa_error(io, VXA_RC_UNKNOWN,
44 "unknown zlib error: %d", zrc);
45 }
46 }
47
48 int vxacodec_init(struct vxacodec *c, struct vxaio *io)
49 {
50 c->decoder = vxa_dzlib_data;
51 c->decodersize = vxa_dzlib_length;
52 }
53
54 int vxacodec_encode(vxacodec *c, vxaio *io)
55 {
56 io->method = VXA_M_DEFLATE;
57
58 z_stream zs;
59 memset(&zs, 0, sizeof(zs));
60
61 // Allocate input and output data buffers
62 char *iobuf = malloc(BUFSIZE*2);
63 if (iobuf == NULL) {
64 return vxa_error(io, VXA_RC_NO_MEMORY,
65 "No memory for zlib I/O buffers");
66 }
67 char *inbuf = iobuf;
68 char *outbuf = iobuf + BUFSIZE;
69
70 // Just encode input data into a raw deflate stream,
71 // leaving the client to do any wrapping (e.g., ZIP)
72 int zrc = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
73 -15, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
74 if (zrc != Z_OK) {
75 enderr:
76 free(iobuf);
77 return xlrc(io, &zs, zrc);
78 }
79
80 // Compress the input stream
81 ssize_t inlen;
82 while ((inlen = io->readf(io, inbuf, BUFSIZE)) > 0) {
83
84 // Compress this input block
85 zs.next_in = inbuf;
86 zs.avail_in = inlen;
87 do {
88 zs.next_out = outbuf;
89 zs.avail_out = BUFSIZE;
90 if ((zrc = deflate(&zs, 0)) != Z_OK) {
91 zerr:
92 deflateEnd(&zs);
93 free(iobuf);
94 return xlrc(io, &zs, zrc);
95 }
96
97 // Write any output the decompressor produced
98 ssize_t outlen = io->writef(io, outbuf,
99 BUFSIZE - zs.avail_out);
100 if (outlen < 0)
101 goto ioerr;
102
103 // Continue decompressing the input block until done
104 } while (zs.avail_in > 0);
105 }
106 if (inlen < 0) {
107 ioerr:
108 deflateEnd(&zs);
109 free(iobuf);
110 return io->errcode;
111 }
112
113 // Flush the output
114 zs.avail_in = 0;
115 int done = 0;
116 do {
117 zs.next_out = outbuf;
118 zs.avail_out = BUFSIZE;
119 zrc = deflate(&zs, Z_FINISH);
120 if (zrc == Z_STREAM_END)
121 done = 1;
122 else if (zrc != Z_OK)
123 goto zerr;
124
125 // Write compressor output
126 ssize_t outlen = io->writef(io, outbuf,
127 BUFSIZE - zs.avail_out);
128 if (outlen < 0)
129 goto ioerr;
130
131 } while (!done);
132
133 zrc = deflateEnd(&zs);
134 if (zrc != Z_OK)
135 goto enderr;
136 free(iobuf);
137 return 0;
138 }
139
140 int vxacodec_decode(vxacodec *c, vxaio *io)
141 {
142 // Decode gzip format or raw deflate stream as appropriate
143 int wbits;
144 switch (io->method) {
145 case VXA_M_GZIP:
146 wbits = 16+15; // Decode GZIP format stream
147 break;
148 case VXA_M_DEFLATE:
149 wbits = -15; // Decode raw deflate stream
150 break;
151 default:
152 return vxa_error(io, VXA_RC_WRONG_FORMAT,
153 "zlib: unsupported method code %08x",
154 io->method);
155 }
156
157 z_stream zs;
158 memset(&zs, 0, sizeof(zs));
159
160 // Allocate input and output data buffers
161 char *iobuf = malloc(BUFSIZE*2);
162 if (iobuf == NULL) {
163 return vxa_error(io, VXA_RC_NO_MEMORY,
164 "No memory for zlib I/O buffers");
165 }
166 char *inbuf = iobuf;
167 char *outbuf = iobuf + BUFSIZE;
168
169 // Initialize the decompressor in the appropriate mode.
170 int zrc = inflateInit2(&zs, wbits);
171 if (zrc != Z_OK) {
172 enderr:
173 free(iobuf);
174 return xlrc(io, &zs, zrc);
175 }
176
177 // Deompress the input stream
178 int done = 0;
179 do {
180 // Read a block of input data
181 ssize_t inlen = io->readf(io, inbuf, BUFSIZE);
182 if (inlen == 0)
183 vxa_error(io, VXA_RC_CORRUPT_DATA,
184 "compressed input data truncated");
185 if (inlen <= 0) {
186 ioerr:
187 inflateEnd(&zs);
188 free(iobuf);
189 return io->errcode;
190 }
191
192 // Decompress this input block
193 zs.next_in = inbuf;
194 zs.avail_in = inlen;
195 do {
196 zs.next_out = outbuf;
197 zs.avail_out = BUFSIZE;
198 zrc = inflate(&zs, 0);
199 if (zrc == Z_STREAM_END)
200 done = 1;
201 else if (zrc != Z_OK) {
202 zerr:
203 inflateEnd(&zs);
204 free(iobuf);
205 return xlrc(io, &zs, zrc);
206 }
207
208 // Write any output the decompressor produced
209 ssize_t outlen = io->writef(io, outbuf,
210 BUFSIZE - zs.avail_out);
211 if (outlen < 0)
212 goto ioerr;
213
214 // Continue decompressing until done
215 } while (zs.avail_in > 0 && !done);
216 } while (!done);
217
218 zrc = inflateEnd(&zs);
219 if (zrc != Z_OK)
220 goto enderr;
221
222 free(iobuf);
223
224 return VXA_RC_OK;
225 }
226
227 int vxacodec_recognize(vxacodec *c, vxaio *io, const void *header, size_t size)
228 {
229 const uint8_t *inp = header;
230
231 // See if the initial data provided looks like a GZIP file.
232 if (size >= 3 && inp[0] == 0x1f && inp[1] == 0x8b && inp[2] == 8) {
233 // Apparently a GZIP stream...
234 io->method = VXA_M_GZIP; // "gzip"
235 return vxa_error(io, VXA_RC_COMPRESSED,
236 "input already compressed in gzip format");
237 }
238
239 // Format not recognized, but we could try compressing it anyway...
240 return VXA_RC_OK;
241 }
242