LCOV - code coverage report
Current view: directory - frmts/pcidsk/sdk/channel - cbandinterleavedchannel.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 146 100 68.5 %
Date: 2012-12-26 Functions: 10 7 70.0 %

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Purpose:  Implementation of the CBandInterleavedChannel 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_channel.h"
      35                 : #include "pcidsk_buffer.h"
      36                 : #include "pcidsk_exception.h"
      37                 : #include "pcidsk_file.h"
      38                 : #include "core/pcidsk_utils.h"
      39                 : #include "core/cpcidskfile.h"
      40                 : #include "core/clinksegment.h"
      41                 : #include "channel/cbandinterleavedchannel.h"
      42                 : #include <cassert>
      43                 : #include <cstring>
      44                 : #include <cstdio>
      45                 : #include <cstdlib>
      46                 : 
      47                 : using namespace PCIDSK;
      48                 : 
      49                 : /************************************************************************/
      50                 : /*                      CBandInterleavedChannel()                       */
      51                 : /************************************************************************/
      52                 : 
      53             172 : CBandInterleavedChannel::CBandInterleavedChannel( PCIDSKBuffer &image_header, 
      54                 :                                                   uint64 ih_offset, 
      55                 :                                                   PCIDSKBuffer &file_header,
      56                 :                                                   int channelnum,
      57                 :                                                   CPCIDSKFile *file,
      58                 :                                                   uint64 image_offset,
      59                 :                                                   eChanType pixel_type )
      60             172 :         : CPCIDSKChannel( image_header, ih_offset, file, pixel_type, channelnum)
      61                 : 
      62                 : {
      63             172 :     io_handle_p = NULL;
      64             172 :     io_mutex_p = NULL;
      65                 : 
      66                 : /* -------------------------------------------------------------------- */
      67                 : /*      Establish the data layout.                                      */
      68                 : /* -------------------------------------------------------------------- */
      69             172 :     if( strcmp(file->GetInterleaving().c_str(),"FILE") == 0 )
      70                 :     {
      71               3 :         start_byte = atouint64(image_header.Get( 168, 16 ));
      72               3 :         pixel_offset = atouint64(image_header.Get( 184, 8 ));
      73               3 :         line_offset = atouint64(image_header.Get( 192, 8 ));
      74                 :     }
      75                 :     else
      76                 :     {
      77             169 :         start_byte = image_offset;
      78             169 :         pixel_offset = DataTypeSize(pixel_type);
      79             169 :         line_offset = pixel_offset * width;
      80                 :     }
      81                 : 
      82                 : /* -------------------------------------------------------------------- */
      83                 : /*      Establish the file we will be accessing.                        */
      84                 : /* -------------------------------------------------------------------- */
      85             172 :     image_header.Get(64,64,filename);
      86                 : 
      87             172 :     filename = MassageLink( filename );
      88                 : 
      89             172 :     if( filename.length() == 0 )
      90             169 :         file->GetIODetails( &io_handle_p, &io_mutex_p );
      91                 : 
      92                 :     else
      93               3 :         filename = MergeRelativePath( file->GetInterfaces()->io,
      94                 :                                       file->GetFilename(), 
      95               6 :                                       filename );
      96             172 : }
      97                 : 
      98                 : /************************************************************************/
      99                 : /*                      ~CBandInterleavedChannel()                      */
     100                 : /************************************************************************/
     101                 : 
     102             172 : CBandInterleavedChannel::~CBandInterleavedChannel()
     103                 : 
     104                 : {
     105             172 : }
     106                 : 
     107                 : /************************************************************************/
     108                 : /*                             ReadBlock()                              */
     109                 : /************************************************************************/
     110                 : 
     111              61 : int CBandInterleavedChannel::ReadBlock( int block_index, void *buffer,
     112                 :                                         int xoff, int yoff, 
     113                 :                                         int xsize, int ysize )
     114                 : 
     115                 : {
     116              61 :     PCIDSKInterfaces *interfaces = file->GetInterfaces();
     117                 : 
     118                 : /* -------------------------------------------------------------------- */
     119                 : /*      Default window if needed.                                       */
     120                 : /* -------------------------------------------------------------------- */
     121              61 :     if( xoff == -1 && yoff == -1 && xsize == -1 && ysize == -1 )
     122                 :     {
     123              61 :         xoff = 0;
     124              61 :         yoff = 0;
     125              61 :         xsize = GetBlockWidth();
     126              61 :         ysize = GetBlockHeight();
     127                 :     }
     128                 : 
     129                 : /* -------------------------------------------------------------------- */
     130                 : /*      Validate Window                                                 */
     131                 : /* -------------------------------------------------------------------- */
     132             122 :     if( xoff < 0 || xoff + xsize > GetBlockWidth()
     133              61 :         || yoff < 0 || yoff + ysize > GetBlockHeight() )
     134                 :     {
     135                 :         ThrowPCIDSKException( 
     136                 :             "Invalid window in ReadBloc(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
     137               0 :             xoff, yoff, xsize, ysize );
     138                 :     }
     139                 : 
     140                 : /* -------------------------------------------------------------------- */
     141                 : /*      Establish region to read.                                       */
     142                 : /* -------------------------------------------------------------------- */
     143              61 :     int    pixel_size = DataTypeSize( pixel_type );
     144                 :     uint64 offset = start_byte + line_offset * block_index
     145              61 :         + pixel_offset * xoff;
     146              61 :     int    window_size = (int) (pixel_offset*(xsize-1) + pixel_size);
     147                 : 
     148                 : /* -------------------------------------------------------------------- */
     149                 : /*      Get file access handles if we don't already have them.          */
     150                 : /* -------------------------------------------------------------------- */
     151              61 :     if( io_handle_p == NULL )
     152                 :         file->GetIODetails( &io_handle_p, &io_mutex_p, filename.c_str(),
     153               1 :                             file->GetUpdatable() );
     154                 : 
     155                 : /* -------------------------------------------------------------------- */
     156                 : /*      If the imagery is packed, we can read directly into the         */
     157                 : /*      target buffer.                                                  */
     158                 : /* -------------------------------------------------------------------- */
     159              61 :     if( pixel_size == (int) pixel_offset )
     160                 :     {
     161              61 :         MutexHolder holder( *io_mutex_p );
     162                 : 
     163              61 :         interfaces->io->Seek( *io_handle_p, offset, SEEK_SET );
     164              61 :         interfaces->io->Read( buffer, 1, window_size, *io_handle_p );
     165                 :     }
     166                 : 
     167                 : /* -------------------------------------------------------------------- */
     168                 : /*      Otherwise we allocate a working buffer that holds the whole     */
     169                 : /*      line, read into that, and pick out our data of interest.        */
     170                 : /* -------------------------------------------------------------------- */
     171                 :     else
     172                 :     {
     173                 :         int  i;
     174               0 :         PCIDSKBuffer line_from_disk( window_size );
     175                 :         char *this_pixel;
     176                 : 
     177               0 :         MutexHolder holder( *io_mutex_p );
     178                 :         
     179               0 :         interfaces->io->Seek( *io_handle_p, offset, SEEK_SET );
     180                 :         interfaces->io->Read( line_from_disk.buffer, 
     181                 :                               1, line_from_disk.buffer_size, 
     182               0 :                               *io_handle_p );
     183                 : 
     184               0 :         for( i = 0, this_pixel = line_from_disk.buffer; i < xsize; i++ )
     185                 :         {
     186                 :             memcpy( ((char *) buffer) + pixel_size * i, 
     187               0 :                     this_pixel, pixel_size );
     188               0 :             this_pixel += pixel_size;
     189               0 :         }
     190                 :     }
     191                 : 
     192                 : /* -------------------------------------------------------------------- */
     193                 : /*      Do byte swapping if needed.                                     */
     194                 : /* -------------------------------------------------------------------- */
     195              61 :     if( needs_swap )
     196              20 :         SwapPixels( buffer, pixel_type, xsize );
     197                 : 
     198              61 :     return 1;
     199                 : }
     200                 : 
     201                 : /************************************************************************/
     202                 : /*                             WriteBlock()                             */
     203                 : /************************************************************************/
     204                 : 
     205             317 : int CBandInterleavedChannel::WriteBlock( int block_index, void *buffer )
     206                 : 
     207                 : {
     208             317 :     PCIDSKInterfaces *interfaces = file->GetInterfaces();
     209                 : 
     210             317 :     if( !file->GetUpdatable() )
     211               0 :         throw PCIDSKException( "File not open for update in WriteBlock()" );
     212                 : 
     213             317 :     InvalidateOverviews();
     214                 : 
     215                 : /* -------------------------------------------------------------------- */
     216                 : /*      Establish region to read.                                       */
     217                 : /* -------------------------------------------------------------------- */
     218             317 :     int    pixel_size = DataTypeSize( pixel_type );
     219             317 :     uint64 offset = start_byte + line_offset * block_index;
     220             317 :     int    window_size = (int) (pixel_offset*(width-1) + pixel_size);
     221                 : 
     222                 : /* -------------------------------------------------------------------- */
     223                 : /*      Get file access handles if we don't already have them.          */
     224                 : /* -------------------------------------------------------------------- */
     225             317 :     if( io_handle_p == NULL )
     226                 :         file->GetIODetails( &io_handle_p, &io_mutex_p, filename.c_str(),
     227               1 :                             file->GetUpdatable() );
     228                 : 
     229                 : /* -------------------------------------------------------------------- */
     230                 : /*      If the imagery is packed, we can read directly into the         */
     231                 : /*      target buffer.                                                  */
     232                 : /* -------------------------------------------------------------------- */
     233             317 :     if( pixel_size == (int) pixel_offset )
     234                 :     {
     235             317 :         MutexHolder holder( *io_mutex_p );
     236                 : 
     237             317 :         if( needs_swap ) // swap before write.
     238              70 :             SwapPixels( buffer, pixel_type, width );
     239                 : 
     240             317 :         interfaces->io->Seek( *io_handle_p, offset, SEEK_SET );
     241             317 :         interfaces->io->Write( buffer, 1, window_size, *io_handle_p );
     242                 : 
     243             317 :         if( needs_swap ) // restore to original order.
     244              70 :             SwapPixels( buffer, pixel_type, width );
     245                 :     }
     246                 : 
     247                 : /* -------------------------------------------------------------------- */
     248                 : /*      Otherwise we allocate a working buffer that holds the whole     */
     249                 : /*      line, read into that, and pick out our data of interest.        */
     250                 : /* -------------------------------------------------------------------- */
     251                 :     else
     252                 :     {
     253                 :         int  i;
     254               0 :         PCIDSKBuffer line_from_disk( window_size );
     255                 :         char *this_pixel;
     256                 : 
     257               0 :         MutexHolder holder( *io_mutex_p );
     258                 :         
     259               0 :         interfaces->io->Seek( *io_handle_p, offset, SEEK_SET );
     260                 :         interfaces->io->Read( buffer, 1, line_from_disk.buffer_size, 
     261               0 :                               *io_handle_p );
     262                 : 
     263               0 :         for( i = 0, this_pixel = line_from_disk.buffer; i < width; i++ )
     264                 :         {
     265                 :             memcpy( this_pixel, ((char *) buffer) + pixel_size * i, 
     266               0 :                     pixel_size );
     267                 : 
     268               0 :             if( needs_swap ) // swap before write.
     269               0 :                 SwapPixels( this_pixel, pixel_type, 1 );
     270                 : 
     271               0 :             this_pixel += pixel_size;
     272                 :         }
     273                 : 
     274               0 :         interfaces->io->Seek( *io_handle_p, offset, SEEK_SET );
     275                 :         interfaces->io->Write( buffer, 1, line_from_disk.buffer_size, 
     276               0 :                                *io_handle_p );
     277                 :     }
     278                 : 
     279                 : /* -------------------------------------------------------------------- */
     280                 : /*      Do byte swapping if needed.                                     */
     281                 : /* -------------------------------------------------------------------- */
     282                 : 
     283             317 :     return 1;
     284                 : }
     285                 : 
     286                 : /************************************************************************/
     287                 : /*                            GetChanInfo()                             */
     288                 : /************************************************************************/
     289               5 : void CBandInterleavedChannel
     290                 : ::GetChanInfo( std::string &filename_ret, uint64 &image_offset, 
     291                 :                uint64 &pixel_offset, uint64 &line_offset, 
     292                 :                bool &little_endian ) const
     293                 : 
     294                 : {
     295               5 :     image_offset = start_byte;
     296               5 :     pixel_offset = this->pixel_offset;
     297               5 :     line_offset = this->line_offset;
     298               5 :     little_endian = (byte_order == 'S');
     299                 : 
     300                 : /* -------------------------------------------------------------------- */
     301                 : /*      We fetch the filename from the header since it will be the      */
     302                 : /*      "clean" version without any paths.                              */
     303                 : /* -------------------------------------------------------------------- */
     304               5 :     PCIDSKBuffer ih(64);
     305               5 :     file->ReadFromFile( ih.buffer, ih_offset+64, 64 );
     306                 : 
     307               5 :     ih.Get(0,64,filename_ret);
     308               5 :     filename_ret = MassageLink( filename_ret );
     309               5 : }
     310                 : 
     311                 : /************************************************************************/
     312                 : /*                            SetChanInfo()                             */
     313                 : /************************************************************************/
     314                 : 
     315               1 : void CBandInterleavedChannel
     316                 : ::SetChanInfo( std::string filename, uint64 image_offset, 
     317                 :                uint64 pixel_offset, uint64 line_offset, 
     318                 :                bool little_endian )
     319                 : 
     320                 : {
     321               1 :     if( ih_offset == 0 )
     322               0 :         ThrowPCIDSKException( "No Image Header available for this channel." );
     323                 : 
     324                 : /* -------------------------------------------------------------------- */
     325                 : /*      Fetch the existing image header.                                */
     326                 : /* -------------------------------------------------------------------- */
     327               1 :     PCIDSKBuffer ih(1024);
     328                 : 
     329               1 :     file->ReadFromFile( ih.buffer, ih_offset, 1024 );
     330                 : 
     331                 : /* -------------------------------------------------------------------- */
     332                 : /*      If the linked filename is too long to fit in the 64             */
     333                 : /*      character IHi.2 field, then we need to use a link segment to    */
     334                 : /*      store the filename.                                             */
     335                 : /* -------------------------------------------------------------------- */
     336               1 :     std::string IHi2_filename;
     337                 :     
     338               1 :     if( filename.size() > 64 )
     339                 :     {
     340                 :         int link_segment;
     341                 :         
     342               0 :         ih.Get( 64, 64, IHi2_filename );
     343                 :                 
     344               0 :         if( IHi2_filename.substr(0,3) == "LNK" )
     345                 :         {
     346               0 :             link_segment = std::atoi( IHi2_filename.c_str() + 4 );
     347                 :         }
     348                 :         else
     349                 :         {
     350                 :             char link_filename[64];
     351                 :            
     352                 :             link_segment = 
     353                 :                 file->CreateSegment( "Link    ", 
     354                 :                                      "Long external channel filename link.", 
     355               0 :                                      SEG_SYS, 1 );
     356                 : 
     357               0 :             sprintf( link_filename, "LNK %4d", link_segment );
     358               0 :             IHi2_filename = link_filename;
     359                 :         }
     360                 : 
     361                 :         CLinkSegment *link = 
     362               0 :             dynamic_cast<CLinkSegment*>( file->GetSegment( link_segment ) );
     363                 :         
     364               0 :         if( link != NULL )
     365                 :         {
     366               0 :             link->SetPath( filename );
     367               0 :             link->Synchronize();
     368                 :         }
     369                 :     }
     370                 :     
     371                 : /* -------------------------------------------------------------------- */
     372                 : /*      If we used to have a link segment but no longer need it, we     */
     373                 : /*      need to delete the link segment.                                */
     374                 : /* -------------------------------------------------------------------- */
     375                 :     else
     376                 :     {
     377               1 :         ih.Get( 64, 64, IHi2_filename );
     378                 :                 
     379               1 :         if( IHi2_filename.substr(0,3) == "LNK" )
     380                 :         {
     381               0 :             int link_segment = std::atoi( IHi2_filename.c_str() + 4 );
     382                 : 
     383               0 :             file->DeleteSegment( link_segment );
     384                 :         }
     385                 :         
     386               1 :         IHi2_filename = filename;
     387                 :     }
     388                 :         
     389                 : /* -------------------------------------------------------------------- */
     390                 : /*      Update the image header.                                        */
     391                 : /* -------------------------------------------------------------------- */
     392                 :     // IHi.2
     393               1 :     ih.Put( IHi2_filename.c_str(), 64, 64 );
     394                 : 
     395                 :     // IHi.6.1
     396               1 :     ih.Put( image_offset, 168, 16 );
     397                 : 
     398                 :     // IHi.6.2
     399               1 :     ih.Put( pixel_offset, 184, 8 );
     400                 : 
     401                 :     // IHi.6.3
     402               1 :     ih.Put( line_offset, 192, 8 );
     403                 : 
     404                 :     // IHi.6.5
     405               1 :     if( little_endian )
     406               1 :         ih.Put( "S", 201, 1 );
     407                 :     else
     408               0 :         ih.Put( "N", 201, 1 );
     409                 : 
     410               1 :     file->WriteToFile( ih.buffer, ih_offset, 1024 );
     411                 : 
     412                 : /* -------------------------------------------------------------------- */
     413                 : /*      Update local configuration.                                     */
     414                 : /* -------------------------------------------------------------------- */
     415               1 :     this->filename = MergeRelativePath( file->GetInterfaces()->io,
     416                 :                                         file->GetFilename(), 
     417               2 :                                         filename );
     418                 : 
     419               1 :     start_byte = image_offset;
     420               1 :     this->pixel_offset = pixel_offset;
     421               1 :     this->line_offset = line_offset;
     422                 :     
     423               1 :     if( little_endian )
     424               1 :         byte_order = 'S';
     425                 :     else
     426               0 :         byte_order = 'N';
     427                 : 
     428                 : /* -------------------------------------------------------------------- */
     429                 : /*      Determine if we need byte swapping.                             */
     430                 : /* -------------------------------------------------------------------- */
     431               1 :     unsigned short test_value = 1;
     432                 : 
     433               1 :     if( ((uint8 *) &test_value)[0] == 1 )
     434               1 :         needs_swap = (byte_order != 'S');
     435                 :     else
     436               0 :         needs_swap = (byte_order == 'S');
     437                 :     
     438               1 :     if( pixel_type == CHN_8U )
     439               0 :         needs_swap = 0;
     440               1 : }
     441                 : 
     442                 : /************************************************************************/
     443                 : /*                            MassageLink()                             */
     444                 : /*                                                                      */
     445                 : /*      Return the filename after applying translation of long          */
     446                 : /*      linked filenames using a link segment.                          */
     447                 : /************************************************************************/
     448                 : 
     449             177 : std::string CBandInterleavedChannel::MassageLink( std::string filename_in ) const
     450                 : 
     451                 : {
     452             177 :     if (filename_in.find("LNK") == 0)
     453                 :     {
     454               0 :         std::string seg_str(filename_in, 4, 4);
     455               0 :         unsigned int seg_num = std::atoi(seg_str.c_str());
     456                 :         
     457               0 :         if (seg_num == 0)
     458                 :         {
     459                 :             throw PCIDSKException("Unable to find link segment. Link name: %s",
     460               0 :                                   filename_in.c_str());
     461                 :         }
     462                 :         
     463                 :         CLinkSegment* link_seg = 
     464               0 :             dynamic_cast<CLinkSegment*>(file->GetSegment(seg_num));
     465               0 :         if (link_seg == NULL)
     466                 :         {
     467               0 :             throw PCIDSKException("Failed to get Link Information Segment.");
     468                 :         }
     469                 :         
     470               0 :         filename_in = link_seg->GetPath();
     471                 :     }
     472                 : 
     473             177 :     return filename_in;
     474                 : }
     475                 : 

Generated by: LCOV version 1.7