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 : }
|