LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/core - cpcidskfile.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 444 800 55.5 %
Date: 2025-07-02 23:05:47 Functions: 18 26 69.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Purpose:  Implementation of the CPCIDSKFile class.
       4             :  *
       5             :  ******************************************************************************
       6             :  * Copyright (c) 2009
       7             :  * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : #include "pcidsk_file.h"
      12             : #include "pcidsk_exception.h"
      13             : #include "pcidsk_channel.h"
      14             : #include "pcidsk_segment.h"
      15             : #include "core/mutexholder.h"
      16             : #include "core/pcidsk_utils.h"
      17             : #include "core/cpcidskfile.h"
      18             : #include "core/cpcidskblockfile.h"
      19             : 
      20             : // Channel types
      21             : #include "channel/cbandinterleavedchannel.h"
      22             : #include "channel/cpixelinterleavedchannel.h"
      23             : #include "channel/ctiledchannel.h"
      24             : #include "channel/cexternalchannel.h"
      25             : 
      26             : // Segment types
      27             : #include "segment/cpcidskgeoref.h"
      28             : #include "segment/cpcidskpct.h"
      29             : #include "segment/cpcidskbpct.h"
      30             : #include "segment/cpcidsklut.h"
      31             : #include "segment/cpcidskblut.h"
      32             : #include "segment/cpcidskvectorsegment.h"
      33             : #include "segment/metadatasegment.h"
      34             : #include "segment/systiledir.h"
      35             : #include "segment/cpcidskrpcmodel.h"
      36             : #include "segment/cpcidskgcp2segment.h"
      37             : #include "segment/cpcidskbitmap.h"
      38             : #include "segment/cpcidsk_tex.h"
      39             : #include "segment/cpcidsk_array.h"
      40             : #include "segment/cpcidsktoutinmodel.h"
      41             : #include "segment/cpcidskpolymodel.h"
      42             : #include "segment/cpcidskbinarysegment.h"
      43             : #include "core/clinksegment.h"
      44             : 
      45             : #ifdef PCIDSK_IMP_PARAM_SUPPORT
      46             : #define __INT16DEF__
      47             : #define __INT32DEF__
      48             : #define __INT64DEF__
      49             : 
      50             : #define __CINT16TDEF__
      51             : #define __CINT32TDEF__
      52             : #define __CINT64TDEF__
      53             : #define __CFLOAT32TDEF__
      54             : #define __CFLOAT64TDEF__
      55             : 
      56             : #define __CINT16DEF__
      57             : #define __CINT32DEF__
      58             : #define __CINT64DEF__
      59             : #define __CFLOAT32DEF__
      60             : #define __CFLOAT64DEF__
      61             : 
      62             : #include "core/impparam/impparam.h"
      63             : #endif
      64             : 
      65             : #include <cassert>
      66             : #include <cstdlib>
      67             : #include <cstring>
      68             : #include <cstdio>
      69             : #include <limits>
      70             : #include <string>
      71             : #include <fstream>
      72             : #include <sstream>
      73             : #include <iostream>
      74             : #include <algorithm>
      75             : 
      76             : using namespace PCIDSK;
      77             : 
      78             : PCIDSKFile::~PCIDSKFile() = default;
      79             : 
      80             : IOInterfaces::~IOInterfaces() = default;
      81             : 
      82             : EDBFile::~EDBFile() = default;
      83             : 
      84             : /************************************************************************/
      85             : /*                             CPCIDSKFile()                             */
      86             : /************************************************************************/
      87             : 
      88         257 : CPCIDSKFile::CPCIDSKFile( const std::string& filename )
      89             : 
      90             : {
      91         257 :     io_handle = nullptr;
      92         257 :     io_mutex = nullptr;
      93         257 :     updatable = false;
      94         257 :     base_filename = filename;
      95         257 :     width = 0;
      96         257 :     height = 0;
      97         257 :     channel_count = 0;
      98         257 :     segment_count = 0;
      99         257 :     segment_pointers_offset = 0;
     100         257 :     block_size = 0;
     101         257 :     pixel_group_size = 0;
     102         257 :     segment_count = 0;
     103         257 :     segment_pointers_offset = 0;
     104         257 :     block_size = 0;
     105         257 :     pixel_group_size = 0;
     106         257 :     first_line_offset = 0;
     107         257 :     last_block_index = 0;
     108         257 :     last_block_dirty = false;
     109         257 :     last_block_xoff = 0;
     110         257 :     last_block_xsize = 0;
     111         257 :     last_block_data = nullptr;
     112         257 :     last_block_mutex = nullptr;
     113         257 :     file_size = 0;
     114             : 
     115         257 :     file_list.reserve(1024);
     116             : 
     117             : /* -------------------------------------------------------------------- */
     118             : /*      Initialize the metadata object, but do not try to load till     */
     119             : /*      needed.                                                         */
     120             : /* -------------------------------------------------------------------- */
     121         257 :     metadata.Initialize( this, "FIL", 0 );
     122         257 : }
     123             : 
     124             : /************************************************************************/
     125             : /*                            ~CPCIDSKFile()                             */
     126             : /************************************************************************/
     127             : 
     128         514 : CPCIDSKFile::~CPCIDSKFile()
     129             : 
     130             : {
     131             :     try
     132             :     {
     133         257 :         Synchronize();
     134             :     }
     135           0 :     catch( const PCIDSKException& e )
     136             :     {
     137           0 :         fprintf(stderr, "Exception in ~CPCIDSKFile(): %s", e.what()); // ok
     138             :     }
     139             : 
     140             : /* -------------------------------------------------------------------- */
     141             : /*      Cleanup last block buffer.                                      */
     142             : /* -------------------------------------------------------------------- */
     143         257 :     if( last_block_data != nullptr )
     144             :     {
     145           0 :         last_block_index = -1;
     146           0 :         free( last_block_data );
     147           0 :         last_block_data = nullptr;
     148           0 :         delete last_block_mutex;
     149             :     }
     150             : 
     151             : /* -------------------------------------------------------------------- */
     152             : /*      Cleanup channels and segments.                                  */
     153             : /* -------------------------------------------------------------------- */
     154             :     size_t i;
     155         499 :     for( i = 0; i < channels.size(); i++ )
     156             :     {
     157         242 :         delete channels[i];
     158         242 :         channels[i] = nullptr;
     159             :     }
     160             : 
     161      258689 :     for( i = 0; i < segments.size(); i++ )
     162             :     {
     163      258432 :         delete segments[i];
     164      258432 :         segments[i] = nullptr;
     165             :     }
     166             : 
     167             : /* -------------------------------------------------------------------- */
     168             : /*      Close and cleanup IO stuff.                                     */
     169             : /* -------------------------------------------------------------------- */
     170             :     {
     171         514 :         MutexHolder oHolder( io_mutex );
     172             : 
     173         257 :         if( io_handle )
     174             :         {
     175         257 :             interfaces.io->Close( io_handle );
     176         257 :             io_handle = nullptr;
     177             :         }
     178             :     }
     179             : 
     180             :     size_t i_file;
     181             : 
     182         259 :     for( i_file=0; i_file < file_list.size(); i_file++ )
     183             :     {
     184           2 :         delete file_list[i_file].io_mutex;
     185           2 :         file_list[i_file].io_mutex = nullptr;
     186             : 
     187           2 :         interfaces.io->Close( file_list[i_file].io_handle );
     188           2 :         file_list[i_file].io_handle = nullptr;
     189             :     }
     190             : 
     191         257 :     for( i_file=0; i_file < edb_file_list.size(); i_file++ )
     192             :     {
     193           0 :         delete edb_file_list[i_file].io_mutex;
     194           0 :         edb_file_list[i_file].io_mutex = nullptr;
     195             : 
     196           0 :         delete edb_file_list[i_file].file;
     197           0 :         edb_file_list[i_file].file = nullptr;
     198             :     }
     199             : 
     200         257 :     delete io_mutex;
     201         514 : }
     202             : 
     203             : /************************************************************************/
     204             : /*                            Synchronize()                             */
     205             : /************************************************************************/
     206             : 
     207         514 : void CPCIDSKFile::Synchronize()
     208             : 
     209             : {
     210         514 :     if( !GetUpdatable() )
     211         267 :         return;
     212             : 
     213             : /* -------------------------------------------------------------------- */
     214             : /*      Flush out last line caching stuff for pixel interleaved data.   */
     215             : /* -------------------------------------------------------------------- */
     216         247 :     FlushBlock();
     217             : 
     218             : /* -------------------------------------------------------------------- */
     219             : /*      Synchronize all channels.                                       */
     220             : /* -------------------------------------------------------------------- */
     221             :     size_t i;
     222         500 :     for( i = 0; i < channels.size(); i++ )
     223         253 :         channels[i]->Synchronize();
     224             : 
     225             : /* -------------------------------------------------------------------- */
     226             : /*      Synchronize all segments we have instantiated.                  */
     227             : /* -------------------------------------------------------------------- */
     228      253422 :     for( i = 0; i < segments.size(); i++ )
     229             :     {
     230      253175 :         if( segments[i] != nullptr )
     231        2533 :             segments[i]->Synchronize();
     232             :     }
     233             : 
     234             : /* -------------------------------------------------------------------- */
     235             : /*      Ensure the file is synchronized to disk.                        */
     236             : /* -------------------------------------------------------------------- */
     237         494 :     MutexHolder oHolder( io_mutex );
     238             : 
     239         247 :     interfaces.io->Flush( io_handle );
     240             : }
     241             : 
     242             : /************************************************************************/
     243             : /*                             GetChannel()                             */
     244             : /************************************************************************/
     245             : 
     246         275 : PCIDSKChannel *CPCIDSKFile::GetChannel( int band )
     247             : 
     248             : {
     249         275 :     if( band < 1 || band > channel_count )
     250           0 :         return (PCIDSKChannel*)ThrowPCIDSKExceptionPtr( "Out of range band (%d) requested.",
     251           0 :                               band );
     252             : 
     253         275 :     return channels[band-1];
     254             : }
     255             : 
     256             : /************************************************************************/
     257             : /*                             GetSegment()                             */
     258             : /************************************************************************/
     259             : 
     260        4246 : PCIDSK::PCIDSKSegment *CPCIDSKFile::GetSegment( int segment )
     261             : 
     262             : {
     263             : /* -------------------------------------------------------------------- */
     264             : /*      Is this a valid segment?                                        */
     265             : /* -------------------------------------------------------------------- */
     266        4246 :     if( segment < 1 || segment > segment_count )
     267           0 :         return nullptr;
     268             : 
     269        4246 :     const char *segment_pointer = segment_pointers.buffer + (segment-1) * 32;
     270        4246 :     if( segment_pointer[0] != 'A' && segment_pointer[0] != 'L' )
     271           0 :         return nullptr;
     272             : 
     273             : /* -------------------------------------------------------------------- */
     274             : /*      Do we already have a corresponding object?                      */
     275             : /* -------------------------------------------------------------------- */
     276        4246 :     if( segments[segment] != nullptr )
     277        2780 :         return segments[segment];
     278             : 
     279             : /* -------------------------------------------------------------------- */
     280             : /*      Instantiate per the type.                                       */
     281             : /* -------------------------------------------------------------------- */
     282        1466 :     int segment_type = segment_pointers.GetInt((segment-1)*32+1,3);
     283        1466 :     PCIDSKSegment *segobj = nullptr;
     284             : 
     285        1466 :     switch( segment_type )
     286             :     {
     287         121 :       case SEG_GEO:
     288         121 :         segobj = new CPCIDSKGeoref( this, segment, segment_pointer );
     289         121 :         break;
     290             : 
     291           2 :       case SEG_PCT:
     292           2 :         segobj = new CPCIDSK_PCT( this, segment, segment_pointer );
     293           2 :         break;
     294             : 
     295           0 :       case SEG_BPCT:
     296           0 :         segobj = new CPCIDSK_BPCT( this, segment, segment_pointer );
     297           0 :         break;
     298             : 
     299           0 :       case SEG_LUT:
     300           0 :         segobj = new CPCIDSK_LUT( this, segment, segment_pointer );
     301           0 :         break;
     302             : 
     303           0 :       case SEG_BLUT:
     304           0 :         segobj = new CPCIDSK_BLUT( this, segment, segment_pointer );
     305           0 :         break;
     306             : 
     307        1185 :       case SEG_VEC:
     308        1185 :         segobj = new CPCIDSKVectorSegment( this, segment, segment_pointer );
     309        1185 :         break;
     310             : 
     311           0 :       case SEG_BIT:
     312           0 :         segobj = new CPCIDSKBitmap( this, segment, segment_pointer );
     313           0 :         break;
     314             : 
     315           0 :       case SEG_TEX:
     316           0 :         segobj = new CPCIDSK_TEX( this, segment, segment_pointer );
     317           0 :         break;
     318             : 
     319         158 :       case SEG_SYS:
     320         158 :         if (STARTS_WITH(segment_pointer + 4, "SysBMDir") ||
     321         145 :             STARTS_WITH(segment_pointer + 4, "TileDir"))
     322             :         {
     323          32 :             segobj = new SysTileDir( this, segment, segment_pointer );
     324             :         }
     325         126 :         else if( STARTS_WITH(segment_pointer + 4, "METADATA") )
     326          98 :             segobj = new MetadataSegment( this, segment, segment_pointer );
     327          28 :         else if (STARTS_WITH(segment_pointer + 4, "Link    ") )
     328           0 :             segobj = new CLinkSegment(this, segment, segment_pointer);
     329             :         else
     330          28 :             segobj = new CPCIDSKSegment( this, segment, segment_pointer );
     331             : 
     332         158 :         break;
     333             : 
     334           0 :       case SEG_GCP2:
     335           0 :         segobj = new CPCIDSKGCP2Segment(this, segment, segment_pointer);
     336           0 :         break;
     337             : 
     338           0 :       case SEG_ORB:
     339           0 :         segobj = new CPCIDSKEphemerisSegment(this, segment, segment_pointer);
     340           0 :         break;
     341             : 
     342           0 :       case SEG_ARR:
     343           0 :         segobj = new CPCIDSK_ARRAY(this, segment, segment_pointer);
     344           0 :         break;
     345             : 
     346           0 :       case SEG_BIN:
     347           0 :         if (STARTS_WITH(segment_pointer + 4, "RFMODEL "))
     348             :         {
     349           0 :             segobj = new CPCIDSKRPCModelSegment( this, segment, segment_pointer );
     350             :         }
     351           0 :         else if (STARTS_WITH(segment_pointer + 4, "APMODEL "))
     352             :         {
     353           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     354             :         }
     355           0 :         else if (STARTS_WITH(segment_pointer + 4, "POLYMDL "))
     356             :         {
     357           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     358             :         }
     359           0 :         else if (STARTS_WITH(segment_pointer + 4, "TPSMODEL"))
     360             :         {
     361           0 :             segobj = new CPCIDSKGCP2Segment(this, segment, segment_pointer);
     362             :         }
     363           0 :         else if (STARTS_WITH(segment_pointer + 4, "RTCSMDL "))
     364             :         {
     365           0 :             segobj = new CPCIDSKGCP2Segment(this, segment, segment_pointer);
     366             :         }
     367           0 :         else if (STARTS_WITH(segment_pointer + 4, "MMRTCS  "))
     368             :         {
     369           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     370             :         }
     371           0 :         else if (STARTS_WITH(segment_pointer + 4, "MODEL   "))
     372             :         {
     373           0 :             segobj = new CPCIDSKToutinModelSegment(this, segment, segment_pointer);
     374             :         }
     375           0 :         else if (STARTS_WITH(segment_pointer + 4, "MMSPB   "))
     376             :         {
     377           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     378             :         }
     379           0 :         else if (STARTS_WITH(segment_pointer + 4, "MMADS   "))
     380             :         {
     381           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     382             :         }
     383           0 :         else if (STARTS_WITH(segment_pointer + 4, "MMSRS   "))
     384             :         {
     385           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     386             :         }
     387           0 :         else if (STARTS_WITH(segment_pointer + 4, "MMSGS   "))
     388             :         {
     389           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     390             :         }
     391           0 :         else if (STARTS_WITH(segment_pointer + 4, "LRSMODEL"))
     392             :         {
     393           0 :             segobj = new CPCIDSKGCP2Segment(this, segment, segment_pointer);
     394             :         }
     395           0 :         else if (STARTS_WITH(segment_pointer + 4, "MMLRS   "))
     396             :         {
     397           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     398             :         }
     399           0 :         else if (STARTS_WITH(segment_pointer + 4, "EPIPOLAR"))
     400             :         {
     401           0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     402             :         }
     403           0 :         break;
     404             :     }
     405             : 
     406        1466 :     if (segobj == nullptr)
     407           0 :         segobj = new CPCIDSKSegment( this, segment, segment_pointer );
     408             : 
     409        1466 :     segments[segment] = segobj;
     410             : 
     411        1466 :     return segobj;
     412             : }
     413             : 
     414             : /************************************************************************/
     415             : /*                             GetSegment()                             */
     416             : /*                                                                      */
     417             : /*      Find segment by type/name.                                      */
     418             : /************************************************************************/
     419             : 
     420        2522 : PCIDSK::PCIDSKSegment *CPCIDSKFile::GetSegment( int type, const std::string & name,
     421             :                                                 int previous)
     422             : {
     423             :     int  i;
     424             :     char type_str[16];
     425             : 
     426             :     //we want the 3 less significant digit only in case type is too big
     427             :     // Note : that happen with SEG_VEC_TABLE that is equal to 65652 in GDB.
     428             :     //see function BuildChildrenLayer in jtfile.cpp, the call on GDBSegNext
     429             :     //in the loop on gasTypeTable can create issue in PCIDSKSegNext
     430             :     //(in pcic/gdbfrtms/pcidskopen.cpp)
     431        2522 :     CPLsnprintf( type_str, sizeof(type_str), "%03d", (type % 1000) );
     432     2453590 :     for( i = previous; i < segment_count; i++ )
     433             :     {
     434     2451420 :         if( type != SEG_UNKNOWN
     435     2451420 :             && strncmp(segment_pointers.buffer+i*32+1,type_str,3) != 0 )
     436     2450840 :             continue;
     437             : 
     438         577 :         auto pszName = segment_pointers.buffer + i*32 + 4;
     439         577 :         if(!CheckSegNamesEqual(pszName, 8, name.data(), (unsigned)name.size()))
     440         232 :             continue;
     441             : 
     442             :         // Ignore deleted segments.
     443         345 :         if (*(segment_pointers.buffer + i * 32 + 0) == 'D') continue;
     444             : 
     445         345 :         return GetSegment(i+1);
     446             :     }
     447             : 
     448        2177 :     return nullptr;
     449             : }
     450             : 
     451           0 : unsigned int CPCIDSKFile::GetSegmentID(int type, const std::string &name,
     452             :                                        unsigned previous) const
     453             : {
     454             :     //we want the 3 less significant digit only in case type is too big
     455             :     // Note : that happen with SEG_VEC_TABLE that is equal to 65652 in GDB.
     456             :     //see function BuildChildrenLayer in jtfile.cpp, the call on GDBSegNext
     457             :     //in the loop on gasTypeTable can create issue in PCIDSKSegNext
     458             :     //(in pcic/gdbfrtms/pcidskopen.cpp)
     459             :     char type_str[16];
     460           0 :     CPLsnprintf(type_str, sizeof(type_str), "%03d", (type % 1000) );
     461             : 
     462           0 :     for(int i = previous; i < segment_count; i++ )
     463             :     {
     464           0 :         if( type != SEG_UNKNOWN
     465           0 :             && strncmp(segment_pointers.buffer+i*32+1,type_str,3) != 0 )
     466           0 :             continue;
     467             : 
     468           0 :         auto pszName = segment_pointers.buffer + i*32 + 4;
     469           0 :         if(!CheckSegNamesEqual(pszName, 8, name.data(), (unsigned)name.size()))
     470           0 :             continue;
     471             : 
     472             :         // Ignore deleted segments.
     473           0 :         if (*(segment_pointers.buffer + i * 32 + 0) == 'D') continue;
     474             : 
     475           0 :         return i+1;
     476             :     }
     477           0 :     return 0;
     478             : }
     479             : 
     480           0 : std::vector<unsigned> CPCIDSKFile::GetSegmentIDs(int type,
     481             :            const std::function<bool(const char *,unsigned)> & oFilter) const
     482             : {
     483           0 :     std::vector<unsigned> vnSegments;
     484             :     char type_str[16];
     485           0 :     CPLsnprintf(type_str, sizeof(type_str), "%03d", (type % 1000) );
     486             : 
     487           0 :     for(int i = 0; i < segment_count; i++)
     488             :     {
     489           0 :         if( type != SEG_UNKNOWN
     490           0 :             && strncmp(segment_pointers.buffer+i*32+1,type_str,3) != 0 )
     491           0 :             continue;
     492             : 
     493           0 :         auto pszName = segment_pointers.buffer + i*32 + 4;
     494           0 :         if(!oFilter(pszName, 8))
     495           0 :             continue;
     496             : 
     497             :         // Ignore deleted segments.
     498           0 :         if (*(segment_pointers.buffer + i * 32 + 0) == 'D') continue;
     499             : 
     500           0 :         vnSegments.push_back(i + 1);
     501             :     }
     502           0 :     return vnSegments;
     503             : }
     504             : 
     505             : /************************************************************************/
     506             : /*                        InitializeFromHeader()                        */
     507             : /************************************************************************/
     508             : 
     509         257 : void CPCIDSKFile::InitializeFromHeader(int max_channel_count_allowed)
     510             : 
     511             : {
     512             : /* -------------------------------------------------------------------- */
     513             : /*      Process the file header.                                        */
     514             : /* -------------------------------------------------------------------- */
     515         258 :     PCIDSKBuffer fh(512);
     516             : 
     517         257 :     ReadFromFile( fh.buffer, 0, 512 );
     518             : 
     519         257 :     width = atoi(fh.Get(384,8));
     520         257 :     height = atoi(fh.Get(392,8));
     521         257 :     channel_count = atoi(fh.Get(376,8));
     522         257 :     if( width < 0 || height < 0 || channel_count < 0 )
     523             :     {
     524           0 :         return ThrowPCIDSKException(
     525           0 :             "Invalid width, height and/or channel_count" );
     526             :     }
     527         257 :     if( max_channel_count_allowed >= 0 && channel_count > max_channel_count_allowed )
     528             :     {
     529           0 :         return ThrowPCIDSKException(
     530             :             "channel_count = %d exceeds max_channel_count_allowed = %d",
     531             :             channel_count,
     532           0 :             max_channel_count_allowed );
     533             :     }
     534         257 :     file_size = fh.GetUInt64(16,16);
     535             : 
     536         257 :     if (file_size > std::numeric_limits<uint64>::max() / 512)
     537             :     {
     538           0 :         return ThrowPCIDSKException("Invalid file_size: " PCIDSK_FRMT_UINT64,
     539           0 :                                     file_size);
     540             :     }
     541             : 
     542         257 :     uint64 ih_start_block = atouint64(fh.Get(336,16));
     543         257 :     uint64 image_start_block = atouint64(fh.Get(304,16));
     544         257 :     fh.Get(360,8,interleaving);
     545             : 
     546         514 :     if( image_start_block == 0 ||
     547         257 :         image_start_block-1 > std::numeric_limits<uint64>::max() / 512 )
     548             :     {
     549           0 :         return ThrowPCIDSKException(
     550           0 :             "Invalid image_start_block: " PCIDSK_FRMT_UINT64, image_start_block );
     551             :     }
     552         257 :     uint64 image_offset = (image_start_block-1) * 512;
     553             : 
     554         257 :     block_size = 0;
     555         257 :     last_block_index = -1;
     556         257 :     last_block_dirty = false;
     557         257 :     last_block_data = nullptr;
     558         257 :     last_block_mutex = nullptr;
     559             : 
     560             : /* -------------------------------------------------------------------- */
     561             : /*      Load the segment pointers into a PCIDSKBuffer.  For now we      */
     562             : /*      try to avoid doing too much other processing on them.           */
     563             : /* -------------------------------------------------------------------- */
     564         257 :     int segment_block_count = atoi(fh.Get(456,8));
     565         514 :     if( segment_block_count < 0 ||
     566         257 :         segment_block_count > std::numeric_limits<int>::max() / 512 )
     567           0 :         return ThrowPCIDSKException( "Invalid segment_block_count: %d",
     568           0 :                                      segment_block_count );
     569             : 
     570         257 :     segment_pointers_offset = atouint64(fh.Get(440,16));
     571         257 :     if( segment_pointers_offset == 0 ||
     572         257 :         segment_pointers_offset-1 > file_size )
     573             :     {
     574           0 :         return ThrowPCIDSKException(
     575           0 :             "Invalid segment_pointers_offset: " PCIDSK_FRMT_UINT64, segment_pointers_offset );
     576             :     }
     577         257 :     segment_pointers_offset = segment_pointers_offset * 512 - 512;
     578             : 
     579             :     // Sanity check to avoid allocating too much memory
     580         257 :     if( segment_block_count * 512 > 100 * 1024 * 1024 )
     581             :     {
     582           2 :         MutexHolder oHolder( io_mutex );
     583             : 
     584           1 :         interfaces.io->Seek( io_handle, 0, SEEK_END );
     585           1 :         const auto nRealFileSize = interfaces.io->Tell( io_handle );
     586           1 :         if( segment_pointers_offset > nRealFileSize )
     587             :         {
     588           1 :             return ThrowPCIDSKException(
     589           0 :                 "Invalid segment_pointers_offset: " PCIDSK_FRMT_UINT64, segment_pointers_offset );
     590             :         }
     591           0 :         if( static_cast<unsigned>(segment_block_count * 512) > nRealFileSize - segment_pointers_offset )
     592             :         {
     593             :             // I guess we could also decide to error out
     594           0 :             segment_block_count = static_cast<int>((nRealFileSize - segment_pointers_offset) / 512);
     595             :         }
     596             :     }
     597             : 
     598         256 :     segment_count = (segment_block_count * 512) / 32;
     599         256 :     segment_pointers.SetSize( segment_block_count * 512 );
     600             : 
     601         256 :     ReadFromFile( segment_pointers.buffer, segment_pointers_offset,
     602         256 :                   segment_block_count * 512 );
     603             : 
     604         256 :     segments.resize( segment_count + 1 );
     605             : 
     606             : /* -------------------------------------------------------------------- */
     607             : /*      Get the number of each channel type - only used for some        */
     608             : /*      interleaving cases.                                             */
     609             : /* -------------------------------------------------------------------- */
     610         256 :     int count_8u = 0;
     611         256 :     int count_16s = 0;
     612         256 :     int count_16u = 0;
     613         256 :     int count_32r = 0;
     614         256 :     int count_c16u = 0;
     615         256 :     int count_c16s = 0;
     616         256 :     int count_c32r = 0;
     617             : 
     618         256 :     int16 count_32s = 0;
     619         256 :     int16 count_32u = 0;
     620         256 :     int16 count_64s = 0;
     621         256 :     int16 count_64u = 0;
     622         256 :     int16 count_64r = 0;
     623         256 :     int16 count_c32s = 0;
     624         256 :     int16 count_c32u = 0;
     625             : 
     626         256 :     if (strcmp(fh.Get(464,4), "    ") == 0)
     627             :     {
     628           0 :         count_8u = channel_count;
     629             :     }
     630             :     else
     631             :     {
     632         256 :         count_8u = atoi(fh.Get(464,4));
     633         256 :         count_16s = atoi(fh.Get(468,4));
     634         256 :         count_16u = atoi(fh.Get(472,4));
     635         256 :         count_32r = atoi(fh.Get(476,4));
     636         256 :         count_c16u = atoi(fh.Get(480,4));
     637         256 :         count_c16s = atoi(fh.Get(484,4));
     638         256 :         count_c32r = atoi(fh.Get(488,4));
     639             : 
     640         256 :         count_32s = *(int16 *) fh.Get(492,2);
     641         256 :         count_32u = *(int16 *) fh.Get(494,2);
     642         256 :         count_64s = *(int16 *) fh.Get(496,2);
     643         256 :         count_64u = *(int16 *) fh.Get(498,2);
     644         256 :         count_64r = *(int16 *) fh.Get(500,2);
     645         256 :         count_c32s = *(int16 *) fh.Get(502,2);
     646         256 :         count_c32u = *(int16 *) fh.Get(504,2);
     647             : 
     648         256 :         if (!BigEndianSystem())
     649             :         {
     650         256 :             SwapData(&count_32s, 2, 1);
     651         256 :             SwapData(&count_32u, 2, 1);
     652         256 :             SwapData(&count_64s, 2, 1);
     653         256 :             SwapData(&count_64u, 2, 1);
     654         256 :             SwapData(&count_64r, 2, 1);
     655         256 :             SwapData(&count_c32s, 2, 1);
     656         256 :             SwapData(&count_c32u, 2, 1);
     657             :         }
     658             : 
     659             :         // 8224 is two space characters.
     660         256 :         if (count_32s == 8224)
     661           5 :             count_32s = 0;
     662         256 :         if (count_32u == 8224)
     663           5 :             count_32u = 0;
     664         256 :         if (count_64s == 8224)
     665           5 :             count_64s = 0;
     666         256 :         if (count_64u == 8224)
     667           5 :             count_64u = 0;
     668         256 :         if (count_64r == 8224)
     669           5 :             count_64r = 0;
     670         256 :         if (count_c32s == 8224)
     671           5 :             count_c32s = 0;
     672         256 :         if (count_c32u == 8224)
     673           5 :             count_c32u = 0;
     674             :     }
     675             : 
     676         256 :     if (channel_count !=
     677         256 :         count_8u +
     678         256 :         count_16s +
     679         256 :         count_16u +
     680         256 :         count_32s +
     681         256 :         count_32u +
     682         256 :         count_32r +
     683         256 :         count_64s +
     684         256 :         count_64u +
     685         256 :         count_64r +
     686         256 :         count_c16s +
     687         256 :         count_c16u +
     688         256 :         count_c32s +
     689         256 :         count_c32u +
     690             :         count_c32r)
     691             :     {
     692           0 :         return ThrowPCIDSKException("The file seems to contain an unsupported data type.");
     693             :     }
     694             : 
     695             : /* -------------------------------------------------------------------- */
     696             : /*      for pixel interleaved files we need to compute the length of    */
     697             : /*      a scanline padded out to a 512 byte boundary.                   */
     698             : /* -------------------------------------------------------------------- */
     699         256 :     if( interleaving == "PIXEL" )
     700             :     {
     701           0 :         first_line_offset = image_offset;
     702           0 :         pixel_group_size =
     703           0 :             count_8u +
     704           0 :             count_16s*2 +
     705           0 :             count_16u*2 +
     706           0 :             count_32s*4 +
     707           0 :             count_32u*4 +
     708           0 :             count_32r*4 +
     709           0 :             count_64s*8 +
     710           0 :             count_64u*8 +
     711           0 :             count_64r*8 +
     712           0 :             count_c16u*4 +
     713           0 :             count_c16s*4 +
     714           0 :             count_c32u*8 +
     715           0 :             count_c32s*8 +
     716           0 :             count_c32r*8;
     717             : 
     718           0 :         block_size = static_cast<PCIDSK::uint64>(pixel_group_size) * width;
     719           0 :         if( block_size % 512 != 0 )
     720           0 :             block_size += 512 - (block_size % 512);
     721             :         if( block_size != static_cast<size_t>(block_size) )
     722             :         {
     723             :              return ThrowPCIDSKException(
     724             :                 "Allocating " PCIDSK_FRMT_UINT64 " bytes for scanline "
     725             :                 "buffer failed.", block_size );
     726             :         }
     727             : 
     728           0 :         last_block_data = calloc(1, static_cast<size_t>(block_size));
     729           0 :         if( last_block_data == nullptr )
     730             :         {
     731           0 :              return ThrowPCIDSKException(
     732             :                 "Allocating " PCIDSK_FRMT_UINT64 " bytes for scanline "
     733           0 :                 "buffer failed.", block_size );
     734             :         }
     735             : 
     736           0 :         last_block_mutex = interfaces.CreateMutex();
     737           0 :         image_offset = 0;
     738             :     }
     739             : 
     740             : /* -------------------------------------------------------------------- */
     741             : /*      Initialize the list of channels.                                */
     742             : /* -------------------------------------------------------------------- */
     743             :     int channelnum;
     744             : 
     745         498 :     for( channelnum = 1; channelnum <= channel_count; channelnum++ )
     746             :     {
     747         242 :         PCIDSKBuffer ih(1024);
     748         242 :         PCIDSKChannel *channel = nullptr;
     749         484 :         if( ih_start_block == 0 ||
     750         484 :             ih_start_block-1 > std::numeric_limits<uint64>::max() / 512 ||
     751         242 :             (ih_start_block-1)*512 > std::numeric_limits<uint64>::max() - (channelnum-1)*1024 )
     752             :         {
     753           0 :             return ThrowPCIDSKException( "Integer overflow when computing ih_offset");
     754             :         }
     755         242 :         uint64  ih_offset = (ih_start_block-1)*512 + (channelnum-1)*1024;
     756             : 
     757         242 :         ReadFromFile( ih.buffer, ih_offset, 1024 );
     758             : 
     759             :         // fetch the filename, if there is one.
     760         242 :         std::string filename;
     761         242 :         ih.Get(64,64,filename);
     762         242 :         filename.resize(strlen(filename.c_str()));
     763             : 
     764             :         // Check for an extended link file
     765         242 :         bool bLinked = false;
     766         242 :         if (STARTS_WITH(filename.c_str(), "LNK"))
     767             :         {
     768           0 :             std::string seg_str(filename, 4, 4);
     769           0 :             unsigned int seg_num = std::atoi(seg_str.c_str());
     770             : 
     771           0 :             if (seg_num == 0)
     772             :             {
     773             :                 throw PCIDSKException("Unable to find link segment. Link name:%s",
     774           0 :                                       filename.c_str());
     775             :             }
     776             : 
     777             :             CLinkSegment* link_seg =
     778           0 :                 dynamic_cast<CLinkSegment*>(GetSegment(seg_num));
     779           0 :             if (link_seg == nullptr)
     780             :             {
     781           0 :                 throw PCIDSKException("Failed to get Link Information Segment.");
     782             :             }
     783             : 
     784           0 :             filename = link_seg->GetPath();
     785           0 :             bLinked = true;
     786             :         }
     787          28 :         else if (!filename.empty() &&
     788         270 :                  filename != "<uninitialized>" &&
     789         269 :                  filename.substr(0,5) != "/SIS=")
     790             :         {
     791             :             // adjust it relative to the path of the pcidsk file.
     792           4 :             std::string oTmp = interfaces.MergeRelativePath(interfaces.io,base_filename,filename);
     793             : 
     794           6 :             if(std::ifstream( filename.c_str() ).is_open() ||
     795           4 :                std::ifstream( oTmp.c_str() ).is_open() )
     796             :             {
     797           2 :                 bLinked = true;
     798             :             }
     799             : 
     800             :             try
     801             :             {
     802          10 :                 PCIDSK::EDBFile* poEDBFile = interfaces.OpenEDB(oTmp.c_str(),"r");
     803           0 :                 delete poEDBFile;
     804           0 :                 bLinked = true;
     805             :             }
     806           2 :             catch(...)
     807             :             {
     808           2 :                 bLinked = false;
     809             :             }
     810             :         }
     811         242 :         if (bLinked)
     812             :         {
     813             :             // adjust it relative to the path of the pcidsk file.
     814           0 :             filename = interfaces.MergeRelativePath(interfaces.io,base_filename,filename);
     815             :         }
     816             :         // work out channel type from header
     817             :         eChanType pixel_type;
     818         242 :         const char *pixel_type_string = ih.Get( 160, 8 );
     819             : 
     820         242 :         pixel_type = GetDataTypeFromName(pixel_type_string);
     821             : 
     822             :         // For file interleaved channels, we expect a valid channel type.
     823         242 :         if (interleaving == "FILE" && pixel_type == CHN_UNKNOWN)
     824             :         {
     825           0 :             return ThrowPCIDSKException("Invalid or unsupported channel type: %s",
     826           0 :                                         pixel_type_string);
     827             :         }
     828             : 
     829             :         // if we didn't get channel type in header, work out from counts (old).
     830             :         // Check this only if we don't have complex channels:
     831             : 
     832         242 :         if (STARTS_WITH(pixel_type_string,"        "))
     833             :         {
     834           0 :             if( !( count_c32r == 0 && count_c16u == 0 && count_c16s == 0 ) )
     835           0 :                 return ThrowPCIDSKException("Assertion 'count_c32r == 0 && count_c16u == 0 && count_c16s == 0' failed");
     836             : 
     837           0 :             if( channelnum <= count_8u )
     838           0 :                 pixel_type = CHN_8U;
     839           0 :             else if( channelnum <= count_8u + count_16s )
     840           0 :                 pixel_type = CHN_16S;
     841           0 :             else if( channelnum <= count_8u + count_16s + count_16u )
     842           0 :                 pixel_type = CHN_16U;
     843             :             else
     844           0 :                 pixel_type = CHN_32R;
     845             :         }
     846             : 
     847         242 :         if( interleaving == "BAND"  )
     848             :         {
     849         214 :             channel = new CBandInterleavedChannel( ih, ih_offset, fh,
     850             :                                                    channelnum, this,
     851         214 :                                                    image_offset, pixel_type );
     852             : 
     853             : 
     854         214 :             image_offset += (int64)DataTypeSize(channel->GetType())
     855         214 :                 * (int64)width * (int64)height;
     856             :         }
     857             : 
     858          28 :         else if( interleaving == "PIXEL" )
     859             :         {
     860           0 :             channel = new CPixelInterleavedChannel( ih, ih_offset, fh,
     861             :                                                     channelnum, this,
     862             :                                                     (int) image_offset,
     863           0 :                                                     pixel_type );
     864           0 :             image_offset += DataTypeSize(pixel_type);
     865             :         }
     866             : 
     867          28 :         else if( interleaving == "FILE"
     868          28 :                  && STARTS_WITH(filename.c_str(), "/SIS=") )
     869             :         {
     870          25 :             channel = new CTiledChannel( ih, ih_offset, fh,
     871          25 :                                          channelnum, this, pixel_type );
     872             :         }
     873             : 
     874           9 :         else if( bLinked ||
     875           3 :                  (interleaving == "FILE"
     876           3 :                  && filename != ""
     877           3 :                  && !STARTS_WITH(((const char*)ih.buffer)+282, "        ")) )
     878             :         {
     879           0 :             channel = new CExternalChannel( ih, ih_offset, fh, filename,
     880           0 :                                             channelnum, this, pixel_type );
     881             :         }
     882             : 
     883           3 :         else if( interleaving == "FILE" )
     884             :         {
     885           3 :             channel = new CBandInterleavedChannel( ih, ih_offset, fh,
     886             :                                                    channelnum, this,
     887           3 :                                                    0, pixel_type );
     888             :         }
     889             : 
     890             :         else
     891           0 :             return ThrowPCIDSKException( "Unsupported interleaving:%s",
     892           0 :                                        interleaving.c_str() );
     893             : 
     894         242 :         channels.push_back( channel );
     895             :     }
     896             : }
     897             : 
     898             : /************************************************************************/
     899             : /*                            ReadFromFile()                            */
     900             : /************************************************************************/
     901             : 
     902        4513 : void CPCIDSKFile::ReadFromFile( void *buffer, uint64 offset, uint64 size )
     903             : 
     904             : {
     905        4513 :     MutexHolder oHolder( io_mutex );
     906             : 
     907        4513 :     interfaces.io->Seek( io_handle, offset, SEEK_SET );
     908             : 
     909        4513 :     uint64 nReadSize = interfaces.io->Read(buffer, 1, size, io_handle);
     910             : 
     911        4513 :     if (nReadSize != size)
     912             :     {
     913             :         // Only throw an exception if the sum of the offset and size is
     914             :         // greater than the internal file size.
     915           8 :         if (offset + size > file_size * 512)
     916             :         {
     917           0 :             std::stringstream oOffsetStream;
     918           0 :             std::stringstream oSizeStream;
     919             : 
     920           0 :             oOffsetStream << offset;
     921           0 :             oSizeStream << size;
     922             : 
     923           0 :             return ThrowPCIDSKException("Failed to read %s bytes at offset %s in file: %s",
     924           0 :                            oSizeStream.str().c_str(),
     925           0 :                            oOffsetStream.str().c_str(),
     926           0 :                            base_filename.c_str());
     927             :         }
     928             : 
     929             :         // If we were not able to read the requested size, initialize
     930             :         // the remaining bytes to 0.
     931           8 :         std::memset((char *) buffer + nReadSize, 0,
     932           8 :                     static_cast<size_t>(size - nReadSize));
     933             :     }
     934             : }
     935             : 
     936             : /************************************************************************/
     937             : /*                            WriteToFile()                             */
     938             : /************************************************************************/
     939             : 
     940       11754 : void CPCIDSKFile::WriteToFile( const void *buffer, uint64 offset, uint64 size )
     941             : 
     942             : {
     943       11754 :     if( !GetUpdatable() )
     944           0 :         throw PCIDSKException( "File not open for update in WriteToFile()" );
     945             : 
     946       23508 :     MutexHolder oHolder( io_mutex );
     947             : 
     948       11754 :     interfaces.io->Seek( io_handle, offset, SEEK_SET );
     949             : 
     950       11754 :     uint64 nWriteSize = interfaces.io->Write(buffer, 1, size, io_handle);
     951             : 
     952       11754 :     if (nWriteSize != size)
     953             :     {
     954           2 :         std::stringstream oOffsetStream;
     955           2 :         std::stringstream oSizeStream;
     956             : 
     957           1 :         oOffsetStream << offset;
     958           1 :         oSizeStream << size;
     959             : 
     960           3 :         ThrowPCIDSKException("Failed to write %s bytes at offset %s in file: %s",
     961           3 :                        oSizeStream.str().c_str(),
     962           3 :                        oOffsetStream.str().c_str(),
     963             :                        base_filename.c_str());
     964             :     }
     965       11753 : }
     966             : 
     967             : /************************************************************************/
     968             : /*                          ReadAndLockBlock()                          */
     969             : /************************************************************************/
     970             : 
     971           0 : void *CPCIDSKFile::ReadAndLockBlock( int block_index,
     972             :                                      int win_xoff, int win_xsize )
     973             : 
     974             : {
     975           0 :     if( last_block_data == nullptr )
     976           0 :         return ThrowPCIDSKExceptionPtr( "ReadAndLockBlock() called on a file that is not pixel interleaved." );
     977             : 
     978             : /* -------------------------------------------------------------------- */
     979             : /*      Default, and validate windowing.                                */
     980             : /* -------------------------------------------------------------------- */
     981           0 :     if( win_xoff == -1 && win_xsize == -1 )
     982             :     {
     983           0 :         win_xoff = 0;
     984           0 :         win_xsize = GetWidth();
     985             :     }
     986             : 
     987           0 :     if( win_xoff < 0 || win_xoff+win_xsize > GetWidth() )
     988             :     {
     989           0 :         return ThrowPCIDSKExceptionPtr( "CPCIDSKFile::ReadAndLockBlock(): Illegal window - xoff=%d, xsize=%d",
     990           0 :                                    win_xoff, win_xsize );
     991             :     }
     992             : 
     993           0 :     if( block_index == last_block_index
     994           0 :         && win_xoff == last_block_xoff
     995           0 :         && win_xsize == last_block_xsize )
     996             :     {
     997           0 :         last_block_mutex->Acquire();
     998           0 :         return last_block_data;
     999             :     }
    1000             : 
    1001             : /* -------------------------------------------------------------------- */
    1002             : /*      Flush any dirty writable data.                                  */
    1003             : /* -------------------------------------------------------------------- */
    1004             :     // We cannot use FlushBlock() because this method needs to acquire the
    1005             :     // last_block_mutex but we must do everything at once with last_block_data
    1006             :     // to prevent race conditions.
    1007             :     //
    1008             :     // --------------------------------------------------------------------
    1009             :     // Process 1                             Process 2
    1010             :     // FlushBlock()
    1011             :     //                                       FlushBlock()
    1012             :     // last_block_mutex->Acquire();
    1013             :     // ReadFromFile(last_block_data);
    1014             :     // last_block_mutex->Release();
    1015             :     //                                       last_block_mutex->Acquire();
    1016             :     //                                       ReadFromFile(last_block_data);
    1017             :     //                                       last_block_mutex->Release();
    1018             :     // --------------------------------------------------------------------
    1019             :     //
    1020             :     // Now the data in last_block_data set by process 1 will never be flushed
    1021             :     // because process 2 overwrites it without calling FlushBlock.
    1022             : 
    1023           0 :     last_block_mutex->Acquire();
    1024             : 
    1025           0 :     if( last_block_dirty )
    1026             :     {
    1027           0 :         WriteBlock( last_block_index, last_block_data );
    1028           0 :         last_block_dirty = 0;
    1029             :     }
    1030             : /* -------------------------------------------------------------------- */
    1031             : /*      Read the requested window.                                      */
    1032             : /* -------------------------------------------------------------------- */
    1033             : 
    1034           0 :     ReadFromFile( last_block_data,
    1035           0 :                   first_line_offset + block_index*block_size
    1036           0 :                   + static_cast<uint64_t>(win_xoff) * pixel_group_size,
    1037           0 :                   static_cast<uint64_t>(pixel_group_size) * win_xsize );
    1038           0 :     last_block_index = block_index;
    1039           0 :     last_block_xoff = win_xoff;
    1040           0 :     last_block_xsize = win_xsize;
    1041             : 
    1042           0 :     return last_block_data;
    1043             : }
    1044             : 
    1045             : /************************************************************************/
    1046             : /*                            UnlockBlock()                             */
    1047             : /************************************************************************/
    1048             : 
    1049           0 : void CPCIDSKFile::UnlockBlock( bool mark_dirty )
    1050             : 
    1051             : {
    1052           0 :     if( last_block_mutex == nullptr )
    1053           0 :         return;
    1054             : 
    1055           0 :     last_block_dirty |= mark_dirty;
    1056           0 :     last_block_mutex->Release();
    1057             : }
    1058             : 
    1059             : /************************************************************************/
    1060             : /*                             WriteBlock()                             */
    1061             : /************************************************************************/
    1062             : 
    1063           0 : void CPCIDSKFile::WriteBlock( int block_index, void *buffer )
    1064             : 
    1065             : {
    1066           0 :     if( !GetUpdatable() )
    1067           0 :         return ThrowPCIDSKException( "File not open for update in WriteBlock()" );
    1068             : 
    1069           0 :     if( last_block_data == nullptr )
    1070           0 :         return ThrowPCIDSKException( "WriteBlock() called on a file that is not pixel interleaved." );
    1071             : 
    1072           0 :     WriteToFile( buffer,
    1073           0 :                  first_line_offset + block_index*block_size,
    1074             :                  block_size );
    1075             : }
    1076             : 
    1077             : /************************************************************************/
    1078             : /*                             FlushBlock()                             */
    1079             : /************************************************************************/
    1080             : 
    1081         247 : void CPCIDSKFile::FlushBlock()
    1082             : 
    1083             : {
    1084         247 :     if( last_block_dirty )
    1085             :     {
    1086           0 :         last_block_mutex->Acquire();
    1087           0 :         if( last_block_dirty ) // is it still dirty?
    1088             :         {
    1089           0 :             WriteBlock( last_block_index, last_block_data );
    1090           0 :             last_block_dirty = false;
    1091             :         }
    1092           0 :         last_block_mutex->Release();
    1093             :     }
    1094         247 : }
    1095             : 
    1096             : /************************************************************************/
    1097             : /*                         GetEDBFileDetails()                          */
    1098             : /************************************************************************/
    1099             : 
    1100           0 : bool CPCIDSKFile::GetEDBFileDetails( EDBFile** file_p,
    1101             :                                      Mutex **io_mutex_p,
    1102             :                                      const std::string& filename )
    1103             : 
    1104             : {
    1105           0 :     *file_p = nullptr;
    1106           0 :     *io_mutex_p = nullptr;
    1107             : 
    1108             : /* -------------------------------------------------------------------- */
    1109             : /*      Does the file exist already in our file list?                   */
    1110             : /* -------------------------------------------------------------------- */
    1111             :     unsigned int i;
    1112             : 
    1113           0 :     for( i = 0; i < edb_file_list.size(); i++ )
    1114             :     {
    1115           0 :         if( edb_file_list[i].filename == filename )
    1116             :         {
    1117           0 :             *file_p = edb_file_list[i].file;
    1118           0 :             *io_mutex_p = edb_file_list[i].io_mutex;
    1119           0 :             return edb_file_list[i].writable;
    1120             :         }
    1121             :     }
    1122             : 
    1123             : /* -------------------------------------------------------------------- */
    1124             : /*      If not, we need to try and open the file.  Eventually we        */
    1125             : /*      will need better rules about read or update access.             */
    1126             : /* -------------------------------------------------------------------- */
    1127           0 :     ProtectedEDBFile new_file;
    1128             : 
    1129           0 :     new_file.file = nullptr;
    1130           0 :     new_file.writable = false;
    1131             : 
    1132           0 :     if( GetUpdatable() )
    1133             :     {
    1134             :         try
    1135             :         {
    1136           0 :             new_file.file = interfaces.OpenEDB( filename, "r+" );
    1137           0 :             new_file.writable = true;
    1138             :         }
    1139           0 :         catch (PCIDSK::PCIDSKException &)
    1140             :         {
    1141             :         }
    1142           0 :         catch (std::exception &)
    1143             :         {
    1144             :         }
    1145             :     }
    1146             : 
    1147           0 :     if( new_file.file == nullptr )
    1148           0 :         new_file.file = interfaces.OpenEDB( filename, "r" );
    1149             : 
    1150           0 :     if( new_file.file == nullptr )
    1151           0 :         return ThrowPCIDSKException( 0, "Unable to open file '%s'.",
    1152           0 :                               filename.c_str() ) != 0;
    1153             : 
    1154             : /* -------------------------------------------------------------------- */
    1155             : /*      Push the new file into the list of files managed for this       */
    1156             : /*      PCIDSK file.                                                    */
    1157             : /* -------------------------------------------------------------------- */
    1158           0 :     new_file.io_mutex = interfaces.CreateMutex();
    1159           0 :     new_file.filename = filename;
    1160             : 
    1161           0 :     edb_file_list.push_back( new_file );
    1162             : 
    1163           0 :     *file_p = edb_file_list.back().file;
    1164           0 :     *io_mutex_p  = edb_file_list.back().io_mutex;
    1165             : 
    1166           0 :     return new_file.writable;
    1167             : }
    1168             : 
    1169             : /************************************************************************/
    1170             : /*                            GetUniqueEDBFilename()                    */
    1171             : /************************************************************************/
    1172             : /**
    1173             :  * If the PIX file is a link pix where all channels are linked
    1174             :  * to the same file, then this filename is given to be able to
    1175             :  * access it directly without going through PCIDSK code.
    1176             :  */
    1177           0 : std::string CPCIDSKFile::GetUniqueEDBFilename()
    1178             : {
    1179           0 :     bool bAllSameFile = true;
    1180           0 :     bool bAllExternal = true;
    1181             : 
    1182           0 :     std::string oEDBName;
    1183             : 
    1184           0 :     for(int iChan=1 ; iChan <= this->GetChannels() ; iChan++)
    1185             :     {
    1186           0 :         PCIDSK::PCIDSKChannel* poChannel = this->GetChannel(iChan);
    1187             : 
    1188             :         PCIDSK::CExternalChannel* poExt =
    1189           0 :             dynamic_cast<PCIDSK::CExternalChannel*>(poChannel);
    1190             : 
    1191           0 :         if(!poExt)
    1192             :         {
    1193           0 :             bAllExternal = false;
    1194           0 :             break;
    1195             :         }
    1196             : 
    1197             :         //trigger call to AccessDB()
    1198           0 :         poChannel->GetBlockWidth();
    1199             : 
    1200           0 :         std::string osFilename = poExt->GetExternalFilename();
    1201             : 
    1202           0 :         if(oEDBName.size() == 0)
    1203             :         {
    1204           0 :             oEDBName = std::move(osFilename);
    1205             :         }
    1206           0 :         else if(oEDBName != osFilename)
    1207             :         {
    1208           0 :             bAllSameFile = false;
    1209           0 :             break;
    1210             :         }
    1211             :     }
    1212             : 
    1213           0 :     if(bAllExternal && bAllSameFile)
    1214             :     {
    1215           0 :         return oEDBName;
    1216             :     }
    1217           0 :     return "";
    1218             : }
    1219             : 
    1220             : /************************************************************************/
    1221             : /*                              GetEDBChannelMap()                      */
    1222             : /************************************************************************/
    1223             : /**
    1224             :  * Gets the mapping between channels in this CPCIDSKFile and the channels
    1225             :  * they are linked to in the external file.
    1226             :  *
    1227             :  * Current File         External File
    1228             :  * 2 -----------------> 1
    1229             :  * 3 -----------------> 3
    1230             :  * 4 -----------------> 6
    1231             :  *
    1232             :  * This would return this map:
    1233             :  * (2,1), (3,3), (4,6)
    1234             :  *
    1235             :  * @param oExtFilename  The external file we want a mapping for
    1236             :  *
    1237             :  * @return A map with the mapping between the channels in the current file
    1238             :  *         and the channels the refer to in the external file.
    1239             :  */
    1240           0 : std::map<int,int> CPCIDSKFile::GetEDBChannelMap(std::string oExtFilename)
    1241             : {
    1242           0 :     std::map<int,int> vnChanMap;
    1243             : 
    1244           0 :     for(int iChan=1 ; iChan <= this->GetChannels() ; iChan++)
    1245             :     {
    1246           0 :         PCIDSK::PCIDSKChannel* poChannel = this->GetChannel(iChan);
    1247             : 
    1248             :         PCIDSK::CExternalChannel* poExt =
    1249           0 :             dynamic_cast<PCIDSK::CExternalChannel*>(poChannel);
    1250             : 
    1251           0 :         if(poExt)
    1252             :         {
    1253           0 :             std::string oFilename = poExt->GetExternalFilename();
    1254             : 
    1255           0 :             if(oExtFilename == oFilename)
    1256           0 :                 vnChanMap[iChan] = poExt->GetExternalChanNum();
    1257             :         }
    1258             :     }
    1259             : 
    1260           0 :     return vnChanMap;
    1261             : }
    1262             : 
    1263             : /************************************************************************/
    1264             : /*                            GetIODetails()                            */
    1265             : /************************************************************************/
    1266             : 
    1267         216 : void CPCIDSKFile::GetIODetails( void ***io_handle_pp,
    1268             :                                 Mutex ***io_mutex_pp,
    1269             :                                 const std::string& filename,
    1270             :                                 bool writable )
    1271             : 
    1272             : {
    1273         216 :     *io_handle_pp = nullptr;
    1274         216 :     *io_mutex_pp = nullptr;
    1275             : 
    1276             : /* -------------------------------------------------------------------- */
    1277             : /*      Does this reference the PCIDSK file itself?                     */
    1278             : /* -------------------------------------------------------------------- */
    1279         216 :     if( filename.empty() )
    1280             :     {
    1281         214 :         *io_handle_pp = &io_handle;
    1282         214 :         *io_mutex_pp = &io_mutex;
    1283         214 :         return;
    1284             :     }
    1285             : 
    1286             : /* -------------------------------------------------------------------- */
    1287             : /*      Does the file exist already in our file list?                   */
    1288             : /* -------------------------------------------------------------------- */
    1289             :     unsigned int i;
    1290             : 
    1291           2 :     for( i = 0; i < file_list.size(); i++ )
    1292             :     {
    1293           0 :         if( file_list[i].filename == filename
    1294           0 :             && (!writable || file_list[i].writable) )
    1295             :         {
    1296           0 :             *io_handle_pp = &(file_list[i].io_handle);
    1297           0 :             *io_mutex_pp = &(file_list[i].io_mutex);
    1298           0 :             return;
    1299             :         }
    1300             :     }
    1301             : 
    1302             : /* -------------------------------------------------------------------- */
    1303             : /*      If not, we need to try and open the file.  Eventually we        */
    1304             : /*      will need better rules about read or update access.             */
    1305             : /* -------------------------------------------------------------------- */
    1306           2 :     ProtectedFile new_file;
    1307             : 
    1308           2 :     if( writable )
    1309           1 :         new_file.io_handle = interfaces.io->Open( filename, "r+" );
    1310             :     else
    1311           1 :         new_file.io_handle = interfaces.io->Open( filename, "r" );
    1312             : 
    1313           2 :     if( new_file.io_handle == nullptr )
    1314           0 :         return ThrowPCIDSKException( "Unable to open file '%s'.",
    1315           0 :                               filename.c_str() );
    1316             : 
    1317             : /* -------------------------------------------------------------------- */
    1318             : /*      Push the new file into the list of files managed for this       */
    1319             : /*      PCIDSK file.                                                    */
    1320             : /* -------------------------------------------------------------------- */
    1321           2 :     new_file.io_mutex = interfaces.CreateMutex();
    1322           2 :     new_file.filename = filename;
    1323           2 :     new_file.writable = writable;
    1324             : 
    1325           2 :     file_list.push_back( std::move(new_file) );
    1326             : 
    1327           2 :     *io_handle_pp = &(file_list.back().io_handle);
    1328           2 :     *io_mutex_pp  = &(file_list.back().io_mutex);
    1329             : }
    1330             : 
    1331             : /************************************************************************/
    1332             : /*                           DeleteSegment()                            */
    1333             : /************************************************************************/
    1334             : 
    1335           1 : void CPCIDSKFile::DeleteSegment( int segment )
    1336             : 
    1337             : {
    1338             : /* -------------------------------------------------------------------- */
    1339             : /*      Is this an existing segment?                                    */
    1340             : /* -------------------------------------------------------------------- */
    1341           1 :     PCIDSKSegment *poSeg = GetSegment( segment );
    1342             : 
    1343           1 :     if( poSeg == nullptr )
    1344           0 :         return ThrowPCIDSKException( "DeleteSegment(%d) failed, segment does not exist.", segment );
    1345             : 
    1346             : /* -------------------------------------------------------------------- */
    1347             : /*      Wipe associated metadata.                                       */
    1348             : /* -------------------------------------------------------------------- */
    1349           2 :     std::vector<std::string> md_keys = poSeg->GetMetadataKeys();
    1350             :     unsigned int i;
    1351             : 
    1352           1 :     for( i = 0; i < md_keys.size(); i++ )
    1353           0 :         poSeg->SetMetadataValue( md_keys[i], "" );
    1354             : 
    1355             : /* -------------------------------------------------------------------- */
    1356             : /*      Remove the segment object from the segment object cache.  I     */
    1357             : /*      hope the application is not retaining any references to this    */
    1358             : /*      segment!                                                        */
    1359             : /* -------------------------------------------------------------------- */
    1360           1 :     segments[segment] = nullptr;
    1361           1 :     delete poSeg;
    1362             : 
    1363             : /* -------------------------------------------------------------------- */
    1364             : /*      Mark the segment pointer as deleted.                            */
    1365             : /* -------------------------------------------------------------------- */
    1366           1 :     segment_pointers.buffer[(segment-1)*32] = 'D';
    1367             : 
    1368             :     // write the updated segment pointer back to the file.
    1369           1 :     WriteToFile( segment_pointers.buffer + (segment-1)*32,
    1370           1 :                  segment_pointers_offset + (segment-1)*32,
    1371             :                  32 );
    1372             : }
    1373             : 
    1374             : /************************************************************************/
    1375             : /*                           CreateSegment()                            */
    1376             : /************************************************************************/
    1377             : 
    1378        1258 : int CPCIDSKFile::CreateSegment( std::string name, std::string description,
    1379             :                                 eSegType seg_type, int data_blocks )
    1380             : 
    1381             : {
    1382             : /* -------------------------------------------------------------------- */
    1383             : /*      Set the size of fixed length segments.                          */
    1384             : /* -------------------------------------------------------------------- */
    1385        1258 :     int expected_data_blocks = 0;
    1386        1258 :     bool prezero = false;
    1387             : 
    1388        1258 :     switch( seg_type )
    1389             :     {
    1390           1 :       case SEG_PCT:
    1391           1 :         expected_data_blocks = 6;
    1392           1 :         break;
    1393             : 
    1394           0 :       case SEG_BPCT:
    1395           0 :         expected_data_blocks = 12;
    1396           0 :         break;
    1397             : 
    1398           0 :       case SEG_LUT:
    1399           0 :         expected_data_blocks = 2;
    1400           0 :         break;
    1401             : 
    1402           0 :       case SEG_BLUT:
    1403           0 :         expected_data_blocks = 6;
    1404           0 :         break;
    1405             : 
    1406           0 :       case SEG_SIG:
    1407           0 :         expected_data_blocks = 12;
    1408           0 :         break;
    1409             : 
    1410           0 :       case SEG_GCP2:
    1411             :         // expected_data_blocks = 67;
    1412             :         // Change seg type to new GCP segment type
    1413           0 :         expected_data_blocks = 129;
    1414           0 :         break;
    1415             : 
    1416         119 :       case SEG_GEO:
    1417         119 :         expected_data_blocks = 6;
    1418         119 :         break;
    1419             : 
    1420           0 :       case SEG_TEX:
    1421           0 :         expected_data_blocks = 64;
    1422           0 :         prezero = true;
    1423           0 :         break;
    1424             : 
    1425           0 :       case SEG_BIT:
    1426             :       {
    1427           0 :           uint64 bytes = ((width * (uint64) height) + 7) / 8;
    1428           0 :           expected_data_blocks = (int) ((bytes + 511) / 512);
    1429           0 :           prezero = true;
    1430             :       }
    1431           0 :       break;
    1432             : 
    1433        1138 :       default:
    1434        1138 :         break;
    1435             :     }
    1436             : 
    1437        1258 :     if( data_blocks == 0 && expected_data_blocks != 0 )
    1438           1 :         data_blocks = expected_data_blocks;
    1439             : 
    1440             : /* -------------------------------------------------------------------- */
    1441             : /*      Find an empty Segment Pointer.  For System segments we start    */
    1442             : /*      at the end, instead of the beginning to avoid using up          */
    1443             : /*      segment numbers that the user would notice.                     */
    1444             : /* -------------------------------------------------------------------- */
    1445        1258 :     int segment = 1;
    1446        1258 :     int64 seg_start = -1;
    1447        2516 :     PCIDSKBuffer segptr( 32 );
    1448             : 
    1449        1258 :     if( seg_type == SEG_SYS )
    1450             :     {
    1451          73 :         for( segment=segment_count; segment >= 1; segment-- )
    1452             :         {
    1453          73 :             memcpy( segptr.buffer, segment_pointers.buffer+(segment-1)*32, 32);
    1454             : 
    1455          73 :             uint64 this_seg_size = segptr.GetUInt64(23,9);
    1456          73 :             char flag = (char) segptr.buffer[0];
    1457             : 
    1458          73 :             if( flag == 'D'
    1459           0 :                 && (uint64) data_blocks+2 == this_seg_size
    1460           0 :                 && this_seg_size > 0 )
    1461           0 :                 seg_start = segptr.GetUInt64(12,11) - 1;
    1462          73 :             else if( flag == ' ' )
    1463          49 :                 seg_start = 0;
    1464          24 :             else if( flag && this_seg_size == 0 )
    1465           0 :                 seg_start = 0;
    1466             : 
    1467          73 :             if( seg_start != -1 )
    1468          49 :                 break;
    1469             :         }
    1470             :     }
    1471             :     else
    1472             :     {
    1473      534313 :         for( segment=1; segment <= segment_count; segment++ )
    1474             :         {
    1475      534304 :             memcpy( segptr.buffer, segment_pointers.buffer+(segment-1)*32, 32);
    1476             : 
    1477      534304 :             uint64 this_seg_size = segptr.GetUInt64(23,9);
    1478      534304 :             char flag = (char) segptr.buffer[0];
    1479             : 
    1480      534304 :             if( flag == 'D'
    1481           0 :                 && (uint64) data_blocks+2 == this_seg_size
    1482           0 :                 && this_seg_size > 0 )
    1483           0 :                 seg_start = segptr.GetUInt64(12,11) - 1;
    1484      534304 :             else if( flag == ' ' )
    1485        1200 :                 seg_start = 0;
    1486      533104 :             else if( flag && this_seg_size == 0 )
    1487           0 :                 seg_start = 0;
    1488             : 
    1489      534304 :             if( seg_start != -1 )
    1490        1200 :                 break;
    1491             :         }
    1492             :     }
    1493             : 
    1494        1258 :     if( segment <= 0 || segment > segment_count )
    1495           9 :         return ThrowPCIDSKException(0, "All %d segment pointers in use.", segment_count);
    1496             : 
    1497             : /* -------------------------------------------------------------------- */
    1498             : /*      If the segment does not have a data area already, identify      */
    1499             : /*      its location at the end of the file, and extend the file to     */
    1500             : /*      the desired length.                                             */
    1501             : /* -------------------------------------------------------------------- */
    1502        1249 :     if( seg_start == 0 )
    1503             :     {
    1504        1249 :         seg_start = GetFileSize();
    1505        1249 :         ExtendFile( data_blocks + 2, prezero );
    1506             :     }
    1507             :     else
    1508             :     {
    1509           0 :         std::vector<uint8> zeros;
    1510           0 :         uint64 blocks_to_zero = data_blocks + 2;
    1511           0 :         uint64 segiter = seg_start;
    1512             : 
    1513           0 :         zeros.resize( 512 * 32 );
    1514             : 
    1515           0 :         while( blocks_to_zero > 0 )
    1516             :         {
    1517           0 :             uint64 this_time = blocks_to_zero;
    1518           0 :             if( this_time > 32 )
    1519           0 :                 this_time = 32;
    1520             : 
    1521           0 :             WriteToFile( &(zeros[0]), segiter * 512, this_time*512 );
    1522           0 :             blocks_to_zero -= this_time;
    1523           0 :             segiter += this_time;
    1524             :         }
    1525             :     }
    1526             : 
    1527             : /* -------------------------------------------------------------------- */
    1528             : /*      Update the segment pointer information.                         */
    1529             : /* -------------------------------------------------------------------- */
    1530             :     // SP1.1 - Flag
    1531        1248 :     segptr.Put( "A", 0, 1 );
    1532             : 
    1533             :     // SP1.2 - Type
    1534        1248 :     segptr.Put( (int) seg_type, 1, 3 );
    1535             : 
    1536             :     // SP1.3 - Name
    1537        1248 :     segptr.Put( name.c_str(), 4, 8 );
    1538             : 
    1539             :     // SP1.4 - start block
    1540        1248 :     segptr.Put( (uint64) (seg_start + 1), 12, 11 );
    1541             : 
    1542             :     // SP1.5 - data blocks.
    1543        1248 :     segptr.Put( data_blocks+2, 23, 9 );
    1544             : 
    1545             :     // Update in memory copy of segment pointers.
    1546        1248 :     memcpy( segment_pointers.buffer+(segment-1)*32, segptr.buffer, 32);
    1547             : 
    1548             :     // Update on disk.
    1549        1248 :     WriteToFile( segptr.buffer,
    1550        1248 :                  segment_pointers_offset + (segment-1)*32, 32 );
    1551             : 
    1552             : /* -------------------------------------------------------------------- */
    1553             : /*      Prepare segment header.                                         */
    1554             : /* -------------------------------------------------------------------- */
    1555        1248 :     PCIDSKBuffer sh(1024);
    1556             : 
    1557             :     char current_time[17];
    1558             : 
    1559        1248 :     GetCurrentDateTime( current_time );
    1560             : 
    1561        1248 :     sh.Put( " ", 0, 1024 );
    1562             : 
    1563             :     // SH1 - segment content description
    1564        1248 :     sh.Put( description.c_str(), 0, 64 );
    1565             : 
    1566             :     // SH3 - Creation time/date
    1567        1248 :     sh.Put( current_time, 128, 16 );
    1568             : 
    1569             :     // SH4 - Last Update time/date
    1570        1248 :     sh.Put( current_time, 144, 16 );
    1571             : 
    1572             : /* -------------------------------------------------------------------- */
    1573             : /*      Write segment header.                                           */
    1574             : /* -------------------------------------------------------------------- */
    1575        1248 :     WriteToFile( sh.buffer, seg_start * 512, 1024 );
    1576             : 
    1577             : /* -------------------------------------------------------------------- */
    1578             : /*      Initialize the newly created segment.                           */
    1579             : /* -------------------------------------------------------------------- */
    1580        1248 :     PCIDSKSegment *seg_obj = GetSegment( segment );
    1581             : 
    1582        1248 :     seg_obj->Initialize();
    1583             : 
    1584             : #ifdef PCIDSK_IMP_PARAM_SUPPORT
    1585             :     // Update the Last Segment Number Created parameter.
    1586             :     if (seg_type != SEG_SYS)
    1587             :     {
    1588             :         float fLASC = (float) segment;
    1589             :         IMPPutReal("LASC;", &fLASC, 1);
    1590             :     }
    1591             : #endif
    1592             : 
    1593        1248 :     return segment;
    1594             : }// CreateSegment
    1595             : 
    1596             : /************************************************************************/
    1597             : /*                             ExtendFile()                             */
    1598             : /************************************************************************/
    1599             : 
    1600        2434 : void CPCIDSKFile::ExtendFile( uint64 blocks_requested,
    1601             :                               bool prezero, bool writedata )
    1602             : 
    1603             : {
    1604        2434 :     if( prezero )
    1605             :     {
    1606           0 :         const int nBufferSize = 64 * 1024 * 1024;
    1607           0 :         const int nBufferBlocks = nBufferSize / 512;
    1608             : 
    1609           0 :         PCIDSKBuffer oZero(nBufferSize);
    1610             : 
    1611           0 :         std::memset(oZero.buffer, 0, nBufferSize);
    1612             : 
    1613           0 :         uint64 nBlockCount = blocks_requested;
    1614             : 
    1615           0 :         while (nBlockCount > 0)
    1616             :         {
    1617           0 :             uint64 nCurrentBlocks = nBlockCount;
    1618           0 :             if (nCurrentBlocks > nBufferBlocks)
    1619           0 :                 nCurrentBlocks = nBufferBlocks;
    1620             : 
    1621           0 :             WriteToFile(oZero.buffer, file_size * 512, nCurrentBlocks * 512);
    1622             : 
    1623           0 :             nBlockCount -= nCurrentBlocks;
    1624             : 
    1625           0 :             file_size += nCurrentBlocks;
    1626             :         }
    1627             :     }
    1628             :     else
    1629             :     {
    1630        2434 :         if ( writedata )
    1631        2417 :             WriteToFile( "\0", (file_size + blocks_requested) * 512 - 1, 1 );
    1632             : 
    1633        2433 :         file_size += blocks_requested;
    1634             :     }
    1635             : 
    1636        4866 :     PCIDSKBuffer fh3( 16 );
    1637        2433 :     fh3.Put( file_size, 0, 16 );
    1638        2433 :     WriteToFile( fh3.buffer, 16, 16 );
    1639        2433 : }
    1640             : 
    1641             : /************************************************************************/
    1642             : /*                           ExtendSegment()                            */
    1643             : /************************************************************************/
    1644             : 
    1645        1176 : void CPCIDSKFile::ExtendSegment( int segment, uint64 blocks_requested,
    1646             :                                  bool prezero, bool writedata )
    1647             : 
    1648             : {
    1649        1176 :     PCIDSKSegment * poSegment = GetSegment(segment);
    1650             : 
    1651        1176 :     if (!poSegment)
    1652             :     {
    1653           0 :         return ThrowPCIDSKException("ExtendSegment(%d) failed, "
    1654           0 :                                     "segment does not exist.", segment);
    1655             :     }
    1656             : 
    1657             :     // Move the segment at the end of file if necessary.
    1658        1176 :     if (!poSegment->IsAtEOF())
    1659           9 :         MoveSegmentToEOF(segment);
    1660             : 
    1661             :     // Extend the file.
    1662        1176 :     ExtendFile( blocks_requested, prezero, writedata );
    1663             : 
    1664             :     // Update the segment pointer in memory and on disk.
    1665        1176 :     int segptr_off = (segment - 1) * 32;
    1666             : 
    1667        2352 :     segment_pointers.Put(
    1668        1176 :         segment_pointers.GetUInt64(segptr_off+23,9) + blocks_requested,
    1669             :         segptr_off+23, 9 );
    1670             : 
    1671        1176 :     WriteToFile( segment_pointers.buffer + segptr_off,
    1672        1176 :                  segment_pointers_offset + segptr_off,
    1673             :                  32 );
    1674             : 
    1675             :     // Update the segment information.
    1676        1176 :     poSegment->LoadSegmentPointer(segment_pointers.buffer + segptr_off);
    1677             : }
    1678             : 
    1679             : /************************************************************************/
    1680             : /*                          MoveSegmentToEOF()                          */
    1681             : /************************************************************************/
    1682             : 
    1683           9 : void CPCIDSKFile::MoveSegmentToEOF( int segment )
    1684             : 
    1685             : {
    1686           9 :     PCIDSKSegment * poSegment = GetSegment(segment);
    1687             : 
    1688           9 :     if (!poSegment)
    1689             :     {
    1690           0 :         return ThrowPCIDSKException("MoveSegmentToEOF(%d) failed, "
    1691           0 :                                     "segment does not exist.", segment);
    1692             :     }
    1693             : 
    1694           9 :     int segptr_off = (segment - 1) * 32;
    1695             :     uint64 seg_start, seg_size;
    1696             :     uint64 new_seg_start;
    1697             : 
    1698           9 :     seg_start = segment_pointers.GetUInt64( segptr_off + 12, 11 );
    1699           9 :     seg_size = segment_pointers.GetUInt64( segptr_off + 23, 9 );
    1700             : 
    1701             :     // Are we already at the end of the file?
    1702           9 :     if( (seg_start + seg_size - 1) == file_size )
    1703           0 :         return;
    1704             : 
    1705           9 :     new_seg_start = file_size + 1;
    1706             : 
    1707             :     // Grow the file to hold the segment at the end.
    1708           9 :     ExtendFile( seg_size, false, false );
    1709             : 
    1710             :     // Move the segment data to the new location.
    1711             :     uint8 copy_buf[16384];
    1712             :     uint64 srcoff, dstoff, bytes_to_go;
    1713             : 
    1714           9 :     bytes_to_go = seg_size * 512;
    1715           9 :     srcoff = (seg_start - 1) * 512;
    1716           9 :     dstoff = (new_seg_start - 1) * 512;
    1717             : 
    1718          18 :     while( bytes_to_go > 0 )
    1719             :     {
    1720           9 :         uint64 bytes_this_chunk = sizeof(copy_buf);
    1721           9 :         if( bytes_to_go < bytes_this_chunk )
    1722           9 :             bytes_this_chunk = bytes_to_go;
    1723             : 
    1724           9 :         ReadFromFile( copy_buf, srcoff, bytes_this_chunk );
    1725           9 :         WriteToFile( copy_buf, dstoff, bytes_this_chunk );
    1726             : 
    1727           9 :         srcoff += bytes_this_chunk;
    1728           9 :         dstoff += bytes_this_chunk;
    1729           9 :         bytes_to_go -= bytes_this_chunk;
    1730             :     }
    1731             : 
    1732             :     // Update the segment pointer in memory and on disk.
    1733           9 :     segment_pointers.Put( new_seg_start, segptr_off + 12, 11 );
    1734             : 
    1735           9 :     WriteToFile( segment_pointers.buffer + segptr_off,
    1736           9 :                  segment_pointers_offset + segptr_off,
    1737             :                  32 );
    1738             : 
    1739             :     // Update the segment information.
    1740           9 :     poSegment->LoadSegmentPointer(segment_pointers.buffer + segptr_off);
    1741             : }
    1742             : 
    1743             : /************************************************************************/
    1744             : /*                          CreateOverviews()                           */
    1745             : /************************************************************************/
    1746             : /*
    1747             :  const char *pszResampling;
    1748             :              Can be "NEAREST" for Nearest Neighbour resampling (the fastest),
    1749             :              "AVERAGE" for block averaging or "MODE" for block mode.  This
    1750             :              establishing the type of resampling to be applied when preparing
    1751             :              the decimated overviews. Other methods can be set as well, but
    1752             :              not all applications might support a given overview generation
    1753             :              method.
    1754             : */
    1755             : 
    1756           1 : void CPCIDSKFile::CreateOverviews( int chan_count, const int *chan_list,
    1757             :                                    int factor, std::string resampling )
    1758             : 
    1759             : {
    1760           2 :     std::vector<int> default_chan_list;
    1761             : 
    1762             : /* -------------------------------------------------------------------- */
    1763             : /*      Default to processing all bands.                                */
    1764             : /* -------------------------------------------------------------------- */
    1765           1 :     if( chan_count == 0 )
    1766             :     {
    1767           0 :         chan_count = channel_count;
    1768           0 :         default_chan_list.resize( chan_count );
    1769             : 
    1770           0 :         for( int i = 0; i < chan_count; i++ )
    1771           0 :             default_chan_list[i] = i+1;
    1772             : 
    1773           0 :         chan_list = &(default_chan_list[0]);
    1774             :     }
    1775             : 
    1776             : /* -------------------------------------------------------------------- */
    1777             : /*      Work out the creation options that should apply for the         */
    1778             : /*      overview.                                                       */
    1779             : /* -------------------------------------------------------------------- */
    1780           3 :     std::string layout = GetMetadataValue( "_DBLayout" );
    1781           1 :     int         tilesize = PCIDSK_DEFAULT_TILE_SIZE;
    1782           2 :     std::string compression = "NONE";
    1783             : 
    1784           1 :     if( STARTS_WITH( layout.c_str(), "TILED") )
    1785             :     {
    1786           0 :         ParseTileFormat(layout, tilesize, compression);
    1787             :     }
    1788             : 
    1789             : /* -------------------------------------------------------------------- */
    1790             : /*      Make sure we have a block tile directory for managing the       */
    1791             : /*      tile layers.                                                    */
    1792             : /* -------------------------------------------------------------------- */
    1793           2 :     CPCIDSKBlockFile oBlockFile(this);
    1794             : 
    1795           1 :     SysTileDir * poTileDir = oBlockFile.GetTileDir();
    1796             : 
    1797           1 :     if (!poTileDir)
    1798           1 :         poTileDir = oBlockFile.CreateTileDir();
    1799             : 
    1800             : /* ==================================================================== */
    1801             : /*      Loop over the channels.                                         */
    1802             : /* ==================================================================== */
    1803           2 :     for( int chan_index = 0; chan_index < chan_count; chan_index++ )
    1804             :     {
    1805           1 :         int channel_number = chan_list[chan_index];
    1806           1 :         PCIDSKChannel *channel = GetChannel( channel_number );
    1807             : 
    1808             : /* -------------------------------------------------------------------- */
    1809             : /*      Figure out if the given overview level already exists           */
    1810             : /*      for a given channel; if it does, skip creating it.              */
    1811             : /* -------------------------------------------------------------------- */
    1812           1 :         bool overview_exists = false;
    1813           1 :         for( int i = channel->GetOverviewCount()-1; i >= 0; i-- )
    1814             :         {
    1815           0 :             PCIDSKChannel *overview = channel->GetOverview( i );
    1816             : 
    1817           0 :             if( overview->GetWidth() == channel->GetWidth() / factor
    1818           0 :                 && overview->GetHeight() == channel->GetHeight() / factor )
    1819             :             {
    1820           0 :                 overview_exists = true;
    1821             :             }
    1822             :         }
    1823             : 
    1824           1 :         if (overview_exists == false && poTileDir != nullptr)
    1825             :         {
    1826             : /* -------------------------------------------------------------------- */
    1827             : /*      Create the overview as a tiled image layer.                     */
    1828             : /* -------------------------------------------------------------------- */
    1829             :             int virtual_image =
    1830           2 :                 poTileDir->CreateTileLayer(channel->GetWidth() / factor,
    1831           1 :                                            channel->GetHeight() / factor,
    1832             :                                            tilesize, tilesize,
    1833           1 :                                            channel->GetType(),
    1834           1 :                                            compression);
    1835             : 
    1836             : /* -------------------------------------------------------------------- */
    1837             : /*      Attach reference to this overview as metadata.                  */
    1838             : /* -------------------------------------------------------------------- */
    1839             :             char overview_md_key[128];
    1840             :             char overview_md_value[128];
    1841             : 
    1842           1 :             snprintf( overview_md_key, sizeof(overview_md_key),  "_Overview_%d", factor );
    1843           1 :             snprintf( overview_md_value, sizeof(overview_md_value), "%d 0 %s",virtual_image,resampling.c_str());
    1844             : 
    1845           1 :             channel->SetMetadataValue( overview_md_key, overview_md_value );
    1846             : 
    1847             : /* -------------------------------------------------------------------- */
    1848             : /*      Update the internal overview lists                              */
    1849             : /* -------------------------------------------------------------------- */
    1850           1 :             CPCIDSKChannel* cpcidskchannel = dynamic_cast<CPCIDSKChannel *>(channel);
    1851           1 :             if( cpcidskchannel )
    1852           1 :                 cpcidskchannel->UpdateOverviewInfo(overview_md_value, factor);
    1853             :         }
    1854             :     }
    1855           1 : }
    1856             : 

Generated by: LCOV version 1.14