LCOV - code coverage report
Current view: directory - frmts/pcidsk/sdk/segment - cpcidskvectorsegment.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 534 460 86.1 %
Date: 2012-04-28 Functions: 38 32 84.2 %

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Purpose:  Implementation of the CPCIDSKVectorSegment 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                 : 
      28                 : #include "pcidsk_file.h"
      29                 : #include "pcidsk_exception.h"
      30                 : #include "core/pcidsk_utils.h"
      31                 : #include "segment/cpcidskvectorsegment.h"
      32                 : #include <cassert>
      33                 : #include <cstring>
      34                 : #include <cstdio>
      35                 : 
      36                 : using namespace PCIDSK;
      37                 : 
      38                 : /* -------------------------------------------------------------------- */
      39                 : /*      Size of a block in the record/vertice block tables.  This is    */
      40                 : /*      determined by the PCIDSK format and may not be changed.         */
      41                 : /* -------------------------------------------------------------------- */
      42                 : static const int block_page_size = 8192;  
      43                 : 
      44                 : 
      45                 : /* -------------------------------------------------------------------- */
      46                 : /*      Size of one page of loaded shapeids.  This is not related to    */
      47                 : /*      the file format, and may be changed to alter the number of      */
      48                 : /*      shapeid pointers kept in RAM at one time from the shape         */
      49                 : /*      index.                                                          */
      50                 : /* -------------------------------------------------------------------- */
      51                 : static const int shapeid_page_size = 1024;
      52                 : 
      53                 : /************************************************************************/
      54                 : /*                        CPCIDSKVectorSegment()                        */
      55                 : /************************************************************************/
      56                 : 
      57              56 : CPCIDSKVectorSegment::CPCIDSKVectorSegment( PCIDSKFile *file, int segment,
      58                 :                                             const char *segment_pointer )
      59              56 :         : CPCIDSKSegment( file, segment, segment_pointer )
      60                 : 
      61                 : {
      62              56 :     base_initialized = false;
      63                 :     
      64              56 :     last_shapes_id = NullShapeId;
      65              56 :     last_shapes_index = -1;
      66                 : 
      67              56 :     raw_loaded_data_offset = 0;
      68              56 :     vert_loaded_data_offset = 0;
      69              56 :     record_loaded_data_offset = 0;
      70              56 :     raw_loaded_data_dirty = false;
      71              56 :     vert_loaded_data_dirty = false;
      72              56 :     record_loaded_data_dirty = false;
      73                 : 
      74              56 :     shape_index_start = 0;
      75              56 :     shape_index_page_dirty = false;
      76                 : 
      77              56 :     shapeid_map_active = false;
      78              56 :     shapeid_pages_certainly_mapped = -1;
      79                 : 
      80              56 :     vh.vs = this;
      81                 : 
      82              56 :     highest_shapeid_used = NullShapeId;
      83              56 : }
      84                 : 
      85                 : /************************************************************************/
      86                 : /*                       ~CPCIDSKVectorSegment()                        */
      87                 : /************************************************************************/
      88                 : 
      89              56 : CPCIDSKVectorSegment::~CPCIDSKVectorSegment()
      90                 : 
      91                 : {
      92              56 :     Synchronize();
      93              56 : }
      94                 : 
      95                 : /************************************************************************/
      96                 : /*                            Synchronize()                             */
      97                 : /************************************************************************/
      98                 : 
      99              82 : void CPCIDSKVectorSegment::Synchronize()
     100                 : {
     101              82 :     if( base_initialized )
     102                 :     {
     103              80 :         FlushDataBuffer( sec_vert );
     104              80 :         FlushDataBuffer( sec_record );
     105                 : 
     106              80 :         di[sec_vert].Flush();
     107              80 :         di[sec_record].Flush();
     108                 : 
     109              80 :         FlushLoadedShapeIndex();
     110                 : 
     111              96 :         if( GetHeader().GetInt( 192, 16 ) != shape_count 
     112              16 :             && file->GetUpdatable() )
     113                 :         {
     114              12 :             GetHeader().Put( shape_count, 192, 16 );
     115              12 :             FlushHeader();
     116                 :         }
     117                 :     }
     118              82 : }
     119                 : 
     120                 : /************************************************************************/
     121                 : /*                             Initialize()                             */
     122                 : /*                                                                      */
     123                 : /*      Initialize the header of a new vector segment in a              */
     124                 : /*      consistent state for an empty segment.                          */
     125                 : /************************************************************************/
     126                 : 
     127              14 : void CPCIDSKVectorSegment::Initialize()
     128                 : 
     129                 : {
     130              14 :     needs_swap = !BigEndianSystem();
     131                 : 
     132                 : /* -------------------------------------------------------------------- */
     133                 : /*      Initialize the header that occurs within the regular segment    */
     134                 : /*      data.                                                           */
     135                 : /* -------------------------------------------------------------------- */
     136              14 :     vh.InitializeNew();
     137                 : 
     138                 : /* -------------------------------------------------------------------- */
     139                 : /*      Initialize the values in the generic segment header.            */
     140                 : /* -------------------------------------------------------------------- */
     141              14 :     PCIDSKBuffer &head = GetHeader();
     142                 : 
     143              14 :     head.Put( "METRE", 160, 16 );
     144              14 :     head.Put( 1.0, 176, 16 );
     145              14 :     head.Put( 0, 192, 16 );
     146              14 :     head.Put( 0, 208, 16 );
     147              14 :     head.Put( 0, 224, 16 );
     148              14 :     head.Put( "", 240, 16 );
     149              14 :     head.Put( 0, 256, 16 );
     150              14 :     head.Put( 0, 272, 16 );
     151                 : 
     152              14 :     FlushHeader();
     153              14 : }
     154                 : 
     155                 : /************************************************************************/
     156                 : /*                             LoadHeader()                             */
     157                 : /*                                                                      */
     158                 : /*      Initialize minimum information from the vector segment          */
     159                 : /*      header.  We defer this till an actual vector related action     */
     160                 : /*      is taken.                                                       */
     161                 : /************************************************************************/
     162                 : 
     163           57146 : void CPCIDSKVectorSegment::LoadHeader()
     164                 : 
     165                 : {
     166           57146 :     if( base_initialized )
     167           57092 :         return;
     168                 : 
     169              54 :     base_initialized = true;
     170                 : 
     171              54 :     needs_swap = !BigEndianSystem();
     172                 : 
     173              54 :     vh.InitializeExisting();
     174                 : }
     175                 : 
     176                 : /************************************************************************/
     177                 : /*                             ReadField()                              */
     178                 : /*                                                                      */
     179                 : /*      Read a value from the indicated offset in a section of the      */
     180                 : /*      vector segment, and place the value into a ShapeField           */
     181                 : /*      structure based on the passed in field type.                    */
     182                 : /************************************************************************/
     183                 : 
     184          257610 : uint32 CPCIDSKVectorSegment::ReadField( uint32 offset, ShapeField& field,
     185                 :                                         ShapeFieldType field_type,
     186                 :                                         int section )
     187                 : 
     188                 : {
     189          257610 :     switch( field_type )
     190                 :     {
     191                 :       case FieldTypeInteger:
     192                 :       {
     193                 :           int32 value;
     194          111504 :           memcpy( &value, GetData( section, offset, NULL, 4), 4 );
     195          111504 :           if( needs_swap )
     196          111504 :               SwapData( &value, 4, 1 );
     197          111504 :           field.SetValue( value );
     198          111504 :           return offset + 4;
     199                 :       }
     200                 : 
     201                 :       case FieldTypeFloat:
     202                 :       {
     203                 :           float value;
     204               0 :           memcpy( &value, GetData( section, offset, NULL, 4), 4 );
     205               0 :           if( needs_swap )
     206               0 :               SwapData( &value, 4, 1 );
     207               0 :           field.SetValue( value );
     208               0 :           return offset + 4;
     209                 :       }
     210                 : 
     211                 :       case FieldTypeDouble:
     212                 :       {
     213                 :           double value;
     214          111312 :           memcpy( &value, GetData( section, offset, NULL, 8), 8 );
     215          111312 :           if( needs_swap )
     216          111312 :               SwapData( &value, 8, 1 );
     217          111312 :           field.SetValue( value );
     218          111312 :           return offset + 8;
     219                 :       }
     220                 : 
     221                 :       case FieldTypeString:
     222                 :       {
     223                 :           int available;
     224           26234 :           char *srcdata = GetData( section, offset, &available, 1 );
     225                 :         
     226                 :           // Simple case -- all initially available.
     227           26234 :           int string_len = 0;
     228                 : 
     229          190736 :           while( srcdata[string_len] != '\0' && available - string_len > 0 )
     230          138268 :               string_len++;
     231                 : 
     232           26234 :           if( string_len < available && srcdata[string_len] == '\0' )
     233                 :           {
     234           26198 :               std::string value( srcdata, string_len );
     235           26198 :               field.SetValue( value );
     236           26198 :               return offset + string_len + 1;
     237                 :           }
     238                 : 
     239              36 :           std::string value;
     240                 :         
     241             360 :           while( *srcdata != '\0' )
     242                 :           {
     243             288 :               value += *(srcdata++);
     244             288 :               offset++;
     245             288 :               available--;
     246             288 :               if( available == 0 )
     247              36 :                   srcdata = GetData( section, offset, &available, 1 );
     248                 :           }
     249                 : 
     250              36 :           field.SetValue( value );
     251              36 :           return offset+1;
     252                 :       }
     253                 : 
     254                 :       case FieldTypeCountedInt:
     255                 :       {
     256            8560 :           std::vector<int32> value;
     257                 :           int32 count;
     258            8560 :           char *srcdata = GetData( section, offset, NULL, 4 );
     259            8560 :           memcpy( &count, srcdata, 4 );
     260            8560 :           if( needs_swap )
     261            8560 :               SwapData( &count, 4, 1 );
     262                 : 
     263            8560 :           value.resize( count );
     264            8560 :           if( count > 0 )
     265                 :           {
     266             252 :               memcpy( &(value[0]), GetData(section,offset+4,NULL,4*count), 4*count );
     267             252 :               if( needs_swap )
     268             252 :                   SwapData( &(value[0]), 4, count );
     269                 :           }
     270                 : 
     271            8560 :           field.SetValue( value );
     272            8560 :           return offset + 4 + 4*count;
     273                 :       }
     274                 : 
     275                 :       default:
     276               0 :         assert( 0 );
     277                 :         return offset;
     278                 :     }
     279                 : }
     280                 : 
     281                 : /************************************************************************/
     282                 : /*                             WriteField()                             */
     283                 : /*                                                                      */
     284                 : /*      Write a field value into a buffer, growing the buffer if        */
     285                 : /*      needed to hold the value.                                       */
     286                 : /************************************************************************/
     287                 : 
     288              94 : uint32 CPCIDSKVectorSegment::WriteField( uint32 offset, 
     289                 :                                          const ShapeField& field, 
     290                 :                                          PCIDSKBuffer& buffer )
     291                 : 
     292                 : {
     293                 : /* -------------------------------------------------------------------- */
     294                 : /*      How much space do we need for this value?                       */
     295                 : /* -------------------------------------------------------------------- */
     296              94 :     uint32 item_size = 0;
     297                 : 
     298              94 :     switch( field.GetType() )
     299                 :     {
     300                 :       case FieldTypeInteger:
     301              30 :         item_size = 4;
     302              30 :         break;
     303                 : 
     304                 :       case FieldTypeFloat:
     305               0 :         item_size = 4;
     306               0 :         break;
     307                 : 
     308                 :       case FieldTypeDouble:
     309              10 :         item_size = 8;
     310              10 :         break;
     311                 : 
     312                 :       case FieldTypeString:
     313              54 :         item_size = field.GetValueString().size() + 1;
     314              54 :         break;
     315                 : 
     316                 :       case FieldTypeCountedInt:
     317               0 :         item_size = field.GetValueCountedInt().size() * 4 + 4;
     318               0 :         break;
     319                 : 
     320                 :       default:
     321               0 :         assert( 0 );
     322                 :         item_size = 0;
     323                 :         break;
     324                 :     }
     325                 : 
     326                 : /* -------------------------------------------------------------------- */
     327                 : /*      Do we need to grow the buffer to hold this?  Try to make it     */
     328                 : /*      plenty larger.                                                  */
     329                 : /* -------------------------------------------------------------------- */
     330              94 :     if( item_size + offset > (uint32) buffer.buffer_size )
     331              20 :         buffer.SetSize( buffer.buffer_size*2 + item_size );
     332                 : 
     333                 : /* -------------------------------------------------------------------- */
     334                 : /*      Write to the buffer, and byte swap if needed.                   */
     335                 : /* -------------------------------------------------------------------- */
     336              94 :     switch( field.GetType() )
     337                 :     {
     338                 :       case FieldTypeInteger:
     339                 :       {
     340              30 :           int32 value = field.GetValueInteger();
     341              30 :           if( needs_swap )
     342              30 :               SwapData( &value, 4, 1 );
     343              30 :           memcpy( buffer.buffer+offset, &value, 4 );
     344              30 :           break;
     345                 :       }
     346                 : 
     347                 :       case FieldTypeFloat:
     348                 :       {
     349               0 :           float value = field.GetValueFloat();
     350               0 :           if( needs_swap )
     351               0 :               SwapData( &value, 4, 1 );
     352               0 :           memcpy( buffer.buffer+offset, &value, 4 );
     353               0 :           break;
     354                 :       }
     355                 : 
     356                 :       case FieldTypeDouble:
     357                 :       {
     358              10 :           double value = field.GetValueDouble();
     359              10 :           if( needs_swap )
     360              10 :               SwapData( &value, 8, 1 );
     361              10 :           memcpy( buffer.buffer+offset, &value, 8 );
     362              10 :           break;
     363                 :       }
     364                 : 
     365                 :       case FieldTypeString:
     366                 :       {
     367              54 :           std::string value = field.GetValueString();
     368              54 :           memcpy( buffer.buffer+offset, value.c_str(), item_size );
     369              54 :           break;
     370                 :       }
     371                 : 
     372                 :       case FieldTypeCountedInt:
     373                 :       {
     374               0 :           std::vector<int32> value = field.GetValueCountedInt();
     375               0 :           uint32 count = value.size();
     376               0 :           memcpy( buffer.buffer+offset, &count, 4 );
     377               0 :           if( count > 0 )
     378                 :           {
     379               0 :               memcpy( buffer.buffer+offset+4, &(value[0]), count * 4 );
     380               0 :               if( needs_swap )
     381               0 :                   SwapData( buffer.buffer+offset, 4, count+1 );
     382                 :           }
     383               0 :           break;
     384                 :       }
     385                 : 
     386                 :       default:
     387               0 :         assert( 0 );
     388                 :         break;
     389                 :     }
     390                 : 
     391              94 :     return offset + item_size;
     392                 : }
     393                 : 
     394                 : /************************************************************************/
     395                 : /*                              GetData()                               */
     396                 : /************************************************************************/
     397                 : 
     398          277680 : char *CPCIDSKVectorSegment::GetData( int section, uint32 offset, 
     399                 :                                      int *bytes_available, int min_bytes,
     400                 :                                      bool update )
     401                 : 
     402                 : {
     403          277680 :     if( min_bytes == 0 )
     404               0 :         min_bytes = 1;
     405                 : 
     406                 : /* -------------------------------------------------------------------- */
     407                 : /*      Select the section to act on.                                   */
     408                 : /* -------------------------------------------------------------------- */
     409          277680 :     PCIDSKBuffer *pbuf = NULL;
     410          277680 :     uint32       *pbuf_offset = NULL;
     411          277680 :     bool         *pbuf_dirty = NULL;
     412                 : 
     413          277680 :     if( section == sec_raw )
     414                 :     {
     415            1284 :         pbuf = &raw_loaded_data;
     416            1284 :         pbuf_offset = &raw_loaded_data_offset;
     417            1284 :         pbuf_dirty = &raw_loaded_data_dirty;
     418                 :     }
     419          276396 :     else if( section == sec_vert )
     420                 :     {
     421           19338 :         pbuf = &vert_loaded_data;
     422           19338 :         pbuf_offset = &vert_loaded_data_offset;
     423           19338 :         pbuf_dirty = &vert_loaded_data_dirty;
     424                 :     }
     425          257058 :     else if( section == sec_record )
     426                 :     {
     427          257058 :         pbuf = &record_loaded_data;
     428          257058 :         pbuf_offset = &record_loaded_data_offset;
     429          257058 :         pbuf_dirty = &record_loaded_data_dirty;
     430                 :     }
     431                 : 
     432                 : /* -------------------------------------------------------------------- */
     433                 : /*      If the desired data is not within our loaded section, reload    */
     434                 : /*      one or more blocks around the request.                          */
     435                 : /* -------------------------------------------------------------------- */
     436          277680 :     if( offset < *pbuf_offset
     437                 :         || offset+min_bytes > *pbuf_offset + pbuf->buffer_size )
     438                 :     {
     439            1038 :         if( *pbuf_dirty )
     440               0 :             FlushDataBuffer( section );
     441                 : 
     442                 :         // we want whole 8K blocks around the target region.
     443            1038 :         uint32 load_offset = offset - (offset % block_page_size);
     444            1038 :         int size = (offset + min_bytes - load_offset + block_page_size - 1);
     445                 : 
     446            1038 :         size -= (size % block_page_size);
     447                 : 
     448                 :         // If the request goes beyond the end of the file, and we are 
     449                 :         // in update mode, grow the segment by writing at the end of
     450                 :         // the requested section.  This will throw an exception if we
     451                 :         // are unable to grow the file. 
     452            2022 :         if( section != sec_raw
     453             984 :             && load_offset + size > di[section].GetIndex()->size() * block_page_size
     454                 :             && update )
     455                 :         {
     456              14 :             PCIDSKBuffer zerobuf(block_page_size);
     457                 : 
     458              14 :             memset( zerobuf.buffer, 0, block_page_size );
     459                 :             WriteSecToFile( section, zerobuf.buffer, 
     460              14 :                             (load_offset + size) / block_page_size - 1, 1 );
     461                 :         }
     462                 : 
     463            1038 :         *pbuf_offset = load_offset;
     464            1038 :         pbuf->SetSize( size );
     465                 : 
     466                 :         ReadSecFromFile( section, pbuf->buffer, 
     467            1038 :                          load_offset / block_page_size, size / block_page_size );
     468                 :     }
     469                 : 
     470                 : /* -------------------------------------------------------------------- */
     471                 : /*      If an update request goes beyond the end of the last data       */
     472                 : /*      byte in a data section, then update the bytes used.  Now        */
     473                 : /*      read into our buffer.                                           */
     474                 : /* -------------------------------------------------------------------- */
     475          554076 :     if( section != sec_raw
     476          276396 :         && offset + min_bytes > di[section].GetSectionEnd() )
     477              18 :         di[section].SetSectionEnd( offset + min_bytes );
     478                 :     
     479                 : /* -------------------------------------------------------------------- */
     480                 : /*      Return desired info.                                            */
     481                 : /* -------------------------------------------------------------------- */
     482          277680 :     if( bytes_available != NULL )
     483           26270 :         *bytes_available = *pbuf_offset + pbuf->buffer_size - offset;
     484                 : 
     485          277680 :     if( update )
     486              36 :         *pbuf_dirty = true;
     487                 : 
     488          277680 :     return pbuf->buffer + offset - *pbuf_offset;
     489                 : }
     490                 : 
     491                 : /************************************************************************/
     492                 : /*                          ReadSecFromFile()                           */
     493                 : /*                                                                      */
     494                 : /*      Read one or more blocks from the desired "section" of the       */
     495                 : /*      segment data, going through the block pointer map for           */
     496                 : /*      vect/record sections.                                           */
     497                 : /************************************************************************/
     498                 : 
     499            1038 : void CPCIDSKVectorSegment::ReadSecFromFile( int section, char *buffer, 
     500                 :                                             int block_offset, 
     501                 :                                             int block_count )
     502                 : 
     503                 : {
     504                 : /* -------------------------------------------------------------------- */
     505                 : /*      Raw is a simple case, directly gulp.                            */
     506                 : /* -------------------------------------------------------------------- */
     507            1038 :     if( section == sec_raw )
     508                 :     {
     509              54 :         ReadFromFile( buffer, block_offset*block_page_size, block_count*block_page_size );
     510              54 :         return;
     511                 :     }
     512                 : 
     513                 : /* -------------------------------------------------------------------- */
     514                 : /*      Process one 8K block at a time in case they are discontigous    */
     515                 : /*      which they often are.                                           */
     516                 : /* -------------------------------------------------------------------- */
     517                 :     int i;
     518             984 :     const std::vector<uint32> *block_map = di[section].GetIndex();
     519                 : 
     520             984 :     assert( block_count + block_offset <= (int) block_map->size() );
     521                 : 
     522            2614 :     for( i = 0; i < block_count; i++ )
     523                 :     {
     524                 :         ReadFromFile( buffer + i * block_page_size, 
     525                 :                       block_page_size * (*block_map)[block_offset+i], 
     526            1630 :                       block_page_size );
     527                 :     }
     528                 : }
     529                 : 
     530                 : /************************************************************************/
     531                 : /*                          FlushDataBuffer()                           */
     532                 : /*                                                                      */
     533                 : /*      Flush the indicated data buffer to disk if it is marked         */
     534                 : /*      dirty.                                                          */
     535                 : /************************************************************************/
     536                 : 
     537             160 : void CPCIDSKVectorSegment::FlushDataBuffer( int section )
     538                 : 
     539                 : {
     540                 : /* -------------------------------------------------------------------- */
     541                 : /*      Select the section to act on.                                   */
     542                 : /* -------------------------------------------------------------------- */
     543             160 :     PCIDSKBuffer *pbuf = NULL;
     544             160 :     uint32       *pbuf_offset = NULL;
     545             160 :     bool         *pbuf_dirty = NULL;
     546                 : 
     547             160 :     if( section == sec_raw )
     548                 :     {
     549               0 :         pbuf = &raw_loaded_data;
     550               0 :         pbuf_offset = &raw_loaded_data_offset;
     551               0 :         pbuf_dirty = &raw_loaded_data_dirty;
     552                 :     }
     553             160 :     else if( section == sec_vert )
     554                 :     {
     555              80 :         pbuf = &vert_loaded_data;
     556              80 :         pbuf_offset = &vert_loaded_data_offset;
     557              80 :         pbuf_dirty = &vert_loaded_data_dirty;
     558                 :     }
     559              80 :     else if( section == sec_record )
     560                 :     {
     561              80 :         pbuf = &record_loaded_data;
     562              80 :         pbuf_offset = &record_loaded_data_offset;
     563              80 :         pbuf_dirty = &record_loaded_data_dirty;
     564                 :     }
     565                 : 
     566             160 :     if( ! *pbuf_dirty || pbuf->buffer_size == 0 )
     567             132 :         return;
     568                 : 
     569                 : /* -------------------------------------------------------------------- */
     570                 : /*      We need to write something.                                     */
     571                 : /* -------------------------------------------------------------------- */
     572              28 :     assert( (pbuf->buffer_size % block_page_size) == 0 );
     573              28 :     assert( (*pbuf_offset % block_page_size) == 0 );
     574                 : 
     575                 :     WriteSecToFile( section, pbuf->buffer, 
     576                 :                     *pbuf_offset / block_page_size, 
     577              28 :                     pbuf->buffer_size / block_page_size );
     578                 : 
     579              28 :     *pbuf_dirty = false;
     580                 : }
     581                 : 
     582                 : /************************************************************************/
     583                 : /*                           WriteSecToFile()                           */
     584                 : /*                                                                      */
     585                 : /*      Read one or more blocks from the desired "section" of the       */
     586                 : /*      segment data, going through the block pointer map for           */
     587                 : /*      vect/record sections.                                           */
     588                 : /************************************************************************/
     589                 : 
     590              42 : void CPCIDSKVectorSegment::WriteSecToFile( int section, char *buffer, 
     591                 :                                            int block_offset, 
     592                 :                                            int block_count )
     593                 : 
     594                 : {
     595                 : /* -------------------------------------------------------------------- */
     596                 : /*      Raw is a simple case, directly gulp.                            */
     597                 : /* -------------------------------------------------------------------- */
     598              42 :     if( section == sec_raw )
     599                 :     {
     600                 :         WriteToFile( buffer, block_offset*block_page_size, 
     601               0 :                      block_count*block_page_size );
     602               0 :         return;
     603                 :     }
     604                 : 
     605                 : /* -------------------------------------------------------------------- */
     606                 : /*      Do we need to grow this data section to be able to do the       */
     607                 : /*      write?                                                          */
     608                 : /* -------------------------------------------------------------------- */
     609              42 :     const std::vector<uint32> *block_map = di[section].GetIndex();
     610                 : 
     611              42 :     if( block_count + block_offset > (int) block_map->size() )
     612                 :     {
     613                 :         vh.GrowBlockIndex( section, 
     614              14 :                            block_count + block_offset - block_map->size() );
     615                 :     }
     616                 : 
     617                 : /* -------------------------------------------------------------------- */
     618                 : /*      Process one 8K block at a time in case they are discontigous    */
     619                 : /*      which they often are.                                           */
     620                 : /* -------------------------------------------------------------------- */
     621                 :     int i;
     622              84 :     for( i = 0; i < block_count; i++ )
     623                 :     {
     624                 :         WriteToFile( buffer + i * block_page_size, 
     625                 :                      block_page_size * (*block_map)[block_offset+i], 
     626              42 :                      block_page_size );
     627                 :     }
     628                 : }
     629                 : 
     630                 : /************************************************************************/
     631                 : /*                           GetProjection()                            */
     632                 : /************************************************************************/
     633                 : 
     634              54 : std::vector<double> CPCIDSKVectorSegment::GetProjection( std::string &geosys )
     635                 : 
     636                 : {
     637              54 :     LoadHeader();
     638                 : 
     639                 : /* -------------------------------------------------------------------- */
     640                 : /*      Fetch the projparms string from the proj section of the         */
     641                 : /*      vector segment header.                                          */
     642                 : /* -------------------------------------------------------------------- */
     643              54 :     ShapeField projparms;
     644                 : 
     645              54 :     ReadField( vh.section_offsets[hsec_proj]+32, projparms, 
     646              54 :                FieldTypeString, sec_raw );
     647                 : 
     648                 : /* -------------------------------------------------------------------- */
     649                 : /*      Read the geosys (units) string from SDH5.VEC1 in the segment    */
     650                 : /*      header.                                                         */
     651                 : /* -------------------------------------------------------------------- */
     652              54 :     GetHeader().Get( 160, 16, geosys, 0 ); // do not unpad!
     653                 : 
     654              54 :     return ProjParmsFromText( geosys, projparms.GetValueString() );
     655                 : }
     656                 : 
     657                 : /************************************************************************/
     658                 : /*                           SetProjection()                            */
     659                 : /************************************************************************/
     660                 : 
     661               4 : void CPCIDSKVectorSegment::SetProjection( std::string geosys,
     662                 :                                           std::vector<double> parms )
     663                 : 
     664                 : {
     665               4 :     LoadHeader();
     666                 : 
     667                 : /* -------------------------------------------------------------------- */
     668                 : /*      Apply parameters in the vector segment "proj" header section.   */
     669                 : /* -------------------------------------------------------------------- */
     670               4 :     PCIDSKBuffer proj(32);
     671                 :     uint32       proj_size;
     672               4 :     ShapeField   value;
     673                 : 
     674               4 :     value.SetValue( ProjParmsToText( parms ) );
     675                 : 
     676               4 :     ReadFromFile( proj.buffer, vh.section_offsets[hsec_proj], 32 );
     677               4 :     proj_size = WriteField( 32, value, proj );
     678                 : 
     679               4 :     vh.GrowSection( hsec_proj, proj_size );
     680               4 :     WriteToFile( proj.buffer, vh.section_offsets[hsec_proj], proj_size );
     681                 : 
     682                 : /* -------------------------------------------------------------------- */
     683                 : /*      Write the geosys string to the generic segment header.          */
     684                 : /* -------------------------------------------------------------------- */
     685               4 :     GetHeader().Put( geosys.c_str(), 160, 16 );
     686               4 :     FlushHeader();
     687               4 : }
     688                 : 
     689                 : /************************************************************************/
     690                 : /*                          IndexFromShapeId()                          */
     691                 : /*                                                                      */
     692                 : /*      Translate a shapeid into a shape index.  Several mechanisms     */
     693                 : /*      are used to accelerate this when possible.                      */
     694                 : /************************************************************************/
     695                 : 
     696           27996 : int CPCIDSKVectorSegment::IndexFromShapeId( ShapeId id )
     697                 : 
     698                 : {
     699           27996 :     if( id == NullShapeId )
     700               0 :         return -1;
     701                 : 
     702           27996 :     LoadHeader();
     703                 : 
     704                 : /* -------------------------------------------------------------------- */
     705                 : /*      Does this match our last lookup?                                */
     706                 : /* -------------------------------------------------------------------- */
     707           27996 :     if( id == last_shapes_id )
     708           27978 :         return last_shapes_index;
     709                 : 
     710                 : /* -------------------------------------------------------------------- */
     711                 : /*      Is this the next shapeid in sequence, and is it in our          */
     712                 : /*      loaded index cache?                                             */
     713                 : /* -------------------------------------------------------------------- */
     714              18 :     if( id == last_shapes_id + 1 
     715                 :         && last_shapes_index + 1 >= shape_index_start
     716                 :         && last_shapes_index + 1 < shape_index_start + (int) shape_index_ids.size() )
     717                 :     {
     718              14 :         last_shapes_index++;
     719              14 :         last_shapes_id++;
     720              14 :         return last_shapes_index;
     721                 :     }
     722                 : 
     723                 : /* -------------------------------------------------------------------- */
     724                 : /*      Activate the shapeid map, if it is not already active.          */
     725                 : /* -------------------------------------------------------------------- */
     726               4 :     if( !shapeid_map_active )
     727                 :     {
     728               2 :         PopulateShapeIdMap();
     729                 :     }
     730                 : 
     731                 : /* -------------------------------------------------------------------- */
     732                 : /*      Is this already in our shapeid map?                             */
     733                 : /* -------------------------------------------------------------------- */
     734               4 :     if( shapeid_map.count( id ) == 1 )
     735               4 :         return shapeid_map[id];
     736                 : 
     737               0 :     return -1;
     738                 : }
     739                 : 
     740                 : /************************************************************************/
     741                 : /*                          LoadShapeIdPage()                           */
     742                 : /************************************************************************/
     743                 : 
     744              28 : void CPCIDSKVectorSegment::LoadShapeIdPage( int page )
     745                 : 
     746                 : {
     747                 : /* -------------------------------------------------------------------- */
     748                 : /*      Load a chunk of shape index information into a                  */
     749                 : /*      PCIDSKBuffer.                                                   */
     750                 : /* -------------------------------------------------------------------- */
     751                 :     uint32 shape_index_byte_offset = 
     752              28 :         vh.section_offsets[hsec_shape]
     753                 :         + di[sec_record].offset_on_disk_within_section
     754              28 :         + di[sec_record].size_on_disk + 4;
     755                 : 
     756              28 :     int entries_to_load = shapeid_page_size;
     757                 : 
     758              28 :     shape_index_start = page * shapeid_page_size;
     759              28 :     if( shape_index_start + entries_to_load > shape_count )
     760              28 :         entries_to_load = shape_count - shape_index_start;
     761                 : 
     762              28 :     PCIDSKBuffer wrk_index;
     763              28 :     wrk_index.SetSize( entries_to_load * 12 );
     764                 :     
     765                 :     ReadFromFile( wrk_index.buffer, 
     766                 :                   shape_index_byte_offset + shape_index_start*12,
     767              28 :                   wrk_index.buffer_size );
     768                 : 
     769                 : /* -------------------------------------------------------------------- */
     770                 : /*      Parse into the vectors for easier use.                          */
     771                 : /* -------------------------------------------------------------------- */
     772                 :     int i;
     773                 : 
     774              28 :     shape_index_ids.resize( entries_to_load );
     775              28 :     shape_index_vertex_off.resize( entries_to_load );
     776              28 :     shape_index_record_off.resize( entries_to_load );
     777                 : 
     778            1948 :     for( i = 0; i < entries_to_load; i++ )
     779                 :     {
     780            1920 :         memcpy( &(shape_index_ids[i]), wrk_index.buffer + i*12, 4 );
     781            1920 :         memcpy( &(shape_index_vertex_off[i]), wrk_index.buffer + i*12+4, 4 );
     782            1920 :         memcpy( &(shape_index_record_off[i]), wrk_index.buffer + i*12+8, 4 );
     783                 :     }
     784                 : 
     785              28 :     if( needs_swap && entries_to_load > 0 )
     786                 :     {
     787              28 :         SwapData( &(shape_index_ids[0]), 4, entries_to_load );
     788              28 :         SwapData( &(shape_index_vertex_off[0]), 4, entries_to_load );
     789              28 :         SwapData( &(shape_index_record_off[0]), 4, entries_to_load );
     790                 :     }
     791                 : 
     792              28 :     PushLoadedIndexIntoMap();
     793              28 : }
     794                 : 
     795                 : /************************************************************************/
     796                 : /*                         AccessShapeByIndex()                         */
     797                 : /*                                                                      */
     798                 : /*      This method is responsible for loading the set of               */
     799                 : /*      information for shape "shape_index" into the shape_index data   */
     800                 : /*      structures if it is not already there.                          */
     801                 : /************************************************************************/
     802                 : 
     803           28118 : void CPCIDSKVectorSegment::AccessShapeByIndex( int shape_index )
     804                 : 
     805                 : {
     806           28118 :     LoadHeader();
     807                 : 
     808                 : /* -------------------------------------------------------------------- */
     809                 : /*      Is the requested index already loaded?                          */
     810                 : /* -------------------------------------------------------------------- */
     811           28118 :     if( shape_index >= shape_index_start
     812                 :         && shape_index < shape_index_start + (int) shape_index_ids.size() )
     813           28076 :         return;
     814                 : 
     815                 :     // this is for requesting the next shapeindex after shapecount on
     816                 :     // a partial page. 
     817              42 :     if( shape_index == shape_count
     818                 :         && (int) shape_index_ids.size() < shapeid_page_size
     819                 :         && shape_count == (int) shape_index_ids.size() + shape_index_start )
     820              14 :         return;
     821                 : 
     822                 : /* -------------------------------------------------------------------- */
     823                 : /*      If the currently loaded shapeindex is dirty, we should write    */
     824                 : /*      it now.                                                         */
     825                 : /* -------------------------------------------------------------------- */
     826              28 :     FlushLoadedShapeIndex();
     827                 : 
     828                 : /* -------------------------------------------------------------------- */
     829                 : /*      Load the page of shapeid information for this shape index.      */
     830                 : /* -------------------------------------------------------------------- */
     831              28 :     LoadShapeIdPage( shape_index / shapeid_page_size );
     832                 : }
     833                 : 
     834                 : /************************************************************************/
     835                 : /*                       PushLoadedIndexIntoMap()                       */
     836                 : /************************************************************************/
     837                 : 
     838              30 : void CPCIDSKVectorSegment::PushLoadedIndexIntoMap()
     839                 : 
     840                 : {
     841                 : /* -------------------------------------------------------------------- */
     842                 : /*      If the shapeid map is active, apply the current pages           */
     843                 : /*      shapeids if it does not already appear to have been             */
     844                 : /*      applied.                                                        */
     845                 : /* -------------------------------------------------------------------- */
     846              30 :     int loaded_page = shape_index_start / shapeid_page_size;
     847                 : 
     848              30 :     if( shapeid_map_active && shape_index_ids.size() > 0 )
     849                 :     {
     850                 :         unsigned int i;
     851                 : 
     852             950 :         for( i = 0; i < shape_index_ids.size(); i++ )
     853                 :         {
     854             948 :             if( shape_index_ids[i] != NullShapeId )
     855             948 :                 shapeid_map[shape_index_ids[i]] = i+shape_index_start;
     856                 :         }
     857                 : 
     858               2 :         if( loaded_page == shapeid_pages_certainly_mapped+1 )
     859               2 :             shapeid_pages_certainly_mapped++;
     860                 :     }
     861              30 : }
     862                 : 
     863                 : /************************************************************************/
     864                 : /*                         PopulateShapeIdMap()                         */
     865                 : /*                                                                      */
     866                 : /*      Completely populate the shapeid->index map.                     */
     867                 : /************************************************************************/
     868                 : 
     869               2 : void CPCIDSKVectorSegment::PopulateShapeIdMap()
     870                 : 
     871                 : {
     872                 : /* -------------------------------------------------------------------- */
     873                 : /*      Enable shapeid_map mode, and load the current page.             */
     874                 : /* -------------------------------------------------------------------- */
     875               2 :     if( !shapeid_map_active )
     876                 :     {
     877               2 :         shapeid_map_active = true;
     878               2 :         PushLoadedIndexIntoMap();
     879                 :     }
     880                 : 
     881                 : /* -------------------------------------------------------------------- */
     882                 : /*      Load all outstanding pages.                                     */
     883                 : /* -------------------------------------------------------------------- */
     884               2 :     int shapeid_pages = (shape_count+shapeid_page_size-1) / shapeid_page_size;
     885                 : 
     886               4 :     while( shapeid_pages_certainly_mapped+1 < shapeid_pages )
     887                 :     {
     888               0 :         LoadShapeIdPage( shapeid_pages_certainly_mapped+1 );
     889                 :     }
     890               2 : }
     891                 : 
     892                 : /************************************************************************/
     893                 : /*                             FindFirst()                              */
     894                 : /************************************************************************/
     895                 : 
     896             176 : ShapeId CPCIDSKVectorSegment::FindFirst()
     897                 : { 
     898             176 :     LoadHeader();
     899                 : 
     900             176 :     if( shape_count == 0 )
     901               0 :         return NullShapeId;
     902                 : 
     903             176 :     AccessShapeByIndex( 0 );
     904                 : 
     905             176 :     last_shapes_id = shape_index_ids[0];
     906             176 :     last_shapes_index = 0;
     907                 : 
     908             176 :     return last_shapes_id;
     909                 : }
     910                 : 
     911                 : /************************************************************************/
     912                 : /*                              FindNext()                              */
     913                 : /************************************************************************/
     914                 : 
     915            9562 : ShapeId CPCIDSKVectorSegment::FindNext( ShapeId previous_id )
     916                 : { 
     917            9562 :     if( previous_id == NullShapeId ) 
     918               0 :         return FindFirst();
     919                 : 
     920            9562 :     int previous_index = IndexFromShapeId( previous_id );
     921                 :     
     922            9562 :     if( previous_index == shape_count - 1 )
     923              94 :         return NullShapeId;
     924                 : 
     925            9468 :     AccessShapeByIndex( previous_index+1 );
     926                 : 
     927            9468 :     last_shapes_index = previous_index+1;
     928            9468 :     last_shapes_id = shape_index_ids[last_shapes_index - shape_index_start];
     929                 :     
     930            9468 :     return last_shapes_id;
     931                 : }
     932                 : 
     933                 : /************************************************************************/
     934                 : /*                           GetShapeCount()                            */
     935                 : /************************************************************************/
     936                 : 
     937             138 : int CPCIDSKVectorSegment::GetShapeCount()
     938                 : 
     939                 : {
     940             138 :     LoadHeader();
     941                 : 
     942             138 :     return shape_count;
     943                 : }
     944                 : 
     945                 : /************************************************************************/
     946                 : /*                            GetVertices()                             */
     947                 : /************************************************************************/
     948                 : 
     949            9672 : void CPCIDSKVectorSegment::GetVertices( ShapeId shape_id,
     950                 :                                         std::vector<ShapeVertex> &vertices )
     951                 : 
     952                 : {
     953            9672 :     int shape_index = IndexFromShapeId( shape_id );
     954                 : 
     955            9672 :     if( shape_index == -1 )
     956                 :         ThrowPCIDSKException( "Attempt to call GetVertices() on non-existing shape id '%d'.",
     957               0 :                               (int) shape_id );
     958                 : 
     959            9672 :     AccessShapeByIndex( shape_index );
     960                 : 
     961            9672 :     uint32 vert_off = shape_index_vertex_off[shape_index - shape_index_start];
     962                 :     uint32 vertex_count;
     963                 : 
     964            9672 :     if( vert_off == 0xffffffff )
     965                 :     {
     966               0 :         vertices.resize(0);
     967               0 :         return;
     968                 :     }
     969                 : 
     970            9672 :     memcpy( &vertex_count, GetData( sec_vert, vert_off+4, NULL, 4 ), 4 );
     971            9672 :     if( needs_swap )
     972            9672 :         SwapData( &vertex_count, 4, 1 );
     973                 : 
     974            9672 :     vertices.resize( vertex_count );
     975                 :     
     976                 :     // We ought to change this to process the available data and
     977                 :     // then request more. 
     978            9672 :     if( vertex_count > 0 )
     979                 :     {
     980                 :         memcpy( &(vertices[0]), 
     981                 :                 GetData( sec_vert, vert_off+8, NULL, vertex_count*24),
     982            9624 :                 vertex_count * 24 );
     983            9624 :         if( needs_swap )
     984            9624 :             SwapData( &(vertices[0]), 8, vertex_count*3 );
     985                 :     }
     986                 : }
     987                 : 
     988                 : /************************************************************************/
     989                 : /*                           GetFieldCount()                            */
     990                 : /************************************************************************/
     991                 : 
     992             304 : int CPCIDSKVectorSegment::GetFieldCount()
     993                 : 
     994                 : {
     995             304 :     LoadHeader();
     996                 : 
     997             304 :     return vh.field_names.size();
     998                 : }
     999                 : 
    1000                 : /************************************************************************/
    1001                 : /*                            GetFieldName()                            */
    1002                 : /************************************************************************/
    1003                 : 
    1004             162 : std::string CPCIDSKVectorSegment::GetFieldName( int field_index )
    1005                 : 
    1006                 : {
    1007             162 :     LoadHeader();
    1008                 : 
    1009             162 :     return vh.field_names[field_index];
    1010                 : }
    1011                 : 
    1012                 : /************************************************************************/
    1013                 : /*                        GetFieldDescription()                         */
    1014                 : /************************************************************************/
    1015                 : 
    1016               0 : std::string CPCIDSKVectorSegment::GetFieldDescription( int field_index )
    1017                 : 
    1018                 : {
    1019               0 :     LoadHeader();
    1020                 : 
    1021               0 :     return vh.field_descriptions[field_index];
    1022                 : }
    1023                 : 
    1024                 : /************************************************************************/
    1025                 : /*                            GetFieldType()                            */
    1026                 : /************************************************************************/
    1027                 : 
    1028             162 : ShapeFieldType CPCIDSKVectorSegment::GetFieldType( int field_index )
    1029                 : 
    1030                 : {
    1031             162 :     LoadHeader();
    1032                 : 
    1033             162 :     return vh.field_types[field_index];
    1034                 : }
    1035                 : 
    1036                 : /************************************************************************/
    1037                 : /*                           GetFieldFormat()                           */
    1038                 : /************************************************************************/
    1039                 : 
    1040               0 : std::string CPCIDSKVectorSegment::GetFieldFormat( int field_index )
    1041                 : 
    1042                 : {
    1043               0 :     LoadHeader();
    1044                 : 
    1045               0 :     return vh.field_formats[field_index];
    1046                 : }
    1047                 : 
    1048                 : /************************************************************************/
    1049                 : /*                          GetFieldDefault()                           */
    1050                 : /************************************************************************/
    1051                 : 
    1052               0 : ShapeField CPCIDSKVectorSegment::GetFieldDefault( int field_index )
    1053                 : 
    1054                 : {
    1055               0 :     LoadHeader();
    1056                 : 
    1057               0 :     return vh.field_defaults[field_index];
    1058                 : }
    1059                 : 
    1060                 : /************************************************************************/
    1061                 : /*                             GetFields()                              */
    1062                 : /************************************************************************/
    1063                 : 
    1064            8712 : void CPCIDSKVectorSegment::GetFields( ShapeId id, 
    1065                 :                                       std::vector<ShapeField>& list )
    1066                 : 
    1067                 : {
    1068                 :     unsigned int i;
    1069            8712 :     int shape_index = IndexFromShapeId( id );
    1070                 : 
    1071            8712 :     if( shape_index == -1 )
    1072                 :         ThrowPCIDSKException( "Attempt to call GetFields() on non-existing shape id '%d'.",
    1073               0 :                               (int) id );
    1074                 : 
    1075            8712 :     AccessShapeByIndex( shape_index );
    1076                 : 
    1077            8712 :     uint32 offset = shape_index_record_off[shape_index - shape_index_start];
    1078                 : 
    1079            8712 :     list.resize(vh.field_names.size());
    1080                 : 
    1081            8712 :     if( offset == 0xffffffff )
    1082                 :     {
    1083             130 :         for( i = 0; i < vh.field_names.size(); i++ )
    1084               0 :             list[i] = vh.field_defaults[i];
    1085                 :     }
    1086                 :     else
    1087                 :     {
    1088            8582 :         offset += 4; // skip size
    1089                 : 
    1090          265340 :         for( i = 0; i < vh.field_names.size(); i++ )
    1091          256758 :             offset = ReadField( offset, list[i], vh.field_types[i], sec_record );
    1092                 :     }
    1093            8712 : }
    1094                 : 
    1095                 : /************************************************************************/
    1096                 : /*                              AddField()                              */
    1097                 : /************************************************************************/
    1098                 : 
    1099               6 : void CPCIDSKVectorSegment::AddField( std::string name, ShapeFieldType type,
    1100                 :                                      std::string description,
    1101                 :                                      std::string format,
    1102                 :                                      ShapeField *default_value )
    1103                 : 
    1104                 : {
    1105               6 :     ShapeField fallback_default;
    1106                 : 
    1107               6 :     LoadHeader();
    1108                 : 
    1109                 : /* -------------------------------------------------------------------- */
    1110                 : /*      If no default is provided, use the obvious value.               */
    1111                 : /* -------------------------------------------------------------------- */
    1112               6 :     if( default_value == NULL )
    1113                 :     {
    1114               6 :         switch( type )
    1115                 :         {
    1116                 :           case FieldTypeFloat: 
    1117               0 :             fallback_default.SetValue( (float) 0.0 );
    1118               0 :             break;
    1119                 :           case FieldTypeDouble: 
    1120               2 :             fallback_default.SetValue( (double) 0.0 );
    1121               2 :             break;
    1122                 :           case FieldTypeInteger: 
    1123               2 :             fallback_default.SetValue( (int32) 0 );
    1124               2 :             break;
    1125                 :           case FieldTypeCountedInt: 
    1126                 :           {
    1127               0 :             std::vector<int32> empty_list;
    1128               0 :             fallback_default.SetValue( empty_list );
    1129               0 :             break;
    1130                 :           }
    1131                 :           case FieldTypeString:
    1132               2 :             fallback_default.SetValue( "" );
    1133                 :             break;
    1134                 : 
    1135                 :           case FieldTypeNone:
    1136                 :             break;
    1137                 :         }
    1138                 : 
    1139               6 :         default_value = &fallback_default;
    1140                 :     }
    1141                 : 
    1142                 : /* -------------------------------------------------------------------- */
    1143                 : /*      Make sure the default field is of the correct type.             */
    1144                 : /* -------------------------------------------------------------------- */
    1145               6 :     if( default_value->GetType() != type )
    1146                 :     {
    1147                 :         ThrowPCIDSKException( "Attempt to add field with a default value of "
    1148               0 :                               "a different type than the field." );
    1149                 :     }
    1150                 : 
    1151               6 :     if( type == FieldTypeNone )
    1152                 :     {
    1153               0 :         ThrowPCIDSKException( "Creating fields of type None not supported." );
    1154                 :     }
    1155                 : 
    1156                 : /* -------------------------------------------------------------------- */
    1157                 : /*      Add the field to the definition list.                           */
    1158                 : /* -------------------------------------------------------------------- */
    1159               6 :     vh.field_names.push_back( name );
    1160               6 :     vh.field_types.push_back( type );
    1161               6 :     vh.field_descriptions.push_back( description );
    1162               6 :     vh.field_formats.push_back( format );
    1163               6 :     vh.field_defaults.push_back( *default_value );
    1164                 : 
    1165               6 :     vh.WriteFieldDefinitions();
    1166                 : 
    1167                 : /* -------------------------------------------------------------------- */
    1168                 : /*      If we have existing features, we should go through adding       */
    1169                 : /*      this new field.                                                 */
    1170                 : /* -------------------------------------------------------------------- */
    1171               6 :     if( shape_count > 0 )
    1172                 :     {
    1173                 :         ThrowPCIDSKException( "Support for adding fields in populated layers "
    1174               0 :                               "has not yet been implemented." );
    1175               6 :     }
    1176               6 : }
    1177                 : 
    1178                 : /************************************************************************/
    1179                 : /*                            CreateShape()                             */
    1180                 : /************************************************************************/
    1181                 : 
    1182              26 : ShapeId CPCIDSKVectorSegment::CreateShape( ShapeId id )
    1183                 : 
    1184                 : {
    1185              26 :     LoadHeader();
    1186                 : 
    1187                 : /* -------------------------------------------------------------------- */
    1188                 : /*      Make sure we have the last shapeid index page loaded.           */
    1189                 : /* -------------------------------------------------------------------- */
    1190              26 :     AccessShapeByIndex( shape_count );
    1191                 : 
    1192                 : /* -------------------------------------------------------------------- */
    1193                 : /*      Do we need to assign a shapeid?                                 */
    1194                 : /* -------------------------------------------------------------------- */
    1195              26 :     if( id == NullShapeId )
    1196                 :     {
    1197              14 :         if( highest_shapeid_used == NullShapeId )
    1198              12 :             id = 0;
    1199                 :         else
    1200               2 :             id = highest_shapeid_used + 1;
    1201                 :     }
    1202              26 :     if( id > highest_shapeid_used )
    1203              26 :         highest_shapeid_used = id;
    1204                 :     else
    1205                 :     {
    1206               0 :         PopulateShapeIdMap();
    1207               0 :         if( shapeid_map.count(id) > 0 )
    1208                 :         {
    1209               0 :             ThrowPCIDSKException( "Attempt to create a shape with id '%d', but that already exists.", id );
    1210                 :         }
    1211                 :     }
    1212                 : 
    1213                 : /* -------------------------------------------------------------------- */
    1214                 : /*      Push this new shape on to our list of shapeids in the           */
    1215                 : /*      current page, and mark the page as dirty.                       */
    1216                 : /* -------------------------------------------------------------------- */
    1217              26 :     shape_index_ids.push_back( id );
    1218              26 :     shape_index_record_off.push_back( 0xffffffff );
    1219              26 :     shape_index_vertex_off.push_back( 0xffffffff );
    1220              26 :     shape_index_page_dirty = true;
    1221                 :     
    1222              26 :     if( shapeid_map_active )
    1223               0 :         shapeid_map[id] = shape_count;
    1224                 : 
    1225              26 :     shape_count++;
    1226                 : 
    1227              26 :     return id;
    1228                 : }
    1229                 : 
    1230                 : /************************************************************************/
    1231                 : /*                            DeleteShape()                             */
    1232                 : /*                                                                      */
    1233                 : /*      Delete a shape by shapeid.                                      */
    1234                 : /************************************************************************/
    1235                 : 
    1236              14 : void CPCIDSKVectorSegment::DeleteShape( ShapeId id )
    1237                 : 
    1238                 : {
    1239              14 :     int shape_index = IndexFromShapeId( id );
    1240                 : 
    1241              14 :     if( shape_index == -1 )
    1242                 :         ThrowPCIDSKException( "Attempt to call DeleteShape() on non-existing shape '%d'.",
    1243               0 :                               (int) id );
    1244                 : 
    1245                 : /* ==================================================================== */
    1246                 : /*      Our strategy is to move the last shape in our index down to     */
    1247                 : /*      replace the shape that we are deleting.  Unfortunately this     */
    1248                 : /*      will result in an out of sequence shapeid, but it is hard to    */
    1249                 : /*      avoid that without potentially rewriting much of the shape      */
    1250                 : /*      index.                                                          */
    1251                 : /*                                                                      */
    1252                 : /*      Note that the following sequence *does* work for special        */
    1253                 : /*      cases like deleting the last shape in the list, or deleting     */
    1254                 : /*      a shape on the same page as the last shape.   At worst a wee    */
    1255                 : /*      bit of extra work is done.                                      */
    1256                 : /* ==================================================================== */
    1257                 : 
    1258                 : /* -------------------------------------------------------------------- */
    1259                 : /*      Load the page of shapeids containing the last shape in our      */
    1260                 : /*      index, capture the last shape's details, and remove it.         */
    1261                 : /* -------------------------------------------------------------------- */
    1262                 : 
    1263                 :     uint32 vert_off, rec_off;
    1264                 :     ShapeId  last_id;
    1265                 : 
    1266              14 :     AccessShapeByIndex( shape_count-1 );
    1267                 :     
    1268              14 :     last_id = shape_index_ids[shape_count-1-shape_index_start];
    1269              14 :     vert_off = shape_index_vertex_off[shape_count-1-shape_index_start];
    1270              14 :     rec_off = shape_index_record_off[shape_count-1-shape_index_start];
    1271                 : 
    1272                 :     // We don't actually have to modify this area of the index on disk.
    1273                 :     // Some of the stuff at the end just becomes unreferenced when we
    1274                 :     // decrement shape_count.
    1275                 : 
    1276                 : /* -------------------------------------------------------------------- */
    1277                 : /*      Load the page with the shape we are deleting, and put last      */
    1278                 : /*      the shapes information over it.                                 */
    1279                 : /* -------------------------------------------------------------------- */
    1280              14 :     AccessShapeByIndex( shape_index );
    1281                 : 
    1282              14 :     shape_index_ids[shape_index-shape_index_start] = last_id;
    1283              14 :     shape_index_vertex_off[shape_index-shape_index_start] = vert_off;
    1284              14 :     shape_index_record_off[shape_index-shape_index_start] = rec_off;
    1285                 :     
    1286              14 :     shape_index_page_dirty = true;
    1287                 : 
    1288              14 :     if( shapeid_map_active )
    1289               0 :         shapeid_map.erase( id );
    1290                 : 
    1291              14 :     shape_count--;
    1292              14 : }
    1293                 : 
    1294                 : /************************************************************************/
    1295                 : /*                            SetVertices()                             */
    1296                 : /************************************************************************/
    1297                 : 
    1298              28 : void CPCIDSKVectorSegment::SetVertices( ShapeId id, 
    1299                 :                                         const std::vector<ShapeVertex>& list )
    1300                 : 
    1301                 : {
    1302              28 :     int shape_index = IndexFromShapeId( id );
    1303                 : 
    1304              28 :     if( shape_index == -1 )
    1305                 :         ThrowPCIDSKException( "Attempt to call SetVertices() on non-existing shape '%d'.",
    1306               0 :                               (int) id );
    1307                 : 
    1308              28 :     PCIDSKBuffer vbuf( list.size() * 24 + 8 );
    1309                 : 
    1310              28 :     AccessShapeByIndex( shape_index );
    1311                 : 
    1312                 : /* -------------------------------------------------------------------- */
    1313                 : /*      Is the current space big enough to hold the new vertex set?     */
    1314                 : /* -------------------------------------------------------------------- */
    1315              28 :     uint32 vert_off = shape_index_vertex_off[shape_index - shape_index_start];
    1316                 :     uint32 chunk_size;
    1317                 : 
    1318              28 :     if( vert_off != 0xffffffff )
    1319                 :     {
    1320              14 :         memcpy( &chunk_size, GetData( sec_vert, vert_off, NULL, 4 ), 4 );
    1321              14 :         if( needs_swap )
    1322              14 :             SwapData( &chunk_size, 4, 1 );
    1323                 : 
    1324              14 :         if( chunk_size < (uint32) vbuf.buffer_size )
    1325                 :         {
    1326               0 :             vert_off = 0xffffffff;
    1327                 :         }
    1328                 :     }
    1329                 : 
    1330                 : /* -------------------------------------------------------------------- */
    1331                 : /*      Do we need to put this at the end of the section?               */
    1332                 : /* -------------------------------------------------------------------- */
    1333              28 :     if( vert_off == 0xffffffff )
    1334                 :     {
    1335              14 :         vert_off = di[sec_vert].GetSectionEnd();
    1336              14 :         chunk_size = vbuf.buffer_size;
    1337                 :     }
    1338                 : 
    1339                 : /* -------------------------------------------------------------------- */
    1340                 : /*      Format the vertices in a buffer.                                */
    1341                 : /* -------------------------------------------------------------------- */
    1342              28 :     uint32 vert_count = list.size();
    1343                 :     unsigned int i;
    1344                 : 
    1345              28 :     memcpy( vbuf.buffer, &chunk_size, 4 );
    1346              28 :     memcpy( vbuf.buffer+4, &vert_count, 4 );
    1347              28 :     if( needs_swap )
    1348              28 :         SwapData( vbuf.buffer, 4, 2 );
    1349                 :     
    1350              52 :     for( i = 0; i < vert_count; i++ )
    1351                 :     {
    1352              24 :         memcpy( vbuf.buffer + 8 + i*24 +  0, &(list[i].x), 8 );
    1353              24 :         memcpy( vbuf.buffer + 8 + i*24 +  8, &(list[i].y), 8 );
    1354              24 :         memcpy( vbuf.buffer + 8 + i*24 + 16, &(list[i].z), 8 );
    1355                 :     }
    1356                 :     
    1357              28 :     if( needs_swap )
    1358              28 :         SwapData( vbuf.buffer + 8, 8, 3*vert_count );
    1359                 : 
    1360                 : /* -------------------------------------------------------------------- */
    1361                 : /*      Write the data into the working buffer.                         */
    1362                 : /* -------------------------------------------------------------------- */
    1363                 :     memcpy( GetData( sec_vert, vert_off, NULL, vbuf.buffer_size, true ),
    1364              28 :             vbuf.buffer, vbuf.buffer_size );
    1365                 : 
    1366                 : /* -------------------------------------------------------------------- */
    1367                 : /*      Record the offset                                               */
    1368                 : /* -------------------------------------------------------------------- */
    1369              28 :     if( shape_index_vertex_off[shape_index - shape_index_start] != vert_off )
    1370                 :     {
    1371              14 :         shape_index_vertex_off[shape_index - shape_index_start] = vert_off;
    1372              14 :         shape_index_page_dirty = true;
    1373              28 :     }
    1374              28 : }
    1375                 : 
    1376                 : /************************************************************************/
    1377                 : /*                             SetFields()                              */
    1378                 : /************************************************************************/
    1379                 : 
    1380               8 : void CPCIDSKVectorSegment::SetFields( ShapeId id, 
    1381                 :                                       const std::vector<ShapeField>& list_in )
    1382                 : 
    1383                 : {
    1384                 :     uint32 i;
    1385               8 :     int shape_index = IndexFromShapeId( id );
    1386               8 :     std::vector<ShapeField> full_list;
    1387               8 :     const std::vector<ShapeField> *listp = NULL;
    1388                 : 
    1389               8 :     if( shape_index == -1 )
    1390                 :         ThrowPCIDSKException( "Attempt to call SetFields() on non-existing shape id '%d'.",
    1391               0 :                               (int) id );
    1392                 : 
    1393               8 :     if( list_in.size() > vh.field_names.size() )
    1394                 :     {
    1395                 :         ThrowPCIDSKException( 
    1396                 :             "Attempt to write %d fields to a layer with only %d fields.", 
    1397               0 :             list_in.size(), vh.field_names.size() );
    1398                 :     }
    1399                 : 
    1400               8 :     if( list_in.size() < vh.field_names.size() )
    1401                 :     {
    1402               0 :         full_list = list_in;
    1403                 : 
    1404                 :         // fill out missing fields in list with defaults.
    1405               0 :         for( i = list_in.size(); i < vh.field_names.size(); i++ )
    1406               0 :             full_list[i] = vh.field_defaults[i];
    1407                 :         
    1408               0 :         listp = &full_list;
    1409                 :     }
    1410                 :     else
    1411               8 :         listp = &list_in;
    1412                 : 
    1413               8 :     AccessShapeByIndex( shape_index );
    1414                 : 
    1415                 : /* -------------------------------------------------------------------- */
    1416                 : /*      Format the fields in the buffer.                                */
    1417                 : /* -------------------------------------------------------------------- */
    1418               8 :     PCIDSKBuffer fbuf(4);
    1419               8 :     uint32 offset = 4;
    1420                 : 
    1421              32 :     for( i = 0; i < listp->size(); i++ )
    1422              24 :         offset = WriteField( offset, (*listp)[i], fbuf );
    1423                 : 
    1424               8 :     fbuf.SetSize( offset );
    1425                 : 
    1426                 : /* -------------------------------------------------------------------- */
    1427                 : /*      Is the current space big enough to hold the new field set?      */
    1428                 : /* -------------------------------------------------------------------- */
    1429               8 :     uint32 rec_off = shape_index_record_off[shape_index - shape_index_start];
    1430               8 :     uint32 chunk_size = offset;
    1431                 : 
    1432               8 :     if( rec_off != 0xffffffff )
    1433                 :     {
    1434               4 :         memcpy( &chunk_size, GetData( sec_record, rec_off, NULL, 4 ), 4 );
    1435               4 :         if( needs_swap )
    1436               4 :             SwapData( &chunk_size, 4, 1 );
    1437                 : 
    1438               4 :         if( chunk_size < (uint32) fbuf.buffer_size )
    1439                 :         {
    1440               0 :             rec_off = 0xffffffff;
    1441                 :         }
    1442                 :     }
    1443                 : 
    1444                 : /* -------------------------------------------------------------------- */
    1445                 : /*      Do we need to put this at the end of the section?               */
    1446                 : /* -------------------------------------------------------------------- */
    1447               8 :     if( rec_off == 0xffffffff )
    1448                 :     {
    1449               4 :         rec_off = di[sec_record].GetSectionEnd();
    1450               4 :         chunk_size = fbuf.buffer_size;
    1451                 :     }
    1452                 : 
    1453                 : /* -------------------------------------------------------------------- */
    1454                 : /*      Set the chunk size, and number of fields.                       */
    1455                 : /* -------------------------------------------------------------------- */
    1456               8 :     memcpy( fbuf.buffer + 0, &chunk_size, 4 ); 
    1457                 : 
    1458               8 :     if( needs_swap )
    1459               8 :         SwapData( fbuf.buffer, 4, 1 );
    1460                 : 
    1461                 : /* -------------------------------------------------------------------- */
    1462                 : /*      Write the data into the working buffer.                         */
    1463                 : /* -------------------------------------------------------------------- */
    1464                 :     memcpy( GetData( sec_record, rec_off, NULL, fbuf.buffer_size, true ),
    1465               8 :             fbuf.buffer, fbuf.buffer_size );
    1466                 : 
    1467                 : /* -------------------------------------------------------------------- */
    1468                 : /*      Record the offset                                               */
    1469                 : /* -------------------------------------------------------------------- */
    1470               8 :     if( shape_index_record_off[shape_index - shape_index_start] != rec_off )
    1471                 :     {
    1472               4 :         shape_index_record_off[shape_index - shape_index_start] = rec_off;
    1473               4 :         shape_index_page_dirty = true;
    1474               8 :     }
    1475               8 : }
    1476                 : 
    1477                 : /************************************************************************/
    1478                 : /*                       FlushLoadedShapeIndex()                        */
    1479                 : /************************************************************************/
    1480                 : 
    1481             108 : void CPCIDSKVectorSegment::FlushLoadedShapeIndex()
    1482                 : 
    1483                 : {
    1484             108 :     if( !shape_index_page_dirty )
    1485              84 :         return;
    1486                 : 
    1487              24 :     uint32 offset = vh.ShapeIndexPrepare( shape_count * 12 + 4 );
    1488                 : 
    1489              24 :     PCIDSKBuffer write_buffer( shapeid_page_size * 12 );
    1490                 : 
    1491                 :     // Update the count field.
    1492              24 :     memcpy( write_buffer.buffer, &shape_count, 4 );
    1493              24 :     if( needs_swap )
    1494              24 :         SwapData( write_buffer.buffer, 4, 1 );
    1495              24 :     WriteToFile( write_buffer.buffer, offset, 4 );
    1496                 : 
    1497                 :     // Write out the page of shapeid information.
    1498                 :     unsigned int i;
    1499              62 :     for( i = 0; i < shape_index_ids.size(); i++ )
    1500                 :     {
    1501                 :         memcpy( write_buffer.buffer + 12*i, 
    1502              38 :                 &(shape_index_ids[i]), 4 );
    1503                 :         memcpy( write_buffer.buffer + 12*i + 4, 
    1504              38 :                 &(shape_index_vertex_off[i]), 4 );
    1505                 :         memcpy( write_buffer.buffer + 12*i + 8, 
    1506              38 :                 &(shape_index_record_off[i]), 4 );
    1507                 :     }
    1508                 : 
    1509              24 :     if( needs_swap )
    1510              24 :         SwapData( write_buffer.buffer, 4, shape_index_ids.size() * 3 );
    1511                 : 
    1512                 :     WriteToFile( write_buffer.buffer, 
    1513                 :                  offset + 4 + shape_index_start * 12, 
    1514              24 :                  12 * shape_index_ids.size() );
    1515                 :     
    1516                 :     // invalidate the raw buffer.
    1517              24 :     raw_loaded_data.buffer_size = 0;
    1518                 : 
    1519                 :     
    1520              24 :     shape_index_page_dirty = false;
    1521                 : }
    1522                 : 

Generated by: LCOV version 1.7