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