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