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

Generated by: LCOV version 1.14