LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/segment - vecsegheader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 167 190 87.9 %
Date: 2024-11-21 22:18:42 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Purpose:  Implementation of the VecSegHeader class.
       4             :  *
       5             :  * This class is used to manage reading and writing of the vector segment
       6             :  * header section, growing them as needed.  It is exclusively a private
       7             :  * helper class for the CPCIDSKVectorSegment.
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2010
      11             :  * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : #include "pcidsk.h"
      17             : #include "core/pcidsk_utils.h"
      18             : #include "segment/vecsegheader.h"
      19             : #include "segment/cpcidskvectorsegment.h"
      20             : #include <cassert>
      21             : #include <cstring>
      22             : #include <cstdio>
      23             : #include <limits>
      24             : 
      25             : using namespace PCIDSK;
      26             : 
      27             : /************************************************************************/
      28             : /*                            VecSegHeader()                            */
      29             : /************************************************************************/
      30             : 
      31        1185 : VecSegHeader::VecSegHeader()
      32             : 
      33             : {
      34        1185 :     vs = nullptr;
      35        1185 :     initialized = false;
      36        1185 :     needs_swap = !BigEndianSystem();
      37        1185 :     header_blocks = 0;
      38        1185 : }
      39             : 
      40             : /************************************************************************/
      41             : /*                           ~VecSegHeader()                            */
      42             : /************************************************************************/
      43             : 
      44        1185 : VecSegHeader::~VecSegHeader()
      45             : 
      46             : {
      47        1185 : }
      48             : 
      49             : /************************************************************************/
      50             : /*                           InitializeNew()                            */
      51             : /*                                                                      */
      52             : /*      Initialize the header of a new vector segment in a              */
      53             : /*      consistent state for an empty segment.                          */
      54             : /************************************************************************/
      55             : 
      56        1088 : void VecSegHeader::InitializeNew()
      57             : 
      58             : {
      59        2176 :     PCIDSKBuffer header( 8 * 1024 );
      60             :     uint32   ivalue, hoffset;
      61             : 
      62        1088 :     memset( header.buffer, 0, header.buffer_size );
      63             : 
      64             :     // magic cookie
      65        1088 :     ivalue = 0xffffffff;
      66        1088 :     memcpy( header.buffer + 0, &ivalue, 4 );
      67        1088 :     memcpy( header.buffer + 4, &ivalue, 4 );
      68             : 
      69        1088 :     ivalue = 21;
      70        1088 :     memcpy( header.buffer + 8, &ivalue, 4 );
      71        1088 :     ivalue = 4;
      72        1088 :     memcpy( header.buffer + 12, &ivalue, 4 );
      73        1088 :     ivalue = 19;
      74        1088 :     memcpy( header.buffer + 16, &ivalue, 4 );
      75        1088 :     ivalue = 69;
      76        1088 :     memcpy( header.buffer + 20, &ivalue, 4 );
      77        1088 :     ivalue = 1;
      78        1088 :     memcpy( header.buffer + 24, &ivalue, 4 );
      79             : 
      80             :     // blocks in header.
      81        1088 :     ivalue = 1;
      82        1088 :     memcpy( header.buffer + 68, &ivalue, 4 );
      83             : 
      84             :     // offset to Projection
      85        1088 :     hoffset = 88;
      86        1088 :     memcpy( header.buffer + 72, &hoffset, 4 );
      87             : 
      88             :     // Project segment
      89             :     double dvalue;
      90        1088 :     dvalue = 0.0;
      91        1088 :     memcpy( header.buffer + hoffset, &dvalue, 8 );
      92        1088 :     memcpy( header.buffer + hoffset+8, &dvalue, 8 );
      93        1088 :     dvalue = 1.0;
      94        1088 :     memcpy( header.buffer + hoffset+16, &dvalue, 8 );
      95        1088 :     memcpy( header.buffer + hoffset+24, &dvalue, 8 );
      96        1088 :     if( needs_swap )
      97        1088 :         SwapData( header.buffer + hoffset, 8, 4 );
      98        1088 :     hoffset += 33;
      99             : 
     100             :     // offset to RST
     101        1088 :     memcpy( header.buffer + 76, &hoffset, 4 );
     102             : 
     103             :     // RST - two zeros means no rst + empty string.
     104        1088 :     hoffset += 9;
     105             : 
     106             :     // offset to Records
     107        1088 :     memcpy( header.buffer + 80, &hoffset, 4 );
     108             : 
     109             :     // Records - zeros means no fields.
     110        1088 :     hoffset += 4;
     111             : 
     112             :     // offset to Shapes
     113        1088 :     memcpy( header.buffer + 84, &hoffset, 4 );
     114             : 
     115             :     // Shapes - zero means no shapes.
     116        1088 :     hoffset += 4;
     117             : 
     118        1088 :     if( needs_swap )
     119        1088 :         SwapData( header.buffer, 4, 22 );
     120             : 
     121        1088 :     vs->WriteToFile( header.buffer, 0, header.buffer_size );
     122        1088 : }
     123             : 
     124             : /************************************************************************/
     125             : /*                         InitializeExisting()                         */
     126             : /*                                                                      */
     127             : /*      Establish the location and sizes of the various header          */
     128             : /*      sections.                                                       */
     129             : /************************************************************************/
     130             : 
     131        1183 : void VecSegHeader::InitializeExisting()
     132             : 
     133             : {
     134        1183 :     if( initialized )
     135           0 :         return;
     136             : 
     137        1183 :     initialized = true;
     138             : 
     139             : /* -------------------------------------------------------------------- */
     140             : /*      Check fixed portion of the header to ensure this is a V6        */
     141             : /*      style vector segment.                                           */
     142             : /* -------------------------------------------------------------------- */
     143             :     static const unsigned char magic[24] =
     144             :         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     145             :           0, 0, 0, 21, 0, 0, 0, 4, 0, 0, 0, 19, 0, 0, 0, 69 };
     146             : 
     147        1183 :     if( memcmp( vs->GetData( sec_raw, 0, nullptr, 24 ), magic, 24 ) != 0 )
     148             :     {
     149           0 :         return ThrowPCIDSKException( "Unexpected vector header values, possibly it is not a V6 vector segment?" );
     150             :     }
     151             : 
     152             : /* -------------------------------------------------------------------- */
     153             : /*      Establish how big the header is currently.                      */
     154             : /* -------------------------------------------------------------------- */
     155        1183 :     memcpy( &header_blocks, vs->GetData( sec_raw, 68, nullptr, 4 ), 4 );
     156        1183 :     if( needs_swap )
     157        1183 :         SwapData( &header_blocks, 4, 1 );
     158             : 
     159             : /* -------------------------------------------------------------------- */
     160             : /*      Load section offsets.                                           */
     161             : /* -------------------------------------------------------------------- */
     162        1183 :     memcpy( section_offsets, vs->GetData( sec_raw, 72, nullptr, 16 ), 16 );
     163        1183 :     if( needs_swap )
     164        1183 :         SwapData( section_offsets, 4, 4 );
     165             : 
     166             : /* -------------------------------------------------------------------- */
     167             : /*      Determine the size of the projection section.                   */
     168             : /* -------------------------------------------------------------------- */
     169        1183 :     ShapeField work_value;
     170        1183 :     uint32 next_off = section_offsets[hsec_proj];
     171             : 
     172        1183 :     next_off += 32; // xoff/yoff/xsize/ysize values.
     173             : 
     174        1183 :     next_off = vs->ReadField( next_off, work_value, FieldTypeString, sec_raw );
     175        1183 :     section_sizes[hsec_proj] = next_off - section_offsets[hsec_proj];
     176             : 
     177             : /* -------------------------------------------------------------------- */
     178             : /*      Determine the size of the RST.                                  */
     179             : /* -------------------------------------------------------------------- */
     180             :     // yikes, not too sure!  for now assume it is empty.
     181        1183 :     section_sizes[hsec_rst] = 8;
     182             : 
     183             : /* -------------------------------------------------------------------- */
     184             : /*      Load the field definitions.                                     */
     185             : /* -------------------------------------------------------------------- */
     186             :     int  field_count, i;
     187             : 
     188        1183 :     next_off = section_offsets[hsec_record];
     189             : 
     190        1183 :     next_off = vs->ReadField( next_off, work_value, FieldTypeInteger, sec_raw );
     191        1183 :     field_count = work_value.GetValueInteger();
     192             : 
     193        1333 :     for( i = 0; i < field_count; i++ )
     194             :     {
     195         150 :         next_off = vs->ReadField( next_off, work_value, FieldTypeString, sec_raw );
     196         150 :         field_names.push_back( work_value.GetValueString() );
     197             : 
     198         150 :         next_off = vs->ReadField( next_off, work_value, FieldTypeString, sec_raw );
     199         150 :         field_descriptions.push_back( work_value.GetValueString() );
     200             : 
     201         150 :         next_off = vs->ReadField( next_off, work_value, FieldTypeInteger, sec_raw );
     202         150 :         int field_type = work_value.GetValueInteger();
     203         150 :         if( field_type < 0 || field_type > FieldTypeCountedInt )
     204           0 :             return ThrowPCIDSKException( "Invalid field type: %d", field_type );
     205         150 :         field_types.push_back( static_cast<ShapeFieldType> (field_type) );
     206             : 
     207         150 :         next_off = vs->ReadField( next_off, work_value, FieldTypeString, sec_raw );
     208         150 :         field_formats.push_back( work_value.GetValueString() );
     209             : 
     210         150 :         next_off = vs->ReadField( next_off, work_value, field_types[i], sec_raw );
     211         150 :         field_defaults.push_back( work_value );
     212             :     }
     213             : 
     214        1183 :     section_sizes[hsec_record] = next_off - section_offsets[hsec_record];
     215             : 
     216             : /* -------------------------------------------------------------------- */
     217             : /*      Fetch the vertex block basics.                                  */
     218             : /* -------------------------------------------------------------------- */
     219        1183 :     next_off = section_offsets[hsec_shape];
     220             : 
     221        1183 :     vs->di[sec_vert].Initialize( vs, sec_vert );
     222        1183 :     next_off += vs->di[sec_vert].SerializedSize();
     223             : 
     224             : /* -------------------------------------------------------------------- */
     225             : /*      Fetch the record block basics.                                  */
     226             : /* -------------------------------------------------------------------- */
     227        1183 :     vs->di[sec_record].Initialize( vs, sec_record );
     228        1183 :     next_off += vs->di[sec_record].SerializedSize();
     229             : 
     230             : /* -------------------------------------------------------------------- */
     231             : /*      Fetch the shapeid basics.                                       */
     232             : /* -------------------------------------------------------------------- */
     233        1183 :     memcpy( &(vs->total_shape_count), vs->GetData(sec_raw,next_off,nullptr,4), 4);
     234        1183 :     if( needs_swap )
     235        1183 :         SwapData(&(vs->total_shape_count), 4, 1);
     236        1183 :     if( vs->total_shape_count < 0 )
     237           0 :         return ThrowPCIDSKException( "Invalid shape_count: %d", vs->total_shape_count );
     238             : 
     239        1183 :     next_off += 4;
     240        1183 :     vs->shape_index_start = 0;
     241             : 
     242        1183 :     uint64 section_size = next_off - section_offsets[hsec_shape]
     243        1183 :         + static_cast<uint64>(vs->total_shape_count) * 12;
     244        1183 :     if( section_size > std::numeric_limits<uint32>::max() )
     245           0 :         return ThrowPCIDSKException( "Invalid section_size" );
     246             : 
     247        1183 :     section_sizes[hsec_shape] = static_cast<uint32>(section_size);
     248             : }
     249             : 
     250             : /************************************************************************/
     251             : /*                       WriteFieldDefinitions()                        */
     252             : /************************************************************************/
     253             : 
     254          35 : void VecSegHeader::WriteFieldDefinitions()
     255             : 
     256             : {
     257          70 :     PCIDSKBuffer hbuf( 1000 );
     258          35 :     uint32  offset = 0, i;
     259          35 :     ShapeField wrkfield;
     260             : 
     261          35 :     wrkfield.SetValue( (int32) field_names.size() );
     262          35 :     offset = vs->WriteField( offset, wrkfield, hbuf );
     263             : 
     264         138 :     for( i = 0; i < field_names.size(); i++ )
     265             :     {
     266         103 :         wrkfield.SetValue( field_names[i] );
     267         103 :         offset = vs->WriteField( offset, wrkfield, hbuf );
     268             : 
     269         103 :         wrkfield.SetValue( field_descriptions[i] );
     270         103 :         offset = vs->WriteField( offset, wrkfield, hbuf );
     271             : 
     272         103 :         wrkfield.SetValue( (int32) field_types[i] );
     273         103 :         offset = vs->WriteField( offset, wrkfield, hbuf );
     274             : 
     275         103 :         wrkfield.SetValue( field_formats[i] );
     276         103 :         offset = vs->WriteField( offset, wrkfield, hbuf );
     277             : 
     278         103 :         offset = vs->WriteField( offset, field_defaults[i], hbuf );
     279             :     }
     280             : 
     281          35 :     hbuf.SetSize( offset );
     282             : 
     283          35 :     GrowSection( hsec_record, hbuf.buffer_size );
     284          35 :     vs->WriteToFile( hbuf.buffer, section_offsets[hsec_record],
     285          35 :                      hbuf.buffer_size );
     286             : 
     287             :     // invalidate the raw buffer.
     288          35 :     vs->raw_loaded_data.buffer_size = 0;
     289          35 : }
     290             : 
     291             : /************************************************************************/
     292             : /*                            GrowSection()                             */
     293             : /*                                                                      */
     294             : /*      If necessary grow/move the header section specified to have     */
     295             : /*      the desired amount of room.  Returns true if the header         */
     296             : /*      section has moved.                                              */
     297             : /************************************************************************/
     298             : 
     299         252 : bool VecSegHeader::GrowSection( int hsec, uint32 new_size )
     300             : 
     301             : {
     302             : /* -------------------------------------------------------------------- */
     303             : /*      Trivial case.                                                   */
     304             : /* -------------------------------------------------------------------- */
     305         252 :     if( section_sizes[hsec] >= new_size )
     306             :     {
     307          86 :         section_sizes[hsec] = new_size;
     308          86 :         return false;
     309             :     }
     310             : 
     311             : /* -------------------------------------------------------------------- */
     312             : /*      Can we grow the section in its current location without         */
     313             : /*      overlapping anything else?                                      */
     314             : /* -------------------------------------------------------------------- */
     315             :     int ihsec;
     316         166 :     bool grow_ok = true;
     317         166 :     uint32 last_used = 0;
     318             : 
     319         830 :     for( ihsec = 0; ihsec < 4; ihsec++ )
     320             :     {
     321         664 :         if( ihsec == hsec )
     322         166 :             continue;
     323             : 
     324         498 :         if( section_offsets[ihsec] + section_sizes[ihsec] > last_used )
     325         482 :             last_used = section_offsets[ihsec] + section_sizes[ihsec];
     326             : 
     327         904 :         if( section_offsets[hsec] >=
     328         498 :             section_offsets[ihsec] + section_sizes[ihsec] )
     329         406 :             continue;
     330             : 
     331          92 :         if( section_offsets[ihsec] >= section_offsets[hsec] + new_size )
     332           0 :             continue;
     333             : 
     334             :         // apparent overlap
     335          92 :         grow_ok = false;
     336             :     }
     337             : 
     338             : /* -------------------------------------------------------------------- */
     339             : /*      If we can grow in place and have space there is nothing to do.  */
     340             : /* -------------------------------------------------------------------- */
     341         166 :     if( grow_ok
     342          86 :         && section_offsets[hsec] + new_size
     343          86 :         < header_blocks * block_page_size )
     344             :     {
     345          86 :         section_sizes[hsec] = new_size;
     346          86 :         return false;
     347             :     }
     348             : 
     349             : /* -------------------------------------------------------------------- */
     350             : /*      Where will the section be positioned after grow?  It might      */
     351             : /*      be nice to search for a big enough hole in the existing area    */
     352             : /*      to fit the section.                                             */
     353             : /* -------------------------------------------------------------------- */
     354             :     uint32 new_base;
     355             : 
     356          80 :     if( grow_ok )
     357           0 :         new_base = section_offsets[hsec];
     358             :     else
     359          80 :         new_base = last_used;
     360             : 
     361             : /* -------------------------------------------------------------------- */
     362             : /*      Does the header need to grow?                                   */
     363             : /* -------------------------------------------------------------------- */
     364          80 :     if( new_base + new_size > header_blocks * block_page_size )
     365             :     {
     366           0 :         GrowHeader( (new_base+new_size+block_page_size-1) / block_page_size
     367           0 :                     - header_blocks );
     368             :     }
     369             : 
     370             : /* -------------------------------------------------------------------- */
     371             : /*      Move the old section to the new location.                       */
     372             : /* -------------------------------------------------------------------- */
     373          80 :     bool actual_move = false;
     374             : 
     375          80 :     if( new_base != section_offsets[hsec] )
     376             :     {
     377          80 :         vs->MoveData( section_offsets[hsec], new_base, section_sizes[hsec] );
     378          80 :         actual_move = true;
     379             :     }
     380             : 
     381          80 :     section_sizes[hsec] = new_size;
     382          80 :     section_offsets[hsec] = new_base;
     383             : 
     384             : /* -------------------------------------------------------------------- */
     385             : /*      Update the section offsets list.                                */
     386             : /* -------------------------------------------------------------------- */
     387          80 :     if( actual_move )
     388             :     {
     389          80 :         uint32 new_offset = section_offsets[hsec];
     390          80 :         if( needs_swap )
     391          80 :             SwapData( &new_offset, 4, 1 );
     392          80 :         vs->WriteToFile( &new_offset, 72 + hsec * 4, 4 );
     393             :     }
     394             : 
     395          80 :     return true;
     396             : }
     397             : 
     398             : /************************************************************************/
     399             : /*                           GrowBlockIndex()                           */
     400             : /*                                                                      */
     401             : /*      Allocate the requested number of additional blocks to the       */
     402             : /*      data block index.                                               */
     403             : /************************************************************************/
     404             : 
     405          80 : void VecSegHeader::GrowBlockIndex( int section, int new_blocks )
     406             : 
     407             : {
     408          80 :     if( new_blocks == 0 )
     409           0 :         return;
     410             : 
     411          80 :     uint32  next_block = (uint32) (vs->GetContentSize() / block_page_size);
     412             : 
     413         160 :     while( new_blocks > 0 )
     414             :     {
     415          80 :         vs->di[section].AddBlockToIndex( next_block++ );
     416          80 :         new_blocks--;
     417             :     }
     418             : 
     419          80 :     if( GrowSection( hsec_shape, section_sizes[hsec_shape] + 4*new_blocks ) )
     420             :     {
     421           0 :         vs->di[sec_vert].SetDirty();
     422           0 :         vs->di[sec_record].SetDirty();
     423           0 :         vs->shape_index_page_dirty = true; // we need to rewrite at new location
     424             :     }
     425             : }
     426             : 
     427             : /************************************************************************/
     428             : /*                         ShapeIndexPrepare()                          */
     429             : /*                                                                      */
     430             : /*      When CPCIDSKVectorSegment::FlushLoadedShapeIndex() needs to     */
     431             : /*      write out all the shapeid's and offsets, it calls this          */
     432             : /*      method to find the offset from the start of the segment at      */
     433             : /*      which it should do the writing.                                 */
     434             : /*                                                                      */
     435             : /*      We use this opportunity to flush out the vertex, and record     */
     436             : /*      block offsets if necessary, and to grow the header if needed    */
     437             : /*      to hold the proposed shapeindex size.   The passed in size      */
     438             : /*      is the size in bytes from "Number of Shapes" on in the          */
     439             : /*      "Shape section" of the header.                                  */
     440             : /************************************************************************/
     441             : 
     442          51 : uint32 VecSegHeader::ShapeIndexPrepare( uint32 size )
     443             : 
     444             : {
     445          51 :     GrowSection( hsec_shape,
     446             :                  size
     447          51 :                  + vs->di[sec_vert].size_on_disk
     448          51 :                  + vs->di[sec_record].size_on_disk );
     449             : 
     450          51 :     return section_offsets[hsec_shape]
     451          51 :         + vs->di[sec_vert].size_on_disk
     452          51 :         + vs->di[sec_record].size_on_disk;
     453             : }
     454             : 
     455             : /************************************************************************/
     456             : /*                             GrowHeader()                             */
     457             : /*                                                                      */
     458             : /*      Grow the header by the requested number of blocks.  This        */
     459             : /*      will often involve migrating existing vector or record          */
     460             : /*      section blocks on to make space since the header must be        */
     461             : /*      contiguous.                                                     */
     462             : /************************************************************************/
     463             : 
     464           0 : void VecSegHeader::GrowHeader( uint32 new_blocks )
     465             : 
     466             : {
     467             : //    fprintf( stderr, "GrowHeader(%d) to %d\n",
     468             : //             new_blocks, header_blocks + new_blocks );
     469             : 
     470             : /* -------------------------------------------------------------------- */
     471             : /*      Process the two existing block maps, moving stuff on if         */
     472             : /*      needed.                                                         */
     473             : /* -------------------------------------------------------------------- */
     474           0 :     vs->di[sec_vert].VacateBlockRange( header_blocks, new_blocks );
     475           0 :     vs->di[sec_record].VacateBlockRange( header_blocks, new_blocks );
     476             : 
     477             : /* -------------------------------------------------------------------- */
     478             : /*      Write to ensure the segment is the new size.                    */
     479             : /* -------------------------------------------------------------------- */
     480           0 :     vs->WriteToFile( "\0", (header_blocks+new_blocks) * block_page_size - 1, 1);
     481             : 
     482             : /* -------------------------------------------------------------------- */
     483             : /*      Update to new header size.                                      */
     484             : /* -------------------------------------------------------------------- */
     485           0 :     header_blocks += new_blocks;
     486             : 
     487           0 :     uint32 header_block_buf = header_blocks;
     488             : 
     489           0 :     if( needs_swap )
     490           0 :         SwapData( &header_block_buf, 4, 1 );
     491             : 
     492           0 :     vs->WriteToFile( &header_block_buf, 68, 4 );
     493           0 : }
     494             : 

Generated by: LCOV version 1.14