LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/channel - cpcidskchannel.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 118 194 60.8 %
Date: 2025-05-31 00:00:17 Functions: 14 26 53.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Purpose:  Implementation of the CPCIDSKChannel Abstract class.
       4             :  *
       5             :  ******************************************************************************
       6             :  * Copyright (c) 2009
       7             :  * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #include "pcidsk_config.h"
      13             : #include "pcidsk_types.h"
      14             : #include "core/pcidsk_utils.h"
      15             : #include "pcidsk_exception.h"
      16             : #include "pcidsk_channel.h"
      17             : #include "core/cpcidskfile.h"
      18             : #include "channel/cpcidskchannel.h"
      19             : #include "channel/ctiledchannel.h"
      20             : #include <cstring>
      21             : #include <cassert>
      22             : #include <cstdlib>
      23             : #include <cstring>
      24             : #include <cstdio>
      25             : 
      26             : using namespace PCIDSK;
      27             : 
      28             : /************************************************************************/
      29             : /*                           CPCIDSKChannel()                           */
      30             : /************************************************************************/
      31             : 
      32         253 : CPCIDSKChannel::CPCIDSKChannel( PCIDSKBuffer &image_header,
      33             :                                 uint64 ih_offsetIn,
      34             :                                 CPCIDSKFile *fileIn,
      35             :                                 eChanType pixel_typeIn,
      36         253 :                                 int channel_numberIn )
      37             : 
      38             : {
      39         253 :     this->pixel_type = pixel_typeIn;
      40         253 :     this->file = fileIn;
      41         253 :     this->channel_number = channel_numberIn;
      42         253 :     this->ih_offset = ih_offsetIn;
      43         253 :     is_locked = false;
      44         253 :     byte_order = 'N';
      45         253 :     needs_swap = !BigEndianSystem();
      46             : 
      47         253 :     width = file->GetWidth();
      48         253 :     height = file->GetHeight();
      49             : 
      50         253 :     block_width = width;
      51         253 :     block_height = 1;
      52             : 
      53             : /* -------------------------------------------------------------------- */
      54             : /*      Establish if we need to byte swap the data on load/store.       */
      55             : /* -------------------------------------------------------------------- */
      56         253 :     if( channel_number != -1 )
      57             :     {
      58         242 :         unsigned short test_value = 1;
      59             : 
      60         242 :         is_locked = image_header.buffer[200] == 'W';
      61         242 :         byte_order = image_header.buffer[201];
      62         242 :         if( (reinterpret_cast<uint8 *>(&test_value))[0] == 1 )
      63         242 :             needs_swap = (byte_order != 'S');
      64             :         else
      65           0 :             needs_swap = (byte_order == 'S');
      66             : 
      67         242 :         if( pixel_type == CHN_8U )
      68         173 :             needs_swap = 0;
      69             : 
      70         242 :         LoadHistory( image_header );
      71             : 
      72             : /* -------------------------------------------------------------------- */
      73             : /*      Initialize the metadata object, but do not try to load till     */
      74             : /*      needed.  We avoid doing this for unassociated channels such     */
      75             : /*      as overviews.                                                   */
      76             : /* -------------------------------------------------------------------- */
      77         242 :         metadata.Initialize( file, "IMG", channel_number );
      78             :     }
      79             : 
      80             : /* -------------------------------------------------------------------- */
      81             : /*      No overviews for unassociated files, so just mark them as       */
      82             : /*      initialized.                                                    */
      83             : /* -------------------------------------------------------------------- */
      84         253 :     overviews_initialized = (channel_number == -1);
      85         253 : }
      86             : 
      87             : /************************************************************************/
      88             : /*                          ~CPCIDSKChannel()                           */
      89             : /************************************************************************/
      90             : 
      91         253 : CPCIDSKChannel::~CPCIDSKChannel()
      92             : 
      93             : {
      94         253 :     InvalidateOverviewInfo();
      95         253 : }
      96             : 
      97             : /************************************************************************/
      98             : /*                       InvalidateOverviewInfo()                       */
      99             : /*                                                                      */
     100             : /*      This is called when CreateOverviews() creates overviews - we    */
     101             : /*      invalidate our loaded info and re-establish on a next request.  */
     102             : /************************************************************************/
     103             : 
     104         253 : void CPCIDSKChannel::InvalidateOverviewInfo()
     105             : 
     106             : {
     107         264 :     for( size_t io=0; io < overview_bands.size(); io++ )
     108             :     {
     109          11 :         if( overview_bands[io] != nullptr )
     110             :         {
     111          11 :             delete overview_bands[io];
     112          11 :             overview_bands[io] = nullptr;
     113             :         }
     114             :     }
     115             : 
     116         253 :     overview_infos.clear();
     117         253 :     overview_bands.clear();
     118         253 :     overview_decimations.clear();
     119             : 
     120         253 :     overviews_initialized = false;
     121         253 : }
     122             : 
     123             : /************************************************************************/
     124             : /*                         SortOverviewComp()                           */
     125             : /************************************************************************/
     126             : 
     127          10 : static bool SortOverviewComp(const std::string &first,
     128             :                              const std::string &second)
     129             : {
     130          10 :     if( !STARTS_WITH(first.c_str(), "_Overview_") ||
     131           0 :         !STARTS_WITH(second.c_str(), "_Overview_") )
     132             :     {
     133          10 :         return false;
     134             :     }
     135           0 :     int nFirst = atoi(first.c_str() + 10);
     136           0 :     int nSecond = atoi(second.c_str() + 10);
     137           0 :     return nFirst < nSecond;
     138             : }
     139             : 
     140             : /************************************************************************/
     141             : /*                       EstablishOverviewInfo()                        */
     142             : /************************************************************************/
     143        1588 : void CPCIDSKChannel::EstablishOverviewInfo() const
     144             : 
     145             : {
     146        1588 :     if( overviews_initialized )
     147        1355 :         return;
     148             : 
     149         233 :     overviews_initialized = true;
     150             : 
     151         466 :     std::vector<std::string> keys = GetMetadataKeys();
     152         233 :     std::sort(keys.begin(), keys.end(), SortOverviewComp); // sort overviews
     153             :     size_t i;
     154             : 
     155         250 :     for( i = 0; i < keys.size(); i++ )
     156             :     {
     157          17 :         if( !STARTS_WITH(keys[i].c_str(), "_Overview_") )
     158           7 :             continue;
     159             : 
     160          10 :         overview_infos.push_back( GetMetadataValue( keys[i] ) );
     161          10 :         overview_bands.push_back( nullptr );
     162          10 :         overview_decimations.push_back( atoi(keys[i].c_str()+10) );
     163             :     }
     164             : }
     165             : 
     166             : /************************************************************************/
     167             : /*                       UpdateOverviewInfo()                           */
     168             : /************************************************************************/
     169             : /** Update the in-memory information for an overview.
     170             :   * This method will add overview information to the in-memory arrays
     171             :   *
     172             :   * @param  pszOverviewMDValue  Overview value
     173             :   *
     174             :   * @param  nFactor             Overview factor i.e. 2, 4, etc
     175             :   */
     176           1 : void CPCIDSKChannel::UpdateOverviewInfo(const char *pszOverviewMDValue,
     177             :                                         int nFactor)
     178             : {
     179           1 :     overview_infos.push_back( pszOverviewMDValue );
     180           1 :     overview_bands.push_back( nullptr );
     181           1 :     overview_decimations.push_back( nFactor );
     182           1 : }
     183             : 
     184             : /************************************************************************/
     185             : /*                           GetBlockCount()                            */
     186             : /************************************************************************/
     187             : 
     188           0 : int CPCIDSKChannel::GetBlockCount() const
     189             : 
     190             : {
     191             :     // We deliberately call GetBlockWidth() and GetWidth() to trigger
     192             :     // computation of the values for tiled layers.  At some point it would
     193             :     // be good to cache the block count as this computation is a bit expensive
     194             : 
     195           0 :     int x_block_count = (GetWidth() + GetBlockWidth() - 1) / GetBlockWidth();
     196           0 :     int y_block_count = (GetHeight() + GetBlockHeight() - 1) / GetBlockHeight();
     197             : 
     198           0 :     return x_block_count * y_block_count;
     199             : }
     200             : 
     201             : /************************************************************************/
     202             : /*                          GetOverviewCount()                          */
     203             : /************************************************************************/
     204             : 
     205         911 : int CPCIDSKChannel::GetOverviewCount()
     206             : 
     207             : {
     208         911 :     EstablishOverviewInfo();
     209             : 
     210         911 :     return static_cast<int>(overview_infos.size());
     211             : }
     212             : 
     213             : /************************************************************************/
     214             : /*                            GetOverview()                             */
     215             : /************************************************************************/
     216             : 
     217          11 : PCIDSKChannel *CPCIDSKChannel::GetOverview( int overview_index )
     218             : 
     219             : {
     220          11 :     EstablishOverviewInfo();
     221             : 
     222          11 :     if( overview_index < 0 || overview_index >= (int) overview_infos.size() )
     223           0 :         return (PCIDSKChannel*)ThrowPCIDSKExceptionPtr( "Non existent overview (%d) requested.",
     224           0 :                               overview_index );
     225             : 
     226          11 :     if( overview_bands[overview_index] == nullptr )
     227             :     {
     228          22 :         PCIDSKBuffer image_header(1024), file_header(1024);
     229             :         char  pseudo_filename[65];
     230             : 
     231          11 :         snprintf( pseudo_filename, sizeof(pseudo_filename), "/SIS=%d",
     232          11 :                  atoi(overview_infos[overview_index].c_str()) );
     233             : 
     234          11 :         image_header.Put( pseudo_filename, 64, 64 );
     235             : 
     236          11 :         overview_bands[overview_index] =
     237             :             new CTiledChannel( image_header, 0, file_header, -1, file,
     238          11 :                                CHN_UNKNOWN );
     239             :     }
     240             : 
     241          11 :     return overview_bands[overview_index];
     242             : }
     243             : 
     244             : /************************************************************************/
     245             : /*                          IsOverviewValid()                           */
     246             : /************************************************************************/
     247             : 
     248           0 : bool CPCIDSKChannel::IsOverviewValid( int overview_index )
     249             : 
     250             : {
     251           0 :     EstablishOverviewInfo();
     252             : 
     253           0 :     if( overview_index < 0 || overview_index >= (int) overview_infos.size() )
     254           0 :         return ThrowPCIDSKException(0, "Non existent overview (%d) requested.",
     255           0 :                               overview_index ) != 0;
     256             : 
     257           0 :     int sis_id, validity=0;
     258             : 
     259           0 :     sscanf( overview_infos[overview_index].c_str(), "%d %d",
     260             :             &sis_id, &validity );
     261             : 
     262           0 :     return validity != 0;
     263             : }
     264             : 
     265             : /************************************************************************/
     266             : /*                       GetOverviewResampling()                        */
     267             : /************************************************************************/
     268             : 
     269           0 : std::string CPCIDSKChannel::GetOverviewResampling( int overview_index )
     270             : 
     271             : {
     272           0 :     EstablishOverviewInfo();
     273             : 
     274           0 :     if( overview_index < 0 || overview_index >= (int) overview_infos.size() )
     275             :     {
     276           0 :         ThrowPCIDSKException( "Non existent overview (%d) requested.",
     277             :                               overview_index );
     278           0 :         return "";
     279             :     }
     280             : 
     281           0 :     int sis_id, validity=0;
     282             :     char resampling[17];
     283             : 
     284           0 :     sscanf( overview_infos[overview_index].c_str(), "%d %d %16s",
     285             :             &sis_id, &validity, &(resampling[0]) );
     286             : 
     287           0 :     return resampling;
     288             : }
     289             : 
     290             : /************************************************************************/
     291             : /*                        SetOverviewValidity()                         */
     292             : /************************************************************************/
     293             : 
     294          21 : void CPCIDSKChannel::SetOverviewValidity( int overview_index,
     295             :                                           bool new_validity )
     296             : 
     297             : {
     298          21 :     EstablishOverviewInfo();
     299             : 
     300          21 :     if( overview_index < 0 || overview_index >= (int) overview_infos.size() )
     301           0 :         return ThrowPCIDSKException( "Non existent overview (%d) requested.",
     302          19 :                               overview_index );
     303             : 
     304          21 :     int sis_id, validity=0;
     305             :     char resampling[17];
     306             : 
     307          21 :     sscanf( overview_infos[overview_index].c_str(), "%d %d %16s",
     308             :             &sis_id, &validity, &(resampling[0]) );
     309             : 
     310             :     // are we already set to this value?
     311          21 :     if( new_validity == (validity != 0) )
     312          19 :         return;
     313             : 
     314             :     char new_info[48];
     315             : 
     316           2 :     snprintf( new_info, sizeof(new_info), "%d %d %s",
     317             :              sis_id, (new_validity ? 1 : 0 ), resampling );
     318             : 
     319           2 :     overview_infos[overview_index] = new_info;
     320             : 
     321             :     // write back to metadata.
     322             :     char key[20];
     323           2 :     snprintf( key, sizeof(key), "_Overview_%d", overview_decimations[overview_index] );
     324             : 
     325           2 :     SetMetadataValue( key, new_info );
     326             : }
     327             : 
     328             : /************************************************************************/
     329             : /*                        InvalidateOverviews()                         */
     330             : /*                                                                      */
     331             : /*      Whenever a write is done on this band, we will invalidate       */
     332             : /*      any previously valid overviews.                                 */
     333             : /************************************************************************/
     334             : 
     335         645 : void CPCIDSKChannel::InvalidateOverviews()
     336             : 
     337             : {
     338         645 :     EstablishOverviewInfo();
     339             : 
     340         665 :     for( int i = 0; i < GetOverviewCount(); i++ )
     341          20 :         SetOverviewValidity( i, false );
     342         645 : }
     343             : 
     344             : /************************************************************************/
     345             : /*                  GetOverviewLevelMapping()                           */
     346             : /************************************************************************/
     347             : 
     348           0 : std::vector<int> CPCIDSKChannel::GetOverviewLevelMapping() const
     349             : {
     350           0 :     EstablishOverviewInfo();
     351             : 
     352           0 :     return overview_decimations;
     353             : }
     354             : 
     355             : /************************************************************************/
     356             : /*                              GetFilename()                           */
     357             : /************************************************************************/
     358           0 : std::string CPCIDSKChannel::GetFilename() const
     359             : {
     360           0 :     return file->GetFilename();
     361             : }
     362             : 
     363             : /************************************************************************/
     364             : /*                           GetDescription()                           */
     365             : /************************************************************************/
     366             : 
     367         249 : std::string CPCIDSKChannel::GetDescription()
     368             : 
     369             : {
     370         249 :     if( ih_offset == 0 )
     371           0 :         return "";
     372             : 
     373         498 :     PCIDSKBuffer ih_1(64);
     374         498 :     std::string ret;
     375             : 
     376         249 :     file->ReadFromFile( ih_1.buffer, ih_offset, 64 );
     377         249 :     ih_1.Get(0,64,ret);
     378             : 
     379         249 :     return ret;
     380             : }
     381             : 
     382             : /************************************************************************/
     383             : /*                           SetDescription()                           */
     384             : /************************************************************************/
     385             : 
     386           3 : void CPCIDSKChannel::SetDescription( const std::string &description )
     387             : 
     388             : {
     389           3 :     if( ih_offset == 0 )
     390           0 :         return ThrowPCIDSKException( "Description cannot be set on overviews." );
     391             : 
     392           6 :     PCIDSKBuffer ih_1(64);
     393           3 :     ih_1.Put( description.c_str(), 0, 64 );
     394           3 :     file->WriteToFile( ih_1.buffer, ih_offset, 64 );
     395             : }
     396             : 
     397             : /************************************************************************/
     398             : /*                            LoadHistory()                             */
     399             : /************************************************************************/
     400             : 
     401         242 : void CPCIDSKChannel::LoadHistory( const PCIDSKBuffer &image_header )
     402             : 
     403             : {
     404             :     // Read the history from the image header. PCIDSK supports
     405             :     // 8 history entries per channel.
     406             : 
     407         484 :     std::string hist_msg;
     408         242 :     history_.clear();
     409        2178 :     for (unsigned int i = 0; i < 8; i++)
     410             :     {
     411        1936 :         image_header.Get(384 + i * 80, 80, hist_msg);
     412             : 
     413             :         // Some programs seem to push history records with a trailing '\0'
     414             :         // so do some extra processing to cleanup.  FUN records on segment
     415             :         // 3 of eltoro.pix are an example of this.
     416        1936 :         size_t size = hist_msg.size();
     417           0 :         while( size > 0
     418        1936 :                && (hist_msg[size-1] == ' ' || hist_msg[size-1] == '\0') )
     419           0 :             size--;
     420             : 
     421        1936 :         hist_msg.resize(size);
     422             : 
     423        1936 :         history_.push_back(hist_msg);
     424             :     }
     425         242 : }
     426             : 
     427             : /************************************************************************/
     428             : /*                         GetHistoryEntries()                          */
     429             : /************************************************************************/
     430             : 
     431           0 : std::vector<std::string> CPCIDSKChannel::GetHistoryEntries() const
     432             : {
     433           0 :     return history_;
     434             : }
     435             : 
     436             : /************************************************************************/
     437             : /*                         SetHistoryEntries()                          */
     438             : /************************************************************************/
     439             : 
     440           0 : void CPCIDSKChannel::SetHistoryEntries(const std::vector<std::string> &entries)
     441             : 
     442             : {
     443           0 :     if( ih_offset == 0 )
     444           0 :         return ThrowPCIDSKException( "Attempt to update history on a raster that is not\na conventional band with an image header." );
     445             : 
     446           0 :     PCIDSKBuffer image_header(1024);
     447             : 
     448           0 :     file->ReadFromFile( image_header.buffer, ih_offset, 1024 );
     449             : 
     450           0 :     for( unsigned int i = 0; i < 8; i++ )
     451             :     {
     452           0 :         const char *msg = "";
     453           0 :         if( entries.size() > i )
     454           0 :             msg = entries[i].c_str();
     455             : 
     456           0 :         image_header.Put( msg, 384 + i * 80, 80 );
     457             :     }
     458             : 
     459           0 :     file->WriteToFile( image_header.buffer, ih_offset, 1024 );
     460             : 
     461             :     // Force reloading of history_
     462           0 :     LoadHistory( image_header );
     463             : }
     464             : 
     465             : /************************************************************************/
     466             : /*                            PushHistory()                             */
     467             : /************************************************************************/
     468             : 
     469           0 : void CPCIDSKChannel::PushHistory( const std::string &app,
     470             :                                   const std::string &message )
     471             : 
     472             : {
     473             : #define MY_MIN(a,b)      ((a<b) ? a : b)
     474             : 
     475             :     char current_time[17];
     476             :     char history[81];
     477             : 
     478           0 :     GetCurrentDateTime( current_time );
     479             : 
     480           0 :     memset( history, ' ', 80 );
     481           0 :     history[80] = '\0';
     482             : 
     483           0 :     memcpy( history + 0, app.c_str(), MY_MIN(app.size(),7) );
     484           0 :     history[7] = ':';
     485             : 
     486           0 :     memcpy( history + 8, message.c_str(), MY_MIN(message.size(),56) );
     487           0 :     memcpy( history + 64, current_time, 16 );
     488             : 
     489           0 :     std::vector<std::string> history_entries = GetHistoryEntries();
     490             : 
     491             :     // coverity[string_null]
     492           0 :     history_entries.insert( history_entries.begin(), history );
     493           0 :     history_entries.resize(8);
     494             : 
     495           0 :     SetHistoryEntries( history_entries );
     496           0 : }
     497             : 
     498             : /************************************************************************/
     499             : /*                            GetChanInfo()                             */
     500             : /************************************************************************/
     501           7 : void CPCIDSKChannel::GetChanInfo( std::string &filename, uint64 &image_offset,
     502             :                                   uint64 &pixel_offset, uint64 &line_offset,
     503             :                                   bool &little_endian ) const
     504             : 
     505             : {
     506           7 :     image_offset = 0;
     507           7 :     pixel_offset = 0;
     508           7 :     line_offset = 0;
     509           7 :     little_endian = true;
     510           7 :     filename = "";
     511           7 : }
     512             : 
     513             : /************************************************************************/
     514             : /*                            SetChanInfo()                             */
     515             : /************************************************************************/
     516             : 
     517           0 : void CPCIDSKChannel::SetChanInfo( CPL_UNUSED std::string filename,
     518             :                                   CPL_UNUSED uint64 image_offset,
     519             :                                   CPL_UNUSED uint64 pixel_offset,
     520             :                                   CPL_UNUSED uint64 line_offset,
     521             :                                   CPL_UNUSED bool little_endian )
     522             : {
     523           0 :     return ThrowPCIDSKException( "Attempt to SetChanInfo() on a channel that is not FILE interleaved." );
     524             : }
     525             : 
     526             : /************************************************************************/
     527             : /*                            GetEChanInfo()                            */
     528             : /************************************************************************/
     529           0 : void CPCIDSKChannel::GetEChanInfo( std::string &filename, int &echannel,
     530             :                                    int &exoff, int &eyoff,
     531             :                                    int &exsize, int &eysize ) const
     532             : 
     533             : {
     534           0 :     echannel = 0;
     535           0 :     exoff = 0;
     536           0 :     eyoff = 0;
     537           0 :     exsize = 0;
     538           0 :     eysize = 0;
     539           0 :     filename = "";
     540           0 : }
     541             : 
     542             : /************************************************************************/
     543             : /*                            SetEChanInfo()                            */
     544             : /************************************************************************/
     545             : 
     546           0 : void CPCIDSKChannel::SetEChanInfo( CPL_UNUSED std::string filename,
     547             :                                    CPL_UNUSED int echannel,
     548             :                                    CPL_UNUSED int exoff,
     549             :                                    CPL_UNUSED int eyoff,
     550             :                                    CPL_UNUSED int exsize,
     551             :                                    CPL_UNUSED int eysize )
     552             : {
     553           0 :     return ThrowPCIDSKException( "Attempt to SetEChanInfo() on a channel that is not FILE interleaved." );
     554             : }

Generated by: LCOV version 1.14