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