LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/blockdir - blockdir.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 88 146 60.3 %
Date: 2024-05-14 13:00:50 Functions: 13 23 56.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Purpose:  Block directory API.
       4             :  *
       5             :  ******************************************************************************
       6             :  * Copyright (c) 2011
       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 "blockdir/blockdir.h"
      29             : #include "blockdir/blocklayer.h"
      30             : #include "blockdir/blockfile.h"
      31             : #include "core/pcidsk_utils.h"
      32             : #include "pcidsk_exception.h"
      33             : #include <sstream>
      34             : #include <cstring>
      35             : #include <cassert>
      36             : #include <algorithm>
      37             : 
      38             : using namespace PCIDSK;
      39             : 
      40             : /************************************************************************/
      41             : /*                                BlockDir()                            */
      42             : /************************************************************************/
      43             : 
      44             : /**
      45             :  * Constructor.
      46             :  *
      47             :  * @param poFile The associated file object.
      48             :  * @param nSegment The segment of the block directory.
      49             :  */
      50          24 : BlockDir::BlockDir(BlockFile * poFile, uint16 nSegment)
      51             :     : mpoFile(poFile),
      52             :       mnSegment(nSegment),
      53             :       mnVersion(0),
      54          24 :       mchEndianness(BigEndianSystem() ? 'B' : 'L'),
      55             :       mbNeedsSwap(false),
      56             :       mnValidInfo(0),
      57             :       mbModified(false),
      58          48 :       mbOnDisk(true)
      59             : {
      60          24 :     assert(poFile && nSegment != INVALID_SEGMENT);
      61             : 
      62          24 :     mpoFreeBlockLayer = nullptr;
      63          24 : }
      64             : 
      65             : /************************************************************************/
      66             : /*                                BlockDir()                            */
      67             : /************************************************************************/
      68             : 
      69             : /**
      70             :  * Constructor.
      71             :  *
      72             :  * @param poFile The associated file object.
      73             :  * @param nSegment The segment of the block directory.
      74             :  * @param nVersion The version of the block directory.
      75             :  */
      76           8 : BlockDir::BlockDir(BlockFile * poFile, uint16 nSegment, uint16 nVersion)
      77             : 
      78             :     : mpoFile(poFile),
      79             :       mnSegment(nSegment),
      80             :       mnVersion(nVersion),
      81           8 :       mchEndianness(BigEndianSystem() ? 'B' : 'L'),
      82             :       mbNeedsSwap(false),
      83             :       mnValidInfo(0),
      84             :       mbModified(true),
      85          16 :       mbOnDisk(false)
      86             : {
      87           8 :     assert(poFile && nSegment != INVALID_SEGMENT);
      88             : 
      89           8 :     mpoFreeBlockLayer = nullptr;
      90           8 : }
      91             : 
      92             : /************************************************************************/
      93             : /*                               ~BlockDir()                            */
      94             : /************************************************************************/
      95             : 
      96             : /**
      97             :  * Destructor.
      98             :  */
      99          32 : BlockDir::~BlockDir(void)
     100             : {
     101          68 :     for (size_t iLayer = 0; iLayer < moLayerList.size(); iLayer++)
     102          36 :         delete moLayerList[iLayer];
     103             : 
     104          32 :     delete mpoFreeBlockLayer;
     105             : 
     106          32 :     delete mpoFile;
     107          32 : }
     108             : 
     109             : /************************************************************************/
     110             : /*                                  Sync()                              */
     111             : /************************************************************************/
     112             : 
     113             : /**
     114             :  * Synchronizes the block directory to disk.
     115             :  */
     116          50 : void BlockDir::Sync(void)
     117             : {
     118          50 :     if (!mbModified)
     119          42 :         return;
     120             : 
     121           8 :     if (!mpoFile->GetUpdatable())
     122           0 :         return;
     123             : 
     124           8 :     if (!IsValid())
     125             :     {
     126           0 :         ThrowPCIDSKException("Failed to save: %s",
     127           0 :                              mpoFile->GetFilename().c_str());
     128             :     }
     129             : 
     130           8 :     WriteDir();
     131             : 
     132           8 :     mbModified = false;
     133             : }
     134             : 
     135             : /************************************************************************/
     136             : /*                                GetFile()                             */
     137             : /************************************************************************/
     138             : 
     139             : /**
     140             :  * Gets the associated file of the block directory.
     141             :  *
     142             :  * @return The associated file of the block directory.
     143             :  */
     144          90 : BlockFile * BlockDir::GetFile(void) const
     145             : {
     146          90 :     return mpoFile;
     147             : }
     148             : 
     149             : /************************************************************************/
     150             : /*                            GetSegmentIndex()                         */
     151             : /************************************************************************/
     152             : 
     153             : /**
     154             :  * Gets the index of the block directory segment.
     155             :  *
     156             :  * @return The index of the block directory segment.
     157             :  */
     158           0 : uint16 BlockDir::GetSegmentIndex(void) const
     159             : {
     160           0 :     return mnSegment;
     161             : }
     162             : 
     163             : /************************************************************************/
     164             : /*                               GetVersion()                           */
     165             : /************************************************************************/
     166             : 
     167             : /**
     168             :  * Gets the version of the block directory.
     169             :  *
     170             :  * @return The version of the block directory.
     171             :  */
     172           0 : uint16 BlockDir::GetVersion(void) const
     173             : {
     174           0 :     return mnVersion;
     175             : }
     176             : 
     177             : /************************************************************************/
     178             : /*                               NeedsSwap()                            */
     179             : /************************************************************************/
     180             : 
     181             : /**
     182             :  * Checks if the block directory on disk needs swapping.
     183             :  *
     184             :  * @return If the block directory on disk needs swapping.
     185             :  */
     186          19 : bool BlockDir::NeedsSwap(void) const
     187             : {
     188          19 :     return mbNeedsSwap;
     189             : }
     190             : 
     191             : /************************************************************************/
     192             : /*                                IsValid()                             */
     193             : /************************************************************************/
     194             : 
     195             : /**
     196             :  * Checks if the block directory is valid.
     197             :  *
     198             :  * @note The block directory is considered valid if the last
     199             :  *       two bytes of the header are the same as when the header was read.
     200             :  *
     201             :  * @return If the block directory is valid.
     202             :  */
     203           8 : bool BlockDir::IsValid(void) const
     204             : {
     205           8 :     if (!mbOnDisk)
     206           8 :         return true;
     207             : 
     208             :     // Read the block directory header from disk.
     209             :     uint8 abyHeader[512];
     210             : 
     211           0 :     mpoFile->ReadFromSegment(mnSegment, abyHeader, 0, 512);
     212             : 
     213             :     // The last 2 bytes of the header are for the valid info.
     214             :     uint16 nValidInfo;
     215             : 
     216           0 :     memcpy(&nValidInfo, abyHeader + 512 - 2, 2);
     217             : 
     218           0 :     SwapValue(&nValidInfo);
     219             : 
     220             :     // Check if the valid info has changed since the last read.
     221           0 :     return nValidInfo == mnValidInfo;
     222             : }
     223             : 
     224             : /************************************************************************/
     225             : /*                               IsModified()                           */
     226             : /************************************************************************/
     227             : 
     228             : /**
     229             :  * Checks if the block directory is modified.
     230             :  *
     231             :  * @return If the block directory is modified.
     232             :  */
     233           0 : bool BlockDir::IsModified(void) const
     234             : {
     235           0 :     return mbModified;
     236             : }
     237             : 
     238             : /************************************************************************/
     239             : /*                             GetLayerCount()                          */
     240             : /************************************************************************/
     241             : 
     242             : /**
     243             :  * Gets the number of block layers.
     244             :  *
     245             :  * @return The number of block layers.
     246             :  */
     247           0 : uint32 BlockDir::GetLayerCount(void) const
     248             : {
     249           0 :     return (uint32) moLayerList.size();
     250             : }
     251             : 
     252             : /************************************************************************/
     253             : /*                              GetLayerType()                          */
     254             : /************************************************************************/
     255             : 
     256             : /**
     257             :  * Gets the type of the block layer specified index.
     258             :  *
     259             :  * @param iLayer The index of the block layer.
     260             :  *
     261             :  * @return The type of the specified block layer.
     262             :  */
     263           0 : uint16 BlockDir::GetLayerType(uint32 iLayer) const
     264             : {
     265           0 :     if (iLayer >= moLayerList.size())
     266           0 :         return BLTDead;
     267             : 
     268           0 :     return moLayerList[iLayer]->GetLayerType();
     269             : }
     270             : 
     271             : /************************************************************************/
     272             : /*                              GetLayerSize()                          */
     273             : /************************************************************************/
     274             : 
     275             : /**
     276             :  * Gets the size in bytes of the block layer specified index.
     277             :  *
     278             :  * @param iLayer The index of the block layer.
     279             :  *
     280             :  * @return The size in bytes of the block layer specified index.
     281             :  */
     282           0 : uint64 BlockDir::GetLayerSize(uint32 iLayer) const
     283             : {
     284           0 :     if (iLayer >= moLayerList.size())
     285           0 :         return 0;
     286             : 
     287           0 :     return moLayerList[iLayer]->GetLayerSize();
     288             : }
     289             : 
     290             : /************************************************************************/
     291             : /*                                IsValid()                             */
     292             : /************************************************************************/
     293             : 
     294             : /**
     295             :  * Checks if the block layer at the specified index is valid.
     296             :  *
     297             :  * @param iLayer The index of the block layer.
     298             :  *
     299             :  * @return If the the specified block layer is valid.
     300             :  */
     301           0 : bool BlockDir::IsLayerValid(uint32 iLayer) const
     302             : {
     303           0 :     return GetLayerType(iLayer) != BLTDead;
     304             : }
     305             : 
     306             : /************************************************************************/
     307             : /*                                GetLayer()                            */
     308             : /************************************************************************/
     309             : 
     310             : /**
     311             :  * Gets the block layer at the specified index.
     312             :  *
     313             :  * @param iLayer The index of the block layer.
     314             :  *
     315             :  * @return The block layer at the specified index.
     316             :  */
     317          62 : BlockLayer * BlockDir::GetLayer(uint32 iLayer)
     318             : {
     319          62 :     if (iLayer >= moLayerList.size())
     320           0 :         return nullptr;
     321             : 
     322          62 :     return moLayerList[iLayer];
     323             : }
     324             : 
     325             : /************************************************************************/
     326             : /*                              CreateLayer()                           */
     327             : /************************************************************************/
     328             : 
     329             : /**
     330             :  * Creates a block layer of the specified type.
     331             :  *
     332             :  * @param nLayerType The type of the block layer to create.
     333             :  *
     334             :  * @return The index of the new block layer.
     335             :  */
     336           8 : uint32 BlockDir::CreateLayer(int16 nLayerType)
     337             : {
     338             :     // Try to find an invalid layer.
     339           8 :     uint32 nNewLayerIndex = INVALID_LAYER;
     340             : 
     341           8 :     for (size_t iLayer = 0; iLayer < moLayerList.size(); iLayer++)
     342             :     {
     343           0 :         if (!moLayerList[iLayer]->IsValid())
     344             :         {
     345           0 :             nNewLayerIndex = (uint32) iLayer;
     346             : 
     347           0 :             break;
     348             :         }
     349             :     }
     350             : 
     351           8 :     if (nNewLayerIndex == INVALID_LAYER)
     352             :     {
     353           8 :         nNewLayerIndex = (uint32) moLayerList.size();
     354             : 
     355             :         try
     356             :         {
     357           8 :             moLayerList.resize(moLayerList.size() + 1);
     358             :         }
     359           0 :         catch (const std::exception & ex)
     360             :         {
     361           0 :             return ThrowPCIDSKException(0, "Out of memory in BlockDir::CreateLayer(): %s", ex.what());
     362             :         }
     363             :     }
     364             :     else
     365             :     {
     366           0 :         delete moLayerList[nNewLayerIndex];
     367             :     }
     368             : 
     369             :     // Call the virtual method _CreateLayer() to create the layer.
     370           8 :     moLayerList[nNewLayerIndex] = _CreateLayer(nLayerType, nNewLayerIndex);
     371             : 
     372           8 :     mbModified = true;
     373             : 
     374           8 :     return nNewLayerIndex;
     375             : }
     376             : 
     377             : /************************************************************************/
     378             : /*                              DeleteLayer()                           */
     379             : /************************************************************************/
     380             : 
     381             : /**
     382             :  * Deletes the block layer with the specified index.
     383             :  *
     384             :  * @param iLayer The index of the block layer to delete.
     385             :  */
     386           0 : void BlockDir::DeleteLayer(uint32 iLayer)
     387             : {
     388           0 :     BlockLayer * poLayer = GetLayer(iLayer);
     389             : 
     390           0 :     assert(poLayer && poLayer->IsValid());
     391           0 :     if (!poLayer || !poLayer->IsValid())
     392           0 :         return;
     393             : 
     394           0 :     poLayer->Resize(0);
     395             : 
     396             :     // Call the virtual method _DeleteLayer() to delete the layer.
     397           0 :     _DeleteLayer(iLayer);
     398             : 
     399           0 :     mbModified = true;
     400             : }
     401             : 
     402             : /************************************************************************/
     403             : /*                            CreateNewBlocks()                         */
     404             : /************************************************************************/
     405             : 
     406             : /**
     407             :  * Creates the specified number of new blocks.
     408             :  *
     409             :  * @param nBlockCount The number of blocks to create.
     410             :  *
     411             :  * @return The specified number of new blocks.
     412             :  */
     413          16 : BlockInfoList BlockDir::CreateNewBlocks(uint32 nBlockCount)
     414             : {
     415          16 :     ValidateNewBlocks(nBlockCount, false);
     416             : 
     417          16 :     BlockInfoList oNewBlocks(nBlockCount);
     418             : 
     419          16 :     BlockInfoList::iterator oIter = oNewBlocks.begin();
     420          16 :     BlockInfoList::iterator oEnd = oNewBlocks.end();
     421             : 
     422          32 :     for (; oIter != oEnd; ++oIter)
     423             :     {
     424          16 :         oIter->nSegment = INVALID_SEGMENT;
     425          16 :         oIter->nStartBlock = INVALID_BLOCK;
     426             :     }
     427             : 
     428          16 :     mbModified = true;
     429             : 
     430          32 :     return oNewBlocks;
     431             : }
     432             : 
     433             : /************************************************************************/
     434             : /*                            CreateFreeBlocks()                        */
     435             : /************************************************************************/
     436             : 
     437             : /**
     438             :  * Creates the specified number of free blocks.
     439             :  *
     440             :  * @note The new blocks are going to be added to the free block layer.
     441             :  *
     442             :  * @param nBlockCount The number of blocks to create.
     443             :  */
     444           8 : void BlockDir::CreateFreeBlocks(uint32 nBlockCount)
     445             : {
     446           8 :     if (!mpoFreeBlockLayer)
     447           0 :         ReadFreeBlockLayer();
     448             : 
     449           8 :     ValidateNewBlocks(nBlockCount, true);
     450             : 
     451           8 :     uint32 nBlockSize = GetBlockSize();
     452             : 
     453             :     uint16 nDataSegment =
     454           8 :         mpoFile->ExtendSegment(GetDataSegmentName(), GetDataSegmentDesc(),
     455           8 :                                (uint64) nBlockCount * nBlockSize);
     456             : 
     457           8 :     uint64 nBlockOffset = mpoFile->GetSegmentSize(nDataSegment);
     458             : 
     459           8 :     assert(nBlockOffset % nBlockSize == 0);
     460             : 
     461             :     // Reverse the block list because GetFreeBlock() is LIFO.
     462           8 :     BlockInfoList oFreeBlockList;
     463             : 
     464           8 :     oFreeBlockList.reserve(nBlockCount);
     465             : 
     466         136 :     for (uint32 iBlock = 0; iBlock < nBlockCount; iBlock++)
     467             :     {
     468             :         BlockInfo sFreeBlock;
     469             : 
     470         128 :         nBlockOffset -= nBlockSize;
     471             : 
     472         128 :         sFreeBlock.nSegment = nDataSegment;
     473         128 :         sFreeBlock.nStartBlock = (uint32) (nBlockOffset / nBlockSize);
     474             : 
     475         128 :         oFreeBlockList.push_back(sFreeBlock);
     476             :     }
     477             : 
     478           8 :     mpoFreeBlockLayer->PushBlocks(oFreeBlockList);
     479             : 
     480           8 :     mbModified = true;
     481           8 : }
     482             : 
     483             : /************************************************************************/
     484             : /*                             AddFreeBlocks()                          */
     485             : /************************************************************************/
     486             : 
     487             : /**
     488             :  * Adds the the specified block list to the free block layer.
     489             :  *
     490             :  * @note Only the blocks which are allocated will be added to the
     491             :  *       free block layer.
     492             :  *
     493             :  * @param oBlockList The block list to add.
     494             :  */
     495           0 : void BlockDir::AddFreeBlocks(const BlockInfoList & oBlockList)
     496             : {
     497           0 :     if (!mpoFreeBlockLayer)
     498           0 :         ReadFreeBlockLayer();
     499             : 
     500           0 :     BlockInfoList oValidBlockList;
     501             : 
     502           0 :     oValidBlockList.reserve(oBlockList.size());
     503             : 
     504             :     // Reverse the block list because GetFreeBlock() is LIFO.
     505           0 :     BlockInfoList::const_reverse_iterator oIter = oBlockList.rbegin();
     506           0 :     BlockInfoList::const_reverse_iterator oEnd = oBlockList.rend();
     507             : 
     508           0 :     for (; oIter != oEnd; ++oIter)
     509             :     {
     510           0 :         if (oIter->nSegment != INVALID_SEGMENT &&
     511           0 :             oIter->nStartBlock != INVALID_BLOCK)
     512             :         {
     513           0 :             oValidBlockList.push_back(*oIter);
     514             :         }
     515             :     }
     516             : 
     517           0 :     mpoFreeBlockLayer->PushBlocks(oValidBlockList);
     518             : 
     519           0 :     mbModified = true;
     520           0 : }
     521             : 
     522             : /************************************************************************/
     523             : /*                              GetFreeBlock()                          */
     524             : /************************************************************************/
     525             : 
     526             : /**
     527             :  * Gets a free block from the free block layer.
     528             :  *
     529             :  * @note The block will be removed from the free block layer.
     530             :  *
     531             :  * @return A free block from the free block layer.
     532             :  */
     533          16 : BlockInfo BlockDir::GetFreeBlock(void)
     534             : {
     535          16 :     if (!mpoFreeBlockLayer)
     536           0 :         ReadFreeBlockLayer();
     537             : 
     538             :     // If we need more free blocks, create a minimum of 16 blocks.
     539          16 :     if (mpoFreeBlockLayer->GetBlockCount() == 0)
     540           8 :         CreateFreeBlocks(std::max((uint32) 16, GetNewBlockCount()));
     541             : 
     542          16 :     if (mpoFreeBlockLayer->GetBlockCount() <= 0)
     543           0 :         ThrowPCIDSKException("Cannot create new blocks.");
     544             : 
     545             :     BlockInfo sFreeBlock;
     546          16 :     sFreeBlock.nSegment = INVALID_SEGMENT;
     547          16 :     sFreeBlock.nStartBlock = INVALID_BLOCK;
     548             : 
     549          32 :     const BlockInfoList & oFreeBlockList = mpoFreeBlockLayer->PopBlocks(1);
     550             : 
     551          16 :     assert(oFreeBlockList.size() == 1);
     552             : 
     553          16 :     if (!oFreeBlockList.empty())
     554          16 :         sFreeBlock = oFreeBlockList[0];
     555             : 
     556          16 :     mbModified = true;
     557             : 
     558          32 :     return sFreeBlock;
     559             : }
     560             : 
     561             : /************************************************************************/
     562             : /*                               SwapValue()                            */
     563             : /************************************************************************/
     564             : 
     565             : /**
     566             :  * Swaps the specified value.
     567             :  *
     568             :  * @param pnValue The value to swap.
     569             :  */
     570          32 : void BlockDir::SwapValue(uint16 * pnValue) const
     571             : {
     572          32 :     if (!mbNeedsSwap)
     573          32 :         return;
     574             : 
     575           0 :     SwapData(pnValue, 2, 1);
     576             : }

Generated by: LCOV version 1.14