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

Generated by: LCOV version 1.14