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

Generated by: LCOV version 1.14