LCOV - code coverage report
Current view: directory - frmts/pcidsk/sdk/segment - cpcidsksegment.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 115 84 73.0 %
Date: 2012-04-28 Functions: 23 17 73.9 %

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Purpose:  Implementation of the CPCIDSKSegment class.
       4                 :  * 
       5                 :  ******************************************************************************
       6                 :  * Copyright (c) 2009
       7                 :  * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
       8                 :  *
       9                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      10                 :  * copy of this software and associated documentation files (the "Software"),
      11                 :  * to deal in the Software without restriction, including without limitation
      12                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      13                 :  * and/or sell copies of the Software, and to permit persons to whom the
      14                 :  * Software is furnished to do so, subject to the following conditions:
      15                 :  *
      16                 :  * The above copyright notice and this permission notice shall be included
      17                 :  * in all copies or substantial portions of the Software.
      18                 :  *
      19                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      20                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      22                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      24                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      25                 :  * DEALINGS IN THE SOFTWARE.
      26                 :  ****************************************************************************/
      27                 : 
      28                 : #include "segment/cpcidsksegment.h"
      29                 : #include "core/metadataset.h"
      30                 : #include "core/cpcidskfile.h"
      31                 : #include "core/pcidsk_utils.h"
      32                 : #include "pcidsk_buffer.h"
      33                 : #include "pcidsk_exception.h"
      34                 : #include <cassert>
      35                 : #include <cstdlib>
      36                 : #include <cstring>
      37                 : #include <vector>
      38                 : #include <string>
      39                 : 
      40                 : using namespace PCIDSK;
      41                 : 
      42                 : /************************************************************************/
      43                 : /*                           PCIDSKSegment()                            */
      44                 : /************************************************************************/
      45                 : 
      46             326 : CPCIDSKSegment::CPCIDSKSegment( PCIDSKFile *file, int segment,
      47             326 :                               const char *segment_pointer )
      48                 : 
      49                 : {
      50             326 :     this->file = file;
      51             326 :     this->segment = segment;
      52                 : 
      53             326 :     LoadSegmentPointer( segment_pointer );
      54             326 :     LoadSegmentHeader(); // eventually we might want to defer this.
      55                 : 
      56                 : /* -------------------------------------------------------------------- */
      57                 : /*      Initialize the metadata object, but do not try to load till     */
      58                 : /*      needed.                                                         */
      59                 : /* -------------------------------------------------------------------- */
      60             326 :     metadata = new MetadataSet;
      61             652 :     metadata->Initialize( file, SegmentTypeName(segment_type), segment );
      62             326 : }
      63                 : 
      64                 : /************************************************************************/
      65                 : /*                           ~PCIDSKSegment()                           */
      66                 : /************************************************************************/
      67                 : 
      68             326 : CPCIDSKSegment::~CPCIDSKSegment()
      69                 : 
      70                 : {
      71             326 :     delete metadata;
      72             326 : }
      73                 : 
      74                 : /************************************************************************/
      75                 : /*                          GetMetadataValue()                          */
      76                 : /************************************************************************/
      77              54 : std::string CPCIDSKSegment::GetMetadataValue( const std::string &key ) const
      78                 : {
      79              54 :     return metadata->GetMetadataValue(key);
      80                 : }
      81                 : 
      82                 : /************************************************************************/
      83                 : /*                          SetMetadataValue()                          */
      84                 : /************************************************************************/
      85              12 : void CPCIDSKSegment::SetMetadataValue( const std::string &key, const std::string &value ) 
      86                 : {
      87              12 :     metadata->SetMetadataValue(key,value);
      88              12 : }
      89                 : 
      90                 : /************************************************************************/
      91                 : /*                           GetMetdataKeys()                           */
      92                 : /************************************************************************/
      93               2 : std::vector<std::string> CPCIDSKSegment::GetMetadataKeys() const
      94                 : {
      95               2 :     return metadata->GetMetadataKeys();
      96                 : }
      97                 : 
      98                 : /************************************************************************/
      99                 : /*                         LoadSegmentPointer()                         */
     100                 : /************************************************************************/
     101                 : 
     102             340 : void CPCIDSKSegment::LoadSegmentPointer( const char *segment_pointer )
     103                 : 
     104                 : {
     105             340 :     PCIDSKBuffer segptr( segment_pointer, 32 );
     106                 : 
     107             340 :     segment_flag = segptr.buffer[0];
     108             340 :     segment_type = (eSegType) (atoi(segptr.Get(1,3)));
     109             340 :     data_offset = (atouint64(segptr.Get(12,11))-1) * 512;
     110             340 :     data_size = atouint64(segptr.Get(23,9)) * 512;
     111                 : 
     112             340 :     segptr.Get(4,8,segment_name);
     113             340 : }
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                         LoadSegmentHeader()                          */
     117                 : /************************************************************************/
     118                 : #include <iostream>
     119             326 : void CPCIDSKSegment::LoadSegmentHeader()
     120                 : 
     121                 : {
     122             326 :     header.SetSize(1024);
     123                 : 
     124             326 :     file->ReadFromFile( header.buffer, data_offset, 1024 );
     125                 :     
     126                 :     // Read the history from the segment header. PCIDSK supports
     127                 :     // 8 history entries per segment.
     128             326 :     std::string hist_msg;
     129             326 :     history_.clear();
     130            2934 :     for (unsigned int i = 0; i < 8; i++)
     131                 :     {
     132            2608 :         header.Get(384 + i * 80, 80, hist_msg);
     133                 : 
     134                 :         // Some programs seem to push history records with a trailing '\0'
     135                 :         // so do some extra processing to cleanup.  FUN records on segment
     136                 :         // 3 of eltoro.pix are an example of this.
     137            2608 :         size_t size = hist_msg.size();
     138            5342 :         while( size > 0 
     139                 :                && (hist_msg[size-1] == ' ' || hist_msg[size-1] == '\0') )
     140             126 :             size--;
     141                 : 
     142            2608 :         hist_msg.resize(size);
     143                 :         
     144            2608 :         history_.push_back(hist_msg);
     145             326 :     }
     146             326 : }
     147                 : 
     148                 : /************************************************************************/
     149                 : /*                            FlushHeader()                             */
     150                 : /*                                                                      */
     151                 : /*      This is used primarily after this class or subclasses have      */
     152                 : /*      modified the header buffer and need it pushed back to disk.     */
     153                 : /************************************************************************/
     154                 : 
     155              30 : void CPCIDSKSegment::FlushHeader()
     156                 : 
     157                 : {
     158              30 :     file->WriteToFile( header.buffer, data_offset, 1024 );
     159              30 : }
     160                 : 
     161                 : /************************************************************************/
     162                 : /*                            ReadFromFile()                            */
     163                 : /************************************************************************/
     164                 : 
     165            2488 : void CPCIDSKSegment::ReadFromFile( void *buffer, uint64 offset, uint64 size )
     166                 : 
     167                 : {
     168            2488 :     if( offset+size+1024 > data_size )
     169                 :         ThrowPCIDSKException( 
     170                 :             "Attempt to read past end of segment %d (%d bytes at offset %d)",
     171               0 :             segment, (int) offset, (int) size );
     172            2488 :     file->ReadFromFile( buffer, offset + data_offset + 1024, size );
     173            2488 : }
     174                 : 
     175                 : /************************************************************************/
     176                 : /*                            WriteToFile()                             */
     177                 : /************************************************************************/
     178                 : 
     179             640 : void CPCIDSKSegment::WriteToFile( const void *buffer, uint64 offset, uint64 size )
     180                 : {
     181             640 :     if( offset+size > data_size-1024 )
     182                 :     {
     183              84 :         CPCIDSKFile *poFile = dynamic_cast<CPCIDSKFile *>(file);
     184                 :         
     185              84 :         if (poFile == NULL) {
     186                 :             ThrowPCIDSKException("Attempt to dynamic_cast the file interface "
     187                 :                 "to a CPCIDSKFile failed. This is a programmer error, and should "
     188               0 :                 "be reported to your software provider.");
     189                 :         }
     190                 :         
     191              84 :         if( !IsAtEOF() )
     192              14 :             poFile->MoveSegmentToEOF( segment );
     193                 : 
     194                 :         uint64 blocks_to_add = 
     195              84 :             ((offset+size+511) - (data_size - 1024)) / 512;
     196                 : 
     197                 :         // prezero if we aren't directly writing all the new blocks.
     198                 :         poFile->ExtendSegment( segment, blocks_to_add, 
     199                 :                              !(offset == data_size - 1024
     200              84 :                                && size == blocks_to_add * 512) );
     201              84 :         data_size += blocks_to_add * 512;
     202                 :     }
     203                 : 
     204             640 :     file->WriteToFile( buffer, offset + data_offset + 1024, size );
     205             640 : }
     206                 : 
     207                 : /************************************************************************/
     208                 : /*                           GetDescription()                           */
     209                 : /************************************************************************/
     210                 : 
     211              32 : std::string CPCIDSKSegment::GetDescription()
     212                 : {
     213              32 :     std::string target;
     214                 : 
     215              32 :     header.Get( 0, 64, target );
     216                 : 
     217               0 :     return target;
     218                 : }
     219                 : 
     220                 : /************************************************************************/
     221                 : /*                           SetDescription()                           */
     222                 : /************************************************************************/
     223                 : 
     224               0 : void CPCIDSKSegment::SetDescription( const std::string &description )
     225                 : {
     226               0 :     header.Put( description.c_str(), 0, 64);
     227                 : 
     228               0 :     file->WriteToFile( header.buffer, data_offset, 1024 );
     229               0 : }
     230                 : 
     231                 : /************************************************************************/
     232                 : /*                              IsAtEOF()                               */
     233                 : /************************************************************************/
     234                 : 
     235              84 : bool CPCIDSKSegment::IsAtEOF()
     236                 : {
     237              84 :     if( 512 * file->GetFileSize() == data_offset + data_size )
     238              70 :         return true;
     239                 :     else
     240              14 :         return false;
     241                 : }
     242                 : 
     243                 : /************************************************************************/
     244                 : /*                         GetHistoryEntries()                          */
     245                 : /************************************************************************/
     246                 : 
     247               0 : std::vector<std::string> CPCIDSKSegment::GetHistoryEntries() const
     248                 : {
     249               0 :     return history_;
     250                 : }
     251                 : 
     252                 : /************************************************************************/
     253                 : /*                         SetHistoryEntries()                          */
     254                 : /************************************************************************/
     255                 : 
     256               0 : void CPCIDSKSegment::SetHistoryEntries(const std::vector<std::string> &entries)
     257                 : 
     258                 : {
     259               0 :     for( unsigned int i = 0; i < 8; i++ )
     260                 :     {
     261               0 :         const char *msg = "";
     262               0 :         if( entries.size() > i )
     263               0 :             msg = entries[i].c_str();
     264                 : 
     265               0 :         header.Put( msg, 384 + i * 80, 80 );
     266                 :     }
     267                 : 
     268               0 :     FlushHeader();
     269                 : 
     270                 :     // Force reloading of history_
     271               0 :     LoadSegmentHeader();
     272               0 : }
     273                 : 
     274                 : /************************************************************************/
     275                 : /*                            PushHistory()                             */
     276                 : /************************************************************************/
     277                 : 
     278               0 : void CPCIDSKSegment::PushHistory( const std::string &app,
     279                 :                                   const std::string &message )
     280                 : 
     281                 : {
     282                 : #define MY_MIN(a,b)      ((a<b) ? a : b)
     283                 : 
     284                 :     char current_time[17];
     285                 :     char history[81];
     286                 : 
     287               0 :     GetCurrentDateTime( current_time );
     288                 : 
     289               0 :     memset( history, ' ', 80 );
     290               0 :     history[80] = '\0';
     291                 : 
     292               0 :     memcpy( history + 0, app.c_str(), MY_MIN(app.size(),7) );
     293               0 :     history[7] = ':';
     294                 :     
     295               0 :     memcpy( history + 8, message.c_str(), MY_MIN(message.size(),56) );
     296               0 :     memcpy( history + 64, current_time, 16 );
     297                 : 
     298               0 :     std::vector<std::string> history_entries = GetHistoryEntries();
     299                 : 
     300               0 :     history_entries.insert( history_entries.begin(), history );
     301               0 :     history_entries.resize(8);
     302                 : 
     303               0 :     SetHistoryEntries( history_entries );
     304               0 : }
     305                 : 
     306                 : 
     307                 : /************************************************************************/
     308                 : /*                              MoveData()                              */
     309                 : /*                                                                      */
     310                 : /*      Move a chunk of data within a segment. Overlapping source       */
     311                 : /*      and destination are permitted.                                  */
     312                 : /************************************************************************/
     313                 : 
     314              26 : void CPCIDSKSegment::MoveData( uint64 src_offset, uint64 dst_offset, 
     315                 :                                uint64 size_in_bytes )
     316                 : 
     317                 : {
     318              26 :     bool copy_backwards = false;
     319                 : 
     320                 :     // We move things backwards if the areas overlap and the destination
     321                 :     // is further on in the segment. 
     322              26 :     if( dst_offset > src_offset
     323                 :         && src_offset + size_in_bytes > dst_offset )
     324              12 :         copy_backwards = true;
     325                 : 
     326                 :     
     327                 :     // Move the segment data to the new location.
     328                 :     uint8 copy_buf[16384];
     329                 :     uint64 bytes_to_go;
     330                 : 
     331              26 :     bytes_to_go = size_in_bytes;
     332                 : 
     333              78 :     while( bytes_to_go > 0 )
     334                 :     {
     335              26 :         uint64 bytes_this_chunk = sizeof(copy_buf);
     336              26 :         if( bytes_to_go < bytes_this_chunk )
     337              26 :             bytes_this_chunk = bytes_to_go;
     338                 : 
     339              26 :         if( copy_backwards )
     340                 :         {
     341                 :             ReadFromFile( copy_buf, 
     342                 :                           src_offset + bytes_to_go - bytes_this_chunk, 
     343              12 :                           bytes_this_chunk );
     344                 :             WriteToFile( copy_buf, 
     345                 :                          dst_offset + bytes_to_go - bytes_this_chunk, 
     346              12 :                          bytes_this_chunk );
     347                 :         }
     348                 :         else
     349                 :         {
     350              14 :             ReadFromFile( copy_buf, src_offset, bytes_this_chunk );
     351              14 :             WriteToFile( copy_buf, dst_offset, bytes_this_chunk );
     352                 : 
     353              14 :             src_offset += bytes_this_chunk;
     354              14 :             dst_offset += bytes_this_chunk;
     355                 :         }
     356                 : 
     357              26 :         bytes_to_go -= bytes_this_chunk;
     358                 :     }
     359            4055 : }

Generated by: LCOV version 1.7