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

Generated by: LCOV version 1.14