LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/segment - cpcidskvectorsegment.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 509 636 80.0 %
Date: 2024-04-27 17:22:41 Functions: 35 40 87.5 %

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

Generated by: LCOV version 1.14