LCOV - code coverage report
Current view: directory - frmts/pcidsk/sdk/segment - vecsegheader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 176 157 89.2 %
Date: 2012-04-28 Functions: 11 8 72.7 %

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

Generated by: LCOV version 1.7