LCOV - code coverage report
Current view: directory - frmts/pcidsk/sdk/core - cpcidskfile.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 475 312 65.7 %
Date: 2012-12-26 Functions: 28 19 67.9 %

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Purpose:  Implementation of the CPCIDSKFile class.
       4                 :  * 
       5                 :  ******************************************************************************
       6                 :  * Copyright (c) 2009
       7                 :  * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
       8                 :  *
       9                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      10                 :  * copy of this software and associated documentation files (the "Software"),
      11                 :  * to deal in the Software without restriction, including without limitation
      12                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      13                 :  * and/or sell copies of the Software, and to permit persons to whom the
      14                 :  * Software is furnished to do so, subject to the following conditions:
      15                 :  *
      16                 :  * The above copyright notice and this permission notice shall be included
      17                 :  * in all copies or substantial portions of the Software.
      18                 :  *
      19                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      20                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      22                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      24                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      25                 :  * DEALINGS IN THE SOFTWARE.
      26                 :  ****************************************************************************/
      27                 : #include "pcidsk_file.h"
      28                 : #include "pcidsk_exception.h"
      29                 : #include "pcidsk_channel.h"
      30                 : #include "pcidsk_segment.h"
      31                 : #include "core/mutexholder.h"
      32                 : #include "core/pcidsk_utils.h"
      33                 : #include "core/cpcidskfile.h"
      34                 : 
      35                 : // Channel types
      36                 : #include "channel/cbandinterleavedchannel.h"
      37                 : #include "channel/cpixelinterleavedchannel.h"
      38                 : #include "channel/ctiledchannel.h"
      39                 : #include "channel/cexternalchannel.h"
      40                 : 
      41                 : // Segment types
      42                 : #include "segment/cpcidskgeoref.h"
      43                 : #include "segment/cpcidskpct.h"
      44                 : #include "segment/cpcidskvectorsegment.h"
      45                 : #include "segment/metadatasegment.h"
      46                 : #include "segment/sysblockmap.h"
      47                 : #include "segment/cpcidskrpcmodel.h"
      48                 : #include "segment/cpcidskgcp2segment.h"
      49                 : #include "segment/cpcidskbitmap.h"
      50                 : #include "segment/cpcidsk_tex.h"
      51                 : #include "segment/cpcidsk_array.h"
      52                 : #include "segment/cpcidskapmodel.h"
      53                 : #include "segment/cpcidskads40model.h"
      54                 : #include "segment/cpcidsktoutinmodel.h"
      55                 : #include "segment/cpcidskpolymodel.h"
      56                 : #include "segment/cpcidskbinarysegment.h"
      57                 : #include "core/clinksegment.h"
      58                 : 
      59                 : #include <cassert>
      60                 : #include <cstdlib>
      61                 : #include <cstring>
      62                 : #include <cstdio>
      63                 : #include <string>
      64                 : 
      65                 : #include <iostream>
      66                 : 
      67                 : using namespace PCIDSK;
      68                 : 
      69                 : /************************************************************************/
      70                 : /*                             CPCIDSKFile()                             */
      71                 : /************************************************************************/
      72                 : 
      73             110 : CPCIDSKFile::CPCIDSKFile( std::string filename )
      74                 : 
      75                 : {
      76             110 :     io_handle = NULL;
      77             110 :     io_mutex = NULL;
      78             110 :     updatable = false;
      79             110 :     base_filename = filename;
      80                 : 
      81                 : /* -------------------------------------------------------------------- */
      82                 : /*      Initialize the metadata object, but do not try to load till     */
      83                 : /*      needed.                                                         */
      84                 : /* -------------------------------------------------------------------- */
      85             110 :     metadata.Initialize( this, "FIL", 0 );
      86             110 : }
      87                 : 
      88                 : /************************************************************************/
      89                 : /*                            ~CPCIDSKFile()                             */
      90                 : /************************************************************************/
      91                 : 
      92             110 : CPCIDSKFile::~CPCIDSKFile()
      93                 : 
      94                 : {
      95             110 :     Synchronize();
      96                 : 
      97                 : /* -------------------------------------------------------------------- */
      98                 : /*      Cleanup last block buffer.                                      */
      99                 : /* -------------------------------------------------------------------- */
     100             110 :     if( last_block_data != NULL )
     101                 :     {
     102               0 :         last_block_index = -1;
     103               0 :         free( last_block_data );
     104               0 :         last_block_data = NULL;
     105               0 :         delete last_block_mutex;
     106                 :     }
     107                 : 
     108                 : /* -------------------------------------------------------------------- */
     109                 : /*      Cleanup channels and segments.                                  */
     110                 : /* -------------------------------------------------------------------- */
     111                 :     size_t i;
     112             291 :     for( i = 0; i < channels.size(); i++ )
     113                 :     {
     114             181 :         delete channels[i];
     115             181 :         channels[i] = NULL;
     116                 :     }
     117                 :     
     118          112860 :     for( i = 0; i < segments.size(); i++ )
     119                 :     {
     120          112750 :         delete segments[i];
     121          112750 :         segments[i] = NULL;
     122                 :     }
     123                 :     
     124                 : /* -------------------------------------------------------------------- */
     125                 : /*      Close and cleanup IO stuff.                                     */
     126                 : /* -------------------------------------------------------------------- */
     127                 :     {
     128             110 :         MutexHolder oHolder( io_mutex );
     129                 : 
     130             110 :         if( io_handle )
     131                 :         {
     132             110 :             interfaces.io->Close( io_handle );
     133             110 :             io_handle = NULL;
     134             110 :         }
     135                 :     }
     136                 : 
     137                 :     size_t i_file;
     138                 : 
     139             112 :     for( i_file=0; i_file < file_list.size(); i_file++ )
     140                 :     {
     141               2 :         delete file_list[i_file].io_mutex;
     142               2 :         file_list[i_file].io_mutex = NULL;
     143                 : 
     144               2 :         interfaces.io->Close( file_list[i_file].io_handle );
     145               2 :         file_list[i_file].io_handle = NULL;
     146                 :     }
     147                 : 
     148             110 :     for( i_file=0; i_file < edb_file_list.size(); i_file++ )
     149                 :     {
     150               0 :         delete edb_file_list[i_file].io_mutex;
     151               0 :         edb_file_list[i_file].io_mutex = NULL;
     152                 : 
     153               0 :         delete edb_file_list[i_file].file;
     154               0 :         edb_file_list[i_file].file = NULL;
     155                 :     }
     156                 : 
     157             110 :     delete io_mutex;
     158             110 : }
     159                 : 
     160                 : /************************************************************************/
     161                 : /*                            Synchronize()                             */
     162                 : /************************************************************************/
     163                 : 
     164             208 : void CPCIDSKFile::Synchronize()
     165                 : 
     166                 : {
     167             208 :     if( !GetUpdatable() )
     168              96 :         return;
     169                 : 
     170                 : /* -------------------------------------------------------------------- */
     171                 : /*      Flush out last line caching stuff for pixel interleaved data.   */
     172                 : /* -------------------------------------------------------------------- */
     173             112 :     FlushBlock();
     174                 : 
     175                 : /* -------------------------------------------------------------------- */
     176                 : /*      Synchronize all channels.                                       */
     177                 : /* -------------------------------------------------------------------- */
     178                 :     size_t i;
     179             297 :     for( i = 0; i < channels.size(); i++ )
     180             185 :         channels[i]->Synchronize();
     181                 :     
     182                 : /* -------------------------------------------------------------------- */
     183                 : /*      Synchronize all segments we have instantiated.                  */
     184                 : /* -------------------------------------------------------------------- */
     185          114912 :     for( i = 0; i < segments.size(); i++ )
     186                 :     {
     187          114800 :         if( segments[i] != NULL )
     188             183 :             segments[i]->Synchronize();
     189                 :     }
     190                 : 
     191                 : /* -------------------------------------------------------------------- */
     192                 : /*      Ensure the file is synhronized to disk.                         */
     193                 : /* -------------------------------------------------------------------- */
     194             112 :     MutexHolder oHolder( io_mutex );
     195                 : 
     196             112 :     interfaces.io->Flush( io_handle );
     197                 : }
     198                 : 
     199                 : /************************************************************************/
     200                 : /*                             GetChannel()                             */
     201                 : /************************************************************************/
     202                 : 
     203             368 : PCIDSKChannel *CPCIDSKFile::GetChannel( int band )
     204                 : 
     205                 : {
     206             368 :     if( band < 1 || band > channel_count )
     207                 :         ThrowPCIDSKException( "Out of range band (%d) requested.", 
     208               0 :                               band );
     209                 : 
     210             368 :     return channels[band-1];
     211                 : }
     212                 : 
     213                 : /************************************************************************/
     214                 : /*                             GetSegment()                             */
     215                 : /************************************************************************/
     216                 : 
     217             392 : PCIDSK::PCIDSKSegment *CPCIDSKFile::GetSegment( int segment )
     218                 : 
     219                 : {
     220                 : /* -------------------------------------------------------------------- */
     221                 : /*      Is this a valid segment?                                        */
     222                 : /* -------------------------------------------------------------------- */
     223             392 :     if( segment < 1 || segment > segment_count )
     224               0 :         return NULL;
     225                 : 
     226             392 :     const char *segment_pointer = segment_pointers.buffer + (segment-1) * 32;
     227             392 :     if( segment_pointer[0] != 'A' && segment_pointer[0] != 'L' )
     228               0 :         return NULL;
     229                 : 
     230                 : /* -------------------------------------------------------------------- */
     231                 : /*      Do we already have a corresponding object?                      */
     232                 : /* -------------------------------------------------------------------- */
     233             392 :     if( segments[segment] != NULL )
     234             229 :         return segments[segment];
     235                 : 
     236                 : /* -------------------------------------------------------------------- */
     237                 : /*      Instantiate per the type.                                       */
     238                 : /* -------------------------------------------------------------------- */
     239             163 :     int segment_type = segment_pointers.GetInt((segment-1)*32+1,3);
     240             163 :     PCIDSKSegment *segobj = NULL;
     241                 : 
     242             163 :     switch( segment_type )
     243                 :     {
     244                 :       case SEG_GEO:
     245              54 :         segobj = new CPCIDSKGeoref( this, segment, segment_pointer );
     246              54 :         break;
     247                 : 
     248                 :       case SEG_PCT:
     249               2 :         segobj = new CPCIDSK_PCT( this, segment, segment_pointer );
     250               2 :         break;
     251                 : 
     252                 :       case SEG_VEC:
     253              28 :         segobj = new CPCIDSKVectorSegment( this, segment, segment_pointer );
     254              28 :         break;
     255                 : 
     256                 :       case SEG_BIT:
     257               8 :         segobj = new CPCIDSKBitmap( this, segment, segment_pointer );
     258               8 :         break;
     259                 : 
     260                 :       case SEG_TEX:
     261               0 :         segobj = new CPCIDSK_TEX( this, segment, segment_pointer );
     262               0 :         break;
     263                 : 
     264                 :       case SEG_SYS:
     265              71 :         if( strncmp(segment_pointer + 4, "SysBMDir",8) == 0 )
     266              14 :             segobj = new SysBlockMap( this, segment, segment_pointer );
     267              57 :         else if( strncmp(segment_pointer + 4, "METADATA",8) == 0 )
     268              43 :             segobj = new MetadataSegment( this, segment, segment_pointer );
     269              14 :         else if (strncmp(segment_pointer + 4, "Link    ", 8) == 0)
     270               0 :             segobj = new CLinkSegment(this, segment, segment_pointer);
     271                 :         else
     272              14 :             segobj = new CPCIDSKSegment( this, segment, segment_pointer );
     273                 : 
     274              71 :         break;
     275                 :         
     276                 :       case SEG_GCP2:
     277               0 :         segobj = new CPCIDSKGCP2Segment(this, segment, segment_pointer);
     278               0 :         break;
     279                 :     
     280                 :       case SEG_ORB:
     281               0 :         segobj = new CPCIDSKEphemerisSegment(this, segment, segment_pointer);
     282               0 :         break;
     283                 : 
     284                 :       case SEG_ARR:
     285               0 :         segobj = new CPCIDSK_ARRAY(this, segment, segment_pointer);
     286               0 :         break;
     287                 : 
     288                 :       case SEG_BIN:
     289               0 :         if (!strncmp(segment_pointer + 4, "RFMODEL ", 8))
     290                 :         {
     291               0 :             segobj = new CPCIDSKRPCModelSegment( this, segment, segment_pointer );
     292                 :         }
     293               0 :         else if (!strncmp(segment_pointer + 4, "APMODEL ", 8)) 
     294                 :         {
     295               0 :             segobj = new CPCIDSKAPModelSegment(this, segment, segment_pointer);
     296                 :         }
     297               0 :         else if (!strncmp(segment_pointer + 4, "ADSMODEL", 8)) 
     298                 :         {
     299               0 :             segobj = new CPCIDSKADS40ModelSegment(this, segment, segment_pointer);
     300                 :         }
     301               0 :         else if (!strncmp(segment_pointer + 4, "POLYMDL ", 8)) 
     302                 :         {
     303               0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     304                 :         }
     305               0 :         else if (!strncmp(segment_pointer + 4, "TPSMODEL", 8)) 
     306                 :         {
     307               0 :             segobj = new CPCIDSKGCP2Segment(this, segment, segment_pointer);
     308                 :         }
     309               0 :         else if (!strncmp(segment_pointer + 4, "MODEL   ", 8)) 
     310                 :         {
     311               0 :             segobj = new CPCIDSKToutinModelSegment(this, segment, segment_pointer);
     312                 :         }
     313               0 :         else if (!strncmp(segment_pointer + 4, "MMSPB   ", 8)) 
     314                 :         {
     315               0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     316                 :         }
     317               0 :         else if (!strncmp(segment_pointer + 4, "MMADS   ", 8)) 
     318                 :         {
     319               0 :             segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
     320                 :         }
     321                 :         break;
     322                 :     }
     323                 :     
     324             163 :     if (segobj == NULL)
     325               0 :         segobj = new CPCIDSKSegment( this, segment, segment_pointer );
     326                 :         
     327             163 :     segments[segment] = segobj;
     328                 : 
     329             163 :     return segobj;
     330                 : }
     331                 : 
     332                 : /************************************************************************/
     333                 : /*                             GetSegment()                             */
     334                 : /*                                                                      */
     335                 : /*      Find segment by type/name.                                      */
     336                 : /************************************************************************/
     337                 : 
     338             560 : PCIDSK::PCIDSKSegment *CPCIDSKFile::GetSegment( int type, std::string name, 
     339                 :                                                 int previous )
     340                 : 
     341                 : {
     342                 :     int  i;
     343                 :     char type_str[4];
     344                 : 
     345             560 :     name += "        "; // white space pad name.
     346                 : 
     347                 :     //we want the 3 less significant digit only in case type is too big
     348                 :     // Note : that happen with SEG_VEC_TABLE that is equal to 65652 in GDB.
     349                 :     //see function BuildChildrenLayer in jtfile.cpp, the call on GDBSegNext
     350                 :     //in the loop on gasTypeTable can create issue in PCIDSKSegNext 
     351                 :     //(in pcic/gdbfrtms/pcidskopen.cpp)
     352             560 :     sprintf( type_str, "%03d", (type % 1000) );
     353                 : 
     354          544146 :     for( i = previous; i < segment_count; i++ )
     355                 :     {
     356          543728 :         if( type != SEG_UNKNOWN 
     357                 :             && strncmp(segment_pointers.buffer+i*32+1,type_str,3) != 0 )
     358          543530 :             continue;
     359                 : 
     360             198 :         if( name != "        " 
     361                 :             && strncmp(segment_pointers.buffer+i*32+4,name.c_str(),8) != 0 )
     362              56 :             continue;
     363                 : 
     364                 :         // Ignore deleted segments.
     365             142 :         if (*(segment_pointers.buffer + i * 32 + 0) == 'D') continue;
     366                 : 
     367             142 :         return GetSegment(i+1);
     368                 :     }
     369                 : 
     370             418 :     return NULL;
     371                 : }
     372                 : 
     373                 : 
     374                 : /************************************************************************/
     375                 : /*                            GetSegments()                             */
     376                 : /************************************************************************/
     377                 : 
     378               0 : std::vector<PCIDSK::PCIDSKSegment *> CPCIDSKFile::GetSegments()
     379                 : 
     380                 : {
     381               0 :     PCIDSK::ThrowPCIDSKException( "Objects list access not implemented yet." );
     382                 : 
     383               0 :     std::vector<PCIDSK::PCIDSKSegment *> list;
     384                 :     return list;
     385                 : }
     386                 : 
     387                 : /************************************************************************/
     388                 : /*                        InitializeFromHeader()                        */
     389                 : /************************************************************************/
     390                 : 
     391             110 : void CPCIDSKFile::InitializeFromHeader()
     392                 : 
     393                 : {
     394                 : /* -------------------------------------------------------------------- */
     395                 : /*      Process the file header.                                        */
     396                 : /* -------------------------------------------------------------------- */
     397             110 :     PCIDSKBuffer fh(512);
     398                 : 
     399             110 :     ReadFromFile( fh.buffer, 0, 512 );
     400                 : 
     401             110 :     width = atoi(fh.Get(384,8));
     402             110 :     height = atoi(fh.Get(392,8));
     403             110 :     channel_count = atoi(fh.Get(376,8));
     404             110 :     file_size = fh.GetUInt64(16,16);
     405                 : 
     406             110 :     uint64 ih_start_block = atouint64(fh.Get(336,16));
     407             110 :     uint64 image_start_block = atouint64(fh.Get(304,16));
     408             110 :     fh.Get(360,8,interleaving);
     409                 : 
     410             110 :     uint64 image_offset = (image_start_block-1) * 512;
     411                 : 
     412             110 :     block_size = 0;
     413             110 :     last_block_index = -1;
     414             110 :     last_block_dirty = 0;
     415             110 :     last_block_data = NULL;
     416             110 :     last_block_mutex = NULL;
     417                 : 
     418                 : /* -------------------------------------------------------------------- */
     419                 : /*      Load the segment pointers into a PCIDSKBuffer.  For now we      */
     420                 : /*      try to avoid doing too much other processing on them.           */
     421                 : /* -------------------------------------------------------------------- */
     422             110 :     int segment_block_count = atoi(fh.Get(456,8));
     423                 :     
     424             110 :     segment_count = (segment_block_count * 512) / 32;
     425             110 :     segment_pointers.SetSize( segment_block_count * 512 );
     426             110 :     segment_pointers_offset = atouint64(fh.Get(440,16)) * 512 - 512;
     427                 :     ReadFromFile( segment_pointers.buffer, segment_pointers_offset,
     428             110 :                   segment_block_count * 512 );
     429                 : 
     430             110 :     segments.resize( segment_count + 1 );
     431                 : 
     432                 : /* -------------------------------------------------------------------- */
     433                 : /*      Get the number of each channel type - only used for some        */
     434                 : /*      interleaving cases.                                             */
     435                 : /* -------------------------------------------------------------------- */
     436             110 :     int count_8u = 0, count_16s = 0, count_16u = 0, count_32r = 0;
     437             110 :     int count_c16u = 0, count_c16s = 0, count_c32r = 0;
     438                 : 
     439             110 :     if (strcmp(fh.Get(464,4), "    ") == 0)
     440                 :     {
     441               0 :             count_8u = channel_count;
     442                 :     }
     443                 :     else
     444                 :     {
     445             110 :             count_8u = atoi(fh.Get(464,4));
     446             110 :             count_16s = atoi(fh.Get(468,4));
     447             110 :             count_16u = atoi(fh.Get(472,4));
     448             110 :             count_32r = atoi(fh.Get(476,4));
     449             110 :             count_c16u = atoi(fh.Get(480,4));
     450             110 :             count_c16s = atoi(fh.Get(484,4));
     451             110 :             count_c32r = atoi(fh.Get(488,4));
     452                 :     }
     453                 : /* -------------------------------------------------------------------- */
     454                 : /*      for pixel interleaved files we need to compute the length of    */
     455                 : /*      a scanline padded out to a 512 byte boundary.                   */
     456                 : /* -------------------------------------------------------------------- */
     457             110 :     if( interleaving == "PIXEL" )
     458                 :     {
     459               0 :         first_line_offset = image_offset;
     460               0 :         pixel_group_size = count_8u + count_16s*2 + count_16u*2 + count_32r*4;
     461                 :         
     462               0 :         block_size = pixel_group_size * width;
     463               0 :         if( block_size % 512 != 0 )
     464               0 :             block_size += 512 - (block_size % 512);
     465                 : 
     466               0 :         last_block_data = malloc((size_t) block_size);
     467               0 :         if( last_block_data == NULL )
     468                 :             ThrowPCIDSKException( "Allocating %d bytes for scanline buffer failed.", 
     469               0 :                                        (int) block_size );
     470                 : 
     471               0 :         last_block_mutex = interfaces.CreateMutex();
     472               0 :         image_offset = 0;
     473                 :     }
     474                 : 
     475                 : /* -------------------------------------------------------------------- */
     476                 : /*      Initialize the list of channels.                                */
     477                 : /* -------------------------------------------------------------------- */
     478                 :     int channelnum;
     479                 : 
     480             291 :     for( channelnum = 1; channelnum <= channel_count; channelnum++ )
     481                 :     {
     482             181 :         PCIDSKBuffer ih(1024);
     483             181 :         PCIDSKChannel *channel = NULL;
     484             181 :         uint64  ih_offset = (ih_start_block-1)*512 + (channelnum-1)*1024;
     485                 :         
     486             181 :         ReadFromFile( ih.buffer, ih_offset, 1024 );
     487                 : 
     488                 :         // fetch the filename, if there is one.
     489             181 :         std::string filename;
     490             181 :         ih.Get(64,64,filename);
     491                 : 
     492                 :         // adjust it relative to the path of the pcidsk file.
     493                 :         filename = MergeRelativePath( interfaces.io,
     494             181 :                                       base_filename, filename );
     495                 : 
     496                 :         // work out channel type from header
     497                 :         eChanType pixel_type;
     498             181 :         const char *pixel_type_string = ih.Get( 160, 8 );
     499                 :     
     500             181 :         pixel_type = GetDataTypeFromName(pixel_type_string);
     501                 : 
     502                 :         // if we didn't get channel type in header, work out from counts (old).
     503                 :         // Check this only if we don't have complex channels:
     504                 :         
     505             181 :         if (strncmp(pixel_type_string,"        ",8) == 0 ) 
     506                 :         {
     507               0 :             assert( count_c32r == 0 && count_c16u == 0 && count_c16s == 0 );
     508               0 :             if( channelnum <= count_8u )
     509               0 :                 pixel_type = CHN_8U;
     510               0 :             else if( channelnum <= count_8u + count_16s )
     511               0 :                 pixel_type = CHN_16S;
     512               0 :             else if( channelnum <= count_8u + count_16s + count_16u )
     513               0 :                 pixel_type = CHN_16U;
     514                 :             else 
     515               0 :                 pixel_type = CHN_32R;
     516                 :         }
     517                 :             
     518             181 :         if( interleaving == "BAND"  )
     519                 :         {
     520                 :             channel = new CBandInterleavedChannel( ih, ih_offset, fh, 
     521                 :                                                    channelnum, this,
     522             169 :                                                    image_offset, pixel_type );
     523                 : 
     524                 :             
     525             169 :             image_offset += (int64)DataTypeSize(channel->GetType())
     526             507 :                 * (int64)width * (int64)height;
     527                 :         }
     528                 : 
     529              12 :         else if( interleaving == "PIXEL" )
     530                 :         {
     531                 :             channel = new CPixelInterleavedChannel( ih, ih_offset, fh, 
     532                 :                                                     channelnum, this,
     533                 :                                                     (int) image_offset, 
     534               0 :                                                     pixel_type );
     535               0 :             image_offset += DataTypeSize(pixel_type);
     536                 :         }
     537                 : 
     538              12 :         else if( interleaving == "FILE" 
     539                 :                  && strncmp(filename.c_str(),"/SIS=",5) == 0 )
     540                 :         {
     541                 :             channel = new CTiledChannel( ih, ih_offset, fh, 
     542               9 :                                          channelnum, this, pixel_type );
     543                 :         }
     544                 : 
     545               3 :         else if( interleaving == "FILE" 
     546                 :                  && filename != ""
     547                 :                  && strncmp(((const char*)ih.buffer)+250, "        ", 8 ) != 0 )
     548                 :         {
     549                 :             channel = new CExternalChannel( ih, ih_offset, fh, filename,
     550               0 :                                             channelnum, this, pixel_type );
     551                 :         }
     552                 : 
     553               3 :         else if( interleaving == "FILE" )
     554                 :         {
     555                 :             channel = new CBandInterleavedChannel( ih, ih_offset, fh, 
     556                 :                                                    channelnum, this,
     557               3 :                                                    0, pixel_type );
     558                 :         }
     559                 : 
     560                 :         else
     561                 :             ThrowPCIDSKException( "Unsupported interleaving:%s", 
     562               0 :                                        interleaving.c_str() );
     563                 : 
     564             181 :         channels.push_back( channel );
     565             110 :     }
     566             110 : }
     567                 : 
     568                 : /************************************************************************/
     569                 : /*                            ReadFromFile()                            */
     570                 : /************************************************************************/
     571                 : 
     572            2182 : void CPCIDSKFile::ReadFromFile( void *buffer, uint64 offset, uint64 size )
     573                 : 
     574                 : {
     575            2182 :     MutexHolder oHolder( io_mutex );
     576                 : 
     577            2182 :     interfaces.io->Seek( io_handle, offset, SEEK_SET );
     578            2182 :     if( interfaces.io->Read( buffer, 1, size, io_handle ) != size )
     579                 :         ThrowPCIDSKException( "PCIDSKFile:Failed to read %d bytes at %d.", 
     580               0 :                                    (int) size, (int) offset );
     581            2182 : }
     582                 : 
     583                 : /************************************************************************/
     584                 : /*                            WriteToFile()                             */
     585                 : /************************************************************************/
     586                 : 
     587             880 : void CPCIDSKFile::WriteToFile( const void *buffer, uint64 offset, uint64 size )
     588                 : 
     589                 : {
     590             880 :     if( !GetUpdatable() )
     591               0 :         throw PCIDSKException( "File not open for update in WriteToFile()" );
     592                 : 
     593             880 :     MutexHolder oHolder( io_mutex );
     594                 : 
     595             880 :     interfaces.io->Seek( io_handle, offset, SEEK_SET );
     596             880 :     if( interfaces.io->Write( buffer, 1, size, io_handle ) != size )
     597                 :         ThrowPCIDSKException( "PCIDSKFile:Failed to write %d bytes at %d.",
     598               0 :                                    (int) size, (int) offset );
     599             880 : }
     600                 : 
     601                 : /************************************************************************/
     602                 : /*                          ReadAndLockBlock()                          */
     603                 : /************************************************************************/
     604                 : 
     605               0 : void *CPCIDSKFile::ReadAndLockBlock( int block_index, 
     606                 :                                      int win_xoff, int win_xsize )
     607                 : 
     608                 : {
     609               0 :     if( last_block_data == NULL )
     610               0 :         ThrowPCIDSKException( "ReadAndLockBlock() called on a file that is not pixel interleaved." );
     611                 : 
     612                 : /* -------------------------------------------------------------------- */
     613                 : /*      Default, and validate windowing.                                */
     614                 : /* -------------------------------------------------------------------- */
     615               0 :     if( win_xoff == -1 && win_xsize == -1 )
     616                 :     {
     617               0 :         win_xoff = 0;
     618               0 :         win_xsize = GetWidth();
     619                 :     }
     620                 : 
     621               0 :     if( win_xoff < 0 || win_xoff+win_xsize > GetWidth() )
     622                 :     {
     623                 :         ThrowPCIDSKException( "CPCIDSKFile::ReadAndLockBlock(): Illegal window - xoff=%d, xsize=%d", 
     624               0 :                                    win_xoff, win_xsize );
     625                 :     }
     626                 : 
     627               0 :     if( block_index == last_block_index 
     628                 :         && win_xoff == last_block_xoff
     629                 :         && win_xsize == last_block_xsize )
     630                 :     {
     631               0 :         last_block_mutex->Acquire();
     632               0 :         return last_block_data;
     633                 :     }
     634                 : 
     635                 : /* -------------------------------------------------------------------- */
     636                 : /*      Flush any dirty writable data.                                  */
     637                 : /* -------------------------------------------------------------------- */
     638               0 :     FlushBlock();
     639                 : 
     640                 : /* -------------------------------------------------------------------- */
     641                 : /*      Read the requested window.                                      */
     642                 : /* -------------------------------------------------------------------- */
     643               0 :     last_block_mutex->Acquire();
     644                 : 
     645                 :     ReadFromFile( last_block_data, 
     646                 :                   first_line_offset + block_index*block_size
     647                 :                   + win_xoff * pixel_group_size,
     648               0 :                   pixel_group_size * win_xsize );
     649               0 :     last_block_index = block_index;
     650               0 :     last_block_xoff = win_xoff;
     651               0 :     last_block_xsize = win_xsize;
     652                 :     
     653               0 :     return last_block_data;
     654                 : }
     655                 : 
     656                 : /************************************************************************/
     657                 : /*                            UnlockBlock()                             */
     658                 : /************************************************************************/
     659                 : 
     660               0 : void CPCIDSKFile::UnlockBlock( bool mark_dirty )
     661                 : 
     662                 : {
     663               0 :     if( last_block_mutex == NULL )
     664               0 :         return;
     665                 : 
     666               0 :     last_block_dirty |= mark_dirty;
     667               0 :     last_block_mutex->Release();
     668                 : }
     669                 : 
     670                 : /************************************************************************/
     671                 : /*                             WriteBlock()                             */
     672                 : /************************************************************************/
     673                 : 
     674               0 : void CPCIDSKFile::WriteBlock( int block_index, void *buffer )
     675                 : 
     676                 : {
     677               0 :     if( !GetUpdatable() )
     678               0 :         throw PCIDSKException( "File not open for update in WriteBlock()" );
     679                 : 
     680               0 :     if( last_block_data == NULL )
     681               0 :         ThrowPCIDSKException( "WriteBlock() called on a file that is not pixel interleaved." );
     682                 : 
     683                 :     WriteToFile( buffer,
     684                 :                  first_line_offset + block_index*block_size,
     685               0 :                  block_size );
     686               0 : }
     687                 : 
     688                 : /************************************************************************/
     689                 : /*                             FlushBlock()                             */
     690                 : /************************************************************************/
     691                 : 
     692             112 : void CPCIDSKFile::FlushBlock()
     693                 : 
     694                 : {
     695             112 :     if( last_block_dirty ) 
     696                 :     {
     697               0 :         last_block_mutex->Acquire();
     698               0 :         if( last_block_dirty ) // is it still dirty?
     699                 :         {
     700               0 :             WriteBlock( last_block_index, last_block_data );
     701               0 :             last_block_dirty = 0;
     702                 :         }
     703               0 :         last_block_mutex->Release();
     704                 :     }
     705             112 : }
     706                 : 
     707                 : /************************************************************************/
     708                 : /*                         GetEDBFileDetails()                          */
     709                 : /************************************************************************/
     710                 : 
     711               0 : bool CPCIDSKFile::GetEDBFileDetails( EDBFile** file_p, 
     712                 :                                      Mutex **io_mutex_p, 
     713                 :                                      std::string filename )
     714                 : 
     715                 : {
     716               0 :     *file_p = NULL;
     717               0 :     *io_mutex_p = NULL;
     718                 :     
     719                 : /* -------------------------------------------------------------------- */
     720                 : /*      Does the file exist already in our file list?                   */
     721                 : /* -------------------------------------------------------------------- */
     722                 :     unsigned int i;
     723                 : 
     724               0 :     for( i = 0; i < edb_file_list.size(); i++ )
     725                 :     {
     726               0 :         if( edb_file_list[i].filename == filename )
     727                 :         {
     728               0 :             *file_p = edb_file_list[i].file;
     729               0 :             *io_mutex_p = edb_file_list[i].io_mutex;
     730               0 :             return edb_file_list[i].writable;
     731                 :         }
     732                 :     }
     733                 : 
     734                 : /* -------------------------------------------------------------------- */
     735                 : /*      If not, we need to try and open the file.  Eventually we        */
     736                 : /*      will need better rules about read or update access.             */
     737                 : /* -------------------------------------------------------------------- */
     738               0 :     ProtectedEDBFile new_file;
     739                 : 
     740               0 :     new_file.file = NULL;
     741               0 :     new_file.writable = false;
     742                 : 
     743               0 :     if( GetUpdatable() )
     744                 :     {
     745                 :         try {
     746               0 :             new_file.file = interfaces.OpenEDB( filename, "r+" );
     747               0 :             new_file.writable = true;
     748                 :         } 
     749               0 :         catch( PCIDSK::PCIDSKException ex ) {}
     750               0 :         catch( std::exception ex ) {}
     751                 :     }
     752                 : 
     753               0 :     if( new_file.file == NULL )
     754               0 :         new_file.file = interfaces.OpenEDB( filename, "r" );
     755                 : 
     756               0 :     if( new_file.file == NULL )
     757                 :         ThrowPCIDSKException( "Unable to open file '%s'.", 
     758               0 :                               filename.c_str() );
     759                 : 
     760                 : /* -------------------------------------------------------------------- */
     761                 : /*      Push the new file into the list of files managed for this       */
     762                 : /*      PCIDSK file.                                                    */
     763                 : /* -------------------------------------------------------------------- */
     764               0 :     new_file.io_mutex = interfaces.CreateMutex();
     765               0 :     new_file.filename = filename;
     766                 : 
     767               0 :     edb_file_list.push_back( new_file );
     768                 : 
     769               0 :     *file_p = edb_file_list[edb_file_list.size()-1].file;
     770               0 :     *io_mutex_p  = edb_file_list[edb_file_list.size()-1].io_mutex;
     771                 : 
     772               0 :     return new_file.writable;
     773                 : }
     774                 : 
     775                 : /************************************************************************/
     776                 : /*                            GetIODetails()                            */
     777                 : /************************************************************************/
     778                 : 
     779             185 : void CPCIDSKFile::GetIODetails( void ***io_handle_pp, 
     780                 :                                 Mutex ***io_mutex_pp, 
     781                 :                                 std::string filename,
     782                 :                                 bool writable )
     783                 : 
     784                 : {
     785             185 :     *io_handle_pp = NULL;
     786             185 :     *io_mutex_pp = NULL;
     787                 : 
     788                 : /* -------------------------------------------------------------------- */
     789                 : /*      Does this reference the PCIDSK file itself?                     */
     790                 : /* -------------------------------------------------------------------- */
     791             185 :     if( filename.size() == 0 )
     792                 :     {
     793             183 :         *io_handle_pp = &io_handle;
     794             183 :         *io_mutex_pp = &io_mutex;
     795             183 :         return;
     796                 :     }
     797                 : 
     798                 : /* -------------------------------------------------------------------- */
     799                 : /*      Does the file exist already in our file list?                   */
     800                 : /* -------------------------------------------------------------------- */
     801                 :     unsigned int i;
     802                 : 
     803               2 :     for( i = 0; i < file_list.size(); i++ )
     804                 :     {
     805               0 :         if( file_list[i].filename == filename
     806                 :             && (!writable || file_list[i].writable) )
     807                 :         {
     808               0 :             *io_handle_pp = &(file_list[i].io_handle);
     809               0 :             *io_mutex_pp = &(file_list[i].io_mutex);
     810               0 :             return;
     811                 :         }
     812                 :     }
     813                 : 
     814                 : /* -------------------------------------------------------------------- */
     815                 : /*      If not, we need to try and open the file.  Eventually we        */
     816                 : /*      will need better rules about read or update access.             */
     817                 : /* -------------------------------------------------------------------- */
     818               2 :     ProtectedFile new_file;
     819                 :     
     820               2 :     if( writable )
     821               1 :         new_file.io_handle = interfaces.io->Open( filename, "r+" );
     822                 :     else
     823               1 :         new_file.io_handle = interfaces.io->Open( filename, "r" );
     824                 :         
     825               2 :     if( new_file.io_handle == NULL )
     826                 :         ThrowPCIDSKException( "Unable to open file '%s'.", 
     827               0 :                               filename.c_str() );
     828                 : 
     829                 : /* -------------------------------------------------------------------- */
     830                 : /*      Push the new file into the list of files managed for this       */
     831                 : /*      PCIDSK file.                                                    */
     832                 : /* -------------------------------------------------------------------- */
     833               2 :     new_file.io_mutex = interfaces.CreateMutex();
     834               2 :     new_file.filename = filename;
     835               2 :     new_file.writable = writable;
     836                 : 
     837               2 :     file_list.push_back( new_file );
     838                 : 
     839               2 :     *io_handle_pp = &(file_list[file_list.size()-1].io_handle);
     840               2 :     *io_mutex_pp  = &(file_list[file_list.size()-1].io_mutex);
     841                 : }
     842                 : 
     843                 : /************************************************************************/
     844                 : /*                           DeleteSegment()                            */
     845                 : /************************************************************************/
     846                 : 
     847               1 : void CPCIDSKFile::DeleteSegment( int segment )
     848                 : 
     849                 : {
     850                 : /* -------------------------------------------------------------------- */
     851                 : /*      Is this an existing segment?                                    */
     852                 : /* -------------------------------------------------------------------- */
     853               1 :     PCIDSKSegment *poSeg = GetSegment( segment );
     854                 : 
     855               1 :     if( poSeg == NULL )
     856               0 :         ThrowPCIDSKException( "DeleteSegment(%d) failed, segment does not exist.", segment );
     857                 : 
     858                 : /* -------------------------------------------------------------------- */
     859                 : /*      Wipe associated metadata.                                       */
     860                 : /* -------------------------------------------------------------------- */
     861               1 :     std::vector<std::string> md_keys = poSeg->GetMetadataKeys();
     862                 :     unsigned int i;
     863                 : 
     864               2 :     for( i = 0; i < md_keys.size(); i++ )
     865               0 :         poSeg->SetMetadataValue( md_keys[i], "" );
     866                 : 
     867                 : /* -------------------------------------------------------------------- */
     868                 : /*      Remove the segment object from the segment object cache.  I     */
     869                 : /*      hope the application is not retaining any references to this    */
     870                 : /*      segment!                                                        */
     871                 : /* -------------------------------------------------------------------- */
     872               1 :     segments[segment] = NULL;
     873               1 :     delete poSeg;
     874                 : 
     875                 : /* -------------------------------------------------------------------- */
     876                 : /*      Mark the segment pointer as deleted.                            */
     877                 : /* -------------------------------------------------------------------- */
     878               1 :     segment_pointers.buffer[(segment-1)*32] = 'D';
     879                 : 
     880                 :     // write the updated segment pointer back to the file. 
     881                 :     WriteToFile( segment_pointers.buffer + (segment-1)*32, 
     882                 :                  segment_pointers_offset + (segment-1)*32, 
     883               1 :                  32 );
     884               1 : }
     885                 : 
     886                 : /************************************************************************/
     887                 : /*                           CreateSegment()                            */
     888                 : /************************************************************************/
     889                 : 
     890              90 : int CPCIDSKFile::CreateSegment( std::string name, std::string description,
     891                 :                                 eSegType seg_type, int data_blocks )
     892                 : 
     893                 : {
     894                 : /* -------------------------------------------------------------------- */
     895                 : /*  Set the size of fixed length segments.        */
     896                 : /* -------------------------------------------------------------------- */
     897              90 :     int expected_data_blocks = 0;
     898              90 :     bool prezero = false;
     899                 : 
     900              90 :     switch( seg_type )
     901                 :     {
     902                 :       case SEG_LUT:
     903               0 :   expected_data_blocks = 2;
     904               0 :   break;
     905                 : 
     906                 :       case SEG_PCT:
     907               1 :   expected_data_blocks = 6;
     908               1 :   break;
     909                 : 
     910                 :       case SEG_SIG:
     911               0 :   expected_data_blocks = 12;
     912               0 :   break;
     913                 : 
     914                 :       case SEG_GCP2:
     915                 :   // expected_data_blocks = 67;
     916                 :   // Change seg type to new GCP segment type
     917               0 :   expected_data_blocks = 129;
     918               0 :   break;
     919                 :   
     920                 :       case SEG_GEO:
     921              52 :   expected_data_blocks = 6;
     922              52 :   break;
     923                 : 
     924                 :       case SEG_TEX:
     925               0 :         expected_data_blocks = 64;
     926               0 :         prezero = true;
     927               0 :         break;
     928                 : 
     929                 :       case SEG_BIT:
     930                 :       {
     931               0 :           uint64 bytes = ((width * (uint64) height) + 7) / 8;
     932               0 :           expected_data_blocks = (int) ((bytes + 511) / 512);
     933               0 :           prezero = true;
     934                 :       }
     935                 :       break;
     936                 : 
     937                 :       default:
     938                 :         break;
     939                 :     }
     940                 : 
     941              90 :     if( data_blocks == 0 && expected_data_blocks != 0 )
     942               1 :         data_blocks = expected_data_blocks;
     943                 : 
     944                 : /* -------------------------------------------------------------------- */
     945                 : /*      Find an empty Segment Pointer.  For System segments we start    */
     946                 : /*      at the end, instead of the beginning to avoid using up          */
     947                 : /*      segment numbers that the user would notice.                     */
     948                 : /* -------------------------------------------------------------------- */
     949              90 :     int segment = 1;
     950              90 :     int64 seg_start = -1;
     951              90 :     PCIDSKBuffer segptr( 32 );
     952                 : 
     953              90 :     if( seg_type == SEG_SYS )
     954                 :     {
     955              42 :         for( segment=segment_count; segment >= 1; segment-- )
     956                 :         {
     957              42 :             memcpy( segptr.buffer, segment_pointers.buffer+(segment-1)*32, 32);
     958                 : 
     959              42 :             uint64 this_seg_size = segptr.GetUInt64(23,9);
     960              42 :             char flag = (char) segptr.buffer[0];
     961                 : 
     962              42 :             if( flag == 'D' 
     963                 :                 && (uint64) data_blocks+2 == this_seg_size 
     964                 :                 && this_seg_size > 0 )
     965               0 :                 seg_start = segptr.GetUInt64(12,11) - 1;
     966              42 :             else if( flag == ' ' )
     967              30 :                 seg_start = 0;
     968              12 :             else if( flag && this_seg_size == 0 )
     969               0 :                 seg_start = 0;
     970                 : 
     971              42 :             if( seg_start != -1 )
     972              30 :                 break;
     973                 :         }
     974                 :     }
     975                 :     else
     976                 :     {
     977              83 :         for( segment=1; segment <= segment_count; segment++ )
     978                 :         {
     979              83 :             memcpy( segptr.buffer, segment_pointers.buffer+(segment-1)*32, 32);
     980                 : 
     981              83 :             uint64 this_seg_size = segptr.GetUInt64(23,9);
     982              83 :             char flag = (char) segptr.buffer[0];
     983                 : 
     984              83 :             if( flag == 'D' 
     985                 :                 && (uint64) data_blocks+2 == this_seg_size 
     986                 :                 && this_seg_size > 0 )
     987               0 :                 seg_start = segptr.GetUInt64(12,11) - 1;
     988              83 :             else if( flag == ' ' )
     989              60 :                 seg_start = 0;
     990              23 :             else if( flag && this_seg_size == 0 )
     991               0 :                 seg_start = 0;
     992                 : 
     993              83 :             if( seg_start != -1 )
     994              60 :                 break;
     995                 :         }
     996                 :     }
     997                 :     
     998              90 :     if( segment > segment_count )
     999               0 :         ThrowPCIDSKException( "All %d segment pointers in use.", segment_count);
    1000                 : 
    1001                 : /* -------------------------------------------------------------------- */
    1002                 : /*      If the segment does not have a data area already, identify      */
    1003                 : /*      it's location at the end of the file, and extend the file to    */
    1004                 : /*      the desired length.                                             */
    1005                 : /* -------------------------------------------------------------------- */
    1006              90 :     if( seg_start == 0 )
    1007                 :     {
    1008              90 :         seg_start = GetFileSize();
    1009              90 :         ExtendFile( data_blocks + 2, prezero );
    1010                 :     }
    1011                 : 
    1012                 : /* -------------------------------------------------------------------- */
    1013                 : /*      Update the segment pointer information.                         */
    1014                 : /* -------------------------------------------------------------------- */
    1015                 :     // SP1.1 - Flag
    1016              90 :     segptr.Put( "A", 0, 1 );
    1017                 : 
    1018                 :     // SP1.2 - Type
    1019              90 :     segptr.Put( (int) seg_type, 1, 3 );
    1020                 : 
    1021                 :     // SP1.3 - Name
    1022              90 :     segptr.Put( name.c_str(), 4, 8 );
    1023                 :     
    1024                 :     // SP1.4 - start block
    1025              90 :     segptr.Put( (uint64) (seg_start + 1), 12, 11 );
    1026                 :     
    1027                 :     // SP1.5 - data blocks.
    1028              90 :     segptr.Put( data_blocks+2, 23, 9 );
    1029                 : 
    1030                 :     // Update in memory copy of segment pointers.
    1031              90 :     memcpy( segment_pointers.buffer+(segment-1)*32, segptr.buffer, 32);
    1032                 : 
    1033                 :     // Update on disk. 
    1034                 :     WriteToFile( segptr.buffer, 
    1035              90 :                  segment_pointers_offset + (segment-1)*32, 32 );
    1036                 :     
    1037                 : /* -------------------------------------------------------------------- */
    1038                 : /*      Prepare segment header.                                         */
    1039                 : /* -------------------------------------------------------------------- */
    1040              90 :     PCIDSKBuffer sh(1024);
    1041                 : 
    1042                 :     char current_time[17];
    1043                 : 
    1044              90 :     GetCurrentDateTime( current_time );
    1045                 : 
    1046              90 :     sh.Put( " ", 0, 1024 );
    1047                 : 
    1048                 :     // SH1 - segment content description
    1049              90 :     sh.Put( description.c_str(), 0, 64 );
    1050                 : 
    1051                 :     // SH3 - Creation time/date
    1052              90 :     sh.Put( current_time, 128, 16 );
    1053                 : 
    1054                 :     // SH4 - Last Update time/date
    1055              90 :     sh.Put( current_time, 144, 16 );
    1056                 : 
    1057                 : /* -------------------------------------------------------------------- */
    1058                 : /*      Write segment header.                                           */
    1059                 : /* -------------------------------------------------------------------- */
    1060              90 :     WriteToFile( sh.buffer, seg_start * 512, 1024 );
    1061                 : 
    1062                 : /* -------------------------------------------------------------------- */
    1063                 : /*      Initialize the newly created segment.                           */
    1064                 : /* -------------------------------------------------------------------- */
    1065              90 :     PCIDSKSegment *seg_obj = GetSegment( segment );
    1066                 : 
    1067              90 :     seg_obj->Initialize();
    1068                 : 
    1069              90 :     return segment;
    1070                 : }
    1071                 : 
    1072                 : /************************************************************************/
    1073                 : /*                             ExtendFile()                             */
    1074                 : /************************************************************************/
    1075                 : 
    1076             139 : void CPCIDSKFile::ExtendFile( uint64 blocks_requested, bool prezero )
    1077                 : 
    1078                 : {
    1079             139 :     if( prezero )
    1080                 :     {
    1081               5 :         std::vector<uint8> zeros;
    1082               5 :         uint64 blocks_to_zero = blocks_requested;
    1083                 :         
    1084               5 :         zeros.resize( 512 * 32 );
    1085                 :         
    1086              43 :         while( blocks_to_zero > 0 )
    1087                 :         {
    1088              33 :             uint64 this_time = blocks_to_zero;
    1089              33 :             if( this_time > 32 )
    1090              28 :                 this_time = 32;
    1091                 : 
    1092              33 :             WriteToFile( &(zeros[0]), file_size * 512, this_time*512 );
    1093              33 :             blocks_to_zero -= this_time;
    1094              33 :             file_size += this_time;
    1095               5 :         }
    1096                 :     }
    1097                 :     else
    1098                 :     {
    1099             134 :         WriteToFile( "\0", (file_size + blocks_requested) * 512 - 1, 1 );
    1100             134 :         file_size += blocks_requested;
    1101                 :     }
    1102                 : 
    1103             139 :     PCIDSKBuffer fh3( 16 );
    1104             139 :     fh3.Put( file_size, 0, 16 );
    1105             139 :     WriteToFile( fh3.buffer, 16, 16 );
    1106             139 : }
    1107                 : 
    1108                 : /************************************************************************/
    1109                 : /*                           ExtendSegment()                            */
    1110                 : /************************************************************************/
    1111                 : 
    1112              42 : void CPCIDSKFile::ExtendSegment( int segment, uint64 blocks_requested,
    1113                 :                                  bool prezero )
    1114                 : 
    1115                 : {
    1116                 :     // for now we take it for granted that the segment is valid and at th
    1117                 :     // end of the file - later we should support moving it. 
    1118                 : 
    1119              42 :     ExtendFile( blocks_requested, prezero );
    1120                 : 
    1121                 :     // Update the block count. 
    1122                 :     segment_pointers.Put( 
    1123                 :         segment_pointers.GetUInt64((segment-1)*32+23,9) + blocks_requested,
    1124              42 :         (segment-1)*32+23, 9 );
    1125                 : 
    1126                 :     // write the updated segment pointer back to the file. 
    1127                 :     WriteToFile( segment_pointers.buffer + (segment-1)*32, 
    1128                 :                  segment_pointers_offset + (segment-1)*32, 
    1129              42 :                  32 );
    1130              42 : }
    1131                 : 
    1132                 : /************************************************************************/
    1133                 : /*                          MoveSegmentToEOF()                          */
    1134                 : /************************************************************************/
    1135                 : 
    1136               7 : void CPCIDSKFile::MoveSegmentToEOF( int segment )
    1137                 : 
    1138                 : {
    1139               7 :     int segptr_off = (segment - 1) * 32;
    1140                 :     uint64 seg_start, seg_size;
    1141                 :     uint64 new_seg_start;
    1142                 : 
    1143               7 :     seg_start = segment_pointers.GetUInt64( segptr_off + 12, 11 );
    1144               7 :     seg_size = segment_pointers.GetUInt64( segptr_off + 23, 9 );
    1145                 : 
    1146                 :     // Are we already at the end of the file?
    1147               7 :     if( (seg_start + seg_size - 1) == file_size )
    1148               0 :         return;
    1149                 : 
    1150               7 :     new_seg_start = file_size + 1;
    1151                 : 
    1152                 :     // Grow the file to hold the segment at the end.
    1153               7 :     ExtendFile( seg_size, false );
    1154                 : 
    1155                 :     // Move the segment data to the new location.
    1156                 :     uint8 copy_buf[16384];
    1157                 :     uint64 srcoff, dstoff, bytes_to_go;
    1158                 : 
    1159               7 :     bytes_to_go = seg_size * 512;
    1160               7 :     srcoff = (seg_start - 1) * 512;
    1161               7 :     dstoff = (new_seg_start - 1) * 512;
    1162                 : 
    1163              21 :     while( bytes_to_go > 0 )
    1164                 :     {
    1165               7 :         uint64 bytes_this_chunk = sizeof(copy_buf);
    1166               7 :         if( bytes_to_go < bytes_this_chunk )
    1167               7 :             bytes_this_chunk = bytes_to_go;
    1168                 : 
    1169               7 :         ReadFromFile( copy_buf, srcoff, bytes_this_chunk );
    1170               7 :         WriteToFile( copy_buf, dstoff, bytes_this_chunk );
    1171                 : 
    1172               7 :         srcoff += bytes_this_chunk;
    1173               7 :         dstoff += bytes_this_chunk;
    1174               7 :         bytes_to_go -= bytes_this_chunk;
    1175                 :     }
    1176                 : 
    1177                 :     // Update segment pointer in memory and on disk. 
    1178               7 :     segment_pointers.Put( new_seg_start, segptr_off + 12, 11 );
    1179                 : 
    1180                 :     WriteToFile( segment_pointers.buffer + segptr_off, 
    1181                 :                  segment_pointers_offset + segptr_off, 
    1182               7 :                  32 );
    1183                 :     
    1184                 :     // Update the segments own information.
    1185               7 :     if( segments[segment] != NULL )
    1186                 :     {
    1187                 :         CPCIDSKSegment *seg = 
    1188               7 :             dynamic_cast<CPCIDSKSegment *>( segments[segment] );
    1189                 : 
    1190               7 :         seg->LoadSegmentPointer( segment_pointers.buffer + segptr_off );
    1191                 :     }
    1192                 : }
    1193                 : 
    1194                 : /************************************************************************/
    1195                 : /*                          CreateOverviews()                           */
    1196                 : /************************************************************************/
    1197                 : /*
    1198                 :  const char *pszResampling;
    1199                 :        Can be "NEAREST" for Nearest Neighbour resampling (the fastest),
    1200                 :              "AVERAGE" for block averaging or "MODE" for block mode.  This
    1201                 :              establishing the type of resampling to be applied when preparing
    1202                 :              the decimated overviews. Other methods can be set as well, but
    1203                 :              not all applications might support a given overview generation
    1204                 :              method.
    1205                 : */
    1206                 : 
    1207               1 : void CPCIDSKFile::CreateOverviews( int chan_count, int *chan_list, 
    1208                 :                                    int factor, std::string resampling )
    1209                 : 
    1210                 : {
    1211               1 :     std::vector<int> default_chan_list;
    1212                 : 
    1213                 : /* -------------------------------------------------------------------- */
    1214                 : /*      Default to processing all bands.                                */
    1215                 : /* -------------------------------------------------------------------- */
    1216               1 :     if( chan_count == 0 )
    1217                 :     {
    1218               0 :         chan_count = channel_count;
    1219               0 :         default_chan_list.resize( chan_count );
    1220                 : 
    1221               0 :         for( int i = 0; i < chan_count; i++ )
    1222               0 :             default_chan_list[i] = i+1;
    1223                 : 
    1224               0 :         chan_list = &(default_chan_list[0]);
    1225                 :     }
    1226                 : 
    1227                 : /* -------------------------------------------------------------------- */
    1228                 : /*      Work out the creation options that should apply for the         */
    1229                 : /*      overview.                                                       */
    1230                 : /* -------------------------------------------------------------------- */
    1231               1 :     std::string layout = GetMetadataValue( "_DBLayout" );
    1232               1 :     int         blocksize = 127;
    1233               2 :     std::string compression = "NONE";
    1234                 : 
    1235               2 :     if( strncmp( layout.c_str(), "TILED", 5 ) == 0 )
    1236                 :     {
    1237               0 :         ParseTileFormat( layout, blocksize, compression );
    1238                 :     }
    1239                 : 
    1240                 : /* -------------------------------------------------------------------- */
    1241                 : /*      Make sure we have a blockmap segment for managing the tiled     */
    1242                 : /*      layers.                                                         */
    1243                 : /* -------------------------------------------------------------------- */
    1244               1 :     PCIDSKSegment *bm_seg = GetSegment( SEG_SYS, "SysBMDir" );
    1245                 :     SysBlockMap *bm;
    1246                 : 
    1247               1 :     if( bm_seg == NULL )
    1248                 :     {
    1249                 :         CreateSegment( "SysBMDir", 
    1250                 :                        "System Block Map Directory - Do not modify.",
    1251               1 :                        SEG_SYS, 0 );
    1252               2 :         bm_seg = GetSegment( SEG_SYS, "SysBMDir" );
    1253               1 :         bm = dynamic_cast<SysBlockMap *>(bm_seg);
    1254               1 :         bm->Initialize();
    1255                 :     }
    1256                 :     else
    1257               0 :         bm = dynamic_cast<SysBlockMap *>(bm_seg);
    1258                 :         
    1259                 : /* ==================================================================== */
    1260                 : /*      Loop over the channels.                                         */
    1261                 : /* ==================================================================== */
    1262               2 :     for( int chan_index = 0; chan_index < chan_count; chan_index++ )
    1263                 :     {
    1264               1 :         int channel_number = chan_list[chan_index];
    1265               1 :         PCIDSKChannel *channel = GetChannel( channel_number );
    1266                 :         
    1267                 : /* -------------------------------------------------------------------- */
    1268                 : /*      Figure out if the given overview level already exists           */
    1269                 : /*      for a given channel; if it does, skip creating it.              */
    1270                 : /* -------------------------------------------------------------------- */
    1271               1 :         bool overview_exists = false;
    1272               1 :         for( int i = channel->GetOverviewCount()-1; i >= 0; i-- )
    1273                 :         {
    1274               0 :             PCIDSKChannel *overview = channel->GetOverview( i );
    1275                 :  
    1276               0 :             if( overview->GetWidth() == channel->GetWidth() / factor
    1277               0 :                 && overview->GetHeight() == channel->GetHeight() / factor )
    1278                 :             {
    1279               0 :                 overview_exists = true;
    1280                 :             }
    1281                 :         }
    1282                 : 
    1283               1 :         if (overview_exists == false)
    1284                 :         {
    1285                 : /* -------------------------------------------------------------------- */
    1286                 : /*      Create the overview as a tiled image layer.                     */
    1287                 : /* -------------------------------------------------------------------- */
    1288                 :             int virtual_image = 
    1289               1 :                 bm->CreateVirtualImageFile( channel->GetWidth() / factor, 
    1290               1 :                                             channel->GetHeight() / factor,
    1291                 :                                             blocksize, blocksize, 
    1292               3 :                                             channel->GetType(), compression );
    1293                 : 
    1294                 : /* -------------------------------------------------------------------- */
    1295                 : /*      Attach reference to this overview as metadata.                  */
    1296                 : /* -------------------------------------------------------------------- */
    1297                 :             char overview_md_value[128];
    1298                 :             char overview_md_key[128];
    1299                 : 
    1300               1 :             sprintf( overview_md_key, "_Overview_%d", factor );
    1301               1 :             sprintf( overview_md_value, "%d 0 %s",virtual_image,resampling.c_str());
    1302                 :                      
    1303               1 :             channel->SetMetadataValue( overview_md_key, overview_md_value );
    1304                 :         }
    1305                 : 
    1306                 : /* -------------------------------------------------------------------- */
    1307                 : /*      Force channel to invalidate it's loaded overview list.          */
    1308                 : /* -------------------------------------------------------------------- */
    1309               1 :         dynamic_cast<CPCIDSKChannel *>(channel)->InvalidateOverviewInfo();
    1310               1 :     }
    1311            2140 : }
    1312                 : 

Generated by: LCOV version 1.7