LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/channel - cbandinterleavedchannel.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 114 180 63.3 %
Date: 2024-11-21 22:18:42 Functions: 8 8 100.0 %

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

Generated by: LCOV version 1.14