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/blocktilelayer.h"
13 : #include "blockdir/blockdir.h"
14 : #include "blockdir/blockfile.h"
15 : #include "blockdir/asciitiledir.h"
16 : #include "blockdir/binarytiledir.h"
17 : #include "core/mutexholder.h"
18 : #include "core/pcidsk_utils.h"
19 : #include "pcidsk_types.h"
20 : #include "pcidsk_exception.h"
21 : #include <cstdlib>
22 : #include <cstring>
23 : #include <cassert>
24 : #include <algorithm>
25 : #include <limits>
26 :
27 : #ifdef PCIMAJORVERSION
28 : #include "raster/memcmp.hh"
29 : #include "raster/memset.hh"
30 : #endif
31 :
32 : namespace PCIDSK
33 : {
34 :
35 : /************************************************************************/
36 : /* BlockTileLayer() */
37 : /************************************************************************/
38 :
39 : /**
40 : * Constructor.
41 : *
42 : * @param poBlockDir The associated block directory.
43 : * @param nLayer The index of the block layer.
44 : * @param psBlockLayer The block layer info.
45 : * @param psTileLayer The tile layer info.
46 : */
47 49 : BlockTileLayer::BlockTileLayer(BlockDir * poBlockDir, uint32 nLayer,
48 : BlockLayerInfo * psBlockLayer,
49 49 : TileLayerInfo * psTileLayer)
50 : : BlockLayer(poBlockDir, nLayer),
51 : mpsBlockLayer(psBlockLayer),
52 : mpsTileLayer(psTileLayer),
53 49 : mbModified(false)
54 : {
55 49 : memset(mszDataType, 0, sizeof(mszDataType));
56 49 : memset(mszCompress, 0, sizeof(mszCompress));
57 :
58 49 : mpoTileListMutex = DefaultCreateMutex();
59 49 : }
60 :
61 : /************************************************************************/
62 : /* ~BlockTileLayer() */
63 : /************************************************************************/
64 :
65 : /**
66 : * Destructor.
67 : */
68 49 : BlockTileLayer::~BlockTileLayer(void)
69 : {
70 49 : delete mpoTileListMutex;
71 49 : }
72 :
73 : /************************************************************************/
74 : /* GetTileInfo() */
75 : /************************************************************************/
76 :
77 : /**
78 : * Gets the tile at the specified index.
79 : *
80 : * @param nCol The column of the tile.
81 : * @param nRow The row of the tile.
82 : *
83 : * @return The tile at the specified index.
84 : */
85 : BlockTileLayer::BlockTileInfo *
86 70 : BlockTileLayer::GetTileInfo(uint32 nCol, uint32 nRow)
87 : {
88 70 : if (!IsValid())
89 0 : return nullptr;
90 :
91 70 : uint32 nTilesPerRow = GetTilePerRow();
92 :
93 70 : uint32 iTile = nRow * nTilesPerRow + nCol;
94 :
95 70 : MutexHolder oLock(mpoTileListMutex);
96 :
97 70 : if (moTileList.empty())
98 12 : ReadTileList();
99 :
100 70 : return &moTileList.at(iTile);
101 : }
102 :
103 : /************************************************************************/
104 : /* Sync() */
105 : /************************************************************************/
106 :
107 : /**
108 : * Synchronizes the block tile layer to disk.
109 : */
110 50 : void BlockTileLayer::Sync(void)
111 : {
112 50 : if (!mbModified)
113 42 : return;
114 :
115 : try
116 : {
117 8 : if (!GetFile()->GetUpdatable())
118 0 : return;
119 : }
120 0 : catch (...)
121 : {
122 0 : return;
123 : }
124 :
125 8 : MutexHolder oLock(mpoTileListMutex);
126 :
127 8 : if (!mbModified)
128 0 : return;
129 :
130 8 : WriteTileList();
131 :
132 8 : mbModified = false;
133 : }
134 :
135 : /************************************************************************/
136 : /* IsCorrupted() */
137 : /************************************************************************/
138 28 : bool BlockTileLayer::IsCorrupted(void) const
139 : {
140 : // Dead layers have a tile size of 0, but it should be considered valid.
141 28 : if (GetLayerType() == BLTDead)
142 0 : return false;
143 :
144 : // The tile layer is corrupted when the image size is 0.
145 28 : if (GetXSize() == 0 || GetYSize() == 0)
146 0 : return true;
147 :
148 : uint64 nTileSize =
149 28 : static_cast<uint64>(GetTileXSize()) * GetTileYSize() * GetDataTypeSize();
150 :
151 28 : return nTileSize == 0 || nTileSize > std::numeric_limits<uint32>::max();
152 : }
153 :
154 : /************************************************************************/
155 : /* GetTileCount() */
156 : /************************************************************************/
157 :
158 : /**
159 : * Gets the number of tiles in the tile layer.
160 : *
161 : * @return The number of tiles in the tile layer.
162 : */
163 61 : uint32 BlockTileLayer::GetTileCount(void) const
164 : {
165 61 : return DIV_ROUND_UP(GetXSize(), GetTileXSize()) *
166 61 : DIV_ROUND_UP(GetYSize(), GetTileYSize());
167 : }
168 :
169 : /************************************************************************/
170 : /* GetTilePerRow() */
171 : /************************************************************************/
172 :
173 : /**
174 : * Gets the number of tiles per row in the tile layer.
175 : *
176 : * @return The number of tiles per row in the tile layer.
177 : */
178 107 : uint32 BlockTileLayer::GetTilePerRow(void) const
179 : {
180 107 : return DIV_ROUND_UP(GetXSize(), GetTileXSize());
181 : }
182 :
183 : /************************************************************************/
184 : /* GetTilePerCol() */
185 : /************************************************************************/
186 :
187 : /**
188 : * Gets the number of tiles per column in the tile layer.
189 : *
190 : * @return The number of tiles per column in the tile layer.
191 : */
192 0 : uint32 BlockTileLayer::GetTilePerCol(void) const
193 : {
194 0 : return DIV_ROUND_UP(GetYSize(), GetTileYSize());
195 : }
196 :
197 : /************************************************************************/
198 : /* GetTileSize() */
199 : /************************************************************************/
200 :
201 : /**
202 : * Gets the size in bytes of a tile.
203 : *
204 : * @return The size in bytes of a tile.
205 : */
206 45 : uint32 BlockTileLayer::GetTileSize(void) const
207 : {
208 45 : return GetTileXSize() * GetTileYSize() * GetDataTypeSize();
209 : }
210 :
211 : /************************************************************************/
212 : /* GetDataTypeSize() */
213 : /************************************************************************/
214 :
215 : /**
216 : * Gets the data type size in bytes.
217 : *
218 : * @return The data type size in bytes.
219 : */
220 73 : uint32 BlockTileLayer::GetDataTypeSize(void) const
221 : {
222 73 : return DataTypeSize(GetDataTypeFromName(GetDataType()));
223 : }
224 :
225 : /************************************************************************/
226 : /* IsTileValid() */
227 : /************************************************************************/
228 :
229 : /**
230 : * Checks if the specified tile is valid.
231 : *
232 : * @param nCol The column of the tile.
233 : * @param nRow The row of the tile.
234 : *
235 : * @return If the specified tile is valid.
236 : */
237 0 : bool BlockTileLayer::IsTileValid(uint32 nCol, uint32 nRow)
238 : {
239 0 : BlockTileInfo * psTile = GetTileInfo(nCol, nRow);
240 :
241 0 : return (psTile && psTile->nOffset != INVALID_OFFSET && psTile->nSize != 0 &&
242 0 : AreBlocksAllocated(psTile->nOffset, psTile->nSize));
243 : }
244 :
245 : /************************************************************************/
246 : /* GetTileDataSize() */
247 : /************************************************************************/
248 :
249 : /**
250 : * Gets the size in bytes of the specified tile.
251 : *
252 : * @param nCol The column of the tile.
253 : * @param nRow The row of the tile.
254 : *
255 : * @return The size in bytes of the specified tile.
256 : */
257 4 : uint32 BlockTileLayer::GetTileDataSize(uint32 nCol, uint32 nRow)
258 : {
259 4 : BlockTileInfo * psTile = GetTileInfo(nCol, nRow);
260 :
261 4 : return psTile ? psTile->nSize : 0;
262 : }
263 :
264 : /************************************************************************/
265 : /* WriteSparseTile() */
266 : /************************************************************************/
267 :
268 : /**
269 : * Writes the specified tile only if the data is sparse.
270 : *
271 : * @param pData The data of the tile.
272 : * @param nCol The column of the tile.
273 : * @param nRow The row of the tile.
274 : *
275 : * @return If the specified tile data is sparse.
276 : */
277 8 : bool BlockTileLayer::WriteSparseTile(const void * pData,
278 : uint32 nCol, uint32 nRow)
279 : {
280 8 : MutexHolder oLock(mpoTileListMutex);
281 :
282 8 : uint32 nValue = 0;
283 :
284 8 : bool bIsSparse = true;
285 :
286 8 : uint32 nTileSize = GetTileSize();
287 :
288 : // Check if we can use a sparse tile with a 4 byte value.
289 8 : if (dynamic_cast<BinaryTileDir *>(mpoBlockDir) && nTileSize % 4 == 0)
290 : {
291 6 : uint32 * pnIter = (uint32 *) pData;
292 :
293 6 : nValue = *pnIter;
294 :
295 : #ifdef PCIMAJORVERSION
296 : bIsSparse = raster::memcmp32(pnIter, nValue,
297 : nTileSize / sizeof(uint32));
298 : #else
299 6 : uint32 * pnEnd = pnIter + nTileSize / sizeof(uint32);
300 364 : for (; pnIter < pnEnd; ++pnIter)
301 : {
302 364 : if (*pnIter != nValue)
303 : {
304 6 : bIsSparse = false;
305 6 : break;
306 : }
307 : }
308 : #endif
309 : }
310 : // Check if we can use a sparse tile with a value of 0.
311 : else
312 : {
313 2 : nValue = 0;
314 :
315 : #ifdef PCIMAJORVERSION
316 : bIsSparse = raster::memcmp8((uchar *) pData, 0, nTileSize);
317 : #else
318 2 : uchar * pnIter = (uchar *) pData;
319 2 : uchar * pnEnd = pnIter + nTileSize;
320 718 : for (; pnIter < pnEnd; ++pnIter)
321 : {
322 718 : if (*pnIter != nValue)
323 : {
324 2 : bIsSparse = false;
325 2 : break;
326 : }
327 : }
328 : #endif
329 : }
330 :
331 : // If the tile data is sparse store the sparse value in the nSize member
332 : // of the BlockTileInfo structure.
333 8 : if (bIsSparse)
334 : {
335 0 : BlockTileInfo * psTile = GetTileInfo(nCol, nRow);
336 0 : if( psTile != nullptr ) // TODO: what if it is null
337 : {
338 : // Free the blocks used by the tile.
339 0 : if (psTile->nOffset != INVALID_OFFSET)
340 0 : FreeBlocks(psTile->nOffset, psTile->nSize);
341 :
342 0 : psTile->nOffset = INVALID_OFFSET;
343 :
344 0 : psTile->nSize = nValue;
345 :
346 0 : mbModified = true;
347 : }
348 : }
349 :
350 16 : return bIsSparse;
351 : }
352 :
353 : /************************************************************************/
354 : /* WriteTile() */
355 : /************************************************************************/
356 :
357 : /**
358 : * Writes the specified tile.
359 : *
360 : * @param pData The data of the tile.
361 : * @param nCol The column of the tile.
362 : * @param nRow The row of the tile.
363 : * @param nSize The size of the tile.
364 : */
365 8 : void BlockTileLayer::WriteTile(const void * pData,
366 : uint32 nCol, uint32 nRow, uint32 nSize)
367 : {
368 8 : MutexHolder oLock(mpoTileListMutex);
369 :
370 8 : if (!IsValid())
371 0 : return;
372 :
373 8 : BlockTileInfo * psTile = GetTileInfo(nCol, nRow);
374 :
375 8 : if (!psTile)
376 0 : return;
377 :
378 8 : if (nSize == 0)
379 4 : nSize = GetTileSize();
380 :
381 8 : if (psTile->nOffset == INVALID_OFFSET)
382 : {
383 8 : psTile->nOffset = GetLayerSize();
384 :
385 8 : psTile->nSize = nSize;
386 :
387 8 : mbModified = true;
388 : }
389 :
390 8 : if (psTile->nSize < nSize)
391 : {
392 0 : psTile->nOffset = GetLayerSize();
393 :
394 0 : psTile->nSize = nSize;
395 :
396 0 : mbModified = true;
397 : }
398 8 : else if (psTile->nSize > nSize)
399 : {
400 0 : psTile->nSize = nSize;
401 :
402 0 : mbModified = true;
403 : }
404 :
405 8 : WriteToLayer(pData, psTile->nOffset, psTile->nSize);
406 : }
407 :
408 : /************************************************************************/
409 : /* ReadSparseTile() */
410 : /************************************************************************/
411 :
412 : /**
413 : * Reads the specified tile only if the data is sparse.
414 : *
415 : * @param pData The data of the tile.
416 : * @param nCol The column of the tile.
417 : * @param nRow The row of the tile.
418 : *
419 : * @return If the specified tile data is sparse.
420 : */
421 29 : bool BlockTileLayer::ReadSparseTile(void * pData, uint32 nCol, uint32 nRow)
422 : {
423 29 : if (!IsValid())
424 0 : return false;
425 :
426 29 : BlockTileInfo * psTile = GetTileInfo(nCol, nRow);
427 :
428 29 : if (!psTile)
429 0 : return false;
430 :
431 29 : if (psTile->nOffset != INVALID_OFFSET)
432 29 : return false;
433 :
434 0 : uint32 nTileSize = GetTileSize();
435 :
436 : // Check if we can use a sparse tile with a 4 byte value.
437 0 : if (dynamic_cast<BinaryTileDir *>(mpoBlockDir) && nTileSize % 4 == 0)
438 : {
439 : #ifdef PCIMAJORVERSION
440 : raster::memset32((uint32 *) pData, psTile->nSize,
441 : nTileSize / sizeof(uint32));
442 : #else
443 0 : uint32 * pnIter = (uint32 *) pData;
444 0 : uint32 * pnEnd = pnIter + nTileSize / sizeof(uint32);
445 0 : for (; pnIter < pnEnd; ++pnIter)
446 0 : *pnIter = psTile->nSize;
447 : #endif
448 : }
449 : // Check if we can use a sparse tile with a value of 0.
450 : else
451 : {
452 0 : memset(pData, 0, nTileSize);
453 : }
454 :
455 0 : return true;
456 : }
457 :
458 : /************************************************************************/
459 : /* ReadTile() */
460 : /************************************************************************/
461 :
462 : /**
463 : * Reads the specified tile.
464 : *
465 : * @param pData The data of the tile.
466 : * @param nCol The column of the tile.
467 : * @param nRow The row of the tile.
468 : * @param nSize The buffer size.
469 : *
470 : * @return The size of the tile.
471 : */
472 29 : uint32 BlockTileLayer::ReadTile(void * pData, uint32 nCol, uint32 nRow, uint32 nSize)
473 : {
474 29 : if (!IsValid())
475 0 : return 0;
476 :
477 29 : BlockTileInfo * psTile = GetTileInfo(nCol, nRow);
478 :
479 29 : if (!psTile)
480 0 : return 0;
481 :
482 29 : if (psTile->nOffset == INVALID_OFFSET)
483 0 : return 0;
484 :
485 29 : if (psTile->nSize == 0)
486 0 : return 0;
487 :
488 29 : uint32 nReadSize = std::min(nSize, psTile->nSize);
489 :
490 : #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
491 29 : assert(psTile->nSize == nSize);
492 : #endif
493 :
494 29 : if (!ReadFromLayer(pData, psTile->nOffset, nReadSize))
495 0 : return 0;
496 :
497 29 : return nReadSize;
498 : }
499 :
500 : /************************************************************************/
501 : /* ReadPartialSparseTile() */
502 : /************************************************************************/
503 :
504 : /**
505 : * Reads the specified tile only if the data is sparse.
506 : *
507 : * @param pData The data of the tile.
508 : * @param nCol The column of the tile.
509 : * @param nRow The row of the tile.
510 : * @param nOffset The offset of the data.
511 : * @param nSize The size of the data.
512 : *
513 : * @return If the specified tile data is sparse.
514 : */
515 0 : bool BlockTileLayer::ReadPartialSparseTile(void * pData,
516 : uint32 nCol, uint32 nRow,
517 : uint32 nOffset, uint32 nSize)
518 : {
519 0 : if (!IsValid())
520 0 : return false;
521 :
522 0 : BlockTileInfo * psTile = GetTileInfo(nCol, nRow);
523 :
524 0 : if (!psTile)
525 0 : return false;
526 :
527 0 : if (psTile->nOffset != INVALID_OFFSET)
528 0 : return false;
529 :
530 0 : uint32 nTileSize = GetTileSize();
531 :
532 : // Check if we can use a sparse tile with a 4 byte value.
533 0 : if (dynamic_cast<BinaryTileDir *>(mpoBlockDir) && nTileSize % 4 == 0)
534 : {
535 0 : uint32 nValue = psTile->nSize;
536 :
537 : // We need to bitwise shift the value if the offset isn't aligned.
538 0 : uint32 nByteOffset = nOffset % 4;
539 :
540 0 : if (nByteOffset != 0)
541 : {
542 0 : uint32 nBitOffset = nByteOffset * 8;
543 :
544 0 : nValue = (nValue << nBitOffset) | (nValue >> (32 - nBitOffset));
545 : }
546 :
547 0 : uint32 nAlign = nSize / sizeof(uint32);
548 :
549 : #ifdef PCIMAJORVERSION
550 : raster::memset32((uint32 *) pData, nValue, nAlign);
551 : #else
552 0 : uint32 * pnIter = (uint32 *) pData;
553 0 : uint32 * pnEnd = pnIter + nAlign;
554 0 : for (; pnIter < pnEnd; ++pnIter)
555 0 : *pnIter = nValue;
556 : #endif
557 :
558 0 : uint32 nRemaining = nSize % 4;
559 :
560 0 : if (nRemaining != 0)
561 : {
562 0 : uchar * pbyIter = (uchar *) pData + nAlign * 4;
563 :
564 0 : do
565 : {
566 0 : nValue = (nValue << 8) | (nValue >> 24);
567 :
568 0 : *pbyIter++ = (uchar) nValue;
569 : }
570 0 : while (--nRemaining);
571 : }
572 : }
573 : // Check if we can use a sparse tile with a value of 0.
574 : else
575 : {
576 0 : memset(pData, 0, nSize);
577 : }
578 :
579 0 : return true;
580 : }
581 :
582 : /************************************************************************/
583 : /* ReadPartialTile() */
584 : /************************************************************************/
585 :
586 : /**
587 : * Reads the specified tile.
588 : *
589 : * @param pData The data of the tile.
590 : * @param nCol The column of the tile.
591 : * @param nRow The row of the tile.
592 : * @param nOffset The offset of the data.
593 : * @param nSize The size of the data.
594 : *
595 : * @return If the read was successful.
596 : */
597 0 : bool BlockTileLayer::ReadPartialTile(void * pData, uint32 nCol, uint32 nRow,
598 : uint32 nOffset, uint32 nSize)
599 : {
600 0 : if (!IsValid())
601 0 : return false;
602 :
603 0 : BlockTileInfo * psTile = GetTileInfo(nCol, nRow);
604 :
605 0 : if (!psTile)
606 0 : return false;
607 :
608 0 : if (psTile->nOffset == INVALID_OFFSET)
609 0 : return false;
610 :
611 0 : if (psTile->nSize == 0 || psTile->nSize < nOffset + nSize)
612 0 : return false;
613 :
614 0 : if (!ReadFromLayer(pData, psTile->nOffset + nOffset, nSize))
615 0 : return false;
616 :
617 0 : return true;
618 : }
619 :
620 : /************************************************************************/
621 : /* SetTileLayerInfo() */
622 : /************************************************************************/
623 :
624 : /**
625 : * Sets the tile layer information.
626 : *
627 : * @param nXSize The width of the tile layer.
628 : * @param nYSize The height of the tile layer.
629 : * @param nTileXSize The width of a tile.
630 : * @param nTileYSize The height of a tile.
631 : * @param oDataType The data type of the tile layer.
632 : * @param oCompress The compress type of the tile layer.
633 : * @param bNoDataValid If the NoData value is valid.
634 : * @param dfNoDataValue The NoData value of the tile layer.
635 : */
636 8 : void BlockTileLayer::SetTileLayerInfo(uint32 nXSize, uint32 nYSize,
637 : uint32 nTileXSize, uint32 nTileYSize,
638 : const std::string & oDataType,
639 : const std::string & oCompress,
640 : bool bNoDataValid, double dfNoDataValue)
641 : {
642 : uint64 nTileSize =
643 8 : static_cast<uint64>(nTileXSize) * nTileYSize *
644 8 : DataTypeSize(GetDataTypeFromName(oDataType.c_str()));
645 :
646 8 : if (nTileSize == 0 || nTileSize > std::numeric_limits<uint32>::max())
647 : {
648 0 : return ThrowPCIDSKException("Invalid tile dimensions: %d x %d",
649 0 : nTileXSize, nTileYSize);
650 : }
651 :
652 8 : if (nXSize == 0 || nYSize == 0)
653 : {
654 0 : return ThrowPCIDSKException("Invalid tile layer dimensions: %d x %d",
655 0 : nXSize, nYSize);
656 : }
657 :
658 8 : mpsTileLayer->nXSize = nXSize;
659 8 : mpsTileLayer->nYSize = nYSize;
660 8 : mpsTileLayer->nTileXSize = nTileXSize;
661 8 : mpsTileLayer->nTileYSize = nTileYSize;
662 8 : mpsTileLayer->bNoDataValid = bNoDataValid;
663 8 : mpsTileLayer->dfNoDataValue = dfNoDataValue;
664 :
665 8 : memset(mpsTileLayer->szDataType, ' ', 4);
666 8 : memcpy(mpsTileLayer->szDataType, oDataType.data(), oDataType.size());
667 :
668 8 : memset(mpsTileLayer->szCompress, ' ', 8);
669 8 : memcpy(mpsTileLayer->szCompress, oCompress.data(), oCompress.size());
670 :
671 : // Invalidate the cache variables.
672 8 : *mszDataType = 0;
673 8 : *mszCompress = 0;
674 :
675 : // Initialize the tile list.
676 8 : uint32 nTileCount = GetTileCount();
677 :
678 8 : MutexHolder oLock(mpoTileListMutex);
679 :
680 : try
681 : {
682 8 : moTileList.resize(nTileCount);
683 : }
684 0 : catch (const std::exception & ex)
685 : {
686 0 : return ThrowPCIDSKException("Out of memory in BlockTileLayer::SetTileLayerInfo(): %s", ex.what());
687 : }
688 :
689 16 : for (uint32 iTile = 0; iTile < nTileCount; iTile++)
690 : {
691 8 : BlockTileInfo * psTile = &moTileList[iTile];
692 :
693 8 : psTile->nOffset = INVALID_OFFSET;
694 8 : psTile->nSize = 0;
695 : }
696 :
697 : // Write the tile list to disk.
698 8 : WriteTileList();
699 :
700 8 : mbModified = false;
701 :
702 8 : oLock.Release();
703 :
704 : // Make sure that the first tile starts on a block boundary.
705 8 : uint64 nLayerSize = GetLayerSize();
706 8 : uint32 nBlockSize = mpoBlockDir->GetBlockSize();
707 :
708 8 : if (nLayerSize % nBlockSize != 0)
709 8 : Resize((nLayerSize / nBlockSize + 1) * nBlockSize);
710 : }
711 :
712 : /************************************************************************/
713 : /* GetDataType() */
714 : /************************************************************************/
715 :
716 : /**
717 : * Gets the data type of the tile layer.
718 : *
719 : * @return The data type of the tile layer.
720 : */
721 140 : const char * BlockTileLayer::GetDataType(void) const
722 : {
723 280 : MutexHolder oLock(mpoTileListMutex);
724 :
725 140 : if (*mszDataType)
726 104 : return mszDataType;
727 :
728 36 : memcpy(mszDataType, mpsTileLayer->szDataType, 4);
729 :
730 36 : int nIter = 3;
731 :
732 90 : while (nIter > 0 && mszDataType[nIter] == ' ')
733 54 : mszDataType[nIter--] = '\0';
734 :
735 36 : return mszDataType;
736 : }
737 :
738 : /************************************************************************/
739 : /* GetCompressType() */
740 : /************************************************************************/
741 :
742 : /**
743 : * Gets the compress type of the tile layer.
744 : *
745 : * @return The compress type of the tile layer.
746 : */
747 38 : const char * BlockTileLayer::GetCompressType(void) const
748 : {
749 76 : MutexHolder oLock(mpoTileListMutex);
750 :
751 38 : if (*mszCompress)
752 18 : return mszCompress;
753 :
754 20 : memcpy(mszCompress, mpsTileLayer->szCompress, 8);
755 :
756 20 : int nIter = 7;
757 :
758 106 : while (nIter > 0 && mszCompress[nIter] == ' ')
759 86 : mszCompress[nIter--] = '\0';
760 :
761 20 : return mszCompress;
762 : }
763 :
764 : } // namespace PCIDSK
|