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

Generated by: LCOV version 1.14