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

Generated by: LCOV version 1.14