LCOV - code coverage report
Current view: directory - frmts/jpeg - vsidataio.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 76 65 85.5 %
Date: 2012-04-28 Functions: 9 9 100.0 %

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

Generated by: LCOV version 1.7