vx32

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