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 (4835B)
       ---
            1 
            2 #include <stdio.h>
            3 #include <stdlib.h>
            4 #include <stdarg.h>
            5 #include <unistd.h>
            6 #include <setjmp.h>
            7 #include <assert.h>
            8 #include <errno.h>
            9 
           10 #include <vxa/vxa.h>
           11 #include <vxa/codec.h>
           12 
           13 #include "cdjpeg.h"
           14 #include "native.h"
           15 
           16 
           17 char vxacodec_name[] = "jpeg";
           18 
           19 
           20 // Defined in djpeg-bin.c, generated from djpeg by bin2c.pl
           21 extern const uint8_t vxa_djpeg_data[];
           22 extern const int vxa_djpeg_length;
           23 
           24 
           25 int vxacodec_init(vxacodec *c, vxaio *io)
           26 {
           27         c->decoder = vxa_djpeg_data;
           28         c->decodersize = vxa_djpeg_length;
           29 
           30         return VXA_RC_OK;
           31 }
           32 
           33 int vxacodec_encode(struct vxacodec *c, struct vxaio *io)
           34 {
           35         return vxa_error(io, VXA_RC_WRONG_FORMAT,
           36                         "jpeg codec currently doesn't support compression");
           37 }
           38 
           39 static void error_exit(j_common_ptr cinfo)
           40 {
           41         struct client_data *cdata = cinfo->client_data;
           42 
           43         // Jump back to the original entrypoint with an error return
           44         longjmp(cdata->errjmp, 1);
           45 }
           46 
           47 static void output_message(j_common_ptr cinfo)
           48 {
           49         struct client_data *cdata = cinfo->client_data;
           50 
           51         /* Create the message */
           52         char buffer[JMSG_LENGTH_MAX];
           53         cinfo->err->format_message(cinfo, buffer);
           54 
           55         /* Stuff it into the vxaio struct */
           56         vxa_error(cdata->io, VXA_RC_CORRUPT_DATA, "%s", buffer);
           57 }
           58 
           59 static void init_source(j_decompress_ptr cinfo)
           60 {
           61         // Nothing to do
           62 }
           63 
           64 static boolean fill_input_buffer(j_decompress_ptr cinfo)
           65 {
           66         struct client_data *cdata = cinfo->client_data;
           67 
           68         ssize_t inlen = cdata->io->readf(cdata->io, cdata->inbuf, BUFSIZE);
           69         if (inlen == 0)
           70                 vxa_error(cdata->io, VXA_RC_CORRUPT_DATA,
           71                         "compressed JPEG stream is truncated");
           72         if (inlen <= 0)
           73                 longjmp(cdata->errjmp, 1);
           74 
           75         cinfo->src->next_input_byte = cdata->inbuf;
           76         cinfo->src->bytes_in_buffer = inlen;
           77 
           78         return TRUE;
           79 }
           80 
           81 static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
           82 {
           83         struct client_data *cdata = cinfo->client_data;
           84 
           85         while (num_bytes > cinfo->src->bytes_in_buffer) {
           86                 num_bytes -= cinfo->src->bytes_in_buffer;
           87                 fill_input_buffer(cinfo);
           88         }
           89         cinfo->src->next_input_byte += num_bytes;
           90         cinfo->src->bytes_in_buffer -= num_bytes;
           91 }
           92 
           93 static void term_source(j_decompress_ptr cinfo)
           94 {
           95         // Nothing to do
           96 }
           97 
           98 void vxajpeg_flush(struct client_data *cd)
           99 {
          100         if (cd->outpos == 0)
          101                 return;
          102 
          103         ssize_t rc = cd->io->writef(cd->io, cd->outbuf, cd->outpos);
          104         if (rc < 0)
          105                 longjmp(cd->errjmp, 1);
          106         cd->outpos = 0;
          107 }
          108 
          109 int vxacodec_decode(struct vxacodec *c, struct vxaio *io)
          110 {
          111         // Save the vital args in a client_data struct for our callbacks
          112         struct client_data cdata;
          113         cdata.io = io;
          114         cdata.inbuf = NULL;
          115 
          116         // Set up the JPEG library error handler struct
          117         struct jpeg_error_mgr jerr;
          118         memset(&jerr, 0, sizeof(jerr));
          119         jpeg_std_error(&jerr);
          120         jerr.error_exit = error_exit;
          121         jerr.output_message = output_message;
          122 
          123         // Setup the JPEG input source
          124         struct jpeg_source_mgr jsrc;
          125         memset(&jsrc, 0, sizeof(jsrc));
          126         jsrc.init_source = init_source;
          127         jsrc.fill_input_buffer = fill_input_buffer;
          128         jsrc.skip_input_data = skip_input_data;
          129         jsrc.resync_to_restart = jpeg_resync_to_restart;
          130         jsrc.term_source = term_source;
          131 
          132         // Set up the main decompression state struct
          133         struct jpeg_decompress_struct cinfo;
          134         memset(&cinfo, 0, sizeof(cinfo));
          135         cinfo.client_data = &cdata;
          136         cinfo.err = &jerr;
          137         cinfo.src = &jsrc;
          138 
          139         // Set up a JMP_BUF for error_exit() to longjmp to on fatal errors. */
          140         if (setjmp(cdata.errjmp)) {
          141                 jpeg_destroy_decompress(&cinfo);
          142                 if (cdata.inbuf != NULL)
          143                         free(cdata.inbuf);
          144                 return io->errcode;
          145         }
          146 
          147         // Allocate the input and output buffers
          148         cdata.inbuf = malloc(BUFSIZE*2);
          149         if (cdata.inbuf == NULL)
          150                 return vxa_error(io, VXA_RC_NO_MEMORY,
          151                                 "no memory for JPEG decoder input buffer");
          152         cdata.outbuf = cdata.inbuf + BUFSIZE;
          153         cdata.outpos = 0;
          154 
          155         // Initialize the JPEG decoder
          156         jpeg_create_decompress(&cinfo);
          157         (void) jpeg_read_header(&cinfo, TRUE);
          158 
          159         djpeg_dest_ptr dest_mgr = jinit_write_bmp(&cinfo, FALSE);
          160         dest_mgr->output_file = (FILE*)&cdata;        // XX hack hack hack
          161 
          162         (void) jpeg_start_decompress(&cinfo);
          163         dest_mgr->start_output(&cinfo, dest_mgr);
          164 
          165         /* Process data */
          166         while (cinfo.output_scanline < cinfo.output_height) {
          167                 JDIMENSION num_scanlines = jpeg_read_scanlines(
          168                                 &cinfo, dest_mgr->buffer,
          169                                 dest_mgr->buffer_height);
          170                 dest_mgr->put_pixel_rows(&cinfo, dest_mgr, num_scanlines);
          171         }
          172 
          173         dest_mgr->finish_output(&cinfo, dest_mgr);
          174 
          175         vxajpeg_flush(&cdata);
          176 
          177         (void) jpeg_finish_decompress(&cinfo);
          178         jpeg_destroy_decompress(&cinfo);
          179 
          180         free(cdata.inbuf);
          181 
          182         return VXA_RC_OK;
          183 }
          184 
          185 int vxacodec_recognize(struct vxacodec *c, struct vxaio *io,
          186                         const void *header, size_t size)
          187 {
          188         const uint8_t *inp = header;
          189         if (size >= 4 &&
          190                         inp[0] == 0xff &&
          191                         inp[1] == 0xd8 &&        // SOI
          192                         inp[2] == 0xff &&
          193                         inp[3] >= 0xe0) {        // APPx
          194                 io->method = VXA_M_JPEG;
          195                 return vxa_error(io, VXA_RC_COMPRESSED,
          196                                 "input already compressed in JPEG format");
          197         }
          198 
          199         return vxa_error(io, VXA_RC_WRONG_FORMAT,
          200                         "JPEG codec currently can't compress");
          201 }
          202