LCOV - code coverage report
Current view: directory - frmts/jpeg - vsidataio.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 76 63 82.9 %
Date: 2010-01-09 Functions: 9 8 88.9 %

       1                 : /******************************************************************************
       2                 :  * $Id: vsidataio.cpp 15508 2008-10-09 21:24:31Z warmerdam $
       3                 :  *
       4                 :  * Project:  JPEG JFIF Driver
       5                 :  * Purpose:  Implement JPEG read/write io indirection through VSI.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *           Code partially derived from libjpeg jdatasrc.c and jdatadst.c.
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "cpl_vsi.h"
      32                 : 
      33                 : CPL_CVSID("$Id: vsidataio.cpp 15508 2008-10-09 21:24:31Z warmerdam $");
      34                 : 
      35                 : CPL_C_START
      36                 : #include "jpeglib.h"
      37                 : #include "jerror.h"
      38                 : CPL_C_END
      39                 : 
      40                 : 
      41                 : /* Expanded data source object for stdio input */
      42                 : 
      43                 : typedef struct {
      44                 :   struct jpeg_source_mgr pub; /* public fields */
      45                 : 
      46                 :   FILE * infile;    /* source stream */
      47                 :   JOCTET * buffer;    /* start of buffer */
      48                 :   boolean start_of_file;  /* have we gotten any data yet? */
      49                 : } my_source_mgr;
      50                 : 
      51                 : typedef my_source_mgr * my_src_ptr;
      52                 : 
      53                 : #define INPUT_BUF_SIZE  4096  /* choose an efficiently fread'able size */
      54                 : 
      55                 : 
      56                 : /*
      57                 :  * Initialize source --- called by jpeg_read_header
      58                 :  * before any data is actually read.
      59                 :  */
      60                 : 
      61                 : METHODDEF(void)
      62             120 : init_source (j_decompress_ptr cinfo)
      63                 : {
      64             120 :   my_src_ptr src = (my_src_ptr) cinfo->src;
      65                 : 
      66                 :   /* We reset the empty-input-file flag for each image,
      67                 :    * but we don't clear the input buffer.
      68                 :    * This is correct behavior for reading a series of images from one source.
      69                 :    */
      70             120 :   src->start_of_file = TRUE;
      71             120 : }
      72                 : 
      73                 : 
      74                 : /*
      75                 :  * Fill the input buffer --- called whenever buffer is emptied.
      76                 :  *
      77                 :  * In typical applications, this should read fresh data into the buffer
      78                 :  * (ignoring the current state of next_input_byte & bytes_in_buffer),
      79                 :  * reset the pointer & count to the start of the buffer, and return TRUE
      80                 :  * indicating that the buffer has been reloaded.  It is not necessary to
      81                 :  * fill the buffer entirely, only to obtain at least one more byte.
      82                 :  *
      83                 :  * There is no such thing as an EOF return.  If the end of the file has been
      84                 :  * reached, the routine has a choice of ERREXIT() or inserting fake data into
      85                 :  * the buffer.  In most cases, generating a warning message and inserting a
      86                 :  * fake EOI marker is the best course of action --- this will allow the
      87                 :  * decompressor to output however much of the image is there.  However,
      88                 :  * the resulting error message is misleading if the real problem is an empty
      89                 :  * input file, so we handle that case specially.
      90                 :  *
      91                 :  * In applications that need to be able to suspend compression due to input
      92                 :  * not being available yet, a FALSE return indicates that no more data can be
      93                 :  * obtained right now, but more may be forthcoming later.  In this situation,
      94                 :  * the decompressor will return to its caller (with an indication of the
      95                 :  * number of scanlines it has read, if any).  The application should resume
      96                 :  * decompression after it has loaded more data into the input buffer.  Note
      97                 :  * that there are substantial restrictions on the use of suspension --- see
      98                 :  * the documentation.
      99                 :  *
     100                 :  * When suspending, the decompressor will back up to a convenient restart point
     101                 :  * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
     102                 :  * indicate where the restart point will be if the current call returns FALSE.
     103                 :  * Data beyond this point must be rescanned after resumption, so move it to
     104                 :  * the front of the buffer rather than discarding it.
     105                 :  */
     106                 : 
     107                 : METHODDEF(boolean)
     108             757 : fill_input_buffer (j_decompress_ptr cinfo)
     109                 : {
     110             757 :   my_src_ptr src = (my_src_ptr) cinfo->src;
     111                 :   size_t nbytes;
     112                 : 
     113             757 :   nbytes = VSIFReadL(src->buffer, 1, INPUT_BUF_SIZE, src->infile);
     114                 : 
     115             757 :   if (nbytes <= 0) {
     116               0 :     if (src->start_of_file)  /* Treat empty input file as fatal error */
     117               0 :       ERREXIT(cinfo, JERR_INPUT_EMPTY);
     118               0 :     WARNMS(cinfo, JWRN_JPEG_EOF);
     119                 :     /* Insert a fake EOI marker */
     120               0 :     src->buffer[0] = (JOCTET) 0xFF;
     121               0 :     src->buffer[1] = (JOCTET) JPEG_EOI;
     122               0 :     nbytes = 2;
     123                 :   }
     124                 : 
     125             757 :   src->pub.next_input_byte = src->buffer;
     126             757 :   src->pub.bytes_in_buffer = nbytes;
     127             757 :   src->start_of_file = FALSE;
     128                 : 
     129             757 :   return TRUE;
     130                 : }
     131                 : 
     132                 : /* 
     133                 :  * The Intel IPP performance libraries do not necessarily read the 
     134                 :  * entire contents of the buffer with each pass, so each re-fill
     135                 :  * copies the remaining buffer bytes to the front of the buffer,
     136                 :  * then fills up the rest with new data.
     137                 :  */
     138                 : #ifdef IPPJ_HUFF
     139                 : METHODDEF(boolean)
     140                 : fill_input_buffer_ipp (j_decompress_ptr cinfo)
     141                 : {
     142                 :   my_src_ptr src = (my_src_ptr) cinfo->src;
     143                 :   size_t bytes_left = src->pub.bytes_in_buffer;
     144                 :   size_t bytes_to_read = INPUT_BUF_SIZE - bytes_left;
     145                 :   size_t nbytes;
     146                 : 
     147                 :   if(src->start_of_file || cinfo->progressive_mode)
     148                 :   {
     149                 :     return fill_input_buffer(cinfo);
     150                 :   }
     151                 : 
     152                 :   memmove(src->buffer,src->pub.next_input_byte,bytes_left);
     153                 : 
     154                 :   nbytes = VSIFReadL(src->buffer + bytes_left, 1, bytes_to_read, src->infile);
     155                 : 
     156                 :   if(nbytes <= 0)
     157                 :   {
     158                 :     if(src->start_of_file)
     159                 :     {
     160                 :       /* Treat empty input file as fatal error */
     161                 :       ERREXIT(cinfo, JERR_INPUT_EMPTY);
     162                 :     }
     163                 : 
     164                 :     if(src->pub.bytes_in_buffer == 0 && cinfo->unread_marker == 0)
     165                 :     {
     166                 :       WARNMS(cinfo, JWRN_JPEG_EOF);
     167                 : 
     168                 :       /* Insert a fake EOI marker */
     169                 :       src->buffer[0] = (JOCTET)0xFF;
     170                 :       src->buffer[1] = (JOCTET)JPEG_EOI;
     171                 :       nbytes = 2;
     172                 :     }
     173                 : 
     174                 :     src->pub.next_input_byte = src->buffer;
     175                 :     src->pub.bytes_in_buffer = bytes_left + nbytes;
     176                 :     src->start_of_file = FALSE;
     177                 : 
     178                 :     return TRUE;
     179                 :   }
     180                 : 
     181                 :   src->pub.next_input_byte = src->buffer;
     182                 :   src->pub.bytes_in_buffer = bytes_left + nbytes;
     183                 :   src->start_of_file = FALSE;
     184                 : 
     185                 :   return TRUE;
     186                 : }
     187                 : #endif /* IPPJ_HUFF */
     188                 : 
     189                 : 
     190                 : /*
     191                 :  * Skip data --- used to skip over a potentially large amount of
     192                 :  * uninteresting data (such as an APPn marker).
     193                 :  *
     194                 :  * Writers of suspendable-input applications must note that skip_input_data
     195                 :  * is not granted the right to give a suspension return.  If the skip extends
     196                 :  * beyond the data currently in the buffer, the buffer can be marked empty so
     197                 :  * that the next read will cause a fill_input_buffer call that can suspend.
     198                 :  * Arranging for additional bytes to be discarded before reloading the input
     199                 :  * buffer is the application writer's problem.
     200                 :  */
     201                 : 
     202                 : METHODDEF(void)
     203              31 : skip_input_data (j_decompress_ptr cinfo, long num_bytes)
     204                 : {
     205              31 :   my_src_ptr src = (my_src_ptr) cinfo->src;
     206                 : 
     207                 :   /* Just a dumb implementation for now.  Could use fseek() except
     208                 :    * it doesn't work on pipes.  Not clear that being smart is worth
     209                 :    * any trouble anyway --- large skips are infrequent.
     210                 :    */
     211              31 :   if (num_bytes > 0) {
     212              62 :     while (num_bytes > (long) src->pub.bytes_in_buffer) {
     213               0 :       num_bytes -= (long) src->pub.bytes_in_buffer;
     214               0 :       (void) fill_input_buffer(cinfo);
     215                 :       /* note we assume that fill_input_buffer will never return FALSE,
     216                 :        * so suspension need not be handled.
     217                 :        */
     218                 :     }
     219              31 :     src->pub.next_input_byte += (size_t) num_bytes;
     220              31 :     src->pub.bytes_in_buffer -= (size_t) num_bytes;
     221                 :   }
     222              31 : }
     223                 : 
     224                 : 
     225                 : /*
     226                 :  * An additional method that can be provided by data source modules is the
     227                 :  * resync_to_restart method for error recovery in the presence of RST markers.
     228                 :  * For the moment, this source module just uses the default resync method
     229                 :  * provided by the JPEG library.  That method assumes that no backtracking
     230                 :  * is possible.
     231                 :  */
     232                 : 
     233                 : 
     234                 : /*
     235                 :  * Terminate source --- called by jpeg_finish_decompress
     236                 :  * after all data has been read.  Often a no-op.
     237                 :  *
     238                 :  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
     239                 :  * application must deal with any cleanup that should happen even
     240                 :  * for error exit.
     241                 :  */
     242                 : 
     243                 : METHODDEF(void)
     244               0 : term_source (j_decompress_ptr cinfo)
     245                 : {
     246                 :   /* no work necessary here */
     247               0 : }
     248                 : 
     249                 : 
     250                 : /*
     251                 :  * Prepare for input from a stdio stream.
     252                 :  * The caller must have already opened the stream, and is responsible
     253                 :  * for closing it after finishing decompression.
     254                 :  */
     255                 : 
     256             120 : void jpeg_vsiio_src (j_decompress_ptr cinfo, FILE * infile)
     257                 : {
     258                 :   my_src_ptr src;
     259                 : 
     260                 :   /* The source object and input buffer are made permanent so that a series
     261                 :    * of JPEG images can be read from the same file by calling jpeg_stdio_src
     262                 :    * only before the first one.  (If we discarded the buffer at the end of
     263                 :    * one image, we'd likely lose the start of the next one.)
     264                 :    * This makes it unsafe to use this manager and a different source
     265                 :    * manager serially with the same JPEG object.  Caveat programmer.
     266                 :    */
     267             120 :   if (cinfo->src == NULL) {  /* first time for this JPEG object? */
     268                 :     cinfo->src = (struct jpeg_source_mgr *)
     269                 :       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
     270             120 :           sizeof(my_source_mgr));
     271             120 :     src = (my_src_ptr) cinfo->src;
     272                 :     src->buffer = (JOCTET *)
     273                 :       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
     274             120 :           INPUT_BUF_SIZE * sizeof(JOCTET));
     275                 :   }
     276                 : 
     277             120 :   src = (my_src_ptr) cinfo->src;
     278             120 :   src->pub.init_source = init_source;
     279                 : #ifdef IPPJ_HUFF
     280                 :   src->pub.fill_input_buffer = fill_input_buffer_ipp;
     281                 : #else
     282             120 :   src->pub.fill_input_buffer = fill_input_buffer;
     283                 : #endif
     284             120 :   src->pub.skip_input_data = skip_input_data;
     285             120 :   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
     286             120 :   src->pub.term_source = term_source;
     287             120 :   src->infile = infile;
     288             120 :   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
     289             120 :   src->pub.next_input_byte = NULL; /* until buffer loaded */
     290             120 : }
     291                 : 
     292                 : 
     293                 : /* ==================================================================== */
     294                 : /*      The rest was derived from jdatadst.c                            */
     295                 : /* ==================================================================== */
     296                 : 
     297                 : /* Expanded data destination object for stdio output */
     298                 : 
     299                 : typedef struct {
     300                 :   struct jpeg_destination_mgr pub; /* public fields */
     301                 : 
     302                 :   FILE * outfile;   /* target stream */
     303                 :   JOCTET * buffer;    /* start of buffer */
     304                 : } my_destination_mgr;
     305                 : 
     306                 : typedef my_destination_mgr * my_dest_ptr;
     307                 : 
     308                 : #define OUTPUT_BUF_SIZE  4096 /* choose an efficiently fwrite'able size */
     309                 : 
     310                 : 
     311                 : /*
     312                 :  * Initialize destination --- called by jpeg_start_compress
     313                 :  * before any data is actually written.
     314                 :  */
     315                 : 
     316                 : METHODDEF(void)
     317              18 : init_destination (j_compress_ptr cinfo)
     318                 : {
     319              18 :   my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
     320                 : 
     321                 :   /* Allocate the output buffer --- it will be released when done with image */
     322                 :   dest->buffer = (JOCTET *)
     323                 :       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
     324              18 :           OUTPUT_BUF_SIZE * sizeof(JOCTET));
     325                 : 
     326              18 :   dest->pub.next_output_byte = dest->buffer;
     327              18 :   dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
     328              18 : }
     329                 : 
     330                 : 
     331                 : /*
     332                 :  * Empty the output buffer --- called whenever buffer fills up.
     333                 :  *
     334                 :  * In typical applications, this should write the entire output buffer
     335                 :  * (ignoring the current state of next_output_byte & free_in_buffer),
     336                 :  * reset the pointer & count to the start of the buffer, and return TRUE
     337                 :  * indicating that the buffer has been dumped.
     338                 :  *
     339                 :  * In applications that need to be able to suspend compression due to output
     340                 :  * overrun, a FALSE return indicates that the buffer cannot be emptied now.
     341                 :  * In this situation, the compressor will return to its caller (possibly with
     342                 :  * an indication that it has not accepted all the supplied scanlines).  The
     343                 :  * application should resume compression after it has made more room in the
     344                 :  * output buffer.  Note that there are substantial restrictions on the use of
     345                 :  * suspension --- see the documentation.
     346                 :  *
     347                 :  * When suspending, the compressor will back up to a convenient restart point
     348                 :  * (typically the start of the current MCU). next_output_byte & free_in_buffer
     349                 :  * indicate where the restart point will be if the current call returns FALSE.
     350                 :  * Data beyond this point will be regenerated after resumption, so do not
     351                 :  * write it out when emptying the buffer externally.
     352                 :  */
     353                 : 
     354                 : METHODDEF(boolean)
     355               1 : empty_output_buffer (j_compress_ptr cinfo)
     356                 : {
     357               1 :   my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
     358               1 :   size_t bytes_to_write = OUTPUT_BUF_SIZE;
     359                 : 
     360                 : #ifdef IPPJ_HUFF
     361                 : /*
     362                 :  * The Intel IPP performance libraries do not necessarily fill up
     363                 :  * the whole output buffer with each compression pass, so we only
     364                 :  * want to write out the parts of the buffer that are full.
     365                 :  */
     366                 :   if(! cinfo->progressive_mode) {
     367                 :     bytes_to_write -= dest->pub.free_in_buffer;
     368                 :   }
     369                 : #endif
     370                 : 
     371               1 :   if (VSIFWriteL(dest->buffer, 1, bytes_to_write, dest->outfile) != bytes_to_write)
     372               0 :     ERREXIT(cinfo, JERR_FILE_WRITE);
     373                 : 
     374               1 :   dest->pub.next_output_byte = dest->buffer;
     375               1 :   dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
     376                 : 
     377               1 :   return TRUE;
     378                 : }
     379                 : 
     380                 : /*
     381                 :  * Terminate destination --- called by jpeg_finish_compress
     382                 :  * after all data has been written.  Usually needs to flush buffer.
     383                 :  *
     384                 :  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
     385                 :  * application must deal with any cleanup that should happen even
     386                 :  * for error exit.
     387                 :  */
     388                 : 
     389                 : METHODDEF(void)
     390              18 : term_destination (j_compress_ptr cinfo)
     391                 : {
     392              18 :   my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
     393              18 :   size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
     394                 : 
     395                 :   /* Write any data remaining in the buffer */
     396              18 :   if (datacount > 0) {
     397              18 :     if (VSIFWriteL(dest->buffer, 1, datacount, dest->outfile) != datacount)
     398               0 :       ERREXIT(cinfo, JERR_FILE_WRITE);
     399                 :   }
     400              18 :   if( VSIFFlushL(dest->outfile) != 0 )
     401               0 :     ERREXIT(cinfo, JERR_FILE_WRITE);
     402              18 : }
     403                 : 
     404                 : 
     405                 : /*
     406                 :  * Prepare for output to a stdio stream.
     407                 :  * The caller must have already opened the stream, and is responsible
     408                 :  * for closing it after finishing compression.
     409                 :  */
     410                 : 
     411                 : void
     412              18 : jpeg_vsiio_dest (j_compress_ptr cinfo, FILE * outfile)
     413                 : {
     414                 :   my_dest_ptr dest;
     415                 : 
     416                 :   /* The destination object is made permanent so that multiple JPEG images
     417                 :    * can be written to the same file without re-executing jpeg_stdio_dest.
     418                 :    * This makes it dangerous to use this manager and a different destination
     419                 :    * manager serially with the same JPEG object, because their private object
     420                 :    * sizes may be different.  Caveat programmer.
     421                 :    */
     422              18 :   if (cinfo->dest == NULL) { /* first time for this JPEG object? */
     423                 :     cinfo->dest = (struct jpeg_destination_mgr *)
     424                 :       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
     425              18 :           sizeof(my_destination_mgr));
     426                 :   }
     427                 : 
     428              18 :   dest = (my_dest_ptr) cinfo->dest;
     429              18 :   dest->pub.init_destination = init_destination;
     430              18 :   dest->pub.empty_output_buffer = empty_output_buffer;
     431              18 :   dest->pub.term_destination = term_destination;
     432              18 :   dest->outfile = outfile;
     433              18 : }

Generated by: LCOV version 1.7