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