LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/blockdir - binarytiledir.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 206 253 81.4 %
Date: 2024-11-21 22:18:42 Functions: 14 16 87.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/binarytiledir.h"
      13             : #include "blockdir/binarytilelayer.h"
      14             : #include "blockdir/blockfile.h"
      15             : #include "core/pcidsk_utils.h"
      16             : #include "core/pcidsk_scanint.h"
      17             : #include "pcidsk_exception.h"
      18             : #include "pcidsk_buffer.h"
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : #include <cstdio>
      22             : #include <algorithm>
      23             : #include <limits>
      24             : 
      25             : using namespace PCIDSK;
      26             : 
      27             : #define BINARY_TILEDIR_VERSION 1
      28             : 
      29             : /************************************************************************/
      30             : /*                         GetOptimizedBlockSize()                      */
      31             : /************************************************************************/
      32          12 : uint32 BinaryTileDir::GetOptimizedBlockSize(BlockFile * poFile)
      33             : {
      34          12 :     std::string oFileOptions = poFile->GetFileOptions();
      35             : 
      36         132 :     for (char & chIter : oFileOptions)
      37         120 :         chIter = (char) toupper((uchar) chIter);
      38             : 
      39          12 :     uint32 nTileSize = PCIDSK_DEFAULT_TILE_SIZE;
      40             : 
      41          12 :     size_t nPos = oFileOptions.find("TILED");
      42             : 
      43          12 :     if (nPos != std::string::npos)
      44          10 :         nTileSize = atoi(oFileOptions.substr(nPos + 5).c_str());
      45             : 
      46             :     // Setup the block size.
      47          12 :     uint32 nBlockSize = nTileSize * nTileSize;
      48             : 
      49             :     // The minimum block size is 8K.
      50          12 :     if (nBlockSize < 8192)
      51          10 :         nBlockSize = 8192;
      52             : 
      53             :     // The block size should be a multiple of 4K.
      54          12 :     if (nBlockSize % 4096 != 0)
      55           0 :         nBlockSize = (nBlockSize / 4096 + 1) * 4096;
      56             : 
      57          24 :     return nBlockSize;
      58             : }
      59             : 
      60             : /************************************************************************/
      61             : /*                          GetOptimizedDirSize()                       */
      62             : /************************************************************************/
      63           6 : size_t BinaryTileDir::GetOptimizedDirSize(BlockFile * poFile)
      64             : {
      65           6 :     std::string oFileOptions = poFile->GetFileOptions();
      66             : 
      67          66 :     for (char & chIter : oFileOptions)
      68          60 :         chIter = (char) toupper((uchar) chIter);
      69             : 
      70             :     // Compute the ratio.
      71           6 :     double dfRatio = 0.0;
      72             : 
      73             :     // The 35% is for the overviews.
      74           6 :     if (oFileOptions.find("TILED") != std::string::npos)
      75           5 :         dfRatio = 1.35;
      76             :     else
      77           1 :         dfRatio = 0.35;
      78             : 
      79             :     // The 5% is for the new blocks.
      80           6 :     dfRatio += 0.05;
      81             : 
      82           6 :     double dfFileSize = poFile->GetImageFileSize() * dfRatio;
      83             : 
      84           6 :     uint32 nBlockSize = GetOptimizedBlockSize(poFile);
      85             : 
      86           6 :     uint64 nBlockCount = (uint64) (dfFileSize / nBlockSize);
      87             : 
      88           6 :     uint64 nLayerCount = poFile->GetChannels();
      89             : 
      90             :     // The 12 is for the overviews.
      91           6 :     nLayerCount *= 12;
      92             : 
      93           6 :     uint64 nDirSize = 512 +
      94           6 :         (nBlockCount * sizeof(BlockInfo) +
      95           6 :          nLayerCount * sizeof(BlockLayerInfo) +
      96           6 :          nLayerCount * sizeof(TileLayerInfo) +
      97             :          sizeof(BlockLayerInfo));
      98             : 
      99             : #if SIZEOF_VOIDP < 8
     100             :     if (nDirSize > std::numeric_limits<size_t>::max())
     101             :         return ThrowPCIDSKException(0, "Unable to create extremely large file on 32-bit system.");
     102             : #endif
     103             : 
     104          12 :     return static_cast<size_t>(nDirSize);
     105             : }
     106             : 
     107             : /************************************************************************/
     108             : /*                             BinaryTileDir()                          */
     109             : /************************************************************************/
     110             : 
     111             : /**
     112             :  * Constructor.
     113             :  *
     114             :  * @param poFile The associated file object.
     115             :  * @param nSegment The segment of the block directory.
     116             :  */
     117          13 : BinaryTileDir::BinaryTileDir(BlockFile * poFile, uint16 nSegment)
     118          13 :     : BlockTileDir(poFile, nSegment)
     119             : {
     120             :     // Read the block directory header from disk.
     121             :     uint8 abyHeader[512];
     122             : 
     123          13 :     mpoFile->ReadFromSegment(mnSegment, abyHeader, 0, 512);
     124             : 
     125             :     // Get the version of the block directory.
     126          13 :     mnVersion = ScanInt3(abyHeader + 7);
     127             : 
     128             :     // Read the block directory info from the header.
     129          13 :     memcpy(&msBlockDir, abyHeader + 10, sizeof(BlockDirInfo));
     130             : 
     131             :     // The third last byte is for the endianness.
     132          13 :     mchEndianness = abyHeader[512 - 3];
     133          13 :     mbNeedsSwap = (mchEndianness == 'B' ?
     134          13 :                    !BigEndianSystem() : BigEndianSystem());
     135             : 
     136             :     // The last 2 bytes of the header are for the validity info.
     137          13 :     memcpy(&mnValidInfo, abyHeader + 512 - 2, 2);
     138             : 
     139          13 :     SwapBlockDir(&msBlockDir);
     140          13 :     SwapValue(&mnValidInfo);
     141             : 
     142             :     // Check that we support the tile directory version.
     143          13 :     if (mnVersion > BINARY_TILEDIR_VERSION)
     144             :     {
     145           0 :         ThrowPCIDSKException("The tile directory version %d is not supported.", mnVersion);
     146           0 :         return;
     147             :     }
     148             : 
     149             :     // Make sure the block size is a multiple of 4096.
     150          13 :     if (msBlockDir.nBlockSize == 0 || msBlockDir.nBlockSize % 4096 != 0)
     151             :     {
     152           0 :         ThrowPCIDSKException("The tile directory is corrupted.");
     153           0 :         return;
     154             :     }
     155             : 
     156             :     // The size of the block layers.
     157          13 :     uint64 nReadSize =
     158          13 :         (static_cast<uint64>(msBlockDir.nLayerCount) * sizeof(BlockLayerInfo) +
     159             :          static_cast<uint64>(msBlockDir.nLayerCount) * sizeof(TileLayerInfo) +
     160             :          sizeof(BlockLayerInfo));
     161             : 
     162          13 :     if (mpoFile->IsCorruptedSegment(mnSegment, 512, nReadSize))
     163             :     {
     164           0 :         ThrowPCIDSKException("The tile directory is corrupted.");
     165           0 :         return;
     166             :     }
     167             : 
     168             : #if SIZEOF_VOIDP < 8
     169             :     if (nReadSize > std::numeric_limits<size_t>::max())
     170             :     {
     171             :         ThrowPCIDSKException("Unable to open extremely large file on 32-bit system.");
     172             :         return;
     173             :     }
     174             : #endif
     175             : 
     176             :     // Initialize the block layers.
     177             :     try
     178             :     {
     179          13 :         moLayerInfoList.resize(msBlockDir.nLayerCount);
     180          13 :         moTileLayerInfoList.resize(msBlockDir.nLayerCount);
     181             : 
     182          13 :         moLayerList.resize(msBlockDir.nLayerCount);
     183             :     }
     184           0 :     catch (const std::exception & ex)
     185             :     {
     186           0 :         ThrowPCIDSKException("Out of memory in BinaryTileDir(): %s", ex.what());
     187           0 :         return;
     188             :     }
     189             : 
     190          28 :     for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
     191             :     {
     192          15 :         moLayerInfoList[iLayer] = new BlockLayerInfo;
     193          15 :         moTileLayerInfoList[iLayer] = new TileLayerInfo;
     194             : 
     195          15 :         moLayerList[iLayer] = new BinaryTileLayer(this, iLayer,
     196          15 :                                                   moLayerInfoList[iLayer],
     197          15 :                                                   moTileLayerInfoList[iLayer]);
     198             :     }
     199             : 
     200             :     // Read the block layers from disk.
     201          13 :     uint8 * pabyBlockDir = (uint8 *) malloc(static_cast<size_t>(nReadSize));
     202             : 
     203          13 :     if (pabyBlockDir == nullptr)
     204             :     {
     205           0 :         ThrowPCIDSKException("Out of memory in BinaryTileDir().");
     206           0 :         return;
     207             :     }
     208             : 
     209          13 :     PCIDSKBuffer oBlockDirAutoPtr;
     210          13 :     oBlockDirAutoPtr.buffer = (char *) pabyBlockDir;
     211             : 
     212          13 :     uint8 * pabyBlockDirIter = pabyBlockDir;
     213             : 
     214          13 :     mpoFile->ReadFromSegment(mnSegment, pabyBlockDir, 512, nReadSize);
     215             : 
     216             :     // Read the block layers.
     217             :     size_t nSize;
     218             : 
     219          28 :     for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
     220             :     {
     221          15 :         nSize = sizeof(BlockLayerInfo);
     222          15 :         SwapBlockLayer((BlockLayerInfo *) pabyBlockDirIter);
     223          15 :         memcpy(moLayerInfoList[iLayer], pabyBlockDirIter, nSize);
     224          15 :         pabyBlockDirIter += nSize;
     225             :     }
     226             : 
     227             :     // Read the tile layers.
     228          28 :     for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
     229             :     {
     230          15 :         nSize = sizeof(TileLayerInfo);
     231          15 :         SwapTileLayer((TileLayerInfo *) pabyBlockDirIter);
     232          15 :         memcpy(moTileLayerInfoList[iLayer], pabyBlockDirIter, nSize);
     233          15 :         pabyBlockDirIter += nSize;
     234             :     }
     235             : 
     236             :     // Read the free block layer.
     237          13 :     nSize = sizeof(BlockLayerInfo);
     238          13 :     SwapBlockLayer((BlockLayerInfo *) pabyBlockDirIter);
     239          13 :     memcpy(&msFreeBlockLayer, pabyBlockDirIter, nSize);
     240             : 
     241             :     // Check if any of the tile layers are corrupted.
     242          28 :     for (BlockLayer * poLayer : moLayerList)
     243             :     {
     244          15 :         BlockTileLayer * poTileLayer = dynamic_cast<BlockTileLayer *>(poLayer);
     245             : 
     246          15 :         if (poTileLayer == nullptr || poTileLayer->IsCorrupted())
     247             :         {
     248           0 :             ThrowPCIDSKException("The tile directory is corrupted.");
     249           0 :             return;
     250             :         }
     251             :     }
     252             : }
     253             : 
     254             : /************************************************************************/
     255             : /*                             BinaryTileDir()                          */
     256             : /************************************************************************/
     257             : 
     258             : /**
     259             :  * Constructor.
     260             :  *
     261             :  * @param poFile The associated file object.
     262             :  * @param nSegment The segment of the block directory.
     263             :  * @param nBlockSize The size of the blocks.
     264             :  */
     265           6 : BinaryTileDir::BinaryTileDir(BlockFile * poFile, uint16 nSegment,
     266           6 :                              uint32 nBlockSize)
     267           6 :     : BlockTileDir(poFile, nSegment, BINARY_TILEDIR_VERSION)
     268             : {
     269             :     // Initialize the directory info.
     270           6 :     msBlockDir.nLayerCount = 0;
     271           6 :     msBlockDir.nBlockSize = nBlockSize;
     272             : 
     273             :     // Create an empty free block layer.
     274           6 :     msFreeBlockLayer.nLayerType = BLTFree;
     275           6 :     msFreeBlockLayer.nStartBlock = INVALID_BLOCK;
     276           6 :     msFreeBlockLayer.nBlockCount = 0;
     277           6 :     msFreeBlockLayer.nLayerSize = 0;
     278             : 
     279           6 :     mpoFreeBlockLayer = new BinaryTileLayer(this, INVALID_LAYER,
     280           6 :                                             &msFreeBlockLayer, nullptr);
     281           6 : }
     282             : 
     283             : /************************************************************************/
     284             : /*                              GetTileLayer()                          */
     285             : /************************************************************************/
     286             : 
     287             : /**
     288             :  * Gets the block layer at the specified index.
     289             :  *
     290             :  * @param iLayer The index of the block layer.
     291             :  *
     292             :  * @return The block layer at the specified index.
     293             :  */
     294           6 : BinaryTileLayer * BinaryTileDir::GetTileLayer(uint32 iLayer)
     295             : {
     296           6 :     return (BinaryTileLayer *) BlockDir::GetLayer(iLayer);
     297             : }
     298             : 
     299             : /************************************************************************/
     300             : /*                              GetBlockSize()                          */
     301             : /************************************************************************/
     302             : 
     303             : /**
     304             :  * Gets the block size of the block directory.
     305             :  *
     306             :  * @return The block size of the block directory.
     307             :  */
     308         159 : uint32 BinaryTileDir::GetBlockSize(void) const
     309             : {
     310         159 :     return msBlockDir.nBlockSize;
     311             : }
     312             : 
     313             : /************************************************************************/
     314             : /*                               GetDirSize()                           */
     315             : /************************************************************************/
     316             : 
     317             : /**
     318             :  * Gets the size in bytes of the block tile directory.
     319             :  *
     320             :  * @return The size in bytes of the block tile directory.
     321             :  */
     322           6 : size_t BinaryTileDir::GetDirSize(void) const
     323             : {
     324           6 :     uint64 nDirSize = 0;
     325             : 
     326             :     // Add the size of the header.
     327           6 :     nDirSize += 512;
     328             : 
     329             :     // Add the size of the block layers.
     330           6 :     nDirSize += static_cast<uint64>(moLayerInfoList.size()) * sizeof(BlockLayerInfo);
     331             : 
     332             :     // Add the size of the tile layers.
     333           6 :     nDirSize += static_cast<uint64>(moTileLayerInfoList.size()) * sizeof(TileLayerInfo);
     334             : 
     335             :     // Add the size of the free block layer.
     336           6 :     nDirSize += sizeof(BlockLayerInfo);
     337             : 
     338             :     // Add the size of the blocks.
     339          12 :     for (size_t iLayer = 0; iLayer < moLayerInfoList.size(); iLayer++)
     340             :     {
     341           6 :         const BlockLayerInfo * psLayer = moLayerInfoList[iLayer];
     342             : 
     343           6 :         nDirSize += static_cast<uint64>(psLayer->nBlockCount) * sizeof(BlockInfo);
     344             :     }
     345             : 
     346             :     // Add the size of the free blocks.
     347           6 :     nDirSize += static_cast<uint64>(msFreeBlockLayer.nBlockCount) * sizeof(BlockInfo);
     348             : 
     349             : #if SIZEOF_VOIDP < 8
     350             :     if (nDirSize > std::numeric_limits<size_t>::max())
     351             :         return ThrowPCIDSKException(0, "Unable to open extremely large file on 32-bit system or the tile directory is corrupted.");
     352             : #endif
     353           6 :     return static_cast<size_t>(nDirSize);
     354             : }
     355             : 
     356             : /************************************************************************/
     357             : /*                             InitBlockList()                          */
     358             : /************************************************************************/
     359           7 : void BinaryTileDir::InitBlockList(BinaryTileLayer * poLayer)
     360             : {
     361           7 :     if (!poLayer || !poLayer->mpsBlockLayer ||
     362           7 :         poLayer->mpsBlockLayer->nBlockCount == 0)
     363             :     {
     364           0 :         if (poLayer)
     365             :         {
     366           0 :             BlockInfoList oNewBlockList;
     367           0 :             std::swap(poLayer->moBlockList, oNewBlockList);
     368             :         }
     369           0 :         return;
     370             :     }
     371             : 
     372           7 :     BlockLayerInfo * psLayer = poLayer->mpsBlockLayer;
     373             : 
     374             :     // The offset of the blocks.
     375           7 :     uint64 nOffset = (static_cast<uint64>(psLayer->nStartBlock) * sizeof(BlockInfo) +
     376           7 :                       static_cast<uint64>(msBlockDir.nLayerCount) * sizeof(BlockLayerInfo) +
     377           7 :                       static_cast<uint64>(msBlockDir.nLayerCount) * sizeof(TileLayerInfo) +
     378             :                       sizeof(BlockLayerInfo));
     379             : 
     380             :     // The size of the blocks.
     381           7 :     uint64 nReadSize = static_cast<uint64>(psLayer->nBlockCount) * sizeof(BlockInfo);
     382             : 
     383           7 :     if (mpoFile->IsCorruptedSegment(mnSegment, 512 + nOffset, nReadSize))
     384           0 :         return ThrowPCIDSKException("The tile directory is corrupted.");
     385             : 
     386             : #if SIZEOF_VOIDP < 8
     387             :     if (nReadSize > std::numeric_limits<size_t>::max())
     388             :         return ThrowPCIDSKException("Unable to open extremely large file on 32-bit system.");
     389             : #endif
     390             : 
     391             :     // Read the blocks from disk.
     392           7 :     uint8 * pabyBlockDir = (uint8 *) malloc(static_cast<size_t>(nReadSize));
     393             : 
     394           7 :     if (pabyBlockDir == nullptr)
     395           0 :         return ThrowPCIDSKException("Out of memory in BinaryTileDir::InitBlockList().");
     396             : 
     397           7 :     PCIDSKBuffer oBlockDirAutoPtr;
     398           7 :     oBlockDirAutoPtr.buffer = (char *) pabyBlockDir;
     399             : 
     400           7 :     mpoFile->ReadFromSegment(mnSegment, pabyBlockDir, 512 + nOffset, nReadSize);
     401             : 
     402             :     // Setup the block list of the block layer.
     403             :     try
     404             :     {
     405           7 :         poLayer->moBlockList.resize(psLayer->nBlockCount);
     406             :     }
     407           0 :     catch (const std::exception & ex)
     408             :     {
     409           0 :         return ThrowPCIDSKException("Out of memory in BinaryTileDir::InitBlockList(): %s", ex.what());
     410             :     }
     411             : 
     412           7 :     SwapBlock((BlockInfo *) pabyBlockDir, psLayer->nBlockCount);
     413             : 
     414           7 :     memcpy(&poLayer->moBlockList.front(), pabyBlockDir,
     415           7 :            psLayer->nBlockCount * sizeof(BlockInfo));
     416             : }
     417             : 
     418             : /************************************************************************/
     419             : /*                            ReadLayerBlocks()                         */
     420             : /************************************************************************/
     421           7 : void BinaryTileDir::ReadLayerBlocks(uint32 iLayer)
     422             : {
     423           7 :     InitBlockList((BinaryTileLayer *) moLayerList[iLayer]);
     424           7 : }
     425             : 
     426             : /************************************************************************/
     427             : /*                           ReadFreeBlockLayer()                       */
     428             : /************************************************************************/
     429           0 : void BinaryTileDir::ReadFreeBlockLayer(void)
     430             : {
     431           0 :     mpoFreeBlockLayer = new BinaryTileLayer(this, INVALID_LAYER,
     432           0 :                                             &msFreeBlockLayer, nullptr);
     433             : 
     434           0 :     InitBlockList((BinaryTileLayer *) mpoFreeBlockLayer);
     435           0 : }
     436             : 
     437             : /************************************************************************/
     438             : /*                                WriteDir()                            */
     439             : /************************************************************************/
     440           6 : void BinaryTileDir::WriteDir(void)
     441             : {
     442             :     // Make sure all the layer's block list are valid.
     443           6 :     if (mbOnDisk)
     444             :     {
     445           0 :         for (size_t iLayer = 0; iLayer < moLayerList.size(); iLayer++)
     446             :         {
     447           0 :             BinaryTileLayer * poLayer = GetTileLayer((uint32) iLayer);
     448             : 
     449           0 :             if (poLayer->moBlockList.size() != poLayer->GetBlockCount())
     450           0 :                 InitBlockList(poLayer);
     451             :         }
     452             :     }
     453             : 
     454             :     // What is the size of the block directory.
     455           6 :     size_t nDirSize = GetDirSize();
     456             : 
     457             :     // If we are resizing the segment, resize it to the optimized size.
     458           6 :     if (nDirSize > mpoFile->GetSegmentSize(mnSegment))
     459           0 :         nDirSize = std::max(nDirSize, GetOptimizedDirSize(mpoFile));
     460             : 
     461             :     // Write the block directory to disk.
     462           6 :     char * pabyBlockDir = (char *) malloc(nDirSize + 1); // +1 for '\0'.
     463             : 
     464           6 :     if (pabyBlockDir == nullptr)
     465           0 :         return ThrowPCIDSKException("Out of memory in BinaryTileDir::WriteDir().");
     466             : 
     467          12 :     PCIDSKBuffer oBlockDirAutoPtr;
     468           6 :     oBlockDirAutoPtr.buffer = pabyBlockDir;
     469             : 
     470           6 :     char * pabyBlockDirIter = pabyBlockDir;
     471             : 
     472             :     // Initialize the header.
     473           6 :     memset(pabyBlockDir, 0, 512);
     474             : 
     475             :     // The first 10 bytes are for the version.
     476           6 :     memcpy(pabyBlockDirIter, "VERSION", 7);
     477           6 :     snprintf(pabyBlockDirIter + 7, 9, "%3d", mnVersion);
     478           6 :     pabyBlockDirIter += 10;
     479             : 
     480             :     // Write the block directory info.
     481           6 :     msBlockDir.nLayerCount = (uint32) moLayerInfoList.size();
     482             : 
     483           6 :     size_t nSize = sizeof(BlockDirInfo);
     484           6 :     memcpy(pabyBlockDirIter, &msBlockDir, nSize);
     485           6 :     SwapBlockDir((BlockDirInfo *) pabyBlockDirIter);
     486             : 
     487             :     // The third last byte is for the endianness.
     488           6 :     pabyBlockDir[512 - 3] = mchEndianness;
     489             : 
     490             :     // The last 2 bytes of the header are for the validity info.
     491           6 :     uint16 nValidInfo = ++mnValidInfo;
     492           6 :     SwapValue(&nValidInfo);
     493           6 :     memcpy(pabyBlockDir + 512 - 2, &nValidInfo, 2);
     494             : 
     495             :     // The header is 512 bytes.
     496           6 :     pabyBlockDirIter = pabyBlockDir + 512;
     497             : 
     498             :     // Initialize the start block of the block layers.
     499           6 :     uint32 nStartBlock = 0;
     500             : 
     501          12 :     for (size_t iLayer = 0; iLayer < moLayerInfoList.size(); iLayer++)
     502             :     {
     503           6 :         BlockLayerInfo * psLayer = moLayerInfoList[iLayer];
     504             : 
     505           6 :         psLayer->nStartBlock = nStartBlock;
     506             : 
     507           6 :         nStartBlock += psLayer->nBlockCount;
     508             :     }
     509             : 
     510             :     // Write the block layers.
     511          12 :     for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
     512             :     {
     513           6 :         nSize = sizeof(BlockLayerInfo);
     514           6 :         memcpy(pabyBlockDirIter, moLayerInfoList[iLayer], nSize);
     515           6 :         SwapBlockLayer((BlockLayerInfo *) pabyBlockDirIter);
     516           6 :         pabyBlockDirIter += nSize;
     517             :     }
     518             : 
     519             :     // Write the tile layers.
     520          12 :     for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
     521             :     {
     522           6 :         nSize = sizeof(TileLayerInfo);
     523           6 :         memcpy(pabyBlockDirIter, moTileLayerInfoList[iLayer], nSize);
     524           6 :         SwapTileLayer((TileLayerInfo *) pabyBlockDirIter);
     525           6 :         pabyBlockDirIter += nSize;
     526             :     }
     527             : 
     528             :     // Initialize the start block of the free block layer.
     529           6 :     msFreeBlockLayer.nStartBlock = nStartBlock;
     530             : 
     531             :     // Write the free block layer.
     532           6 :     nSize = sizeof(BlockLayerInfo);
     533           6 :     memcpy(pabyBlockDirIter, &msFreeBlockLayer, nSize);
     534           6 :     SwapBlockLayer((BlockLayerInfo *) pabyBlockDirIter);
     535           6 :     pabyBlockDirIter += nSize;
     536             : 
     537             :     // Write the block info list.
     538          12 :     for (size_t iLayer = 0; iLayer < moLayerInfoList.size(); iLayer++)
     539             :     {
     540           6 :         BlockLayerInfo * psLayer = moLayerInfoList[iLayer];
     541             : 
     542           6 :         if (psLayer->nBlockCount == 0)
     543           0 :             continue;
     544             : 
     545           6 :         BinaryTileLayer * poLayer = GetTileLayer((uint32) iLayer);
     546             : 
     547           6 :         nSize = psLayer->nBlockCount * sizeof(BlockInfo);
     548           6 :         memcpy(pabyBlockDirIter, poLayer->GetBlockInfo(0), nSize);
     549           6 :         SwapBlock((BlockInfo *) pabyBlockDirIter, psLayer->nBlockCount);
     550           6 :         pabyBlockDirIter += nSize;
     551             :     }
     552             : 
     553             :     // Write the free block info list.
     554           6 :     if (msFreeBlockLayer.nBlockCount != 0)
     555             :     {
     556           6 :         BinaryTileLayer * poLayer = (BinaryTileLayer *) mpoFreeBlockLayer;
     557             : 
     558           6 :         nSize = msFreeBlockLayer.nBlockCount * sizeof(BlockInfo);
     559           6 :         memcpy(pabyBlockDirIter, poLayer->GetBlockInfo(0), nSize);
     560           6 :         SwapBlock((BlockInfo *) pabyBlockDirIter, msFreeBlockLayer.nBlockCount);
     561           6 :         pabyBlockDirIter += nSize;
     562             :     }
     563             : 
     564             :     // Initialize the remaining bytes so that Valgrind doesn't complain.
     565           6 :     size_t nRemainingBytes = pabyBlockDir + nDirSize - pabyBlockDirIter;
     566             : 
     567           6 :     if (nRemainingBytes)
     568           0 :         memset(pabyBlockDirIter, 0, nRemainingBytes);
     569             : 
     570             :     // Write the block directory to disk.
     571           6 :     mpoFile->WriteToSegment(mnSegment, pabyBlockDir, 0, nDirSize);
     572             : }
     573             : 
     574             : /************************************************************************/
     575             : /*                              _CreateLayer()                          */
     576             : /************************************************************************/
     577             : 
     578             : /**
     579             :  * Creates a block layer of the specified type at the specified index.
     580             :  *
     581             :  * @param nLayerType The type of the block layer to create.
     582             :  * @param iLayer The index of the block layer to create.
     583             :  *
     584             :  * @return The new block layer.
     585             :  */
     586           6 : BlockLayer * BinaryTileDir::_CreateLayer(uint16 nLayerType, uint32 iLayer)
     587             : {
     588           6 :     if (iLayer == moLayerInfoList.size())
     589             :     {
     590             :         try
     591             :         {
     592           6 :             moLayerInfoList.resize(moLayerInfoList.size() + 1);
     593           6 :             moTileLayerInfoList.resize(moLayerInfoList.size());
     594             :         }
     595           0 :         catch (const std::exception & ex)
     596             :         {
     597           0 :             return (BlockLayer *) ThrowPCIDSKExceptionPtr("Out of memory in BinaryTileDir::_CreateLayer(): %s", ex.what());
     598             :         }
     599             : 
     600           6 :         moLayerInfoList[iLayer] = new BlockLayerInfo;
     601           6 :         moTileLayerInfoList[iLayer] = new TileLayerInfo;
     602             :     }
     603             : 
     604             :     // Setup the block layer info.
     605           6 :     BlockLayerInfo * psBlockLayer = moLayerInfoList[iLayer];
     606             : 
     607           6 :     psBlockLayer->nLayerType = nLayerType;
     608           6 :     psBlockLayer->nBlockCount = 0;
     609           6 :     psBlockLayer->nLayerSize = 0;
     610             : 
     611             :     // Setup the tile layer info.
     612           6 :     TileLayerInfo * psTileLayer = moTileLayerInfoList[iLayer];
     613             : 
     614           6 :     memset(psTileLayer, 0, sizeof(TileLayerInfo));
     615             : 
     616           6 :     return new BinaryTileLayer(this, iLayer, psBlockLayer, psTileLayer);
     617             : }
     618             : 
     619             : /************************************************************************/
     620             : /*                              _DeleteLayer()                          */
     621             : /************************************************************************/
     622             : 
     623             : /**
     624             :  * Deletes the block layer with the specified index.
     625             :  *
     626             :  * @param iLayer The index of the block layer to delete.
     627             :  */
     628           0 : void BinaryTileDir::_DeleteLayer(uint32 iLayer)
     629             : {
     630             :     // Invalidate the block layer info.
     631           0 :     BlockLayerInfo * psBlockLayer = moLayerInfoList[iLayer];
     632             : 
     633           0 :     psBlockLayer->nLayerType = BLTDead;
     634           0 :     psBlockLayer->nBlockCount = 0;
     635           0 :     psBlockLayer->nLayerSize = 0;
     636             : 
     637             :     // Invalidate the tile layer info.
     638           0 :     TileLayerInfo * psTileLayer = moTileLayerInfoList[iLayer];
     639             : 
     640           0 :     memset(psTileLayer, 0, sizeof(TileLayerInfo));
     641           0 : }
     642             : 
     643             : /************************************************************************/
     644             : /*                           GetDataSegmentName()                       */
     645             : /************************************************************************/
     646           6 : std::string BinaryTileDir::GetDataSegmentName(void) const
     647             : {
     648           6 :     return "TileData";
     649             : }
     650             : 
     651             : /************************************************************************/
     652             : /*                           GetDataSegmentDesc()                       */
     653             : /************************************************************************/
     654           6 : std::string BinaryTileDir::GetDataSegmentDesc(void) const
     655             : {
     656           6 :     return "Block Tile Data - Do not modify.";
     657             : }
     658             : 
     659             : /************************************************************************/
     660             : /*                              SwapBlockDir()                          */
     661             : /************************************************************************/
     662             : 
     663             : /**
     664             :  * Swaps the specified block directory info array.
     665             :  *
     666             :  * @param psBlockDir The block directory info array.
     667             :  */
     668          19 : void BinaryTileDir::SwapBlockDir(BlockDirInfo * psBlockDir)
     669             : {
     670          19 :     if (!mbNeedsSwap)
     671          19 :         return;
     672             : 
     673           0 :     SwapData(&psBlockDir->nLayerCount, 4, 1);
     674           0 :     SwapData(&psBlockDir->nBlockSize, 4, 1);
     675             : }

Generated by: LCOV version 1.14