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-11-21 22:18:42 Functions: 18 26 69.2 %

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

Generated by: LCOV version 1.14