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

Generated by: LCOV version 1.14