LCOV - code coverage report
Current view: directory - frmts/pcidsk/sdk/channel - ctiledchannel.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 311 268 86.2 %
Date: 2012-12-26 Functions: 23 20 87.0 %

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Purpose:  Implementation of the CTiledChannel class.
       4                 :  *
       5                 :  * This class is used to implement band interleaved channels within a 
       6                 :  * PCIDSK file (which are always packed, and FILE interleaved data from
       7                 :  * external raw files which may not be packed. 
       8                 :  * 
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2009
      11                 :  * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
      12                 :  *
      13                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      14                 :  * copy of this software and associated documentation files (the "Software"),
      15                 :  * to deal in the Software without restriction, including without limitation
      16                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17                 :  * and/or sell copies of the Software, and to permit persons to whom the
      18                 :  * Software is furnished to do so, subject to the following conditions:
      19                 :  *
      20                 :  * The above copyright notice and this permission notice shall be included
      21                 :  * in all copies or substantial portions of the Software.
      22                 :  *
      23                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      24                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      26                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29                 :  * DEALINGS IN THE SOFTWARE.
      30                 :  ****************************************************************************/
      31                 : 
      32                 : #include "pcidsk_config.h"
      33                 : #include "pcidsk_types.h"
      34                 : #include "pcidsk_exception.h"
      35                 : #include "channel/ctiledchannel.h"
      36                 : #include "segment/sysblockmap.h"
      37                 : #include "core/sysvirtualfile.h"
      38                 : #include "core/cpcidskfile.h"
      39                 : #include "core/pcidsk_utils.h"
      40                 : #include <cassert>
      41                 : #include <cstdlib>
      42                 : #include <cstring>
      43                 : 
      44                 : using namespace PCIDSK;
      45                 : 
      46                 : /************************************************************************/
      47                 : /*                           CTiledChannel()                            */
      48                 : /************************************************************************/
      49                 : 
      50              14 : CTiledChannel::CTiledChannel( PCIDSKBuffer &image_header, 
      51                 :                               uint64 ih_offset,
      52                 :                               PCIDSKBuffer &file_header,
      53                 :                               int channelnum,
      54                 :                               CPCIDSKFile *file,
      55                 :                               eChanType pixel_type )
      56              14 :         : CPCIDSKChannel( image_header, ih_offset, file, pixel_type, channelnum)
      57                 : 
      58                 : {
      59                 : /* -------------------------------------------------------------------- */
      60                 : /*      Establish the virtual file we will be accessing.                */
      61                 : /* -------------------------------------------------------------------- */
      62              14 :     std::string filename;
      63                 : 
      64              14 :     image_header.Get(64,64,filename);
      65                 : 
      66              14 :     assert( strstr(filename.c_str(),"SIS=") != NULL );
      67                 : 
      68              14 :     image = atoi(strstr(filename.c_str(),"SIS=") + 4);
      69                 : 
      70              14 :     vfile = NULL;
      71                 : 
      72                 : /* -------------------------------------------------------------------- */
      73                 : /*      If this is an unassociated channel (ie. an overview), we        */
      74                 : /*      will set the size and blocksize values to something             */
      75                 : /*      unreasonable and set them properly in EstablishAccess()         */
      76                 : /* -------------------------------------------------------------------- */
      77              14 :     if( channelnum == -1 )
      78                 :     {
      79               5 :         width = -1;
      80               5 :         height = -1;
      81               5 :         block_width = -1;
      82               5 :         block_height = -1;
      83              14 :     }
      84              14 : }
      85                 : 
      86                 : /************************************************************************/
      87                 : /*                           ~CTiledChannel()                           */
      88                 : /************************************************************************/
      89                 : 
      90              14 : CTiledChannel::~CTiledChannel()
      91                 : 
      92                 : {
      93              14 :     Synchronize();
      94              14 : }
      95                 : 
      96                 : /************************************************************************/
      97                 : /*                          EstablishAccess()                           */
      98                 : /************************************************************************/
      99                 : 
     100             114 : void CTiledChannel::EstablishAccess() const
     101                 : 
     102                 : {
     103             114 :     if( vfile != NULL )
     104             100 :         return;
     105                 :     
     106                 : /* -------------------------------------------------------------------- */
     107                 : /*      Establish the virtual file to access this image.                */
     108                 : /* -------------------------------------------------------------------- */
     109                 :     SysBlockMap *bmap = dynamic_cast<SysBlockMap*>(
     110              14 :         file->GetSegment( SEG_SYS, "SysBMDir" ));
     111                 : 
     112              14 :     if( bmap == NULL )
     113               0 :         ThrowPCIDSKException( "Unable to find SysBMDir segment." );
     114                 : 
     115              14 :     vfile = bmap->GetVirtualFile( image );
     116                 : 
     117                 : /* -------------------------------------------------------------------- */
     118                 : /*      Parse the header.                                               */
     119                 : /* -------------------------------------------------------------------- */
     120              14 :     PCIDSKBuffer theader(128);
     121              14 :     std::string data_type;
     122                 : 
     123              14 :     vfile->ReadFromFile( theader.buffer, 0, 128 );
     124                 : 
     125              14 :     width = theader.GetInt(0,8);
     126              14 :     height = theader.GetInt(8,8);
     127              14 :     block_width = theader.GetInt(16,8);
     128              14 :     block_height = theader.GetInt(24,8);
     129                 : 
     130              14 :     theader.Get(32,4,data_type);
     131              14 :     theader.Get(54, 8, compression);
     132                 :     
     133              14 :     pixel_type = GetDataTypeFromName(data_type);
     134              14 :     if (pixel_type == CHN_UNKNOWN)
     135                 :     {
     136                 :         ThrowPCIDSKException( "Unknown channel type: %s", 
     137               0 :                               data_type.c_str() );
     138                 :     }
     139                 : 
     140                 : /* -------------------------------------------------------------------- */
     141                 : /*      Compute information on the tiles.                               */
     142                 : /* -------------------------------------------------------------------- */
     143              14 :     tiles_per_row = (width + block_width - 1) / block_width;
     144              14 :     tiles_per_col = (height + block_height - 1) / block_height;
     145              14 :     tile_count = tiles_per_row * tiles_per_col;
     146                 : 
     147                 : /* -------------------------------------------------------------------- */
     148                 : /*      Resize our tile info cache.                                     */
     149                 : /* -------------------------------------------------------------------- */
     150                 :     int tile_block_info_count = 
     151              14 :         (tile_count + tile_block_size - 1) / tile_block_size;
     152                 : 
     153              14 :     tile_offsets.resize( tile_block_info_count );
     154              14 :     tile_sizes.resize( tile_block_info_count );
     155              14 :     tile_info_dirty.resize( tile_block_info_count, false );
     156                 : 
     157                 : /* -------------------------------------------------------------------- */
     158                 : /*      Establish byte swapping.  Tiled data files are always big       */
     159                 : /*      endian, regardless of what the headers might imply.             */
     160                 : /* -------------------------------------------------------------------- */
     161              14 :     unsigned short test_value = 1;
     162                 :     
     163              14 :     if( ((uint8 *) &test_value)[0] == 1 )
     164              14 :         needs_swap = pixel_type != CHN_8U;
     165                 :     else
     166               0 :         needs_swap = false;
     167                 : }
     168                 : 
     169                 : /************************************************************************/
     170                 : /*                         LoadTileInfoBlock()                          */
     171                 : /************************************************************************/
     172                 : 
     173               8 : void CTiledChannel::LoadTileInfoBlock( int block )
     174                 : 
     175                 : {
     176               8 :     assert( tile_offsets[block].size() == 0 );
     177                 : 
     178                 : /* -------------------------------------------------------------------- */
     179                 : /*      How many tiles in this block?                                   */
     180                 : /* -------------------------------------------------------------------- */
     181               8 :     int tiles_in_block = tile_block_size;
     182                 : 
     183               8 :     if( block * tile_block_size + tiles_in_block > tile_count )
     184               8 :         tiles_in_block = tile_count - block * tile_block_size;
     185                 : 
     186                 : /* -------------------------------------------------------------------- */
     187                 : /*      Resize the vectors for this block.                              */
     188                 : /* -------------------------------------------------------------------- */
     189               8 :     tile_offsets[block].resize( tiles_in_block );
     190               8 :     tile_sizes[block].resize( tiles_in_block );
     191                 : 
     192                 : /* -------------------------------------------------------------------- */
     193                 : /*      Read the offset and size data from disk.                        */
     194                 : /* -------------------------------------------------------------------- */
     195               8 :     PCIDSKBuffer offset_map( tiles_in_block * 12 + 1 );
     196               8 :     PCIDSKBuffer size_map( tiles_in_block * 8 + 1 );
     197                 : 
     198                 :     vfile->ReadFromFile( offset_map.buffer, 
     199                 :                          128 + block * tile_block_size * 12, 
     200               8 :                          tiles_in_block * 12 );
     201                 :     vfile->ReadFromFile( size_map.buffer, 
     202                 :                          128 + tile_count * 12 + block * tile_block_size * 8,
     203               8 :                          tiles_in_block * 8 );
     204                 :     
     205              16 :     for( int i = 0; i < tiles_in_block; i++ )
     206                 :     {
     207                 :         char chSaved;
     208               8 :         char *target = offset_map.buffer + i*12;
     209                 : 
     210               8 :         chSaved = target[12];
     211               8 :         target[12] = '\0';
     212               8 :         tile_offsets[block][i] = atouint64(target);
     213               8 :         target[12] = chSaved;
     214                 : 
     215               8 :         target = size_map.buffer + i*8;
     216               8 :         chSaved = target[8];
     217               8 :         target[8] = '\0';
     218               8 :         tile_sizes[block][i] = atoi(target);
     219               8 :         target[8] = chSaved;
     220               8 :     }
     221               8 : }
     222                 : 
     223                 : /************************************************************************/
     224                 : /*                         SaveTileInfoBlock()                          */
     225                 : /************************************************************************/
     226                 : 
     227               4 : void CTiledChannel::SaveTileInfoBlock( int block )
     228                 : 
     229                 : {
     230               4 :     assert( tile_offsets[block].size() != 0 );
     231               4 :     int tiles_in_block = tile_offsets[block].size();
     232                 : 
     233                 : /* -------------------------------------------------------------------- */
     234                 : /*      Write the offset and size data to disk.                         */
     235                 : /* -------------------------------------------------------------------- */
     236               4 :     PCIDSKBuffer offset_map( tiles_in_block * 12 + 1 );
     237               4 :     PCIDSKBuffer size_map( tiles_in_block * 8 + 1 );
     238                 : 
     239               8 :     for( int i = 0; i < tiles_in_block; i++ )
     240                 :     {
     241               4 :         if( tile_offsets[block][i] == (uint64) -1 
     242                 :             || tile_offsets[block][i] == 0 )
     243               0 :             offset_map.Put( -1, i*12, 12 );
     244                 :         else
     245               4 :             offset_map.Put( tile_offsets[block][i], i*12, 12 );
     246                 : 
     247               4 :         size_map.Put( tile_sizes[block][i], i*8, 8 );
     248                 :     }
     249                 : 
     250                 :     vfile->WriteToFile( offset_map.buffer, 
     251                 :                         128 + block * tile_block_size * 12, 
     252               4 :                         tiles_in_block * 12 );
     253                 :     vfile->WriteToFile( size_map.buffer, 
     254                 :                         128 + tile_count * 12 + block * tile_block_size * 8,
     255               4 :                         tiles_in_block * 8 );
     256                 : 
     257               4 :     tile_info_dirty[block] = false;
     258               4 : }
     259                 : 
     260                 : /************************************************************************/
     261                 : /*                            GetTileInfo()                             */
     262                 : /*                                                                      */
     263                 : /*      Fetch the tile offset and size for the indicated tile.          */
     264                 : /************************************************************************/
     265                 : 
     266              13 : void CTiledChannel::GetTileInfo( int tile_index, uint64 &offset, int &size )
     267                 : 
     268                 : {
     269              13 :     int block = tile_index / tile_block_size;
     270              13 :     int index_within_block = tile_index - block * tile_block_size;
     271                 : 
     272              13 :     if( tile_offsets[block].size() == 0 )
     273               8 :         LoadTileInfoBlock( block );
     274                 : 
     275              13 :     offset = tile_offsets[block][index_within_block];
     276              13 :     size = tile_sizes[block][index_within_block];
     277              13 : }
     278                 : 
     279                 : /************************************************************************/
     280                 : /*                            SetTileInfo()                             */
     281                 : /************************************************************************/
     282                 : 
     283               4 : void CTiledChannel::SetTileInfo( int tile_index, uint64 offset, int size )
     284                 : 
     285                 : {
     286               4 :     int block = tile_index / tile_block_size;
     287               4 :     int index_within_block = tile_index - block * tile_block_size;
     288                 : 
     289               4 :     if( tile_offsets[block].size() == 0 )
     290               0 :         LoadTileInfoBlock( block );
     291                 : 
     292               4 :     if( offset != tile_offsets[block][index_within_block]
     293                 :         || size != tile_sizes[block][index_within_block] )
     294                 :     {
     295               4 :         tile_offsets[block][index_within_block] = offset;
     296               4 :         tile_sizes[block][index_within_block] = size;
     297                 :         
     298               4 :         tile_info_dirty[block] = true;
     299                 :     }
     300               4 : }
     301                 : 
     302                 : /************************************************************************/
     303                 : /*                            Synchronize()                             */
     304                 : /*                                                                      */
     305                 : /*      Flush updated blockmap to disk if it is dirty.                  */
     306                 : /************************************************************************/
     307                 : 
     308              20 : void CTiledChannel::Synchronize()
     309                 : 
     310                 : {
     311              20 :     if( tile_info_dirty.size() == 0 )
     312               0 :         return;
     313                 : 
     314                 :     int i;
     315                 : 
     316              40 :     for( i = 0; i < (int) tile_info_dirty.size(); i++ )
     317                 :     {
     318              20 :         if( tile_info_dirty[i] )
     319               4 :             SaveTileInfoBlock( i );
     320                 :     }
     321                 : 
     322              20 :     vfile->Synchronize();
     323                 : }
     324                 : 
     325                 : /************************************************************************/
     326                 : /*                             ReadBlock()                              */
     327                 : /************************************************************************/
     328                 : 
     329               9 : int CTiledChannel::ReadBlock( int block_index, void *buffer,
     330                 :                               int xoff, int yoff, 
     331                 :                               int xsize, int ysize )
     332                 : 
     333                 : {
     334               9 :     int pixel_size = DataTypeSize(GetType());
     335                 : 
     336                 : /* -------------------------------------------------------------------- */
     337                 : /*      Default window if needed.                                       */
     338                 : /* -------------------------------------------------------------------- */
     339               9 :     if( xoff == -1 && yoff == -1 && xsize == -1 && ysize == -1 )
     340                 :     {
     341               9 :         xoff = 0;
     342               9 :         yoff = 0;
     343               9 :         xsize = GetBlockWidth();
     344               9 :         ysize = GetBlockHeight();
     345                 :     }
     346                 : 
     347                 : /* -------------------------------------------------------------------- */
     348                 : /*      Validate Window                                                 */
     349                 : /* -------------------------------------------------------------------- */
     350              18 :     if( xoff < 0 || xoff + xsize > GetBlockWidth()
     351               9 :         || yoff < 0 || yoff + ysize > GetBlockHeight() )
     352                 :     {
     353                 :         ThrowPCIDSKException( 
     354                 :             "Invalid window in ReadBloc(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
     355               0 :             xoff, yoff, xsize, ysize );
     356                 :     }
     357                 : 
     358               9 :     if( block_index < 0 || block_index >= tile_count )
     359                 :     {
     360                 :         ThrowPCIDSKException( "Requested non-existant block (%d)", 
     361               0 :                               block_index );
     362                 :     }
     363                 : 
     364                 : /* -------------------------------------------------------------------- */
     365                 : /*      Does this tile exist?  If not return a zeroed buffer.           */
     366                 : /* -------------------------------------------------------------------- */
     367                 :     uint64 tile_offset;
     368                 :     int    tile_size;
     369                 : 
     370               9 :     GetTileInfo( block_index, tile_offset, tile_size );
     371                 : 
     372               9 :     if( tile_size == 0 )
     373                 :     {
     374               4 :         memset( buffer, 0, GetBlockWidth() * GetBlockHeight() * pixel_size );
     375               4 :         return 1;
     376                 :     }
     377                 : 
     378                 : /* -------------------------------------------------------------------- */
     379                 : /*      The simpliest case it an uncompressed direct and complete       */
     380                 : /*      tile read into the destination buffer.                          */
     381                 : /* -------------------------------------------------------------------- */
     382              10 :     if( xoff == 0 && xsize == GetBlockWidth() 
     383               5 :         && yoff == 0 && ysize == GetBlockHeight() 
     384                 :         && tile_size == xsize * ysize * pixel_size 
     385                 :         && compression == "NONE" )
     386                 :     {
     387               3 :         vfile->ReadFromFile( buffer, tile_offset, tile_size );
     388                 : 
     389                 :         // Do byte swapping if needed.
     390               3 :         if( needs_swap )
     391               1 :             SwapPixels( buffer, pixel_type, xsize * ysize );
     392                 : 
     393               3 :         return 1;
     394                 :     }
     395                 : 
     396                 : /* -------------------------------------------------------------------- */
     397                 : /*      Load uncompressed data, one scanline at a time, into the        */
     398                 : /*      target buffer.                                                  */
     399                 : /* -------------------------------------------------------------------- */
     400               2 :     if( compression == "NONE" )
     401                 :     {
     402                 :         int iy;
     403                 : 
     404               0 :         for( iy = 0; iy < ysize; iy++ )
     405                 :         {
     406                 :             vfile->ReadFromFile( ((uint8 *) buffer) 
     407                 :                                  + iy * xsize * pixel_size,
     408                 :                                  tile_offset 
     409                 :                                  + ((iy+yoff)*block_width + xoff) * pixel_size,
     410               0 :                                  xsize * pixel_size );
     411                 :         }
     412                 :         
     413                 :         // Do byte swapping if needed.
     414               0 :         if( needs_swap )
     415               0 :             SwapPixels( buffer, pixel_type, xsize * ysize );
     416                 :         
     417               0 :         return 1;
     418                 :     }
     419                 : 
     420                 : /* -------------------------------------------------------------------- */
     421                 : /*      Load the whole compressed data into a working buffer.           */
     422                 : /* -------------------------------------------------------------------- */
     423               2 :     PCIDSKBuffer oCompressedData( tile_size );
     424               2 :     PCIDSKBuffer oUncompressedData( pixel_size * block_width * block_height );
     425                 : 
     426               2 :     vfile->ReadFromFile( oCompressedData.buffer, tile_offset, tile_size );
     427                 :     
     428                 : /* -------------------------------------------------------------------- */
     429                 : /*      Handle decompression.                                           */
     430                 : /* -------------------------------------------------------------------- */
     431               2 :     if( compression == "RLE" )
     432                 :     {
     433               1 :         RLEDecompressBlock( oCompressedData, oUncompressedData );
     434                 :     }
     435               1 :     else if( strncmp(compression.c_str(),"JPEG",4) == 0 )
     436                 :     {
     437               1 :         JPEGDecompressBlock( oCompressedData, oUncompressedData );
     438                 :     }
     439                 :     else
     440                 :     {
     441                 :         ThrowPCIDSKException( 
     442                 :             "Unable to read tile of unsupported compression type: %s",
     443               0 :             compression.c_str() );
     444                 :     }
     445                 : 
     446                 : /* -------------------------------------------------------------------- */
     447                 : /*      Swap if necessary.  TODO: there is some reason to doubt that    */
     448                 : /*      the old implementation properly byte swapped compressed         */
     449                 : /*      data.  Perhaps this should be conditional?                      */
     450                 : /* -------------------------------------------------------------------- */
     451               2 :     if( needs_swap )
     452                 :         SwapPixels( oUncompressedData.buffer, pixel_type, 
     453               1 :                   GetBlockWidth() * GetBlockHeight() );
     454                 : 
     455                 : /* -------------------------------------------------------------------- */
     456                 : /*      Copy out the desired subwindow.                                 */
     457                 : /* -------------------------------------------------------------------- */
     458                 :     int iy;
     459                 :     
     460             161 :     for( iy = 0; iy < ysize; iy++ )
     461                 :     {
     462                 :         memcpy( ((uint8 *) buffer) + iy * xsize * pixel_size,
     463                 :                 oUncompressedData.buffer 
     464                 :                 + ((iy+yoff)*block_width + xoff) * pixel_size,
     465             159 :                 xsize * pixel_size );
     466                 :     }
     467                 : 
     468               2 :     return 1;
     469                 : }
     470                 : 
     471                 : /************************************************************************/
     472                 : /*                            IsTileEmpty()                             */
     473                 : /************************************************************************/
     474               4 : bool CTiledChannel::IsTileEmpty(void *buffer) const
     475                 : {
     476                 :     assert(sizeof(int32) == 4); // just to be on the safe side...
     477                 : 
     478                 :     unsigned int num_dword = 
     479               4 :         (block_width * block_height * DataTypeSize(pixel_type)) / 4;
     480                 :     unsigned int rem = 
     481               4 :         (block_width * block_height * DataTypeSize(pixel_type)) % 4;
     482                 : 
     483               4 :     int32* int_buf = reinterpret_cast<int32*>(buffer);
     484                 : 
     485               4 :     if (num_dword > 0) {
     486             182 :         for (unsigned int n = 0; n < num_dword; n++) {
     487             182 :             if (int_buf[n]) return false;
     488                 :         }
     489                 :     }
     490                 : 
     491               0 :     char* char_buf = reinterpret_cast<char*>(int_buf + num_dword);
     492               0 :     if (rem > 0) {
     493               0 :         for (unsigned int n = 0; n < rem; n++) {
     494               0 :             if (char_buf[n]) return false;
     495                 :         }
     496                 :     }
     497                 : 
     498               0 :     return true;
     499                 : }
     500                 : 
     501                 : /************************************************************************/
     502                 : /*                             WriteBlock()                             */
     503                 : /************************************************************************/
     504                 : 
     505               4 : int CTiledChannel::WriteBlock( int block_index, void *buffer )
     506                 : 
     507                 : {
     508               4 :     if( !file->GetUpdatable() )
     509               0 :         throw PCIDSKException( "File not open for update in WriteBlock()" );
     510                 : 
     511               4 :     InvalidateOverviews();
     512                 : 
     513               4 :     int pixel_size = DataTypeSize(GetType());
     514               4 :     int pixel_count = GetBlockWidth() * GetBlockHeight();
     515                 : 
     516               4 :     if( block_index < 0 || block_index >= tile_count )
     517                 :     {
     518                 :         ThrowPCIDSKException( "Requested non-existant block (%d)", 
     519               0 :                               block_index );
     520                 :     }
     521                 : 
     522                 : /* -------------------------------------------------------------------- */
     523                 : /*      Fetch existing tile offset and size.                            */
     524                 : /* -------------------------------------------------------------------- */
     525                 :     uint64 tile_offset;
     526                 :     int    tile_size;
     527                 : 
     528               4 :     GetTileInfo( block_index, tile_offset, tile_size );
     529                 : 
     530                 : /* -------------------------------------------------------------------- */
     531                 : /*      The simpliest case it an uncompressed direct and complete       */
     532                 : /*      tile read into the destination buffer.                          */
     533                 : /* -------------------------------------------------------------------- */
     534               4 :     if( compression == "NONE" 
     535                 :         && tile_size == pixel_count * pixel_size )
     536                 :     {
     537                 :         // Do byte swapping if needed.
     538               0 :         if( needs_swap )
     539               0 :             SwapPixels( buffer, pixel_type, pixel_count );
     540                 : 
     541               0 :         vfile->WriteToFile( buffer, tile_offset, tile_size );
     542                 : 
     543               0 :         if( needs_swap )
     544               0 :             SwapPixels( buffer, pixel_type, pixel_count );
     545                 : 
     546               0 :         return 1;
     547                 :     }
     548                 : 
     549               4 :     if ((int64)tile_offset == -1)
     550                 :     {
     551                 :         // Check if the tile is empty. If it is, we can skip writing it,
     552                 :         // unless the tile is already dirty.
     553               4 :         bool is_empty = IsTileEmpty(buffer);
     554                 : 
     555               4 :         if (is_empty) return 1; // we don't need to do anything else
     556                 :     }
     557                 : 
     558                 : /* -------------------------------------------------------------------- */
     559                 : /*      Copy the uncompressed data into a PCIDSKBuffer, and byte        */
     560                 : /*      swap if needed.                                                 */
     561                 : /* -------------------------------------------------------------------- */
     562               4 :     PCIDSKBuffer oUncompressedData( pixel_size * block_width * block_height );
     563                 : 
     564                 :     memcpy( oUncompressedData.buffer, buffer, 
     565               4 :             oUncompressedData.buffer_size );
     566                 : 
     567               4 :     if( needs_swap )
     568               2 :         SwapPixels( oUncompressedData.buffer, pixel_type, pixel_count );
     569                 : 
     570                 : /* -------------------------------------------------------------------- */
     571                 : /*      Compress the imagery.                                           */
     572                 : /* -------------------------------------------------------------------- */
     573               4 :     PCIDSKBuffer oCompressedData;
     574                 : 
     575               4 :     if( compression == "NONE" )
     576                 :     {
     577               2 :         oCompressedData = oUncompressedData;
     578                 :     }
     579               2 :     else if( compression == "RLE" )
     580                 :     {
     581               1 :         RLECompressBlock( oUncompressedData, oCompressedData );
     582                 :     }
     583               1 :     else if( strncmp(compression.c_str(),"JPEG",4) == 0 )
     584                 :     {
     585               1 :         JPEGCompressBlock( oUncompressedData, oCompressedData );
     586                 :     }
     587                 :     else
     588                 :     {
     589                 :         ThrowPCIDSKException( 
     590                 :             "Unable to write tile of unsupported compression type: %s",
     591               0 :             compression.c_str() );
     592                 :     }
     593                 : 
     594                 : /* -------------------------------------------------------------------- */
     595                 : /*      If this fits in the existing space, just write it directly.     */
     596                 : /* -------------------------------------------------------------------- */
     597               4 :     if( oCompressedData.buffer_size <= tile_size )
     598                 :     {
     599               0 :         vfile->WriteToFile( oCompressedData.buffer, tile_offset, tile_size );
     600                 : 
     601               0 :         tile_size = oCompressedData.buffer_size;
     602               0 :         SetTileInfo( block_index, tile_offset, tile_size );
     603                 :     }
     604                 : 
     605                 : /* -------------------------------------------------------------------- */
     606                 : /*      Otherwise we try and write it at the end of the virtual file.   */
     607                 : /* -------------------------------------------------------------------- */
     608                 :     else
     609                 :     {
     610               4 :         uint64 new_offset = vfile->GetLength();
     611                 :         
     612                 :         vfile->WriteToFile( oCompressedData.buffer, 
     613               4 :                             new_offset, oCompressedData.buffer_size );
     614                 : 
     615               4 :         SetTileInfo( block_index, new_offset, oCompressedData.buffer_size );
     616                 :     }
     617                 : 
     618               4 :     return 1;
     619                 : }
     620                 : 
     621                 : /************************************************************************/
     622                 : /*                           GetBlockWidth()                            */
     623                 : /************************************************************************/
     624                 : 
     625              57 : int CTiledChannel::GetBlockWidth() const
     626                 : 
     627                 : {
     628              57 :     EstablishAccess();
     629              57 :     return CPCIDSKChannel::GetBlockWidth();
     630                 : }
     631                 : 
     632                 : /************************************************************************/
     633                 : /*                           GetBlockHeight()                           */
     634                 : /************************************************************************/
     635                 : 
     636              57 : int CTiledChannel::GetBlockHeight() const
     637                 : 
     638                 : {
     639              57 :     EstablishAccess();
     640              57 :     return CPCIDSKChannel::GetBlockHeight();
     641                 : }
     642                 : 
     643                 : /************************************************************************/
     644                 : /*                              GetWidth()                              */
     645                 : /************************************************************************/
     646                 : 
     647               5 : int CTiledChannel::GetWidth() const
     648                 : 
     649                 : {
     650               5 :     if( width == -1 )
     651               0 :         EstablishAccess();
     652                 : 
     653               5 :     return CPCIDSKChannel::GetWidth();
     654                 : }
     655                 : 
     656                 : /************************************************************************/
     657                 : /*                             GetHeight()                              */
     658                 : /************************************************************************/
     659                 : 
     660               5 : int CTiledChannel::GetHeight() const
     661                 : 
     662                 : {
     663               5 :     if( height == -1 )
     664               0 :         EstablishAccess();
     665                 : 
     666               5 :     return CPCIDSKChannel::GetHeight();
     667                 : }
     668                 : 
     669                 : /************************************************************************/
     670                 : /*                              GetType()                               */
     671                 : /************************************************************************/
     672                 : 
     673              45 : eChanType CTiledChannel::GetType() const
     674                 : 
     675                 : {
     676              45 :     if( pixel_type == CHN_UNKNOWN )
     677               0 :         EstablishAccess();
     678                 : 
     679              45 :     return CPCIDSKChannel::GetType();
     680                 : }
     681                 : 
     682                 : /************************************************************************/
     683                 : /*                         RLEDecompressBlock()                         */
     684                 : /************************************************************************/
     685                 : 
     686               1 : void CTiledChannel::RLEDecompressBlock( PCIDSKBuffer &oCompressedData,
     687                 :                                         PCIDSKBuffer &oDecompressedData )
     688                 : 
     689                 :                                
     690                 : {
     691               1 :     int    src_offset=0, dst_offset=0;
     692               1 :     uint8  *src = (uint8 *) oCompressedData.buffer;
     693               1 :     uint8  *dst = (uint8 *) oDecompressedData.buffer;
     694               1 :     int    pixel_size = DataTypeSize(GetType());
     695                 : 
     696                 : /* -------------------------------------------------------------------- */
     697                 : /*      Process till we are out of source data, or our destination      */
     698                 : /*      buffer is full.  These conditions should be satisified at       */
     699                 : /*      the same time!                                                  */
     700                 : /* -------------------------------------------------------------------- */
     701              11 :     while( src_offset + 1 + pixel_size <= oCompressedData.buffer_size
     702                 :            && dst_offset < oDecompressedData.buffer_size )
     703                 :     {
     704                 : /* -------------------------------------------------------------------- */
     705                 : /*      Extract a repeat run                                            */
     706                 : /* -------------------------------------------------------------------- */
     707               9 :         if( src[src_offset] > 127 )
     708                 :         {
     709               5 :             int count = src[src_offset++] - 128;
     710                 :             int i;
     711                 : 
     712               5 :             if( dst_offset + count * pixel_size > oDecompressedData.buffer_size)
     713                 :             {
     714               0 :                 ThrowPCIDSKException( "RLE compressed tile corrupt, overrun avoided." );
     715                 :             }
     716                 : 
     717             526 :             while( count-- > 0 )
     718                 :             {
     719            1548 :                 for( i = 0; i < pixel_size; i++ )
     720            1032 :                     dst[dst_offset++] = src[src_offset+i];
     721                 :             }
     722               5 :             src_offset += pixel_size;
     723                 :         }
     724                 : 
     725                 : /* -------------------------------------------------------------------- */
     726                 : /*      Extract a literal run.                                          */
     727                 : /* -------------------------------------------------------------------- */
     728                 :         else 
     729                 :         {
     730               4 :             int count = src[src_offset++];
     731                 : 
     732               4 :             if( dst_offset + count*pixel_size > oDecompressedData.buffer_size
     733                 :                 || src_offset + count*pixel_size > oCompressedData.buffer_size)
     734                 :             {
     735               0 :                 ThrowPCIDSKException( "RLE compressed tile corrupt, overrun avoided." );
     736                 :             }
     737                 : 
     738                 :             memcpy( dst + dst_offset, src + src_offset, 
     739               4 :                     pixel_size * count );
     740               4 :             src_offset += pixel_size * count;
     741               4 :             dst_offset += pixel_size * count;
     742                 :         }
     743                 : 
     744                 :     }
     745                 : 
     746                 : /* -------------------------------------------------------------------- */
     747                 : /*      Final validation.                                               */
     748                 : /* -------------------------------------------------------------------- */
     749               1 :     if( src_offset != oCompressedData.buffer_size 
     750                 :         || dst_offset != oDecompressedData.buffer_size ) 
     751                 :     {
     752               0 :         ThrowPCIDSKException( "RLE compressed tile corrupt, result incomplete." );
     753                 :     }
     754               1 : }
     755                 : 
     756                 : /************************************************************************/
     757                 : /*                         RLECompressBlock()                           */
     758                 : /*                                                                      */
     759                 : /*      TODO: There does not seem to be any byte order logic in here!   */
     760                 : /************************************************************************/
     761                 : 
     762               1 : void CTiledChannel::RLECompressBlock( PCIDSKBuffer &oUncompressedData,
     763                 :                                       PCIDSKBuffer &oCompressedData )
     764                 : 
     765                 :                                
     766                 : {
     767               1 :     int    src_bytes = oUncompressedData.buffer_size;
     768               1 :     int    pixel_size = DataTypeSize(GetType());
     769               1 :     int    src_offset = 0, dst_offset = 0;
     770                 :     int    i;
     771               1 :     uint8  *src = (uint8 *) oUncompressedData.buffer;
     772                 : 
     773                 : /* -------------------------------------------------------------------- */
     774                 : /*      Loop till input exausted.                                       */
     775                 : /* -------------------------------------------------------------------- */
     776              11 :     while( src_offset < src_bytes )
     777                 :     {
     778               9 :         bool  bGotARun = false;
     779                 :         
     780                 : /* -------------------------------------------------------------------- */
     781                 : /*  Establish the run length, and emit if greater than 3.     */
     782                 : /* -------------------------------------------------------------------- */
     783               9 :         if( src_offset + 3*pixel_size < src_bytes )
     784                 :         {
     785               9 :             int   count = 1;
     786                 : 
     787             529 :             while( count < 127
     788                 :                    && src_offset + count*pixel_size < src_bytes )
     789                 :             {
     790             516 :                 bool  bWordMatch = true;
     791                 : 
     792            1548 :                 for( i = 0; i < pixel_size; i++ )
     793                 :                 {
     794            2064 :                     if( src[src_offset+i] 
     795            1032 :                         != src[src_offset+i+count*pixel_size] )
     796               8 :                         bWordMatch = false;
     797                 :                 }
     798                 : 
     799             516 :                 if( !bWordMatch )
     800               5 :                     break;
     801                 : 
     802             511 :                 count++;
     803                 :             }
     804                 : 
     805               9 :             if( count >= 3 )
     806                 :             {
     807               5 :                 if( oCompressedData.buffer_size < dst_offset + pixel_size+1 )
     808               1 :                     oCompressedData.SetSize( oCompressedData.buffer_size*2+100);
     809                 : 
     810               5 :                 oCompressedData.buffer[dst_offset++] = (char) (count+128);
     811                 : 
     812              15 :                 for( i = 0; i < pixel_size; i++ )
     813              10 :                     oCompressedData.buffer[dst_offset++] = src[src_offset+i];
     814                 : 
     815               5 :                 src_offset += count * pixel_size;
     816                 : 
     817               5 :                 bGotARun = true;
     818                 :             }
     819                 :             else
     820               4 :                 bGotARun = false;
     821                 :         }
     822                 :         
     823                 : /* -------------------------------------------------------------------- */
     824                 : /*      Otherwise emit a literal till we encounter at least a three */
     825                 : /*  word series.              */
     826                 : /* -------------------------------------------------------------------- */
     827               9 :         if( !bGotARun )
     828                 :         {
     829               4 :             int   count = 1;
     830               4 :             int   match_count = 0;
     831                 : 
     832             512 :             while( count < 127
     833                 :                    && src_offset + count*pixel_size < src_bytes )
     834                 :             {
     835             504 :                 bool  bWordMatch = true;
     836                 : 
     837            1512 :                 for( i = 0; i < pixel_size; i++ )
     838                 :                 {
     839            2016 :                     if( src[src_offset+i]
     840            1008 :                         != src[src_offset+i+count*pixel_size] )
     841             724 :                         bWordMatch = false;
     842                 :                 }
     843                 : 
     844             504 :                 if( bWordMatch )
     845               0 :                     match_count++;
     846                 :                 else
     847             504 :                     match_count = 0;
     848                 : 
     849             504 :                 if( match_count > 2 )
     850               0 :                     break;
     851                 : 
     852             504 :                 count++;
     853                 :             }
     854                 :             
     855               4 :             assert( src_offset + count*pixel_size <= src_bytes );
     856                 : 
     857              11 :             while( oCompressedData.buffer_size 
     858                 :                    < dst_offset + count*pixel_size+1 )
     859               3 :                 oCompressedData.SetSize( oCompressedData.buffer_size*2+100 );
     860                 : 
     861               4 :             oCompressedData.buffer[dst_offset++] = (char) count;
     862                 :             memcpy( oCompressedData.buffer + dst_offset, 
     863                 :                     src + src_offset, 
     864               4 :                     count * pixel_size );
     865               4 :             src_offset += count * pixel_size;
     866               4 :             dst_offset += count * pixel_size;
     867                 :         }
     868                 :     }
     869                 : 
     870               1 :     oCompressedData.buffer_size = dst_offset;
     871               1 : }
     872                 : 
     873                 : /************************************************************************/
     874                 : /*                        JPEGDecompressBlock()                         */
     875                 : /************************************************************************/
     876                 : 
     877               1 : void CTiledChannel::JPEGDecompressBlock( PCIDSKBuffer &oCompressedData,
     878                 :                                          PCIDSKBuffer &oDecompressedData )
     879                 : 
     880                 :                                
     881                 : {
     882               1 :     if( file->GetInterfaces()->JPEGDecompressBlock == NULL )
     883               0 :         ThrowPCIDSKException( "JPEG decompression not enabled in the PCIDSKInterfaces of this build." );
     884                 : 
     885               1 :     file->GetInterfaces()->JPEGDecompressBlock( 
     886                 :         (uint8 *) oCompressedData.buffer, oCompressedData.buffer_size,
     887                 :         (uint8 *) oDecompressedData.buffer, oDecompressedData.buffer_size,
     888               2 :         GetBlockWidth(), GetBlockHeight(), GetType() );
     889               1 : }
     890                 : 
     891                 : /************************************************************************/
     892                 : /*                         JPEGCompressBlock()                          */
     893                 : /************************************************************************/
     894                 : 
     895               1 : void CTiledChannel::JPEGCompressBlock( PCIDSKBuffer &oDecompressedData,
     896                 :                                        PCIDSKBuffer &oCompressedData )
     897                 :                                        
     898                 : 
     899                 :                                
     900                 : {
     901               1 :     if( file->GetInterfaces()->JPEGCompressBlock == NULL )
     902               0 :         ThrowPCIDSKException( "JPEG compression not enabled in the PCIDSKInterfaces of this build." );
     903                 : 
     904                 : /* -------------------------------------------------------------------- */
     905                 : /*      What quality should we be using?                                */
     906                 : /* -------------------------------------------------------------------- */
     907               1 :     int quality = 75;
     908                 : 
     909               1 :     if( compression.c_str()[4] >= '1' 
     910               0 :         && compression.c_str()[4] <= '0' )
     911               0 :         quality = atoi(compression.c_str() + 4);
     912                 : 
     913                 : /* -------------------------------------------------------------------- */
     914                 : /*      Make the output buffer plent big to hold any conceivable        */
     915                 : /*      result.                                                         */
     916                 : /* -------------------------------------------------------------------- */
     917               1 :     oCompressedData.SetSize( oDecompressedData.buffer_size * 2 + 1000 );
     918                 : 
     919                 : /* -------------------------------------------------------------------- */
     920                 : /*      invoke.                                                         */
     921                 : /* -------------------------------------------------------------------- */
     922               1 :     file->GetInterfaces()->JPEGCompressBlock( 
     923                 :         (uint8 *) oDecompressedData.buffer, oDecompressedData.buffer_size,
     924                 :         (uint8 *) oCompressedData.buffer, oCompressedData.buffer_size,
     925               2 :         GetBlockWidth(), GetBlockHeight(), GetType(), 75 );
     926               1 : }
     927                 : 

Generated by: LCOV version 1.7