LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/blockdir - blocklayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 123 176 69.9 %
Date: 2024-11-21 22:18:42 Functions: 13 16 81.2 %

          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/blocklayer.h"
      13             : #include "blockdir/blockfile.h"
      14             : #include "pcidsk_exception.h"
      15             : 
      16             : using namespace PCIDSK;
      17             : 
      18             : /************************************************************************/
      19             : /*                               BlockLayer()                           */
      20             : /************************************************************************/
      21             : 
      22             : /**
      23             :  * Constructor.
      24             :  *
      25             :  * @param poBlockDir The associated block directory.
      26             :  * @param nLayer The index of the block layer.
      27             :  */
      28          49 : BlockLayer::BlockLayer(BlockDir * poBlockDir, uint32 nLayer)
      29             :     : mpoBlockDir(poBlockDir),
      30          49 :       mnLayer(nLayer)
      31             : {
      32          49 : }
      33             : 
      34             : /************************************************************************/
      35             : /*                              ~BlockLayer()                           */
      36             : /************************************************************************/
      37             : 
      38             : /**
      39             :  * Destructor.
      40             :  */
      41          49 : BlockLayer::~BlockLayer(void)
      42             : {
      43          49 : }
      44             : 
      45             : /************************************************************************/
      46             : /*                              GetBlockInfo()                          */
      47             : /************************************************************************/
      48             : 
      49             : /**
      50             :  * Gets the layer block at the specified index.
      51             :  *
      52             :  * @param iBlock The index of the layer block.
      53             :  *
      54             :  * @return The layer block at the specified index.
      55             :  */
      56         222 : BlockInfo * BlockLayer::GetBlockInfo(uint32 iBlock)
      57             : {
      58         222 :     if (!IsValid())
      59           0 :         return nullptr;
      60             : 
      61         222 :     uint32 nBlockCount = GetBlockCount();
      62             : 
      63         222 :     if (nBlockCount != moBlockList.size())
      64             :     {
      65          11 :         mpoBlockDir->ReadLayerBlocks(mnLayer);
      66             : 
      67          11 :         if (moBlockList.size() != nBlockCount)
      68           0 :             ThrowPCIDSKExceptionPtr("Corrupted block directory.");
      69             :     }
      70             : 
      71         222 :     if (iBlock >= moBlockList.size())
      72           0 :         return nullptr;
      73             : 
      74         222 :     return &moBlockList[iBlock];
      75             : }
      76             : 
      77             : /************************************************************************/
      78             : /*                             AllocateBlocks()                         */
      79             : /************************************************************************/
      80             : 
      81             : /**
      82             :  * Allocates the blocks of the specified data.
      83             :  *
      84             :  * @param nOffset The offset of the data.
      85             :  * @param nSize The size of the data.
      86             :  */
      87          24 : void BlockLayer::AllocateBlocks(uint64 nOffset, uint64 nSize)
      88             : {
      89          24 :     uint32 nBlockSize = mpoBlockDir->GetBlockSize();
      90             : 
      91          24 :     uint32 iStartBlock = (uint32) (nOffset / nBlockSize);
      92          24 :     uint32 nStartOffset = (uint32) (nOffset % nBlockSize);
      93             : 
      94          24 :     uint32 nNumBlocks = (uint32)
      95          24 :         ((nSize + nStartOffset + nBlockSize - 1) / nBlockSize);
      96             : 
      97          48 :     for (uint32 iBlock = 0; iBlock < nNumBlocks; iBlock++)
      98             :     {
      99          24 :         BlockInfo * psBlock = GetBlockInfo(iStartBlock + iBlock);
     100             : 
     101          24 :         if (!psBlock)
     102           0 :             break;
     103             : 
     104          24 :         if (psBlock->nSegment == INVALID_SEGMENT ||
     105           8 :             psBlock->nStartBlock == INVALID_BLOCK)
     106             :         {
     107          16 :             *psBlock = mpoBlockDir->GetFreeBlock();
     108             :         }
     109             :     }
     110          24 : }
     111             : 
     112             : /************************************************************************/
     113             : /*                           AreBlocksAllocated()                       */
     114             : /************************************************************************/
     115             : 
     116             : /**
     117             :  * Checks if the blocks of the specified data are allocated.
     118             :  *
     119             :  * @param nOffset The offset of the data.
     120             :  * @param nSize The size of the data.
     121             :  *
     122             :  * @return If the blocks of the specified data are allocated.
     123             :  */
     124          46 : bool BlockLayer::AreBlocksAllocated(uint64 nOffset, uint64 nSize)
     125             : {
     126          46 :     uint32 nBlockSize = mpoBlockDir->GetBlockSize();
     127             : 
     128          46 :     uint32 iStartBlock = (uint32) (nOffset / nBlockSize);
     129          46 :     uint32 nStartOffset = (uint32) (nOffset % nBlockSize);
     130             : 
     131          46 :     uint32 nNumBlocks = (uint32)
     132          46 :         ((nSize + nStartOffset + nBlockSize - 1) / nBlockSize);
     133             : 
     134          92 :     for (uint32 iBlock = 0; iBlock < nNumBlocks; iBlock++)
     135             :     {
     136          46 :         BlockInfo * psBlock = GetBlockInfo(iStartBlock + iBlock);
     137             : 
     138          46 :         if (!psBlock)
     139           0 :             return false;
     140             : 
     141          46 :         if (psBlock->nSegment == INVALID_SEGMENT ||
     142          46 :             psBlock->nStartBlock == INVALID_BLOCK)
     143             :         {
     144           0 :             return false;
     145             :         }
     146             :     }
     147             : 
     148          46 :     return true;
     149             : }
     150             : 
     151             : /************************************************************************/
     152             : /*                           GetContiguousCount()                       */
     153             : /************************************************************************/
     154             : 
     155             : /**
     156             :  * Gets the number of contiguous blocks for the specified data.
     157             :  *
     158             :  * @param nOffset The offset of the data.
     159             :  * @param nSize The size of the data.
     160             :  *
     161             :  * @return The number of contiguous blocks for the specified data.
     162             :  */
     163          70 : uint32 BlockLayer::GetContiguousCount(uint64 nOffset, uint64 nSize)
     164             : {
     165          70 :     uint32 nBlockSize = mpoBlockDir->GetBlockSize();
     166             : 
     167          70 :     uint32 iStartBlock = (uint32) (nOffset / nBlockSize);
     168          70 :     uint32 nStartOffset = (uint32) (nOffset % nBlockSize);
     169             : 
     170          70 :     uint32 nNumBlocks = (uint32)
     171          70 :         ((nSize + nStartOffset + nBlockSize - 1) / nBlockSize);
     172             : 
     173          70 :     BlockInfo * psStartBlock = GetBlockInfo(iStartBlock);
     174             : 
     175          70 :     if (!psStartBlock)
     176           0 :         return 0;
     177             : 
     178          70 :     uint32 nContiguousCount = 1;
     179             : 
     180          70 :     for (uint32 iBlock = 1; iBlock < nNumBlocks; iBlock++)
     181             :     {
     182           0 :         BlockInfo * psNextBlock = GetBlockInfo(iStartBlock + iBlock);
     183             : 
     184           0 :         if (!psNextBlock)
     185           0 :             break;
     186             : 
     187           0 :         if (psNextBlock->nSegment != psStartBlock->nSegment)
     188           0 :             break;
     189             : 
     190           0 :         if (psNextBlock->nStartBlock != psStartBlock->nStartBlock + iBlock)
     191           0 :             break;
     192             : 
     193           0 :         nContiguousCount++;
     194             :     }
     195             : 
     196          70 :     return nContiguousCount;
     197             : }
     198             : 
     199             : /************************************************************************/
     200             : /*                               FreeBlocks()                           */
     201             : /************************************************************************/
     202             : 
     203             : /**
     204             :  * Frees the blocks of the specified data.
     205             :  *
     206             :  * @param nOffset The offset of the data.
     207             :  * @param nSize The size of the data.
     208             :  */
     209           0 : void BlockLayer::FreeBlocks(uint64 nOffset, uint64 nSize)
     210             : {
     211           0 :     uint32 nBlockSize = mpoBlockDir->GetBlockSize();
     212             : 
     213           0 :     uint32 iStartBlock = (uint32) ((nOffset + nBlockSize - 1) / nBlockSize);
     214           0 :     uint32 iEndBlock = (uint32) ((nOffset + nSize) / nBlockSize);
     215             : 
     216           0 :     uint32 nNumBlocks = iStartBlock < iEndBlock ? iEndBlock - iStartBlock : 0;
     217             : 
     218           0 :     BlockInfoList oFreeBlocks;
     219             : 
     220           0 :     oFreeBlocks.reserve(nNumBlocks);
     221             : 
     222           0 :     for (uint32 iBlock = 0; iBlock < nNumBlocks; iBlock++)
     223             :     {
     224           0 :         BlockInfo * psBlock = GetBlockInfo(iStartBlock + iBlock);
     225             : 
     226           0 :         if (!psBlock)
     227           0 :             break;
     228             : 
     229           0 :         if (psBlock->nSegment != INVALID_SEGMENT &&
     230           0 :             psBlock->nStartBlock != INVALID_BLOCK)
     231             :         {
     232           0 :             oFreeBlocks.push_back(*psBlock);
     233             : 
     234           0 :             psBlock->nSegment = INVALID_SEGMENT;
     235           0 :             psBlock->nStartBlock = INVALID_BLOCK;
     236             :         }
     237             :     }
     238             : 
     239           0 :     mpoBlockDir->AddFreeBlocks(oFreeBlocks);
     240           0 : }
     241             : 
     242             : /************************************************************************/
     243             : /*                              WriteToLayer()                          */
     244             : /************************************************************************/
     245             : 
     246             : /**
     247             :  * Writes the specified data to the layer.
     248             :  *
     249             :  * @param pData The data buffer to write.
     250             :  * @param nOffset The offset of the data.
     251             :  * @param nSize The size of the data.
     252             :  */
     253          24 : void BlockLayer::WriteToLayer(const void * pData, uint64 nOffset, uint64 nSize)
     254             : {
     255          24 :     if (nOffset + nSize > GetLayerSize())
     256          16 :         Resize(nOffset + nSize);
     257             : 
     258          24 :     AllocateBlocks(nOffset, nSize);
     259             : 
     260          24 :     uint32 nBlockSize = mpoBlockDir->GetBlockSize();
     261             : 
     262          24 :     uint8 * pabyData = (uint8 *) pData;
     263             : 
     264          48 :     for (uint64 iByte = 0; iByte < nSize; )
     265             :     {
     266             :         uint32 nContiguousCount =
     267          24 :             GetContiguousCount(nOffset + iByte, nSize - iByte);
     268             : 
     269          24 :         uint32 iBlock = (uint32) ((nOffset + iByte) / nBlockSize);
     270          24 :         uint32 iWork  = (uint32) ((nOffset + iByte) % nBlockSize);
     271             : 
     272          24 :         uint64 nWorkSize = (uint64)nContiguousCount * nBlockSize - iWork;
     273             : 
     274          24 :         if (nWorkSize > nSize - iByte)
     275          23 :             nWorkSize = nSize - iByte;
     276             : 
     277          24 :         BlockInfo * psBlock = GetBlockInfo(iBlock);
     278             : 
     279          24 :         uint64 nWorkOffset = (uint64) psBlock->nStartBlock * nBlockSize + iWork;
     280             : 
     281          24 :         GetFile()->WriteToSegment(psBlock->nSegment, pabyData + iByte,
     282          24 :                                   nWorkOffset, nWorkSize);
     283             : 
     284          24 :         iByte += nWorkSize;
     285             :     }
     286          24 : }
     287             : 
     288             : /************************************************************************/
     289             : /*                             ReadFromLayer()                          */
     290             : /************************************************************************/
     291             : 
     292             : /**
     293             :  * Reads the specified data from the layer.
     294             :  *
     295             :  * @param pData The data buffer to read.
     296             :  * @param nOffset The offset of the data.
     297             :  * @param nSize The size of the data.
     298             :  */
     299          46 : bool BlockLayer::ReadFromLayer(void * pData, uint64 nOffset, uint64 nSize)
     300             : {
     301          46 :     uint64 nLayerSize = GetLayerSize();
     302             : 
     303          46 :     if (nSize > nLayerSize ||
     304          46 :         nOffset > nLayerSize ||
     305          46 :         nOffset + nSize > nLayerSize)
     306             :     {
     307           0 :         return false;
     308             :     }
     309             : 
     310          46 :     if (!AreBlocksAllocated(nOffset, nSize))
     311           0 :         return false;
     312             : 
     313          46 :     uint32 nBlockSize = mpoBlockDir->GetBlockSize();
     314             : 
     315          46 :     uint8 * pabyData = (uint8 *) pData;
     316             : 
     317          92 :     for (uint64 iByte = 0; iByte < nSize; )
     318             :     {
     319             :         uint32 nContiguousCount =
     320          46 :             GetContiguousCount(nOffset + iByte, nSize - iByte);
     321             : 
     322          46 :         uint32 iBlock = (uint32) ((nOffset + iByte) / nBlockSize);
     323          46 :         uint32 iWork  = (uint32) ((nOffset + iByte) % nBlockSize);
     324             : 
     325          46 :         uint64 nWorkSize = (uint64)nContiguousCount * nBlockSize - iWork;
     326             : 
     327          46 :         if (nWorkSize > nSize - iByte)
     328          43 :             nWorkSize = nSize - iByte;
     329             : 
     330          46 :         BlockInfo * psBlock = GetBlockInfo(iBlock);
     331             : 
     332          46 :         uint64 nWorkOffset = (uint64) psBlock->nStartBlock * nBlockSize + iWork;
     333             : 
     334          46 :         GetFile()->ReadFromSegment(psBlock->nSegment, pabyData + iByte,
     335          46 :                                    nWorkOffset, nWorkSize);
     336             : 
     337          46 :         iByte += nWorkSize;
     338             :     }
     339             : 
     340          46 :     return true;
     341             : }
     342             : 
     343             : /************************************************************************/
     344             : /*                                GetFile()                             */
     345             : /************************************************************************/
     346             : 
     347             : /**
     348             :  * Gets the associated file of the block layer.
     349             :  *
     350             :  * @return The associated file of the block layer.
     351             :  */
     352          90 : BlockFile * BlockLayer::GetFile(void) const
     353             : {
     354          90 :     return mpoBlockDir->GetFile();
     355             : }
     356             : 
     357             : /************************************************************************/
     358             : /*                               NeedsSwap()                            */
     359             : /************************************************************************/
     360             : 
     361             : /**
     362             :  * Checks if the block directory on disk needs swapping.
     363             :  *
     364             :  * @return If the block directory on disk needs swapping.
     365             :  */
     366           0 : bool BlockLayer::NeedsSwap(void) const
     367             : {
     368           0 :     return mpoBlockDir->NeedsSwap();
     369             : }
     370             : 
     371             : /************************************************************************/
     372             : /*                                IsValid()                             */
     373             : /************************************************************************/
     374             : 
     375             : /**
     376             :  * Checks if the block layer is valid.
     377             :  *
     378             :  * @return If the block layer is valid.
     379             :  */
     380         382 : bool BlockLayer::IsValid(void) const
     381             : {
     382         382 :     return GetLayerType() != BLTDead;
     383             : }
     384             : 
     385             : /************************************************************************/
     386             : /*                                 Resize()                             */
     387             : /************************************************************************/
     388             : 
     389             : /**
     390             :  * Resizes the block layer to the specified size in bytes.
     391             :  *
     392             :  * @param nLayerSize The new block layer size in bytes.
     393             :  */
     394          24 : void BlockLayer::Resize(uint64 nLayerSize)
     395             : {
     396          24 :     if (!IsValid())
     397           0 :         return;
     398             : 
     399          24 :     if (nLayerSize == GetLayerSize())
     400           0 :         return;
     401             : 
     402          24 :     uint32 nBlockCount = GetBlockCount();
     403             : 
     404          24 :     uint32 nBlockSize = mpoBlockDir->GetBlockSize();
     405             : 
     406             :     // Check how many blocks are needed.
     407          24 :     uint32 nNeededBlocks =
     408          24 :         (uint32) ((nLayerSize + nBlockSize - 1) / nBlockSize);
     409             : 
     410             :     // Create new blocks.
     411          24 :     if (nNeededBlocks > nBlockCount)
     412             :     {
     413          16 :         uint32 nNewBlocks = nNeededBlocks - nBlockCount;
     414             : 
     415          16 :         PushBlocks(mpoBlockDir->CreateNewBlocks(nNewBlocks));
     416             :     }
     417             :     // Free blocks.
     418           8 :     else if (nNeededBlocks < nBlockCount)
     419             :     {
     420           0 :         uint32 nFreeBlocks = nBlockCount - nNeededBlocks;
     421             : 
     422           0 :         mpoBlockDir->AddFreeBlocks(PopBlocks(nFreeBlocks));
     423             :     }
     424             : 
     425          24 :     _SetLayerSize(nLayerSize);
     426             : }
     427             : 
     428             : /************************************************************************/
     429             : /*                               PushBlocks()                           */
     430             : /************************************************************************/
     431             : 
     432             : /**
     433             :  * Pushes the specified block list at the end of the layer's block list.
     434             :  *
     435             :  * @param oBlockList The block list to add.
     436             :  */
     437          24 : void BlockLayer::PushBlocks(const BlockInfoList & oBlockList)
     438             : {
     439          24 :     uint32 nBlockCount = GetBlockCount();
     440             : 
     441          24 :     if (nBlockCount != moBlockList.size())
     442             :     {
     443           0 :         mpoBlockDir->ReadLayerBlocks(mnLayer);
     444             : 
     445           0 :         if (moBlockList.size() != nBlockCount)
     446           0 :             ThrowPCIDSKException("Corrupted block directory.");
     447             :     }
     448             : 
     449             :     try
     450             :     {
     451          24 :         moBlockList.resize(nBlockCount + oBlockList.size());
     452             :     }
     453           0 :     catch (const std::exception & ex)
     454             :     {
     455           0 :         return ThrowPCIDSKException("Out of memory in BlockLayer::PushBlocks(): %s", ex.what());
     456             :     }
     457             : 
     458         168 :     for (size_t iBlock = 0; iBlock < oBlockList.size(); iBlock++)
     459         144 :         moBlockList[nBlockCount + iBlock] = oBlockList[iBlock];
     460             : 
     461          24 :     _SetBlockCount((uint32) moBlockList.size());
     462             : }
     463             : 
     464             : /************************************************************************/
     465             : /*                               PopBlocks()                            */
     466             : /************************************************************************/
     467             : 
     468             : /**
     469             :  * Pops the specified number of blocks from the end of the layer's block list.
     470             :  *
     471             :  * @param nBlockCount The number of blocks to remove.
     472             :  *
     473             :  * @return The removed block list.
     474             :  */
     475          16 : BlockInfoList BlockLayer::PopBlocks(uint32 nBlockCount)
     476             : {
     477          16 :     uint32 nCurrentBlockCount = GetBlockCount();
     478             : 
     479          16 :     if (nCurrentBlockCount != moBlockList.size())
     480             :     {
     481           0 :         mpoBlockDir->ReadLayerBlocks(mnLayer);
     482             : 
     483           0 :         if (moBlockList.size() != nCurrentBlockCount)
     484           0 :             ThrowPCIDSKException("Corrupted block directory.");
     485             :     }
     486             : 
     487             :     uint32 nRemainingBlockCount;
     488             : 
     489          16 :     BlockInfoList oRemovedBlocks;
     490             : 
     491          16 :     if (nBlockCount < nCurrentBlockCount)
     492             :     {
     493          16 :         nRemainingBlockCount = nCurrentBlockCount - nBlockCount;
     494             : 
     495             :         oRemovedBlocks =
     496          64 :             BlockInfoList(moBlockList.begin() + nRemainingBlockCount,
     497          48 :                           moBlockList.begin() + nCurrentBlockCount);
     498             :     }
     499             :     else
     500             :     {
     501           0 :         nRemainingBlockCount = 0;
     502             : 
     503           0 :         oRemovedBlocks = moBlockList;
     504             :     }
     505             : 
     506             :     try
     507             :     {
     508          16 :         moBlockList.resize(nRemainingBlockCount);
     509             :     }
     510           0 :     catch (const std::exception & ex)
     511             :     {
     512           0 :         ThrowPCIDSKException("Out of memory in BlockLayer::PopBlocks(): %s", ex.what());
     513             :     }
     514             : 
     515          16 :     _SetBlockCount(nRemainingBlockCount);
     516             : 
     517          16 :     return oRemovedBlocks;
     518             : }

Generated by: LCOV version 1.14