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

Generated by: LCOV version 1.14