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