LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/segment - cpcidsksegment.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 87 130 66.9 %
Date: 2024-11-21 22:18:42 Functions: 15 21 71.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Purpose:  Implementation of the CPCIDSKSegment class.
       4             :  *
       5             :  ******************************************************************************
       6             :  * Copyright (c) 2009
       7             :  * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #include "segment/cpcidsksegment.h"
      13             : #include "core/metadataset.h"
      14             : #include "core/cpcidskfile.h"
      15             : #include "core/pcidsk_utils.h"
      16             : #include "pcidsk_buffer.h"
      17             : #include "pcidsk_exception.h"
      18             : #include <cassert>
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : #include <limits>
      22             : #include <vector>
      23             : #include <string>
      24             : 
      25             : using namespace PCIDSK;
      26             : 
      27             : /************************************************************************/
      28             : /*                           PCIDSKSegment()                            */
      29             : /************************************************************************/
      30             : 
      31        1463 : CPCIDSKSegment::CPCIDSKSegment( PCIDSKFile *fileIn, int segmentIn,
      32        1463 :                               const char *segment_pointer )
      33             : 
      34             : {
      35        1463 :     this->file = fileIn;
      36        1463 :     this->segment = segmentIn;
      37             : 
      38        1463 :     LoadSegmentPointer( segment_pointer );
      39        1463 :     LoadSegmentHeader(); // eventually we might want to defer this.
      40             : 
      41             : /* -------------------------------------------------------------------- */
      42             : /*      Initialize the metadata object, but do not try to load till     */
      43             : /*      needed.                                                         */
      44             : /* -------------------------------------------------------------------- */
      45        1463 :     metadata = new MetadataSet;
      46        1463 :     metadata->Initialize( file, SegmentTypeName(segment_type), segment );
      47        1463 : }
      48             : 
      49             : /************************************************************************/
      50             : /*                           ~PCIDSKSegment()                           */
      51             : /************************************************************************/
      52             : 
      53        1491 : CPCIDSKSegment::~CPCIDSKSegment()
      54             : 
      55             : {
      56        1463 :     delete metadata;
      57        1491 : }
      58             : 
      59             : /************************************************************************/
      60             : /*                          GetMetadataValue()                          */
      61             : /************************************************************************/
      62        1183 : std::string CPCIDSKSegment::GetMetadataValue( const std::string &key ) const
      63             : {
      64        1183 :     return metadata->GetMetadataValue(key);
      65             : }
      66             : 
      67             : /************************************************************************/
      68             : /*                          SetMetadataValue()                          */
      69             : /************************************************************************/
      70          33 : void CPCIDSKSegment::SetMetadataValue( const std::string &key, const std::string &value )
      71             : {
      72          33 :     metadata->SetMetadataValue(key,value);
      73          33 : }
      74             : 
      75             : /************************************************************************/
      76             : /*                           GetMetadataKeys()                           */
      77             : /************************************************************************/
      78           1 : std::vector<std::string> CPCIDSKSegment::GetMetadataKeys() const
      79             : {
      80           1 :     return metadata->GetMetadataKeys();
      81             : }
      82             : 
      83             : /************************************************************************/
      84             : /*                         LoadSegmentPointer()                         */
      85             : /************************************************************************/
      86             : 
      87        2648 : void CPCIDSKSegment::LoadSegmentPointer( const char *segment_pointer )
      88             : 
      89             : {
      90        2648 :     PCIDSKBuffer segptr( segment_pointer, 32 );
      91             : 
      92        2648 :     segment_flag = segptr.buffer[0];
      93        2648 :     const int segment_type_int = atoi(segptr.Get(1,3));
      94        2648 :     segment_type = EQUAL(SegmentTypeName(segment_type_int), "UNKNOWN") ?
      95             :         SEG_UNKNOWN : static_cast<eSegType>(segment_type_int);
      96        2648 :     data_offset = atouint64(segptr.Get(12,11));
      97        2648 :     if( data_offset == 0 )
      98           0 :         data_offset = 0; // throw exception maybe ?
      99             :     else
     100             :     {
     101        2648 :         if( data_offset-1 > std::numeric_limits<uint64>::max() / 512 )
     102             :         {
     103           0 :             return ThrowPCIDSKException("too large data_offset");
     104             :         }
     105        2648 :         data_offset = (data_offset-1) * 512;
     106             :     }
     107        2648 :     data_size = atouint64(segptr.Get(23,9));
     108        2648 :     data_size_limit = 999999999ULL * 512;
     109             : 
     110        2648 :     if( data_size > 999999999ULL )
     111             :     {
     112           0 :         return ThrowPCIDSKException("too large data_size");
     113             :     }
     114        2648 :     data_size *= 512;
     115             : 
     116        2648 :     segptr.Get(4,8,segment_name);
     117             : }
     118             : 
     119             : /************************************************************************/
     120             : /*                         LoadSegmentHeader()                          */
     121             : /************************************************************************/
     122             : #include <iostream>
     123        1463 : void CPCIDSKSegment::LoadSegmentHeader()
     124             : 
     125             : {
     126        1463 :     header.SetSize(1024);
     127             : 
     128        1463 :     file->ReadFromFile( header.buffer, data_offset, 1024 );
     129             : 
     130             :     // Read the history from the segment header. PCIDSK supports
     131             :     // 8 history entries per segment.
     132        2926 :     std::string hist_msg;
     133        1463 :     history_.clear();
     134       13167 :     for (unsigned int i = 0; i < 8; i++)
     135             :     {
     136       11704 :         header.Get(384 + i * 80, 80, hist_msg);
     137             : 
     138             :         // Some programs seem to push history records with a trailing '\0'
     139             :         // so do some extra processing to cleanup.  FUN records on segment
     140             :         // 3 of eltoro.pix are an example of this.
     141       11704 :         size_t size = hist_msg.size();
     142           0 :         while( size > 0
     143       11704 :                && (hist_msg[size-1] == ' ' || hist_msg[size-1] == '\0') )
     144           0 :             size--;
     145             : 
     146       11704 :         hist_msg.resize(size);
     147             : 
     148       11704 :         history_.push_back(hist_msg);
     149             :     }
     150        1463 : }
     151             : 
     152             : /************************************************************************/
     153             : /*                            FlushHeader()                             */
     154             : /*                                                                      */
     155             : /*      This is used primarily after this class or subclasses have      */
     156             : /*      modified the header buffer and need it pushed back to disk.     */
     157             : /************************************************************************/
     158             : 
     159        1145 : void CPCIDSKSegment::FlushHeader()
     160             : 
     161             : {
     162        1145 :     file->WriteToFile( header.buffer, data_offset, 1024 );
     163        1145 : }
     164             : 
     165             : /************************************************************************/
     166             : /*                            ReadFromFile()                            */
     167             : /************************************************************************/
     168             : 
     169        2012 : void CPCIDSKSegment::ReadFromFile( void *buffer, uint64 offset, uint64 size )
     170             : 
     171             : {
     172        2012 :     if( offset+size+1024 > data_size )
     173           0 :         return ThrowPCIDSKException("Attempt to read past end of segment %d: "
     174             :                                     "Segment Size: " PCIDSK_FRMT_UINT64 ", "
     175             :                                     "Read Offset: " PCIDSK_FRMT_UINT64 ", "
     176             :                                     "Read Size: " PCIDSK_FRMT_UINT64,
     177           0 :                                     segment, data_size, offset, size);
     178             : 
     179        2012 :     file->ReadFromFile( buffer, offset + data_offset + 1024, size );
     180             : }
     181             : 
     182             : /************************************************************************/
     183             : /*                            WriteToFile()                             */
     184             : /************************************************************************/
     185             : 
     186        2056 : void CPCIDSKSegment::WriteToFile( const void *buffer, uint64 offset, uint64 size )
     187             : {
     188        2056 :     if( offset+size > data_size-1024 )
     189             :     {
     190        1168 :         CPCIDSKFile *poFile = dynamic_cast<CPCIDSKFile *>(file);
     191             : 
     192        1168 :         if (poFile == nullptr) {
     193           0 :             return ThrowPCIDSKException("Attempt to dynamic_cast the file interface "
     194             :                 "to a CPCIDSKFile failed. This is a programmer error, and should "
     195           0 :                 "be reported to your software provider.");
     196             :         }
     197             : 
     198        1168 :         uint64 blocks_to_add =
     199        1168 :             ((offset+size+511) - (data_size - 1024)) / 512;
     200             : 
     201             :         // prezero if we aren't directly writing all the new blocks.
     202        1168 :         poFile->ExtendSegment( segment, blocks_to_add,
     203        2336 :                              !(offset == data_size - 1024
     204        1168 :                                && size == blocks_to_add * 512) );
     205             :         // ExtendSegment() will call LoadSegmentPointer() to update data_size.
     206             :     }
     207             : 
     208        2056 :     assert(file); // avoid CLang Static Analyzer false positive
     209        2056 :     file->WriteToFile( buffer, offset + data_offset + 1024, size );
     210             : }
     211             : 
     212             : /************************************************************************/
     213             : /*                           GetDescription()                           */
     214             : /************************************************************************/
     215             : 
     216           0 : std::string CPCIDSKSegment::GetDescription()
     217             : {
     218           0 :     std::string target;
     219             : 
     220           0 :     header.Get( 0, 64, target );
     221             : 
     222           0 :     return target;
     223             : }
     224             : 
     225             : /************************************************************************/
     226             : /*                           SetDescription()                           */
     227             : /************************************************************************/
     228             : 
     229           0 : void CPCIDSKSegment::SetDescription( const std::string &description )
     230             : {
     231           0 :     header.Put( description.c_str(), 0, 64);
     232             : 
     233           0 :     file->WriteToFile( header.buffer, data_offset, 1024 );
     234           0 : }
     235             : 
     236             : /************************************************************************/
     237             : /*                              IsAtEOF()                               */
     238             : /************************************************************************/
     239             : 
     240        1176 : bool CPCIDSKSegment::IsAtEOF()
     241             : {
     242        1176 :     return data_offset + data_size == file->GetFileSize() * 512;
     243             : }
     244             : 
     245             : /************************************************************************/
     246             : /*                               CanExtend()                            */
     247             : /************************************************************************/
     248           0 : bool CPCIDSKSegment::CanExtend(uint64 size) const
     249             : {
     250           0 :     return data_size + size <= data_size_limit;
     251             : }
     252             : 
     253             : /************************************************************************/
     254             : /*                         GetHistoryEntries()                          */
     255             : /************************************************************************/
     256             : 
     257           0 : std::vector<std::string> CPCIDSKSegment::GetHistoryEntries() const
     258             : {
     259           0 :     return history_;
     260             : }
     261             : 
     262             : /************************************************************************/
     263             : /*                         SetHistoryEntries()                          */
     264             : /************************************************************************/
     265             : 
     266           0 : void CPCIDSKSegment::SetHistoryEntries(const std::vector<std::string> &entries)
     267             : 
     268             : {
     269           0 :     for( unsigned int i = 0; i < 8; i++ )
     270             :     {
     271           0 :         const char *msg = "";
     272           0 :         if( entries.size() > i )
     273           0 :             msg = entries[i].c_str();
     274             : 
     275           0 :         header.Put( msg, 384 + i * 80, 80 );
     276             :     }
     277             : 
     278           0 :     FlushHeader();
     279             : 
     280             :     // Force reloading of history_
     281           0 :     LoadSegmentHeader();
     282           0 : }
     283             : 
     284             : /************************************************************************/
     285             : /*                            PushHistory()                             */
     286             : /************************************************************************/
     287             : 
     288           0 : void CPCIDSKSegment::PushHistory( const std::string &app,
     289             :                                   const std::string &message )
     290             : 
     291             : {
     292             : #define MY_MIN(a,b)      ((a<b) ? a : b)
     293             : 
     294             :     char current_time[17];
     295             :     char history[81];
     296             : 
     297           0 :     GetCurrentDateTime( current_time );
     298             : 
     299           0 :     memset( history, ' ', 80 );
     300           0 :     history[80] = '\0';
     301             : 
     302           0 :     memcpy( history + 0, app.c_str(), MY_MIN(app.size(),7) );
     303           0 :     history[7] = ':';
     304             : 
     305           0 :     memcpy( history + 8, message.c_str(), MY_MIN(message.size(),56) );
     306           0 :     memcpy( history + 64, current_time, 16 );
     307             : 
     308           0 :     std::vector<std::string> history_entries = GetHistoryEntries();
     309             : 
     310             :     // coverity[string_null]
     311           0 :     history_entries.insert( history_entries.begin(), history );
     312           0 :     history_entries.resize(8);
     313             : 
     314           0 :     SetHistoryEntries( history_entries );
     315           0 : }
     316             : 
     317             : 
     318             : /************************************************************************/
     319             : /*                              MoveData()                              */
     320             : /*                                                                      */
     321             : /*      Move a chunk of data within a segment. Overlapping source       */
     322             : /*      and destination are permitted.                                  */
     323             : /************************************************************************/
     324             : 
     325         160 : void CPCIDSKSegment::MoveData( uint64 src_offset, uint64 dst_offset,
     326             :                                uint64 size_in_bytes )
     327             : 
     328             : {
     329         160 :     bool copy_backwards = false;
     330             : 
     331             :     // We move things backwards if the areas overlap and the destination
     332             :     // is further on in the segment.
     333         160 :     if( dst_offset > src_offset
     334         160 :         && src_offset + size_in_bytes > dst_offset )
     335          45 :         copy_backwards = true;
     336             : 
     337             : 
     338             :     // Move the segment data to the new location.
     339             :     uint8 copy_buf[16384];
     340             :     uint64 bytes_to_go;
     341             : 
     342         160 :     bytes_to_go = size_in_bytes;
     343             : 
     344         320 :     while( bytes_to_go > 0 )
     345             :     {
     346         160 :         uint64 bytes_this_chunk = sizeof(copy_buf);
     347         160 :         if( bytes_to_go < bytes_this_chunk )
     348         160 :             bytes_this_chunk = bytes_to_go;
     349             : 
     350         160 :         if( copy_backwards )
     351             :         {
     352          45 :             ReadFromFile( copy_buf,
     353          45 :                           src_offset + bytes_to_go - bytes_this_chunk,
     354          45 :                           bytes_this_chunk );
     355          45 :             WriteToFile( copy_buf,
     356          45 :                          dst_offset + bytes_to_go - bytes_this_chunk,
     357          45 :                          bytes_this_chunk );
     358             :         }
     359             :         else
     360             :         {
     361         115 :             ReadFromFile( copy_buf, src_offset, bytes_this_chunk );
     362         115 :             WriteToFile( copy_buf, dst_offset, bytes_this_chunk );
     363             : 
     364         115 :             src_offset += bytes_this_chunk;
     365         115 :             dst_offset += bytes_this_chunk;
     366             :         }
     367             : 
     368         160 :         bytes_to_go -= bytes_this_chunk;
     369             :     }
     370         160 : }

Generated by: LCOV version 1.14