Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/pcidsk/sdk/blockdir/binarytiledir.cpp
Line
Count
Source
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
43
#define BINARY_TILEDIR_VERSION 1
28
29
/************************************************************************/
30
/*                       GetOptimizedBlockSize()                        */
31
/************************************************************************/
32
uint32 BinaryTileDir::GetOptimizedBlockSize(BlockFile * poFile)
33
0
{
34
0
    std::string oFileOptions = poFile->GetFileOptions();
35
36
0
    for (char & chIter : oFileOptions)
37
0
        chIter = (char) toupper((uchar) chIter);
38
39
0
    uint32 nTileSize = PCIDSK_DEFAULT_TILE_SIZE;
40
41
0
    size_t nPos = oFileOptions.find("TILED");
42
43
0
    if (nPos != std::string::npos)
44
0
        nTileSize = atoi(oFileOptions.substr(nPos + 5).c_str());
45
46
    // Setup the block size.
47
0
    uint32 nBlockSize = nTileSize * nTileSize;
48
49
    // The minimum block size is 8K.
50
0
    if (nBlockSize < 8192)
51
0
        nBlockSize = 8192;
52
53
    // The block size should be a multiple of 4K.
54
0
    if (nBlockSize % 4096 != 0)
55
0
        nBlockSize = (nBlockSize / 4096 + 1) * 4096;
56
57
0
    return nBlockSize;
58
0
}
59
60
/************************************************************************/
61
/*                        GetOptimizedDirSize()                         */
62
/************************************************************************/
63
size_t BinaryTileDir::GetOptimizedDirSize(BlockFile * poFile)
64
0
{
65
0
    std::string oFileOptions = poFile->GetFileOptions();
66
67
0
    for (char & chIter : oFileOptions)
68
0
        chIter = (char) toupper((uchar) chIter);
69
70
    // Compute the ratio.
71
0
    double dfRatio = 0.0;
72
73
    // The 35% is for the overviews.
74
0
    if (oFileOptions.find("TILED") != std::string::npos)
75
0
        dfRatio = 1.35;
76
0
    else
77
0
        dfRatio = 0.35;
78
79
    // The 5% is for the new blocks.
80
0
    dfRatio += 0.05;
81
82
0
    double dfFileSize = poFile->GetImageFileSize() * dfRatio;
83
84
0
    uint32 nBlockSize = GetOptimizedBlockSize(poFile);
85
86
0
    uint64 nBlockCount = (uint64) (dfFileSize / nBlockSize);
87
88
0
    uint64 nLayerCount = poFile->GetChannels();
89
90
    // The 12 is for the overviews.
91
0
    nLayerCount *= 12;
92
93
0
    uint64 nDirSize = 512 +
94
0
        (nBlockCount * sizeof(BlockInfo) +
95
0
         nLayerCount * sizeof(BlockLayerInfo) +
96
0
         nLayerCount * sizeof(TileLayerInfo) +
97
0
         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
0
    return static_cast<size_t>(nDirSize);
105
0
}
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
BinaryTileDir::BinaryTileDir(BlockFile * poFile, uint16 nSegment)
118
43
    : BlockTileDir(poFile, nSegment)
119
43
{
120
    // Read the block directory header from disk.
121
43
    uint8 abyHeader[512];
122
123
43
    mpoFile->ReadFromSegment(mnSegment, abyHeader, 0, 512);
124
125
    // Get the version of the block directory.
126
43
    mnVersion = ScanInt3(abyHeader + 7);
127
128
    // Read the block directory info from the header.
129
43
    memcpy(&msBlockDir, abyHeader + 10, sizeof(BlockDirInfo));
130
131
    // The third last byte is for the endianness.
132
43
    mchEndianness = abyHeader[512 - 3];
133
43
    mbNeedsSwap = (mchEndianness == 'B' ?
134
43
                   !BigEndianSystem() : BigEndianSystem());
135
136
    // The last 2 bytes of the header are for the validity info.
137
43
    memcpy(&mnValidInfo, abyHeader + 512 - 2, 2);
138
139
43
    SwapBlockDir(&msBlockDir);
140
43
    SwapValue(&mnValidInfo);
141
142
    // Check that we support the tile directory version.
143
43
    if (mnVersion > BINARY_TILEDIR_VERSION)
144
1
    {
145
1
        ThrowPCIDSKException("The tile directory version %d is not supported.", mnVersion);
146
1
        return;
147
1
    }
148
149
    // Make sure the block size is a multiple of 4096.
150
42
    if (msBlockDir.nBlockSize == 0 || msBlockDir.nBlockSize % 4096 != 0)
151
3
    {
152
3
        ThrowPCIDSKException("The tile directory is corrupted.");
153
3
        return;
154
3
    }
155
156
    // The size of the block layers.
157
39
    uint64 nReadSize =
158
39
        (static_cast<uint64>(msBlockDir.nLayerCount) * sizeof(BlockLayerInfo) +
159
39
         static_cast<uint64>(msBlockDir.nLayerCount) * sizeof(TileLayerInfo) +
160
39
         sizeof(BlockLayerInfo));
161
162
39
    if (mpoFile->IsCorruptedSegment(mnSegment, 512, nReadSize))
163
0
    {
164
0
        ThrowPCIDSKException("The tile directory is corrupted.");
165
0
        return;
166
0
    }
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
39
    try
178
39
    {
179
39
        moLayerInfoList.resize(msBlockDir.nLayerCount);
180
39
        moTileLayerInfoList.resize(msBlockDir.nLayerCount);
181
182
39
        moLayerList.resize(msBlockDir.nLayerCount);
183
39
    }
184
39
    catch (const std::exception & ex)
185
39
    {
186
0
        ThrowPCIDSKException("Out of memory in BinaryTileDir(): %s", ex.what());
187
0
        return;
188
0
    }
189
190
117
    for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
191
78
    {
192
78
        moLayerInfoList[iLayer] = new BlockLayerInfo;
193
78
        moTileLayerInfoList[iLayer] = new TileLayerInfo;
194
195
78
        moLayerList[iLayer] = new BinaryTileLayer(this, iLayer,
196
78
                                                  moLayerInfoList[iLayer],
197
78
                                                  moTileLayerInfoList[iLayer]);
198
78
    }
199
200
    // Read the block layers from disk.
201
39
    uint8 * pabyBlockDir = (uint8 *) malloc(static_cast<size_t>(nReadSize));
202
203
39
    if (pabyBlockDir == nullptr)
204
0
    {
205
0
        ThrowPCIDSKException("Out of memory in BinaryTileDir().");
206
0
        return;
207
0
    }
208
209
39
    PCIDSKBuffer oBlockDirAutoPtr;
210
39
    oBlockDirAutoPtr.buffer = reinterpret_cast<char *>(pabyBlockDir);
211
212
39
    uint8 * pabyBlockDirIter = pabyBlockDir;
213
214
39
    mpoFile->ReadFromSegment(mnSegment, pabyBlockDir, 512, nReadSize);
215
216
    // Read the block layers.
217
39
    size_t nSize;
218
219
117
    for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
220
78
    {
221
78
        nSize = sizeof(BlockLayerInfo);
222
78
        SwapBlockLayer(reinterpret_cast<BlockLayerInfo *>(pabyBlockDirIter));
223
78
        memcpy(moLayerInfoList[iLayer], pabyBlockDirIter, nSize);
224
78
        pabyBlockDirIter += nSize;
225
78
    }
226
227
    // Read the tile layers.
228
117
    for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
229
78
    {
230
78
        nSize = sizeof(TileLayerInfo);
231
78
        SwapTileLayer(reinterpret_cast<TileLayerInfo *>(pabyBlockDirIter));
232
78
        memcpy(moTileLayerInfoList[iLayer], pabyBlockDirIter, nSize);
233
78
        pabyBlockDirIter += nSize;
234
78
    }
235
236
    // Read the free block layer.
237
39
    nSize = sizeof(BlockLayerInfo);
238
39
    SwapBlockLayer(reinterpret_cast<BlockLayerInfo *>(pabyBlockDirIter));
239
39
    memcpy(&msFreeBlockLayer, pabyBlockDirIter, nSize);
240
241
    // Check if any of the tile layers are corrupted.
242
39
    for (BlockLayer * poLayer : moLayerList)
243
76
    {
244
76
        BlockTileLayer * poTileLayer = dynamic_cast<BlockTileLayer *>(poLayer);
245
246
76
        if (poTileLayer == nullptr || poTileLayer->IsCorrupted())
247
2
        {
248
2
            ThrowPCIDSKException("The tile directory is corrupted.");
249
2
            return;
250
2
        }
251
76
    }
252
39
}
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
BinaryTileDir::BinaryTileDir(BlockFile * poFile, uint16 nSegment,
266
                             uint32 nBlockSize)
267
0
    : BlockTileDir(poFile, nSegment, BINARY_TILEDIR_VERSION)
268
0
{
269
    // Initialize the directory info.
270
0
    msBlockDir.nLayerCount = 0;
271
0
    msBlockDir.nBlockSize = nBlockSize;
272
273
    // Create an empty free block layer.
274
0
    msFreeBlockLayer.nLayerType = BLTFree;
275
0
    msFreeBlockLayer.nStartBlock = INVALID_BLOCK;
276
0
    msFreeBlockLayer.nBlockCount = 0;
277
0
    msFreeBlockLayer.nLayerSize = 0;
278
279
0
    mpoFreeBlockLayer = new BinaryTileLayer(this, INVALID_LAYER,
280
0
                                            &msFreeBlockLayer, nullptr);
281
0
}
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
BinaryTileLayer * BinaryTileDir::GetTileLayer(uint32 iLayer)
295
0
{
296
0
    return (BinaryTileLayer *) BlockDir::GetLayer(iLayer);
297
0
}
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
uint32 BinaryTileDir::GetBlockSize(void) const
309
752
{
310
752
    return msBlockDir.nBlockSize;
311
752
}
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
size_t BinaryTileDir::GetDirSize(void) const
323
0
{
324
0
    uint64 nDirSize = 0;
325
326
    // Add the size of the header.
327
0
    nDirSize += 512;
328
329
    // Add the size of the block layers.
330
0
    nDirSize += static_cast<uint64>(moLayerInfoList.size()) * sizeof(BlockLayerInfo);
331
332
    // Add the size of the tile layers.
333
0
    nDirSize += static_cast<uint64>(moTileLayerInfoList.size()) * sizeof(TileLayerInfo);
334
335
    // Add the size of the free block layer.
336
0
    nDirSize += sizeof(BlockLayerInfo);
337
338
    // Add the size of the blocks.
339
0
    for (size_t iLayer = 0; iLayer < moLayerInfoList.size(); iLayer++)
340
0
    {
341
0
        const BlockLayerInfo * psLayer = moLayerInfoList[iLayer];
342
343
0
        nDirSize += static_cast<uint64>(psLayer->nBlockCount) * sizeof(BlockInfo);
344
0
    }
345
346
    // Add the size of the free blocks.
347
0
    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
0
    return static_cast<size_t>(nDirSize);
354
0
}
355
356
/************************************************************************/
357
/*                           InitBlockList()                            */
358
/************************************************************************/
359
void BinaryTileDir::InitBlockList(BinaryTileLayer * poLayer)
360
36
{
361
36
    if (!poLayer || !poLayer->mpsBlockLayer ||
362
36
        poLayer->mpsBlockLayer->nBlockCount == 0)
363
0
    {
364
0
        if (poLayer)
365
0
        {
366
0
            BlockInfoList oNewBlockList;
367
0
            std::swap(poLayer->moBlockList, oNewBlockList);
368
0
        }
369
0
        return;
370
0
    }
371
372
36
    BlockLayerInfo * psLayer = poLayer->mpsBlockLayer;
373
374
    // The offset of the blocks.
375
36
    uint64 nOffset = (static_cast<uint64>(psLayer->nStartBlock) * sizeof(BlockInfo) +
376
36
                      static_cast<uint64>(msBlockDir.nLayerCount) * sizeof(BlockLayerInfo) +
377
36
                      static_cast<uint64>(msBlockDir.nLayerCount) * sizeof(TileLayerInfo) +
378
36
                      sizeof(BlockLayerInfo));
379
380
    // The size of the blocks.
381
36
    uint64 nReadSize = static_cast<uint64>(psLayer->nBlockCount) * sizeof(BlockInfo);
382
383
36
    if (mpoFile->IsCorruptedSegment(mnSegment, 512 + nOffset, nReadSize))
384
1
        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
35
    uint8 * pabyBlockDir = (uint8 *) malloc(static_cast<size_t>(nReadSize));
393
394
35
    if (pabyBlockDir == nullptr)
395
0
        return ThrowPCIDSKException("Out of memory in BinaryTileDir::InitBlockList().");
396
397
35
    PCIDSKBuffer oBlockDirAutoPtr;
398
35
    oBlockDirAutoPtr.buffer = reinterpret_cast<char *>(pabyBlockDir);
399
400
35
    mpoFile->ReadFromSegment(mnSegment, pabyBlockDir, 512 + nOffset, nReadSize);
401
402
    // Setup the block list of the block layer.
403
35
    try
404
35
    {
405
35
        poLayer->moBlockList.resize(psLayer->nBlockCount);
406
35
    }
407
35
    catch (const std::exception & ex)
408
35
    {
409
0
        return ThrowPCIDSKException("Out of memory in BinaryTileDir::InitBlockList(): %s", ex.what());
410
0
    }
411
412
35
    SwapBlock(reinterpret_cast<BlockInfo *>(pabyBlockDir), psLayer->nBlockCount);
413
414
35
    memcpy(&poLayer->moBlockList.front(), pabyBlockDir,
415
35
           psLayer->nBlockCount * sizeof(BlockInfo));
416
35
}
417
418
/************************************************************************/
419
/*                          ReadLayerBlocks()                           */
420
/************************************************************************/
421
void BinaryTileDir::ReadLayerBlocks(uint32 iLayer)
422
36
{
423
36
    InitBlockList((BinaryTileLayer *) moLayerList[iLayer]);
424
36
}
425
426
/************************************************************************/
427
/*                         ReadFreeBlockLayer()                         */
428
/************************************************************************/
429
void BinaryTileDir::ReadFreeBlockLayer(void)
430
0
{
431
0
    mpoFreeBlockLayer = new BinaryTileLayer(this, INVALID_LAYER,
432
0
                                            &msFreeBlockLayer, nullptr);
433
434
0
    InitBlockList(static_cast<BinaryTileLayer *>(mpoFreeBlockLayer));
435
0
}
436
437
/************************************************************************/
438
/*                              WriteDir()                              */
439
/************************************************************************/
440
void BinaryTileDir::WriteDir(void)
441
0
{
442
    // Make sure all the layer's block list are valid.
443
0
    if (mbOnDisk)
444
0
    {
445
0
        for (size_t iLayer = 0; iLayer < moLayerList.size(); iLayer++)
446
0
        {
447
0
            BinaryTileLayer * poLayer = GetTileLayer((uint32) iLayer);
448
449
0
            if (poLayer->moBlockList.size() != poLayer->GetBlockCount())
450
0
                InitBlockList(poLayer);
451
0
        }
452
0
    }
453
454
    // What is the size of the block directory.
455
0
    size_t nDirSize = GetDirSize();
456
457
    // If we are resizing the segment, resize it to the optimized size.
458
0
    if (nDirSize > mpoFile->GetSegmentSize(mnSegment))
459
0
        nDirSize = std::max(nDirSize, GetOptimizedDirSize(mpoFile));
460
461
    // Write the block directory to disk.
462
0
    char * pabyBlockDir = (char *) malloc(nDirSize + 1); // +1 for '\0'.
463
464
0
    if (pabyBlockDir == nullptr)
465
0
        return ThrowPCIDSKException("Out of memory in BinaryTileDir::WriteDir().");
466
467
0
    PCIDSKBuffer oBlockDirAutoPtr;
468
0
    oBlockDirAutoPtr.buffer = pabyBlockDir;
469
470
0
    char * pabyBlockDirIter = pabyBlockDir;
471
472
    // Initialize the header.
473
0
    memset(pabyBlockDir, 0, 512);
474
475
    // The first 10 bytes are for the version.
476
0
    memcpy(pabyBlockDirIter, "VERSION", 7);
477
0
    snprintf(pabyBlockDirIter + 7, 9, "%3d", mnVersion);
478
0
    pabyBlockDirIter += 10;
479
480
    // Write the block directory info.
481
0
    msBlockDir.nLayerCount = (uint32) moLayerInfoList.size();
482
483
0
    size_t nSize = sizeof(BlockDirInfo);
484
0
    memcpy(pabyBlockDirIter, &msBlockDir, nSize);
485
0
    SwapBlockDir(reinterpret_cast<BlockDirInfo *>(pabyBlockDirIter));
486
487
    // The third last byte is for the endianness.
488
0
    pabyBlockDir[512 - 3] = mchEndianness;
489
490
    // The last 2 bytes of the header are for the validity info.
491
0
    uint16 nValidInfo = ++mnValidInfo;
492
0
    SwapValue(&nValidInfo);
493
0
    memcpy(pabyBlockDir + 512 - 2, &nValidInfo, 2);
494
495
    // The header is 512 bytes.
496
0
    pabyBlockDirIter = pabyBlockDir + 512;
497
498
    // Initialize the start block of the block layers.
499
0
    uint32 nStartBlock = 0;
500
501
0
    for (size_t iLayer = 0; iLayer < moLayerInfoList.size(); iLayer++)
502
0
    {
503
0
        BlockLayerInfo * psLayer = moLayerInfoList[iLayer];
504
505
0
        psLayer->nStartBlock = nStartBlock;
506
507
0
        nStartBlock += psLayer->nBlockCount;
508
0
    }
509
510
    // Write the block layers.
511
0
    for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
512
0
    {
513
0
        nSize = sizeof(BlockLayerInfo);
514
0
        memcpy(pabyBlockDirIter, moLayerInfoList[iLayer], nSize);
515
0
        SwapBlockLayer(reinterpret_cast<BlockLayerInfo *>(pabyBlockDirIter));
516
0
        pabyBlockDirIter += nSize;
517
0
    }
518
519
    // Write the tile layers.
520
0
    for (uint32 iLayer = 0; iLayer < msBlockDir.nLayerCount; iLayer++)
521
0
    {
522
0
        nSize = sizeof(TileLayerInfo);
523
0
        memcpy(pabyBlockDirIter, moTileLayerInfoList[iLayer], nSize);
524
0
        SwapTileLayer(reinterpret_cast<TileLayerInfo *>(pabyBlockDirIter));
525
0
        pabyBlockDirIter += nSize;
526
0
    }
527
528
    // Initialize the start block of the free block layer.
529
0
    msFreeBlockLayer.nStartBlock = nStartBlock;
530
531
    // Write the free block layer.
532
0
    nSize = sizeof(BlockLayerInfo);
533
0
    memcpy(pabyBlockDirIter, &msFreeBlockLayer, nSize);
534
0
    SwapBlockLayer(reinterpret_cast<BlockLayerInfo *>(pabyBlockDirIter));
535
0
    pabyBlockDirIter += nSize;
536
537
    // Write the block info list.
538
0
    for (size_t iLayer = 0; iLayer < moLayerInfoList.size(); iLayer++)
539
0
    {
540
0
        BlockLayerInfo * psLayer = moLayerInfoList[iLayer];
541
542
0
        if (psLayer->nBlockCount == 0)
543
0
            continue;
544
545
0
        BinaryTileLayer * poLayer = GetTileLayer((uint32) iLayer);
546
547
0
        nSize = psLayer->nBlockCount * sizeof(BlockInfo);
548
0
        memcpy(pabyBlockDirIter, poLayer->GetBlockInfo(0), nSize);
549
0
        SwapBlock(reinterpret_cast<BlockInfo *>(pabyBlockDirIter), psLayer->nBlockCount);
550
0
        pabyBlockDirIter += nSize;
551
0
    }
552
553
    // Write the free block info list.
554
0
    if (msFreeBlockLayer.nBlockCount != 0)
555
0
    {
556
0
        BinaryTileLayer * poLayer = static_cast<BinaryTileLayer *>(mpoFreeBlockLayer);
557
558
0
        nSize = msFreeBlockLayer.nBlockCount * sizeof(BlockInfo);
559
0
        memcpy(pabyBlockDirIter, poLayer->GetBlockInfo(0), nSize);
560
0
        SwapBlock(reinterpret_cast<BlockInfo *>(pabyBlockDirIter), msFreeBlockLayer.nBlockCount);
561
0
        pabyBlockDirIter += nSize;
562
0
    }
563
564
    // Initialize the remaining bytes so that Valgrind doesn't complain.
565
0
    size_t nRemainingBytes = pabyBlockDir + nDirSize - pabyBlockDirIter;
566
567
0
    if (nRemainingBytes)
568
0
        memset(pabyBlockDirIter, 0, nRemainingBytes);
569
570
    // Write the block directory to disk.
571
0
    mpoFile->WriteToSegment(mnSegment, pabyBlockDir, 0, nDirSize);
572
0
}
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
BlockLayer * BinaryTileDir::_CreateLayer(uint16 nLayerType, uint32 iLayer)
587
0
{
588
0
    if (iLayer == moLayerInfoList.size())
589
0
    {
590
0
        try
591
0
        {
592
0
            moLayerInfoList.resize(moLayerInfoList.size() + 1);
593
0
            moTileLayerInfoList.resize(moLayerInfoList.size());
594
0
        }
595
0
        catch (const std::exception & ex)
596
0
        {
597
0
            return (BlockLayer *) ThrowPCIDSKExceptionPtr("Out of memory in BinaryTileDir::_CreateLayer(): %s", ex.what());
598
0
        }
599
600
0
        moLayerInfoList[iLayer] = new BlockLayerInfo;
601
0
        moTileLayerInfoList[iLayer] = new TileLayerInfo;
602
0
    }
603
604
    // Setup the block layer info.
605
0
    BlockLayerInfo * psBlockLayer = moLayerInfoList[iLayer];
606
607
0
    psBlockLayer->nLayerType = nLayerType;
608
0
    psBlockLayer->nBlockCount = 0;
609
0
    psBlockLayer->nLayerSize = 0;
610
611
    // Setup the tile layer info.
612
0
    TileLayerInfo * psTileLayer = moTileLayerInfoList[iLayer];
613
614
0
    memset(psTileLayer, 0, sizeof(TileLayerInfo));
615
616
0
    return new BinaryTileLayer(this, iLayer, psBlockLayer, psTileLayer);
617
0
}
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
void BinaryTileDir::_DeleteLayer(uint32 iLayer)
629
0
{
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
std::string BinaryTileDir::GetDataSegmentName(void) const
647
0
{
648
0
    return "TileData";
649
0
}
650
651
/************************************************************************/
652
/*                         GetDataSegmentDesc()                         */
653
/************************************************************************/
654
std::string BinaryTileDir::GetDataSegmentDesc(void) const
655
0
{
656
0
    return "Block Tile Data - Do not modify.";
657
0
}
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
void BinaryTileDir::SwapBlockDir(BlockDirInfo * psBlockDir)
669
43
{
670
43
    if (!mbNeedsSwap)
671
43
        return;
672
673
0
    SwapData(&psBlockDir->nLayerCount, 4, 1);
674
0
    SwapData(&psBlockDir->nBlockSize, 4, 1);
675
0
}