vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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