LTP GCOV extension - code coverage report
Current view: directory - frmts/pcidsk/sdk/core - cpcidskfile.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 441
Code covered: 50.6 % Executed lines: 223

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

Generated by: LTP GCOV extension version 1.5