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

Generated by: LCOV version 1.14