LCOV - code coverage report
Current view: directory - frmts/pcidsk/sdk/segment - sysblockmap.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 148 36 24.3 %
Date: 2010-01-09 Functions: 14 6 42.9 %

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Purpose:  Implementation of the SysBlockMap class.
       4                 :  *
       5                 :  * This class is used to manage access to the SYS virtual block map segment
       6                 :  * (named SysBMDir).  This segment is used to keep track of one or more 
       7                 :  * virtual files stored in SysBData segments.  These virtual files are normally
       8                 :  * used to hold tiled images for primary bands or overviews.  
       9                 :  *
      10                 :  * This class is closely partnered with the SysVirtualFile class, and the
      11                 :  * primary client is the CTiledChannel class. 
      12                 :  * 
      13                 :  ******************************************************************************
      14                 :  * Copyright (c) 2009
      15                 :  * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
      16                 :  *
      17                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      18                 :  * copy of this software and associated documentation files (the "Software"),
      19                 :  * to deal in the Software without restriction, including without limitation
      20                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      21                 :  * and/or sell copies of the Software, and to permit persons to whom the
      22                 :  * Software is furnished to do so, subject to the following conditions:
      23                 :  *
      24                 :  * The above copyright notice and this permission notice shall be included
      25                 :  * in all copies or substantial portions of the Software.
      26                 :  *
      27                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      28                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      29                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      30                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      31                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      32                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      33                 :  * DEALINGS IN THE SOFTWARE.
      34                 :  ****************************************************************************/
      35                 : 
      36                 : #include "pcidsk_exception.h"
      37                 : #include "pcidsk_file.h"
      38                 : #include "core/sysvirtualfile.h"
      39                 : #include "segment/sysblockmap.h"
      40                 : #include "core/cpcidskfile.h"
      41                 : 
      42                 : #include <cassert>
      43                 : #include <vector>
      44                 : #include <cstring>
      45                 : 
      46                 : using namespace PCIDSK;
      47                 : 
      48                 : /************************************************************************/
      49                 : /*                            SysBlockMap()                             */
      50                 : /************************************************************************/
      51                 : 
      52               3 : SysBlockMap::SysBlockMap( PCIDSKFile *file, int segment,
      53                 :                               const char *segment_pointer )
      54               3 :         : CPCIDSKSegment( file, segment, segment_pointer )
      55                 : 
      56                 : {
      57               3 :     loaded = false;
      58               3 :     dirty = false;
      59               3 :     growing_segment = 0;
      60               3 : }
      61                 : 
      62                 : /************************************************************************/
      63                 : /*                            ~SysBlockMap()                            */
      64                 : /************************************************************************/
      65                 : 
      66               6 : SysBlockMap::~SysBlockMap()
      67                 : 
      68                 : {
      69                 :     size_t i;
      70                 :     
      71               6 :     for( i = 0; i < virtual_files.size(); i++ )
      72                 :     {
      73               3 :         delete virtual_files[i];
      74               3 :         virtual_files[i] = NULL;
      75                 :     }
      76                 : 
      77               3 :     Sync();
      78               6 : }
      79                 : 
      80                 : /************************************************************************/
      81                 : /*                             Initialize()                             */
      82                 : /*                                                                      */
      83                 : /*      This method is used after creation of the SysBMDir segment      */
      84                 : /*      to fill in valid contents.  Prepares bare minimum contents.     */
      85                 : /************************************************************************/
      86                 : 
      87               0 : void SysBlockMap::Initialize()
      88                 : 
      89                 : {
      90               0 :     PCIDSKBuffer init_data(512);
      91                 : 
      92               0 :     init_data.Put( "VERSION  1", 0, 10 );
      93               0 :     init_data.Put( 0, 10, 8 );
      94               0 :     init_data.Put( 0, 18, 8 );
      95               0 :     init_data.Put( -1, 26, 8 );
      96               0 :     init_data.Put( "", 34, 512-34 );
      97                 : 
      98               0 :     WriteToFile( init_data.buffer, 0, init_data.buffer_size );
      99                 : #ifdef notdef
     100                 :     // arbitrarily grow the segment a bit to avoid having to move it too soon.
     101                 :     WriteToFile( "\0", 8191, 1 );              
     102                 : #endif
     103               0 : }
     104                 : 
     105                 : /************************************************************************/
     106                 : /*                                Load()                                */
     107                 : /************************************************************************/
     108                 : 
     109               3 : void SysBlockMap::Load()
     110                 : 
     111                 : {
     112               3 :     if( loaded )
     113               0 :         return;
     114                 : 
     115                 :     // TODO: this should likely be protected by a mutex. 
     116                 : 
     117                 : /* -------------------------------------------------------------------- */
     118                 : /*      Load the segment contents into a buffer.                        */
     119                 : /* -------------------------------------------------------------------- */
     120               3 :     seg_data.SetSize( (int) (data_size - 1024) );
     121                 : 
     122               3 :     ReadFromFile( seg_data.buffer, 0, data_size - 1024 );
     123                 : 
     124               3 :     if( strncmp(seg_data.buffer,"VERSION",7) != 0 )
     125               0 :         ThrowPCIDSKException( "SysBlockMap::Load() - block map corrupt." );
     126                 : 
     127               3 :     if( seg_data.GetInt( 7, 3 ) != 1 )
     128               0 :         ThrowPCIDSKException( "SysBlockMap::Load() - unsupported version." );
     129                 : 
     130                 : /* -------------------------------------------------------------------- */
     131                 : /*      Establish our SysVirtualFile array based on the number of       */
     132                 : /*      images listed in the image list.                                */
     133                 : /* -------------------------------------------------------------------- */
     134               3 :     int layer_count = seg_data.GetInt( 10, 8 );
     135                 : 
     136               3 :     block_count = seg_data.GetInt( 18, 8 );
     137               3 :     first_free_block = seg_data.GetInt( 26, 8 );
     138                 : 
     139               3 :     virtual_files.resize( layer_count );
     140                 : 
     141               3 :     block_map_offset = 512;
     142               3 :     layer_list_offset = block_map_offset + 28 * block_count;
     143                 : 
     144               3 :     loaded = true;
     145                 : }
     146                 : 
     147                 : /************************************************************************/
     148                 : /*                                Sync()                                */
     149                 : /************************************************************************/
     150                 : 
     151               3 : void SysBlockMap::Sync()
     152                 : 
     153                 : {
     154               3 :     if( !loaded || !dirty )
     155               3 :         return;
     156                 : 
     157               0 :     WriteToFile( seg_data.buffer, 0, seg_data.buffer_size );
     158                 : 
     159               0 :     dirty = false;
     160                 : }
     161                 : 
     162                 : /************************************************************************/
     163                 : /*                           AllocateBlocks()                           */
     164                 : /*                                                                      */
     165                 : /*      Allocate a bunch of new blocks and attach to the free list.     */
     166                 : /************************************************************************/
     167                 : 
     168               0 : void SysBlockMap::AllocateBlocks()
     169                 : 
     170                 : {
     171                 : /* -------------------------------------------------------------------- */
     172                 : /*      Find a segment we can extend.  We consider any SYS segments     */
     173                 : /*      with a name of SysBData.                                        */
     174                 : /* -------------------------------------------------------------------- */
     175                 :     PCIDSKSegment *seg;
     176                 : 
     177               0 :     if( growing_segment > 0 )
     178                 :     {
     179               0 :         seg = file->GetSegment( growing_segment );
     180               0 :         if( !seg->IsAtEOF() )
     181               0 :             growing_segment = 0;
     182                 :     }
     183                 : 
     184               0 :     if( growing_segment == 0 )
     185                 :     {
     186                 :         PCIDSKSegment *seg;
     187               0 :         int  previous = 0;
     188                 : 
     189               0 :         while( (seg=file->GetSegment( SEG_SYS, "SysBData", previous )) != NULL )
     190                 :         {
     191               0 :             previous = seg->GetSegmentNumber();
     192                 :             
     193               0 :             if( seg->IsAtEOF() )
     194                 :             {
     195               0 :                 growing_segment = previous;
     196               0 :                 break;
     197                 :             }
     198                 :         }
     199                 :     }
     200                 : 
     201                 : /* -------------------------------------------------------------------- */
     202                 : /*      If we didn't find one, then create a new segment.               */
     203                 : /* -------------------------------------------------------------------- */
     204               0 :     if( growing_segment == 0 )
     205                 :     {
     206                 :         growing_segment = 
     207                 :             file->CreateSegment( "SysBData", 
     208                 :                                  "System Block Data for Tiles and Overviews "
     209                 :                                  "- Do not modify",
     210               0 :                                  SEG_SYS, 0L );
     211                 :     }
     212                 : 
     213                 : /* -------------------------------------------------------------------- */
     214                 : /*      Allocate another set of space.                                  */
     215                 : /* -------------------------------------------------------------------- */
     216               0 :     uint64 new_big_blocks = 16;
     217               0 :     int new_bytes = new_big_blocks * SysVirtualFile::block_size;
     218               0 :     seg = file->GetSegment( growing_segment );
     219                 :     int block_index_in_segment = 
     220               0 :         seg->GetContentSize() / SysVirtualFile::block_size;
     221                 : 
     222               0 :     seg->WriteToFile( "\0", seg->GetContentSize() + new_bytes - 1, 1 );
     223                 :     
     224                 : /* -------------------------------------------------------------------- */
     225                 : /*      Resize the SysBMDir segment data, growing the block map area.    */
     226                 : /* -------------------------------------------------------------------- */
     227               0 :     if( block_map_offset + 28 * (block_count + new_big_blocks) 
     228                 :         + virtual_files.size() * 24 > (unsigned int) seg_data.buffer_size )
     229                 :         seg_data.SetSize( 
     230                 :             block_map_offset + 28 * (block_count + new_big_blocks) 
     231               0 :             + virtual_files.size() * 24 );
     232                 : 
     233                 :     // push the layer list on.
     234                 :     memmove( seg_data.buffer + layer_list_offset + new_big_blocks*28, 
     235                 :              seg_data.buffer + layer_list_offset, 
     236               0 :              virtual_files.size() * 24 );
     237                 : 
     238                 : /* -------------------------------------------------------------------- */
     239                 : /*      Fill in info on the new blocks.                                 */
     240                 : /* -------------------------------------------------------------------- */
     241                 :     uint64 block_index;
     242                 : 
     243               0 :     for( block_index = block_count; 
     244                 :          block_index < block_count + new_big_blocks;
     245                 :          block_index++ )
     246                 :     {
     247               0 :         uint64 bi_offset = block_map_offset + block_index * 28;
     248                 : 
     249               0 :         seg_data.Put( growing_segment, bi_offset, 4 );
     250               0 :         seg_data.Put( block_index_in_segment++, bi_offset+4, 8 );
     251               0 :         seg_data.Put( -1, bi_offset+12, 8 );
     252                 : 
     253               0 :         if( block_index == block_count + new_big_blocks - 1 )
     254               0 :             seg_data.Put( -1, bi_offset+20, 8 );
     255                 :         else
     256               0 :             seg_data.Put( block_index+1, bi_offset+20, 8 );
     257                 :     }
     258                 : 
     259               0 :     first_free_block = block_count;
     260               0 :     seg_data.Put( first_free_block, 26, 8 );
     261                 : 
     262               0 :     block_count += new_big_blocks;
     263               0 :     seg_data.Put( block_count, 18, 8 );
     264                 : 
     265               0 :     layer_list_offset = block_map_offset + 28 * block_count;
     266                 : 
     267               0 :     dirty = true;
     268               0 : }
     269                 : 
     270                 : /************************************************************************/
     271                 : /*                          GrowVirtualFile()                           */
     272                 : /*                                                                      */
     273                 : /*      Get one more block for this virtual file.                       */
     274                 : /************************************************************************/
     275                 : 
     276               0 : int SysBlockMap::GrowVirtualFile( int image, int &last_block, 
     277                 :                                   int &block_segment_ret )
     278                 : 
     279                 : {
     280               0 :     Load();
     281                 : 
     282                 : /* -------------------------------------------------------------------- */
     283                 : /*      Do we need to create new free blocks?                           */
     284                 : /* -------------------------------------------------------------------- */
     285               0 :     if( first_free_block == -1 )
     286               0 :         AllocateBlocks();
     287                 : 
     288                 : /* -------------------------------------------------------------------- */
     289                 : /*      Return the first free block, and update the next pointer of     */
     290                 : /*      the previous block.                                             */
     291                 : /* -------------------------------------------------------------------- */
     292               0 :     int alloc_block = first_free_block;
     293                 : 
     294                 :     // update first free block to point to the next free block.
     295               0 :     first_free_block = seg_data.GetInt( block_map_offset+alloc_block*28+20, 8);
     296               0 :     seg_data.Put( first_free_block, 26, 8 );
     297                 : 
     298                 :     // mark block as owned by this layer/image. 
     299               0 :     seg_data.Put( image, block_map_offset + alloc_block*28 + 12, 8 );
     300                 : 
     301                 :     // clear next free block on allocated block - it is the last in the chain
     302               0 :     seg_data.Put( -1, block_map_offset + alloc_block*28 + 20, 8 );
     303                 : 
     304                 :     // point the previous "last block" for this virtual file to this new block
     305               0 :     if( last_block != -1 )
     306               0 :         seg_data.Put( alloc_block, block_map_offset + last_block*28 + 20, 8 );
     307                 :     else
     308               0 :         seg_data.Put( alloc_block, layer_list_offset + image*24 + 4, 8 );
     309                 : 
     310               0 :     dirty = true;
     311                 : 
     312               0 :     block_segment_ret = seg_data.GetInt( block_map_offset+alloc_block*28, 4 );
     313               0 :     last_block = alloc_block;
     314                 : 
     315               0 :     return seg_data.GetInt( block_map_offset+alloc_block*28+4, 8 );
     316                 : }
     317                 : 
     318                 : /************************************************************************/
     319                 : /*                         SetVirtualFileSize()                         */
     320                 : /************************************************************************/
     321                 : 
     322               0 : void SysBlockMap::SetVirtualFileSize( int image_index, uint64 file_length )
     323                 : 
     324                 : {
     325               0 :     seg_data.Put( file_length, layer_list_offset + 24*image_index + 12, 12 );
     326               0 :     dirty = true;
     327               0 : }
     328                 : 
     329                 : /************************************************************************/
     330                 : /*                           GetVirtualFile()                           */
     331                 : /************************************************************************/
     332                 : 
     333               3 : SysVirtualFile *SysBlockMap::GetVirtualFile( int image )
     334                 : 
     335                 : {
     336               3 :     Load();
     337                 : 
     338               3 :     if( image < 0 || image >= (int) virtual_files.size() )
     339                 :         ThrowPCIDSKException( "GetImageSysFile(%d): invalid image index",
     340               0 :                                    image );
     341                 : 
     342               3 :     if( virtual_files[image] != NULL )
     343               0 :         return virtual_files[image];
     344                 : 
     345                 :     uint64  vfile_length = 
     346               3 :         seg_data.GetUInt64( layer_list_offset + 24*image + 12, 12 );
     347                 :     int  start_block = 
     348               3 :         seg_data.GetInt( layer_list_offset + 24*image + 4, 8 );
     349                 : 
     350                 :     virtual_files[image] = 
     351                 :         new SysVirtualFile( dynamic_cast<CPCIDSKFile *>(file), start_block, vfile_length, seg_data,
     352               3 :                             this, image );
     353                 : 
     354               3 :     return virtual_files[image];
     355                 : }
     356                 : 
     357                 : /************************************************************************/
     358                 : /*                         CreateVirtualFile()                          */
     359                 : /************************************************************************/
     360                 : 
     361               0 : int SysBlockMap::CreateVirtualFile()
     362                 : 
     363                 : {
     364               0 :     Load();
     365                 : 
     366                 : /* -------------------------------------------------------------------- */
     367                 : /*      Is there an existing dead layer we can reuse?                   */
     368                 : /* -------------------------------------------------------------------- */
     369                 :     unsigned int layer_index;
     370                 : 
     371               0 :     for( layer_index = 0; layer_index < virtual_files.size(); layer_index++ )
     372                 :     {
     373               0 :         if( seg_data.GetInt( layer_list_offset + 24*layer_index + 0, 4 )
     374                 :             == 1 /* dead */ )
     375                 :         {
     376               0 :             break;
     377                 :         }
     378                 :     }
     379                 : 
     380                 : /* -------------------------------------------------------------------- */
     381                 : /*      If not, extend the layer table.                                 */
     382                 : /* -------------------------------------------------------------------- */
     383               0 :     if( layer_index == virtual_files.size() )
     384                 :     {
     385               0 :         seg_data.Put( (int) layer_index+1, 10, 8 );
     386                 :         
     387               0 :         if( layer_list_offset + (virtual_files.size()+1) * 24 
     388                 :             > (unsigned int) seg_data.buffer_size )
     389               0 :             seg_data.SetSize( layer_list_offset + (virtual_files.size()+1) * 24  );
     390                 : 
     391               0 :         virtual_files.resize(layer_index+1);
     392               0 :         virtual_files[layer_index] = NULL;
     393                 :     }
     394                 : 
     395                 : /* -------------------------------------------------------------------- */
     396                 : /*      Set all the entries for this layer.                             */
     397                 : /* -------------------------------------------------------------------- */
     398               0 :     dirty = true;
     399                 : 
     400               0 :     seg_data.Put( 2, layer_list_offset + 24*layer_index + 0, 4 );
     401               0 :     seg_data.Put( -1, layer_list_offset + 24*layer_index + 4, 8 );
     402               0 :     seg_data.Put( 0, layer_list_offset + 24*layer_index + 12, 12 );
     403                 : 
     404               0 :     return layer_index;
     405                 : }
     406                 : 
     407                 : /************************************************************************/
     408                 : /*                       CreateVirtualImageFile()                       */
     409                 : /************************************************************************/
     410                 : 
     411               0 : int SysBlockMap::CreateVirtualImageFile( int width, int height, 
     412                 :                                          int block_width, int block_height,
     413                 :                                          eChanType chan_type,
     414                 :                                          std::string compression )
     415                 : 
     416                 : {
     417               0 :     if( compression == "" )
     418               0 :         compression = "NONE";
     419                 : 
     420                 : /* -------------------------------------------------------------------- */
     421                 : /*      Create the underlying virtual file.                             */
     422                 : /* -------------------------------------------------------------------- */
     423               0 :     int img_index = CreateVirtualFile();
     424               0 :     SysVirtualFile *vfile = GetVirtualFile( img_index );
     425                 : 
     426                 : /* -------------------------------------------------------------------- */
     427                 : /*      Set up the image header.                                        */
     428                 : /* -------------------------------------------------------------------- */
     429               0 :     PCIDSKBuffer theader(128);
     430                 : 
     431               0 :     theader.Put( "", 0, 128 );
     432                 : 
     433               0 :     theader.Put( width, 0, 8 );
     434               0 :     theader.Put( height, 8, 8 );
     435               0 :     theader.Put( block_width, 16, 8 );
     436               0 :     theader.Put( block_height, 24, 8 );
     437               0 :     theader.Put( DataTypeName(chan_type).c_str(), 32, 4 );
     438               0 :     theader.Put( compression.c_str(), 54, 8 );
     439                 : 
     440               0 :     vfile->WriteToFile( theader.buffer, 0, 128 );
     441                 : 
     442                 : /* -------------------------------------------------------------------- */
     443                 : /*      Setup the tile map - initially with no tiles referenced.        */
     444                 : /* -------------------------------------------------------------------- */
     445               0 :     int tiles_per_row = (width + block_width - 1) / block_width;
     446               0 :     int tiles_per_col = (height + block_height - 1) / block_height;
     447               0 :     int tile_count = tiles_per_row * tiles_per_col;
     448                 :     int i;
     449                 : 
     450               0 :     PCIDSKBuffer tmap( tile_count * 20 );
     451                 : 
     452               0 :     for( i = 0; i < tile_count; i++ )
     453                 :     {
     454               0 :         tmap.Put( -1, i*12, 12 );
     455               0 :         tmap.Put( 0, tile_count*12 + i*8, 8 );
     456                 :     }
     457                 : 
     458               0 :     vfile->WriteToFile( tmap.buffer, 128, tile_count*20 );
     459                 : 
     460               0 :     return img_index;
     461                 : }

Generated by: LCOV version 1.7