LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/segment - vecsegdataindex.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 93 110 84.5 %
Date: 2024-11-21 22:18:42 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Purpose:  Implementation of the VecSegIndex class.
       4             :  *
       5             :  * This class is used to manage a vector segment data block index.  There
       6             :  * will be two instances created, one for the record data (sec_record) and
       7             :  * one for the vertices (sec_vert).  This class is exclusively a private
       8             :  * helper class for VecSegHeader.
       9             :  *
      10             :  ******************************************************************************
      11             :  * Copyright (c) 2010
      12             :  * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
      13             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  ****************************************************************************/
      16             : 
      17             : #include "pcidsk.h"
      18             : #include "core/pcidsk_utils.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             : /*      Size of a block in the record/vertex block tables.  This is    */
      29             : /*      determined by the PCIDSK format and may not be changed.         */
      30             : /* -------------------------------------------------------------------- */
      31             : static const int block_page_size = 8192;
      32             : 
      33             : /************************************************************************/
      34             : /*                          VecSegDataIndex()                           */
      35             : /************************************************************************/
      36             : 
      37        2370 : VecSegDataIndex::VecSegDataIndex()
      38             : 
      39             : {
      40        2370 :     block_initialized = false;
      41        2370 :     vs = nullptr;
      42        2370 :     dirty = false;
      43        2370 :     section = 0;
      44        2370 :     offset_on_disk_within_section = 0;
      45        2370 :     size_on_disk = 0;
      46        2370 :     block_count = 0;
      47        2370 :     bytes = 0;
      48        2370 : }
      49             : 
      50             : /************************************************************************/
      51             : /*                          ~VecSegDataIndex()                          */
      52             : /************************************************************************/
      53             : 
      54        2370 : VecSegDataIndex::~VecSegDataIndex()
      55             : 
      56             : {
      57        2370 : }
      58             : 
      59             : /************************************************************************/
      60             : /*                             Initialize()                             */
      61             : /************************************************************************/
      62             : 
      63        2366 : void VecSegDataIndex::Initialize( CPCIDSKVectorSegment *vsIn, int sectionIn )
      64             : 
      65             : {
      66        2366 :     this->section = sectionIn;
      67        2366 :     this->vs = vsIn;
      68             : 
      69        2366 :     if( section == sec_vert )
      70        1183 :         offset_on_disk_within_section = 0;
      71             :     else
      72        1183 :         offset_on_disk_within_section = vs->di[sec_vert].SerializedSize();
      73             : 
      74        2366 :     uint32 offset = offset_on_disk_within_section
      75        2366 :         + vs->vh.section_offsets[hsec_shape];
      76             : 
      77        2366 :     memcpy( &block_count, vs->GetData(sec_raw,offset,nullptr,4), 4);
      78        2366 :     memcpy( &bytes, vs->GetData(sec_raw,offset+4,nullptr,4), 4);
      79             : 
      80        2366 :     bool needs_swap = !BigEndianSystem();
      81             : 
      82        2366 :     if( needs_swap )
      83             :     {
      84        2366 :         SwapData( &block_count, 4, 1 );
      85        2366 :         SwapData( &bytes, 4, 1 );
      86             :     }
      87             : 
      88        2366 :     if( block_count > (std::numeric_limits<uint32>::max() - 8) /4 )
      89             :     {
      90           0 :         throw PCIDSKException("Invalid block_count: %u", block_count);
      91             :     }
      92             : 
      93        2366 :     size_on_disk = block_count * 4 + 8;
      94        2366 : }
      95             : 
      96             : /************************************************************************/
      97             : /*                           SerializedSize()                           */
      98             : /************************************************************************/
      99             : 
     100        3629 : uint32 VecSegDataIndex::SerializedSize()
     101             : 
     102             : {
     103        3629 :     return 8 + 4 * block_count;
     104             : }
     105             : 
     106             : /************************************************************************/
     107             : /*                           GetBlockIndex()                            */
     108             : /************************************************************************/
     109             : 
     110         508 : const std::vector<uint32> *VecSegDataIndex::GetIndex()
     111             : 
     112             : {
     113             : /* -------------------------------------------------------------------- */
     114             : /*      Load block map if needed.                                       */
     115             : /* -------------------------------------------------------------------- */
     116         508 :     if( !block_initialized )
     117             :     {
     118          94 :         bool needs_swap = !BigEndianSystem();
     119             : 
     120             :         try
     121             :         {
     122          94 :             block_index.resize( block_count );
     123             :         }
     124           0 :         catch( const std::exception& ex )
     125             :         {
     126             :             throw PCIDSKException("Out of memory allocating block_index(%u): %s",
     127           0 :                                   block_count, ex.what());
     128             :         }
     129          94 :         if( block_count > 0 )
     130             :         {
     131          14 :             vs->ReadFromFile( &(block_index[0]),
     132          14 :                               offset_on_disk_within_section
     133          14 :                               + vs->vh.section_offsets[hsec_shape] + 8,
     134          14 :                               4 * block_count );
     135             : 
     136          14 :             if( needs_swap )
     137          14 :                 SwapData( &(block_index[0]), 4, block_count );
     138             :         }
     139             : 
     140          94 :         block_initialized = true;
     141             :     }
     142             : 
     143         508 :     return &block_index;
     144             : }
     145             : 
     146             : /************************************************************************/
     147             : /*                               Flush()                                */
     148             : /************************************************************************/
     149             : 
     150        6742 : void VecSegDataIndex::Flush()
     151             : 
     152             : {
     153        6742 :     if( !dirty )
     154        6662 :         return;
     155             : 
     156          80 :     GetIndex(); // force loading if not already loaded!
     157             : 
     158          80 :     PCIDSKBuffer wbuf( SerializedSize() );
     159             : 
     160          80 :     memcpy( wbuf.buffer + 0, &block_count, 4 );
     161          80 :     memcpy( wbuf.buffer + 4, &bytes, 4 );
     162          80 :     memcpy( wbuf.buffer + 8, &(block_index[0]), 4*block_count );
     163             : 
     164          80 :     bool needs_swap = !BigEndianSystem();
     165             : 
     166          80 :     if( needs_swap )
     167          80 :         SwapData( wbuf.buffer, 4, block_count+2 );
     168             : 
     169             :     // Make sure this section of the header is large enough.
     170          80 :     int32 shift = (int32) wbuf.buffer_size - (int32) size_on_disk;
     171             : 
     172          80 :     if( shift != 0 )
     173             :     {
     174          80 :         uint32 old_section_size = vs->vh.section_sizes[hsec_shape];
     175             : 
     176             : //        fprintf( stderr, "Shifting section %d by %d bytes.\n",
     177             : //                 section, shift );
     178             : 
     179          80 :         vs->vh.GrowSection( hsec_shape, old_section_size + shift );
     180             : 
     181          80 :         if( section == sec_vert )
     182             :         {
     183             :             // move record block index and shape index.
     184          45 :             vs->MoveData( vs->vh.section_offsets[hsec_shape]
     185          45 :                           + vs->di[sec_vert].size_on_disk,
     186          45 :                           vs->vh.section_offsets[hsec_shape]
     187          45 :                           + vs->di[sec_vert].size_on_disk + shift,
     188          45 :                           old_section_size - size_on_disk );
     189             :         }
     190             :         else
     191             :         {
     192             :             // only move shape index.
     193          35 :             vs->MoveData( vs->vh.section_offsets[hsec_shape]
     194          35 :                           + vs->di[sec_vert].size_on_disk
     195          35 :                           + vs->di[sec_record].size_on_disk,
     196          35 :                           vs->vh.section_offsets[hsec_shape]
     197          35 :                           + vs->di[sec_vert].size_on_disk
     198          35 :                           + vs->di[sec_record].size_on_disk
     199          35 :                           + shift,
     200             :                           old_section_size
     201          35 :                           - vs->di[sec_vert].size_on_disk
     202          35 :                           - vs->di[sec_record].size_on_disk );
     203             :         }
     204             : 
     205          80 :         if( section == sec_vert )
     206          45 :             vs->di[sec_record].offset_on_disk_within_section += shift;
     207             :     }
     208             : 
     209             :     // Actually write to disk.
     210          80 :     vs->WriteToFile( wbuf.buffer,
     211          80 :                      offset_on_disk_within_section
     212          80 :                      + vs->vh.section_offsets[hsec_shape],
     213          80 :                      wbuf.buffer_size );
     214             : 
     215          80 :     size_on_disk = wbuf.buffer_size;
     216          80 :     dirty = false;
     217             : }
     218             : 
     219             : /************************************************************************/
     220             : /*                           GetSectionEnd()                            */
     221             : /************************************************************************/
     222             : 
     223         783 : uint32 VecSegDataIndex::GetSectionEnd()
     224             : 
     225             : {
     226         783 :     return bytes;
     227             : }
     228             : 
     229             : /************************************************************************/
     230             : /*                           SetSectionEnd()                            */
     231             : /************************************************************************/
     232             : 
     233         182 : void VecSegDataIndex::SetSectionEnd( uint32 new_end )
     234             : 
     235             : {
     236             :     // should we keep track of the need to write this back to disk?
     237         182 :     bytes = new_end;
     238         182 : }
     239             : 
     240             : /************************************************************************/
     241             : /*                          AddBlockToIndex()                           */
     242             : /************************************************************************/
     243             : 
     244          80 : void VecSegDataIndex::AddBlockToIndex( uint32 block )
     245             : 
     246             : {
     247          80 :     GetIndex(); // force loading.
     248             : 
     249          80 :     block_index.push_back( block );
     250          80 :     block_count++;
     251          80 :     dirty = true;
     252          80 : }
     253             : 
     254             : /************************************************************************/
     255             : /*                              SetDirty()                              */
     256             : /*                                                                      */
     257             : /*      This method is primarily used to mark the need to write the     */
     258             : /*      index when the location changes.                                */
     259             : /************************************************************************/
     260             : 
     261           0 : void VecSegDataIndex::SetDirty()
     262             : 
     263             : {
     264           0 :     dirty = true;
     265           0 : }
     266             : 
     267             : /************************************************************************/
     268             : /*                          VacateBlockRange()                          */
     269             : /*                                                                      */
     270             : /*      Move any blocks in the indicated block range to the end of      */
     271             : /*      the segment to make space for a growing header.                 */
     272             : /************************************************************************/
     273             : 
     274           0 : void VecSegDataIndex::VacateBlockRange( uint32 start, uint32 count )
     275             : 
     276             : {
     277           0 :     GetIndex(); // make sure loaded.
     278             : 
     279             :     unsigned int i;
     280           0 :     uint32  next_block = (uint32) (vs->GetContentSize() / block_page_size);
     281             : 
     282           0 :     for( i = 0; i < block_count; i++ )
     283             :     {
     284           0 :         if( block_index[i] >= start && block_index[i] < start+count )
     285             :         {
     286           0 :             vs->MoveData( block_index[i] * block_page_size,
     287           0 :                           next_block * block_page_size,
     288             :                           block_page_size );
     289           0 :             block_index[i] = next_block;
     290           0 :             dirty = true;
     291           0 :             next_block++;
     292             :         }
     293             :     }
     294           0 : }

Generated by: LCOV version 1.14