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