Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Erdas Imagine (.img) Translator
4 : * Purpose: Implementation of the HFABand, for accessing one Eimg_Layer.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Intergraph Corporation
9 : * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "hfa_p.h"
16 :
17 : #include <cerrno>
18 : #include <climits>
19 : #include <cstddef>
20 : #include <cstdio>
21 : #include <cstring>
22 : #include <algorithm>
23 : #include <limits>
24 :
25 : #include "cpl_conv.h"
26 : #include "cpl_error.h"
27 : #include "cpl_string.h"
28 : #include "cpl_vsi.h"
29 : #include "hfa.h"
30 : #include "gdal_priv.h"
31 :
32 : /************************************************************************/
33 : /* HFABand() */
34 : /************************************************************************/
35 :
36 914 : HFABand::HFABand(HFAInfo_t *psInfoIn, HFAEntry *poNodeIn)
37 : : nBlocks(0), panBlockStart(nullptr), panBlockSize(nullptr),
38 : panBlockFlag(nullptr), nBlockStart(0), nBlockSize(0), nLayerStackCount(0),
39 : nLayerStackIndex(0), nPCTColors(-1), padfPCTBins(nullptr),
40 : psInfo(psInfoIn), fpExternal(nullptr),
41 1828 : eDataType(static_cast<EPTType>(poNodeIn->GetIntField("pixelType"))),
42 1828 : poNode(poNodeIn), nBlockXSize(poNodeIn->GetIntField("blockWidth")),
43 1828 : nBlockYSize(poNodeIn->GetIntField("blockHeight")),
44 1828 : nWidth(poNodeIn->GetIntField("width")),
45 1828 : nHeight(poNodeIn->GetIntField("height")), nBlocksPerRow(0),
46 : nBlocksPerColumn(0), bNoDataSet(false), dfNoData(0.0),
47 914 : bOverviewsPending(true), nOverviews(0), papoOverviews(nullptr)
48 : {
49 914 : const int nDataType = poNodeIn->GetIntField("pixelType");
50 :
51 914 : apadfPCT[0] = nullptr;
52 914 : apadfPCT[1] = nullptr;
53 914 : apadfPCT[2] = nullptr;
54 914 : apadfPCT[3] = nullptr;
55 :
56 914 : if (nWidth <= 0 || nHeight <= 0 || nBlockXSize <= 0 || nBlockYSize <= 0)
57 : {
58 0 : nWidth = 0;
59 0 : nHeight = 0;
60 0 : CPLError(CE_Failure, CPLE_AppDefined,
61 : "HFABand::HFABand : (nWidth <= 0 || nHeight <= 0 || "
62 : "nBlockXSize <= 0 || nBlockYSize <= 0)");
63 0 : return;
64 : }
65 914 : if (nDataType < EPT_MIN || nDataType > EPT_MAX)
66 : {
67 0 : nWidth = 0;
68 0 : nHeight = 0;
69 0 : CPLError(CE_Failure, CPLE_AppDefined,
70 : "HFABand::HFABand : nDataType=%d unhandled", nDataType);
71 0 : return;
72 : }
73 :
74 : // TODO(schwehr): Move to initializer list.
75 914 : nBlocksPerRow = DIV_ROUND_UP(nWidth, nBlockXSize);
76 914 : nBlocksPerColumn = DIV_ROUND_UP(nHeight, nBlockYSize);
77 :
78 914 : if (nBlocksPerRow > INT_MAX / nBlocksPerColumn)
79 : {
80 0 : nWidth = 0;
81 0 : nHeight = 0;
82 0 : CPLError(CE_Failure, CPLE_AppDefined,
83 : "HFABand::HFABand : too big dimensions / block size");
84 0 : return;
85 : }
86 914 : nBlocks = nBlocksPerRow * nBlocksPerColumn;
87 :
88 : // Check for nodata. This is really an RDO (ESRI Raster Data Objects?),
89 : // not used by Imagine itself.
90 914 : HFAEntry *poNDNode = poNode->GetNamedChild("Eimg_NonInitializedValue");
91 :
92 914 : if (poNDNode != nullptr)
93 : {
94 19 : bNoDataSet = true;
95 19 : dfNoData = poNDNode->GetDoubleField("valueBD");
96 : }
97 : }
98 :
99 : /************************************************************************/
100 : /* ~HFABand() */
101 : /************************************************************************/
102 :
103 914 : HFABand::~HFABand()
104 :
105 : {
106 972 : for (int iOverview = 0; iOverview < nOverviews; iOverview++)
107 58 : delete papoOverviews[iOverview];
108 :
109 914 : if (nOverviews > 0)
110 39 : CPLFree(papoOverviews);
111 :
112 914 : CPLFree(panBlockStart);
113 914 : CPLFree(panBlockSize);
114 914 : CPLFree(panBlockFlag);
115 :
116 914 : CPLFree(apadfPCT[0]);
117 914 : CPLFree(apadfPCT[1]);
118 914 : CPLFree(apadfPCT[2]);
119 914 : CPLFree(apadfPCT[3]);
120 914 : CPLFree(padfPCTBins);
121 :
122 914 : if (fpExternal != nullptr)
123 16 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpExternal));
124 914 : }
125 :
126 : /************************************************************************/
127 : /* LoadOverviews() */
128 : /************************************************************************/
129 :
130 183 : CPLErr HFABand::LoadOverviews()
131 :
132 : {
133 183 : if (!bOverviewsPending)
134 56 : return CE_None;
135 :
136 127 : bOverviewsPending = false;
137 :
138 : // Does this band have overviews? Try to find them.
139 127 : HFAEntry *poRRDNames = poNode->GetNamedChild("RRDNamesList");
140 :
141 127 : if (poRRDNames != nullptr)
142 : {
143 : // Limit to 1000 to avoid infinite loop as in
144 : // https://oss-fuzz.com/v2/testcase-detail/6206784937132032
145 82 : for (int iName = 0; iName < 1000; iName++)
146 : {
147 82 : char szField[128] = {};
148 82 : snprintf(szField, sizeof(szField), "nameList[%d].string", iName);
149 :
150 82 : CPLErr eErr = CE_None;
151 82 : const char *pszName = poRRDNames->GetStringField(szField, &eErr);
152 82 : if (pszName == nullptr || eErr != CE_None)
153 : break;
154 :
155 48 : char *pszFilename = CPLStrdup(pszName);
156 48 : char *pszEnd = strstr(pszFilename, "(:");
157 48 : if (pszEnd == nullptr)
158 : {
159 0 : CPLFree(pszFilename);
160 2 : continue;
161 : }
162 :
163 48 : pszEnd[0] = '\0';
164 :
165 48 : char *pszJustFilename = CPLStrdup(CPLGetFilename(pszFilename));
166 48 : HFAInfo_t *psHFA = HFAGetDependent(psInfo, pszJustFilename);
167 48 : CPLFree(pszJustFilename);
168 :
169 : // Try finding the dependent file as this file with the
170 : // extension .rrd. This is intended to address problems
171 : // with users changing the names of their files.
172 48 : if (psHFA == nullptr)
173 : {
174 : char *pszBasename =
175 2 : CPLStrdup(CPLGetBasenameSafe(psInfo->pszFilename).c_str());
176 :
177 2 : pszJustFilename = CPLStrdup(
178 4 : CPLFormFilenameSafe(nullptr, pszBasename, "rrd").c_str());
179 2 : CPLDebug("HFA",
180 : "Failed to find overview file with "
181 : "expected name, try %s instead.",
182 : pszJustFilename);
183 2 : psHFA = HFAGetDependent(psInfo, pszJustFilename);
184 2 : CPLFree(pszJustFilename);
185 2 : CPLFree(pszBasename);
186 : }
187 :
188 48 : if (psHFA == nullptr)
189 : {
190 2 : CPLFree(pszFilename);
191 2 : continue;
192 : }
193 :
194 46 : char *pszPath = pszEnd + 2;
195 : {
196 46 : const int nPathLen = static_cast<int>(strlen(pszPath));
197 46 : if (pszPath[nPathLen - 1] == ')')
198 46 : pszPath[nPathLen - 1] = '\0';
199 : }
200 :
201 693 : for (int i = 0; pszPath[i] != '\0'; i++)
202 : {
203 647 : if (pszPath[i] == ':')
204 46 : pszPath[i] = '.';
205 : }
206 :
207 46 : HFAEntry *poOvEntry = psHFA->poRoot->GetNamedChild(pszPath);
208 46 : CPLFree(pszFilename);
209 :
210 46 : if (poOvEntry == nullptr)
211 0 : continue;
212 :
213 : // We have an overview node. Instantiate a HFABand from it, and
214 : // add to the list.
215 92 : papoOverviews = static_cast<HFABand **>(
216 46 : CPLRealloc(papoOverviews, sizeof(void *) * ++nOverviews));
217 46 : papoOverviews[nOverviews - 1] = new HFABand(psHFA, poOvEntry);
218 46 : if (papoOverviews[nOverviews - 1]->nWidth == 0)
219 : {
220 0 : nWidth = 0;
221 0 : nHeight = 0;
222 0 : delete papoOverviews[nOverviews - 1];
223 0 : papoOverviews[nOverviews - 1] = nullptr;
224 0 : return CE_None;
225 : }
226 : }
227 : }
228 :
229 : // If there are no overviews mentioned in this file, probe for
230 : // an .rrd file anyways.
231 127 : HFAEntry *poBandProxyNode = poNode;
232 127 : HFAInfo_t *psOvHFA = psInfo;
233 :
234 222 : if (nOverviews == 0 &&
235 222 : EQUAL(CPLGetExtensionSafe(psInfo->pszFilename).c_str(), "aux"))
236 : {
237 : const CPLString osRRDFilename =
238 12 : CPLResetExtensionSafe(psInfo->pszFilename, "rrd");
239 : const CPLString osFullRRD =
240 12 : CPLFormFilenameSafe(psInfo->pszPath, osRRDFilename, nullptr);
241 : VSIStatBufL sStatBuf;
242 :
243 6 : if (VSIStatL(osFullRRD, &sStatBuf) == 0)
244 : {
245 0 : psOvHFA = HFAGetDependent(psInfo, osRRDFilename);
246 0 : if (psOvHFA)
247 : poBandProxyNode =
248 0 : psOvHFA->poRoot->GetNamedChild(poNode->GetName());
249 : else
250 0 : psOvHFA = psInfo;
251 : }
252 : }
253 :
254 : // If there are no named overviews, try looking for unnamed
255 : // overviews within the same layer, as occurs in floodplain.img
256 : // for instance, or in the not-referenced rrd mentioned in #3463.
257 127 : if (nOverviews == 0 && poBandProxyNode != nullptr)
258 : {
259 95 : for (HFAEntry *poChild = poBandProxyNode->GetChild();
260 499 : poChild != nullptr; poChild = poChild->GetNext())
261 : {
262 404 : if (EQUAL(poChild->GetType(), "Eimg_Layer_SubSample"))
263 : {
264 0 : papoOverviews = static_cast<HFABand **>(
265 0 : CPLRealloc(papoOverviews, sizeof(void *) * ++nOverviews));
266 0 : papoOverviews[nOverviews - 1] = new HFABand(psOvHFA, poChild);
267 0 : if (papoOverviews[nOverviews - 1]->nWidth == 0)
268 : {
269 0 : nWidth = 0;
270 0 : nHeight = 0;
271 0 : delete papoOverviews[nOverviews - 1];
272 0 : papoOverviews[nOverviews - 1] = nullptr;
273 0 : return CE_None;
274 : }
275 : }
276 : }
277 :
278 : // TODO(schwehr): Can this use std::sort?
279 : // Bubble sort into biggest to smallest order.
280 95 : for (int i1 = 0; i1 < nOverviews; i1++)
281 : {
282 0 : for (int i2 = 0; i2 < nOverviews - 1; i2++)
283 : {
284 0 : if (papoOverviews[i2]->nWidth < papoOverviews[i2 + 1]->nWidth)
285 : {
286 : // TODO(schwehr): Use std::swap.
287 0 : HFABand *poTemp = papoOverviews[i2 + 1];
288 0 : papoOverviews[i2 + 1] = papoOverviews[i2];
289 0 : papoOverviews[i2] = poTemp;
290 : }
291 : }
292 : }
293 : }
294 127 : return CE_None;
295 : }
296 :
297 : /************************************************************************/
298 : /* LoadBlockInfo() */
299 : /************************************************************************/
300 :
301 1488 : CPLErr HFABand::LoadBlockInfo()
302 :
303 : {
304 1488 : if (panBlockFlag != nullptr)
305 1307 : return CE_None;
306 :
307 181 : HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
308 181 : if (poDMS == nullptr)
309 : {
310 16 : if (poNode->GetNamedChild("ExternalRasterDMS") != nullptr)
311 16 : return LoadExternalBlockInfo();
312 :
313 0 : CPLError(CE_Failure, CPLE_AppDefined,
314 : "Can't find RasterDMS field in Eimg_Layer with block list.");
315 :
316 0 : return CE_Failure;
317 : }
318 :
319 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
320 : {
321 : if (sizeof(vsi_l_offset) + 2 * sizeof(int) >
322 : std::numeric_limits<size_t>::max() /
323 : static_cast<unsigned int>(nBlocks))
324 : {
325 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too many blocks");
326 : return CE_Failure;
327 : }
328 : }
329 165 : const int MAX_INITIAL_BLOCKS = 1000 * 1000;
330 165 : const int nInitBlocks = std::min(nBlocks, MAX_INITIAL_BLOCKS);
331 165 : panBlockStart = static_cast<vsi_l_offset *>(
332 165 : VSI_MALLOC2_VERBOSE(sizeof(vsi_l_offset), nInitBlocks));
333 165 : panBlockSize =
334 165 : static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nInitBlocks));
335 165 : panBlockFlag =
336 165 : static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nInitBlocks));
337 :
338 165 : if (panBlockStart == nullptr || panBlockSize == nullptr ||
339 165 : panBlockFlag == nullptr)
340 : {
341 0 : CPLFree(panBlockStart);
342 0 : CPLFree(panBlockSize);
343 0 : CPLFree(panBlockFlag);
344 0 : panBlockStart = nullptr;
345 0 : panBlockSize = nullptr;
346 0 : panBlockFlag = nullptr;
347 0 : return CE_Failure;
348 : }
349 :
350 2646 : for (int iBlock = 0; iBlock < nBlocks; iBlock++)
351 : {
352 2481 : CPLErr eErr = CE_None;
353 :
354 2481 : if (iBlock == MAX_INITIAL_BLOCKS)
355 : {
356 : vsi_l_offset *panBlockStartNew =
357 0 : static_cast<vsi_l_offset *>(VSI_REALLOC_VERBOSE(
358 : panBlockStart, sizeof(vsi_l_offset) * nBlocks));
359 0 : if (panBlockStartNew == nullptr)
360 : {
361 0 : CPLFree(panBlockStart);
362 0 : CPLFree(panBlockSize);
363 0 : CPLFree(panBlockFlag);
364 0 : panBlockStart = nullptr;
365 0 : panBlockSize = nullptr;
366 0 : panBlockFlag = nullptr;
367 0 : return CE_Failure;
368 : }
369 0 : panBlockStart = panBlockStartNew;
370 :
371 : int *panBlockSizeNew = static_cast<int *>(
372 0 : VSI_REALLOC_VERBOSE(panBlockSize, sizeof(int) * nBlocks));
373 0 : if (panBlockSizeNew == nullptr)
374 : {
375 0 : CPLFree(panBlockStart);
376 0 : CPLFree(panBlockSize);
377 0 : CPLFree(panBlockFlag);
378 0 : panBlockStart = nullptr;
379 0 : panBlockSize = nullptr;
380 0 : panBlockFlag = nullptr;
381 0 : return CE_Failure;
382 : }
383 0 : panBlockSize = panBlockSizeNew;
384 :
385 : int *panBlockFlagNew = static_cast<int *>(
386 0 : VSI_REALLOC_VERBOSE(panBlockFlag, sizeof(int) * nBlocks));
387 0 : if (panBlockFlagNew == nullptr)
388 : {
389 0 : CPLFree(panBlockStart);
390 0 : CPLFree(panBlockSize);
391 0 : CPLFree(panBlockFlag);
392 0 : panBlockStart = nullptr;
393 0 : panBlockSize = nullptr;
394 0 : panBlockFlag = nullptr;
395 0 : return CE_Failure;
396 : }
397 0 : panBlockFlag = panBlockFlagNew;
398 : }
399 :
400 2481 : char szVarName[64] = {};
401 2481 : snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].offset", iBlock);
402 2481 : panBlockStart[iBlock] =
403 2481 : static_cast<GUInt32>(poDMS->GetIntField(szVarName, &eErr));
404 2481 : if (eErr == CE_Failure)
405 : {
406 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
407 0 : return eErr;
408 : }
409 :
410 2481 : snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].size", iBlock);
411 2481 : panBlockSize[iBlock] = poDMS->GetIntField(szVarName, &eErr);
412 2481 : if (eErr == CE_Failure)
413 : {
414 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
415 0 : return eErr;
416 : }
417 2481 : if (panBlockSize[iBlock] < 0)
418 : {
419 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size");
420 0 : return CE_Failure;
421 : }
422 :
423 2481 : snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].logvalid",
424 : iBlock);
425 2481 : const int nLogvalid = poDMS->GetIntField(szVarName, &eErr);
426 2481 : if (eErr == CE_Failure)
427 : {
428 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
429 0 : return eErr;
430 : }
431 :
432 2481 : snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].compressionType",
433 : iBlock);
434 2481 : const int nCompressType = poDMS->GetIntField(szVarName, &eErr);
435 2481 : if (eErr == CE_Failure)
436 : {
437 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
438 0 : return eErr;
439 : }
440 :
441 2481 : panBlockFlag[iBlock] = 0;
442 2481 : if (nLogvalid)
443 2298 : panBlockFlag[iBlock] |= BFLG_VALID;
444 2481 : if (nCompressType != 0)
445 2214 : panBlockFlag[iBlock] |= BFLG_COMPRESSED;
446 : }
447 :
448 165 : return CE_None;
449 : }
450 :
451 : /************************************************************************/
452 : /* LoadExternalBlockInfo() */
453 : /************************************************************************/
454 :
455 16 : CPLErr HFABand::LoadExternalBlockInfo()
456 :
457 : {
458 16 : if (panBlockFlag != nullptr)
459 0 : return CE_None;
460 :
461 : // Get the info structure.
462 16 : HFAEntry *poDMS = poNode->GetNamedChild("ExternalRasterDMS");
463 16 : CPLAssert(poDMS != nullptr);
464 :
465 16 : nLayerStackCount = poDMS->GetIntField("layerStackCount");
466 16 : nLayerStackIndex = poDMS->GetIntField("layerStackIndex");
467 :
468 : // Open raw data file.
469 32 : const std::string osFullFilename = HFAGetIGEFilename(psInfo);
470 16 : if (osFullFilename.empty())
471 : {
472 0 : CPLError(CE_Failure, CPLE_OpenFailed,
473 : "Cannot find external data file name");
474 0 : return CE_Failure;
475 : }
476 :
477 16 : if (psInfo->eAccess == HFA_ReadOnly)
478 9 : fpExternal = VSIFOpenL(osFullFilename.c_str(), "rb");
479 : else
480 7 : fpExternal = VSIFOpenL(osFullFilename.c_str(), "r+b");
481 16 : if (fpExternal == nullptr)
482 : {
483 0 : CPLError(CE_Failure, CPLE_OpenFailed,
484 : "Unable to open external data file: %s",
485 : osFullFilename.c_str());
486 0 : return CE_Failure;
487 : }
488 :
489 : // Verify header.
490 16 : char szHeader[49] = {};
491 :
492 32 : if (VSIFReadL(szHeader, sizeof(szHeader), 1, fpExternal) != 1 ||
493 16 : !STARTS_WITH(szHeader, "ERDAS_IMG_EXTERNAL_RASTER"))
494 : {
495 0 : CPLError(CE_Failure, CPLE_AppDefined,
496 : "Raw data file %s appears to be corrupt.",
497 : osFullFilename.c_str());
498 0 : return CE_Failure;
499 : }
500 :
501 : // Allocate blockmap.
502 16 : panBlockFlag =
503 16 : static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nBlocks));
504 16 : if (panBlockFlag == nullptr)
505 : {
506 0 : return CE_Failure;
507 : }
508 :
509 : // Load the validity bitmap.
510 16 : const int nBytesPerRow = (nBlocksPerRow + 7) / 8;
511 : unsigned char *pabyBlockMap = static_cast<unsigned char *>(
512 16 : VSI_MALLOC_VERBOSE(nBytesPerRow * nBlocksPerColumn + 20));
513 16 : if (pabyBlockMap == nullptr)
514 : {
515 0 : return CE_Failure;
516 : }
517 :
518 48 : if (VSIFSeekL(fpExternal,
519 : static_cast<vsi_l_offset>(
520 16 : poDMS->GetBigIntField("layerStackValidFlagsOffset")),
521 32 : SEEK_SET) < 0 ||
522 16 : VSIFReadL(pabyBlockMap, nBytesPerRow * nBlocksPerColumn + 20, 1,
523 : fpExternal) != 1)
524 : {
525 0 : CPLError(CE_Failure, CPLE_FileIO, "Failed to read block validity map.");
526 0 : return CE_Failure;
527 : }
528 :
529 : // Establish block information. Block position is computed
530 : // from data base address. Blocks are never compressed.
531 : // Validity is determined from the validity bitmap.
532 :
533 16 : nBlockStart = poDMS->GetBigIntField("layerStackDataOffset");
534 32 : nBlockSize = (nBlockXSize * static_cast<vsi_l_offset>(nBlockYSize) *
535 16 : HFAGetDataTypeBits(eDataType) +
536 16 : 7) /
537 : 8;
538 :
539 32 : for (int iBlock = 0; iBlock < nBlocks; iBlock++)
540 : {
541 16 : const int nColumn = iBlock % nBlocksPerRow;
542 16 : const int nRow = iBlock / nBlocksPerRow;
543 16 : const int nBit = nRow * nBytesPerRow * 8 + nColumn + 20 * 8;
544 :
545 16 : if ((pabyBlockMap[nBit >> 3] >> (nBit & 7)) & 0x1)
546 16 : panBlockFlag[iBlock] = BFLG_VALID;
547 : else
548 0 : panBlockFlag[iBlock] = 0;
549 : }
550 :
551 16 : CPLFree(pabyBlockMap);
552 :
553 16 : return CE_None;
554 : }
555 :
556 : /************************************************************************/
557 : /* UncompressBlock() */
558 : /* */
559 : /* Uncompress ESRI Grid compression format block. */
560 : /************************************************************************/
561 :
562 : // TODO(schwehr): Get rid of this macro without a goto.
563 : #define CHECK_ENOUGH_BYTES(n) \
564 : if (nSrcBytes < (n)) \
565 : { \
566 : CPLError(CE_Failure, CPLE_AppDefined, \
567 : "Not enough bytes in compressed block"); \
568 : return CE_Failure; \
569 : }
570 :
571 1182 : static CPLErr UncompressBlock(GByte *pabyCData, int nSrcBytes, GByte *pabyDest,
572 : int nMaxPixels, EPTType eDataType)
573 :
574 : {
575 1182 : CHECK_ENOUGH_BYTES(13);
576 :
577 1182 : const GUInt32 nDataMin = CPL_LSBUINT32PTR(pabyCData);
578 1182 : const GInt32 nNumRuns = CPL_LSBSINT32PTR(pabyCData + 4);
579 1182 : const GInt32 nDataOffset = CPL_LSBSINT32PTR(pabyCData + 8);
580 :
581 1182 : const int nNumBits = pabyCData[12];
582 :
583 : // If this is not run length encoded, but just reduced
584 : // precision, handle it now.
585 :
586 1182 : int nPixelsOutput = 0;
587 1182 : GByte *pabyValues = nullptr;
588 1182 : int nValueBitOffset = 0;
589 :
590 1182 : if (nNumRuns == -1)
591 : {
592 24 : pabyValues = pabyCData + 13;
593 24 : nValueBitOffset = 0;
594 :
595 24 : if (nNumBits > INT_MAX / nMaxPixels ||
596 24 : nNumBits * nMaxPixels > INT_MAX - 7)
597 : {
598 0 : CPLError(CE_Failure, CPLE_AppDefined,
599 : "Integer overflow : nNumBits * nMaxPixels + 7");
600 0 : return CE_Failure;
601 : }
602 24 : CHECK_ENOUGH_BYTES(13 + (nNumBits * nMaxPixels + 7) / 8);
603 :
604 : // Loop over block pixels.
605 98328 : for (nPixelsOutput = 0; nPixelsOutput < nMaxPixels; nPixelsOutput++)
606 : {
607 : // Extract the data value in a way that depends on the number
608 : // of bits in it.
609 :
610 98304 : int nRawValue = 0;
611 :
612 98304 : if (nNumBits == 0)
613 : {
614 : // nRawValue = 0;
615 : }
616 98304 : else if (nNumBits == 1)
617 : {
618 0 : nRawValue = (pabyValues[nValueBitOffset >> 3] >>
619 0 : (nValueBitOffset & 7)) &
620 : 0x1;
621 0 : nValueBitOffset++;
622 : }
623 98304 : else if (nNumBits == 2)
624 : {
625 0 : nRawValue = (pabyValues[nValueBitOffset >> 3] >>
626 0 : (nValueBitOffset & 7)) &
627 : 0x3;
628 0 : nValueBitOffset += 2;
629 : }
630 98304 : else if (nNumBits == 4)
631 : {
632 0 : nRawValue = (pabyValues[nValueBitOffset >> 3] >>
633 0 : (nValueBitOffset & 7)) &
634 : 0xf;
635 0 : nValueBitOffset += 4;
636 : }
637 98304 : else if (nNumBits == 8)
638 : {
639 32768 : nRawValue = *pabyValues;
640 32768 : pabyValues++;
641 : }
642 65536 : else if (nNumBits == 16)
643 : {
644 65536 : nRawValue = 256 * *(pabyValues++);
645 65536 : nRawValue += *(pabyValues++);
646 : }
647 0 : else if (nNumBits == 32)
648 : {
649 0 : memcpy(&nRawValue, pabyValues, 4);
650 0 : CPL_MSBPTR32(&nRawValue);
651 0 : pabyValues += 4;
652 : }
653 : else
654 : {
655 0 : CPLError(CE_Failure, CPLE_NotSupported,
656 : "Unsupported nNumBits value: %d", nNumBits);
657 0 : return CE_Failure;
658 : }
659 :
660 : // Offset by the minimum value.
661 98304 : const int nDataValue = CPLUnsanitizedAdd<int>(nRawValue, nDataMin);
662 :
663 : // Now apply to the output buffer in a type specific way.
664 98304 : if (eDataType == EPT_u8)
665 : {
666 0 : pabyDest[nPixelsOutput] = static_cast<GByte>(nDataValue);
667 : }
668 98304 : else if (eDataType == EPT_u1)
669 : {
670 0 : if (nDataValue == 1)
671 0 : pabyDest[nPixelsOutput >> 3] |=
672 0 : (1 << (nPixelsOutput & 0x7));
673 : else
674 0 : pabyDest[nPixelsOutput >> 3] &=
675 0 : ~(1 << (nPixelsOutput & 0x7));
676 : }
677 98304 : else if (eDataType == EPT_u2)
678 : {
679 : // nDataValue & 0x3 is just to avoid UBSAN warning on shifting
680 : // negative values
681 0 : if ((nPixelsOutput & 0x3) == 0)
682 0 : pabyDest[nPixelsOutput >> 2] =
683 : static_cast<GByte>(nDataValue);
684 0 : else if ((nPixelsOutput & 0x3) == 1)
685 0 : pabyDest[nPixelsOutput >> 2] |=
686 0 : static_cast<GByte>((nDataValue & 0x3) << 2);
687 0 : else if ((nPixelsOutput & 0x3) == 2)
688 0 : pabyDest[nPixelsOutput >> 2] |=
689 0 : static_cast<GByte>((nDataValue & 0x3) << 4);
690 : else
691 0 : pabyDest[nPixelsOutput >> 2] |=
692 0 : static_cast<GByte>((nDataValue & 0x3) << 6);
693 : }
694 98304 : else if (eDataType == EPT_u4)
695 : {
696 : // nDataValue & 0xF is just to avoid UBSAN warning on shifting
697 : // negative values
698 0 : if ((nPixelsOutput & 0x1) == 0)
699 0 : pabyDest[nPixelsOutput >> 1] =
700 : static_cast<GByte>(nDataValue);
701 : else
702 0 : pabyDest[nPixelsOutput >> 1] |=
703 0 : static_cast<GByte>((nDataValue & 0xF) << 4);
704 : }
705 98304 : else if (eDataType == EPT_s8)
706 : {
707 0 : reinterpret_cast<GInt8 *>(pabyDest)[nPixelsOutput] =
708 : static_cast<GInt8>(nDataValue);
709 : }
710 98304 : else if (eDataType == EPT_u16)
711 : {
712 0 : reinterpret_cast<GUInt16 *>(pabyDest)[nPixelsOutput] =
713 : static_cast<GUInt16>(nDataValue);
714 : }
715 98304 : else if (eDataType == EPT_s16)
716 : {
717 0 : reinterpret_cast<GInt16 *>(pabyDest)[nPixelsOutput] =
718 : static_cast<GInt16>(nDataValue);
719 : }
720 98304 : else if (eDataType == EPT_s32)
721 : {
722 32768 : reinterpret_cast<GInt32 *>(pabyDest)[nPixelsOutput] =
723 : nDataValue;
724 : }
725 65536 : else if (eDataType == EPT_u32)
726 : {
727 0 : reinterpret_cast<GUInt32 *>(pabyDest)[nPixelsOutput] =
728 0 : nDataValue;
729 : }
730 65536 : else if (eDataType == EPT_f32)
731 : {
732 : // Note, floating point values are handled as if they were
733 : // signed 32-bit integers (bug #1000).
734 65536 : memcpy(&(reinterpret_cast<float *>(pabyDest)[nPixelsOutput]),
735 : &nDataValue, sizeof(float));
736 : }
737 : else
738 : {
739 0 : CPLError(
740 : CE_Failure, CPLE_AppDefined,
741 : "Attempt to uncompress an unsupported pixel data type.");
742 0 : return CE_Failure;
743 : }
744 : }
745 :
746 24 : return CE_None;
747 : }
748 :
749 : // Establish data pointers for runs.
750 1158 : if (nNumRuns < 0 || nDataOffset < 0)
751 : {
752 0 : CPLError(CE_Failure, CPLE_AppDefined, "nNumRuns=%d, nDataOffset=%d",
753 : nNumRuns, nDataOffset);
754 0 : return CE_Failure;
755 : }
756 :
757 1158 : if (nNumRuns != 0 &&
758 1158 : (nNumBits > INT_MAX / nNumRuns || nNumBits * nNumRuns > INT_MAX - 7 ||
759 1158 : (nNumBits * nNumRuns + 7) / 8 > INT_MAX - nDataOffset))
760 : {
761 0 : CPLError(CE_Failure, CPLE_AppDefined,
762 : "Integer overflow: nDataOffset + (nNumBits * nNumRuns + 7)/8");
763 0 : return CE_Failure;
764 : }
765 1158 : CHECK_ENOUGH_BYTES(nDataOffset + (nNumBits * nNumRuns + 7) / 8);
766 :
767 1158 : GByte *pabyCounter = pabyCData + 13;
768 1158 : int nCounterOffset = 13;
769 1158 : pabyValues = pabyCData + nDataOffset;
770 1158 : nValueBitOffset = 0;
771 :
772 : // Loop over runs.
773 85193 : for (int iRun = 0; iRun < nNumRuns; iRun++)
774 : {
775 84035 : int nRepeatCount = 0;
776 :
777 : // Get the repeat count. This can be stored as one, two, three
778 : // or four bytes depending on the low order two bits of the
779 : // first byte.
780 84035 : CHECK_ENOUGH_BYTES(nCounterOffset + 1);
781 84035 : if ((*pabyCounter & 0xc0) == 0x00)
782 : {
783 82914 : nRepeatCount = (*(pabyCounter++)) & 0x3f;
784 82914 : nCounterOffset++;
785 : }
786 1121 : else if (((*pabyCounter) & 0xc0) == 0x40)
787 : {
788 1121 : CHECK_ENOUGH_BYTES(nCounterOffset + 2);
789 1121 : nRepeatCount = (*(pabyCounter++)) & 0x3f;
790 1121 : nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
791 1121 : nCounterOffset += 2;
792 : }
793 0 : else if (((*pabyCounter) & 0xc0) == 0x80)
794 : {
795 0 : CHECK_ENOUGH_BYTES(nCounterOffset + 3);
796 0 : nRepeatCount = (*(pabyCounter++)) & 0x3f;
797 0 : nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
798 0 : nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
799 0 : nCounterOffset += 3;
800 : }
801 0 : else if (((*pabyCounter) & 0xc0) == 0xc0)
802 : {
803 0 : CHECK_ENOUGH_BYTES(nCounterOffset + 4);
804 0 : nRepeatCount = (*(pabyCounter++)) & 0x3f;
805 0 : nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
806 0 : nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
807 0 : nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
808 0 : nCounterOffset += 4;
809 : }
810 :
811 : // Extract the data value in a way that depends on the number
812 : // of bits in it.
813 84035 : int nDataValue = 0;
814 :
815 84035 : if (nNumBits == 0)
816 : {
817 : // nDataValue = 0;
818 : }
819 84035 : else if (nNumBits == 1)
820 : {
821 0 : nDataValue =
822 0 : (pabyValues[nValueBitOffset >> 3] >> (nValueBitOffset & 7)) &
823 : 0x1;
824 0 : nValueBitOffset++;
825 : }
826 84035 : else if (nNumBits == 2)
827 : {
828 0 : nDataValue =
829 0 : (pabyValues[nValueBitOffset >> 3] >> (nValueBitOffset & 7)) &
830 : 0x3;
831 0 : nValueBitOffset += 2;
832 : }
833 84035 : else if (nNumBits == 4)
834 : {
835 0 : nDataValue =
836 0 : (pabyValues[nValueBitOffset >> 3] >> (nValueBitOffset & 7)) &
837 : 0xf;
838 0 : nValueBitOffset += 4;
839 : }
840 84035 : else if (nNumBits == 8)
841 : {
842 10722 : nDataValue = *pabyValues;
843 10722 : pabyValues++;
844 : }
845 73313 : else if (nNumBits == 16)
846 : {
847 24147 : nDataValue = 256 * *(pabyValues++);
848 24147 : nDataValue += *(pabyValues++);
849 : }
850 49166 : else if (nNumBits == 32)
851 : {
852 49166 : memcpy(&nDataValue, pabyValues, 4);
853 49166 : CPL_MSBPTR32(&nDataValue);
854 49166 : pabyValues += 4;
855 : }
856 : else
857 : {
858 0 : CPLError(CE_Failure, CPLE_NotSupported, "nNumBits = %d", nNumBits);
859 0 : return CE_Failure;
860 : }
861 :
862 : // Offset by the minimum value.
863 84035 : nDataValue = CPLUnsanitizedAdd<int>(nDataValue, nDataMin);
864 :
865 : // Now apply to the output buffer in a type specific way.
866 84035 : if (nRepeatCount > INT_MAX - nPixelsOutput ||
867 84035 : nPixelsOutput + nRepeatCount > nMaxPixels)
868 : {
869 0 : CPLDebug("HFA", "Repeat count too big: %d", nRepeatCount);
870 0 : nRepeatCount = nMaxPixels - nPixelsOutput;
871 : }
872 :
873 84035 : if (eDataType == EPT_u8)
874 : {
875 45324 : for (int i = 0; i < nRepeatCount; i++)
876 : {
877 : #if DEBUG_VERBOSE
878 : // TODO(schwehr): Do something smarter with out-of-range data.
879 : // Bad data can trigger this assert. r23498
880 : CPLAssert(nDataValue < 256);
881 : #endif
882 41728 : pabyDest[nPixelsOutput++] = static_cast<GByte>(nDataValue);
883 : }
884 : }
885 80439 : else if (eDataType == EPT_u16)
886 : {
887 4209190 : for (int i = 0; i < nRepeatCount; i++)
888 : {
889 : #if DEBUG_VERBOSE
890 : CPLAssert(nDataValue >= 0);
891 : CPLAssert(nDataValue < 65536);
892 : #endif
893 4202500 : reinterpret_cast<GUInt16 *>(pabyDest)[nPixelsOutput++] =
894 : static_cast<GUInt16>(nDataValue);
895 : }
896 : }
897 73745 : else if (eDataType == EPT_s8)
898 : {
899 0 : for (int i = 0; i < nRepeatCount; i++)
900 : {
901 : #if DEBUG_VERBOSE
902 : // TODO(schwehr): Do something smarter with out-of-range data.
903 : // Bad data can trigger this assert. r23498
904 : CPLAssert(nDataValue >= -127);
905 : CPLAssert(nDataValue < 128);
906 : #endif
907 0 : ((GByte *)pabyDest)[nPixelsOutput++] =
908 : static_cast<GByte>(nDataValue);
909 : }
910 : }
911 73745 : else if (eDataType == EPT_s16)
912 : {
913 0 : for (int i = 0; i < nRepeatCount; i++)
914 : {
915 : #if DEBUG_VERBOSE
916 : // TODO(schwehr): Do something smarter with out-of-range data.
917 : // Bad data can trigger this assert. r23498
918 : CPLAssert(nDataValue >= -32768);
919 : CPLAssert(nDataValue < 32768);
920 : #endif
921 0 : reinterpret_cast<GInt16 *>(pabyDest)[nPixelsOutput++] =
922 : static_cast<GInt16>(nDataValue);
923 : }
924 : }
925 73745 : else if (eDataType == EPT_u32)
926 : {
927 16386 : for (int i = 0; i < nRepeatCount; i++)
928 : {
929 : #if DEBUG_VERBOSE
930 : // TODO(schwehr): Do something smarter with out-of-range data.
931 : // Bad data can trigger this assert. r23498
932 : CPLAssert(nDataValue >= 0);
933 : #endif
934 16384 : reinterpret_cast<GUInt32 *>(pabyDest)[nPixelsOutput++] =
935 16384 : static_cast<GUInt32>(nDataValue);
936 : }
937 : }
938 73743 : else if (eDataType == EPT_s32)
939 : {
940 116584 : for (int i = 0; i < nRepeatCount; i++)
941 : {
942 98304 : reinterpret_cast<GInt32 *>(pabyDest)[nPixelsOutput++] =
943 : static_cast<GInt32>(nDataValue);
944 : }
945 : }
946 55463 : else if (eDataType == EPT_f32)
947 : {
948 49164 : float fDataValue = 0.0f;
949 :
950 49164 : memcpy(&fDataValue, &nDataValue, 4);
951 245772 : for (int i = 0; i < nRepeatCount; i++)
952 : {
953 196608 : reinterpret_cast<float *>(pabyDest)[nPixelsOutput++] =
954 : fDataValue;
955 : }
956 : }
957 6299 : else if (eDataType == EPT_u1)
958 : {
959 : #ifdef DEBUG_VERBOSE
960 : CPLAssert(nDataValue == 0 || nDataValue == 1);
961 : #endif
962 4880 : if (nDataValue == 1)
963 : {
964 138116 : for (int i = 0; i < nRepeatCount; i++)
965 : {
966 135672 : pabyDest[nPixelsOutput >> 3] |=
967 135672 : (1 << (nPixelsOutput & 0x7));
968 135672 : nPixelsOutput++;
969 : }
970 : }
971 : else
972 : {
973 42892 : for (int i = 0; i < nRepeatCount; i++)
974 : {
975 40456 : pabyDest[nPixelsOutput >> 3] &=
976 40456 : ~(1 << (nPixelsOutput & 0x7));
977 40456 : nPixelsOutput++;
978 : }
979 : }
980 : }
981 1419 : else if (eDataType == EPT_u2)
982 : {
983 : #ifdef DEBUG_VERBOSE
984 : CPLAssert(nDataValue >= 0 && nDataValue < 4);
985 : #endif
986 17486 : for (int i = 0; i < nRepeatCount; i++)
987 : {
988 16384 : if ((nPixelsOutput & 0x3) == 0)
989 4096 : pabyDest[nPixelsOutput >> 2] =
990 : static_cast<GByte>(nDataValue);
991 12288 : else if ((nPixelsOutput & 0x3) == 1)
992 4096 : pabyDest[nPixelsOutput >> 2] |=
993 4096 : static_cast<GByte>((nDataValue & 0x3) << 2);
994 8192 : else if ((nPixelsOutput & 0x3) == 2)
995 4096 : pabyDest[nPixelsOutput >> 2] |=
996 4096 : static_cast<GByte>((nDataValue & 0x3) << 4);
997 : else
998 4096 : pabyDest[nPixelsOutput >> 2] |=
999 4096 : static_cast<GByte>((nDataValue & 0x3) << 6);
1000 16384 : nPixelsOutput++;
1001 : }
1002 : }
1003 317 : else if (eDataType == EPT_u4)
1004 : {
1005 : #ifdef DEBUG_VERBOSE
1006 : CPLAssert(nDataValue >= 0 && nDataValue < 16);
1007 : #endif
1008 4413 : for (int i = 0; i < nRepeatCount; i++)
1009 : {
1010 4096 : if ((nPixelsOutput & 0x1) == 0)
1011 2048 : pabyDest[nPixelsOutput >> 1] =
1012 : static_cast<GByte>(nDataValue);
1013 : else
1014 2048 : pabyDest[nPixelsOutput >> 1] |=
1015 2048 : static_cast<GByte>((nDataValue & 0xF) << 4);
1016 :
1017 4096 : nPixelsOutput++;
1018 : }
1019 : }
1020 : else
1021 : {
1022 0 : CPLError(CE_Failure, CPLE_AppDefined,
1023 : "Attempt to uncompress an unsupported pixel data type.");
1024 0 : return CE_Failure;
1025 : }
1026 : }
1027 :
1028 1158 : return CE_None;
1029 : }
1030 :
1031 : /************************************************************************/
1032 : /* NullBlock() */
1033 : /* */
1034 : /* Set the block buffer to zero or the nodata value as */
1035 : /* appropriate. */
1036 : /************************************************************************/
1037 :
1038 68 : void HFABand::NullBlock(void *pData)
1039 :
1040 : {
1041 68 : const int nChunkSize = std::max(1, HFAGetDataTypeBits(eDataType) / 8);
1042 68 : int nWords = nBlockXSize * nBlockYSize;
1043 :
1044 68 : if (!bNoDataSet)
1045 : {
1046 : #ifdef ESRI_BUILD
1047 : // We want special defaulting for 1 bit data in ArcGIS.
1048 : if (eDataType >= EPT_u2)
1049 : memset(pData, 0, static_cast<size_t>(nChunkSize) * nWords);
1050 : else
1051 : memset(pData, 255, static_cast<size_t>(nChunkSize) * nWords);
1052 : #else
1053 3 : memset(pData, 0, static_cast<size_t>(nChunkSize) * nWords);
1054 : #endif
1055 : }
1056 : else
1057 : {
1058 65 : GByte abyTmp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1059 :
1060 65 : switch (eDataType)
1061 : {
1062 0 : case EPT_u1:
1063 : {
1064 0 : nWords = (nWords + 7) / 8;
1065 0 : if (dfNoData != 0.0)
1066 0 : ((unsigned char *)abyTmp)[0] = 0xff;
1067 : else
1068 0 : ((unsigned char *)abyTmp)[0] = 0x00;
1069 : }
1070 0 : break;
1071 :
1072 0 : case EPT_u2:
1073 : {
1074 0 : nWords = (nWords + 3) / 4;
1075 0 : if (dfNoData == 0.0)
1076 0 : ((unsigned char *)abyTmp)[0] = 0x00;
1077 0 : else if (dfNoData == 1.0)
1078 0 : ((unsigned char *)abyTmp)[0] = 0x55;
1079 0 : else if (dfNoData == 2.0)
1080 0 : ((unsigned char *)abyTmp)[0] = 0xaa;
1081 : else
1082 0 : ((unsigned char *)abyTmp)[0] = 0xff;
1083 : }
1084 0 : break;
1085 :
1086 0 : case EPT_u4:
1087 : {
1088 : const unsigned char byVal = static_cast<unsigned char>(
1089 0 : std::max(0, std::min(15, static_cast<int>(dfNoData))));
1090 :
1091 0 : nWords = (nWords + 1) / 2;
1092 :
1093 0 : ((unsigned char *)abyTmp)[0] = byVal + (byVal << 4);
1094 : }
1095 0 : break;
1096 :
1097 64 : case EPT_u8:
1098 64 : ((unsigned char *)abyTmp)[0] = static_cast<unsigned char>(
1099 64 : std::max(0, std::min(255, static_cast<int>(dfNoData))));
1100 64 : break;
1101 :
1102 0 : case EPT_s8:
1103 0 : ((signed char *)abyTmp)[0] = static_cast<signed char>(
1104 0 : std::max(-128, std::min(127, static_cast<int>(dfNoData))));
1105 0 : break;
1106 :
1107 0 : case EPT_u16:
1108 : {
1109 0 : GUInt16 nTmp = static_cast<GUInt16>(dfNoData);
1110 0 : memcpy(abyTmp, &nTmp, sizeof(nTmp));
1111 0 : break;
1112 : }
1113 :
1114 0 : case EPT_s16:
1115 : {
1116 0 : GInt16 nTmp = static_cast<GInt16>(dfNoData);
1117 0 : memcpy(abyTmp, &nTmp, sizeof(nTmp));
1118 0 : break;
1119 : }
1120 :
1121 0 : case EPT_u32:
1122 : {
1123 0 : GUInt32 nTmp = static_cast<GUInt32>(dfNoData);
1124 0 : memcpy(abyTmp, &nTmp, sizeof(nTmp));
1125 0 : break;
1126 : }
1127 :
1128 0 : case EPT_s32:
1129 : {
1130 0 : GInt32 nTmp = static_cast<GInt32>(dfNoData);
1131 0 : memcpy(abyTmp, &nTmp, sizeof(nTmp));
1132 0 : break;
1133 : }
1134 :
1135 1 : case EPT_f32:
1136 : {
1137 1 : float fTmp = static_cast<float>(dfNoData);
1138 1 : memcpy(abyTmp, &fTmp, sizeof(fTmp));
1139 1 : break;
1140 : }
1141 :
1142 0 : case EPT_f64:
1143 : {
1144 0 : memcpy(abyTmp, &dfNoData, sizeof(dfNoData));
1145 0 : break;
1146 : }
1147 :
1148 0 : case EPT_c64:
1149 : {
1150 0 : float fTmp = static_cast<float>(dfNoData);
1151 0 : memcpy(abyTmp, &fTmp, sizeof(fTmp));
1152 0 : memset(abyTmp + 4, 0, sizeof(float));
1153 0 : break;
1154 : }
1155 :
1156 0 : case EPT_c128:
1157 : {
1158 0 : memcpy(abyTmp, &dfNoData, sizeof(dfNoData));
1159 0 : memset(abyTmp + 8, 0, sizeof(double));
1160 0 : break;
1161 : }
1162 : }
1163 :
1164 266305 : for (int i = 0; i < nWords; i++)
1165 266240 : memcpy(((GByte *)pData) + nChunkSize * i, abyTmp, nChunkSize);
1166 : }
1167 68 : }
1168 :
1169 : /************************************************************************/
1170 : /* GetRasterBlock() */
1171 : /************************************************************************/
1172 :
1173 1354 : CPLErr HFABand::GetRasterBlock(int nXBlock, int nYBlock, void *pData,
1174 : int nDataSize)
1175 :
1176 : {
1177 1354 : if (LoadBlockInfo() != CE_None)
1178 0 : return CE_Failure;
1179 :
1180 1354 : const int iBlock = nXBlock + nYBlock * nBlocksPerRow;
1181 : const int nDataTypeSizeBytes =
1182 1354 : std::max(1, HFAGetDataTypeBits(eDataType) / 8);
1183 1354 : const int nGDALBlockSize = nDataTypeSizeBytes * nBlockXSize * nBlockYSize;
1184 :
1185 : // If the block isn't valid, we just return all zeros, and an
1186 : // indication of success.
1187 1354 : if ((panBlockFlag[iBlock] & BFLG_VALID) == 0)
1188 : {
1189 68 : NullBlock(pData);
1190 68 : return CE_None;
1191 : }
1192 :
1193 : // Otherwise we really read the data.
1194 1286 : vsi_l_offset nBlockOffset = 0;
1195 1286 : VSILFILE *fpData = nullptr;
1196 :
1197 : // Calculate block offset in case we have spill file. Use predefined
1198 : // block map otherwise.
1199 1286 : if (fpExternal)
1200 : {
1201 9 : fpData = fpExternal;
1202 9 : nBlockOffset = nBlockStart + nBlockSize * iBlock * nLayerStackCount +
1203 9 : nLayerStackIndex * nBlockSize;
1204 : }
1205 : else
1206 : {
1207 1277 : fpData = psInfo->fp;
1208 1277 : nBlockOffset = panBlockStart[iBlock];
1209 1277 : nBlockSize = panBlockSize[iBlock];
1210 : }
1211 :
1212 1286 : if (VSIFSeekL(fpData, nBlockOffset, SEEK_SET) != 0)
1213 : {
1214 : // XXX: We will not report error here, because file just may be
1215 : // in update state and data for this block will be available later.
1216 0 : if (psInfo->eAccess == HFA_Update)
1217 : {
1218 0 : memset(pData, 0, nGDALBlockSize);
1219 0 : return CE_None;
1220 : }
1221 : else
1222 : {
1223 0 : CPLError(CE_Failure, CPLE_FileIO,
1224 : "Seek to %x:%08x on %p failed\n%s",
1225 0 : static_cast<int>(nBlockOffset >> 32),
1226 : static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1227 0 : VSIStrerror(errno));
1228 0 : return CE_Failure;
1229 : }
1230 : }
1231 :
1232 : // If the block is compressed, read into an intermediate buffer
1233 : // and convert.
1234 1286 : if (panBlockFlag[iBlock] & BFLG_COMPRESSED)
1235 : {
1236 : GByte *pabyCData = static_cast<GByte *>(
1237 1182 : VSI_MALLOC_VERBOSE(static_cast<size_t>(nBlockSize)));
1238 1182 : if (pabyCData == nullptr)
1239 : {
1240 0 : return CE_Failure;
1241 : }
1242 :
1243 1182 : if (VSIFReadL(pabyCData, static_cast<size_t>(nBlockSize), 1, fpData) !=
1244 : 1)
1245 : {
1246 0 : CPLFree(pabyCData);
1247 :
1248 : // XXX: Suppose that file in update state
1249 0 : if (psInfo->eAccess == HFA_Update)
1250 : {
1251 0 : memset(pData, 0, nGDALBlockSize);
1252 0 : return CE_None;
1253 : }
1254 : else
1255 : {
1256 0 : CPLError(CE_Failure, CPLE_FileIO,
1257 : "Read of %d bytes at %x:%08x on %p failed.\n%s",
1258 0 : static_cast<int>(nBlockSize),
1259 0 : static_cast<int>(nBlockOffset >> 32),
1260 : static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1261 0 : VSIStrerror(errno));
1262 0 : return CE_Failure;
1263 : }
1264 : }
1265 :
1266 2364 : CPLErr eErr = UncompressBlock(pabyCData, static_cast<int>(nBlockSize),
1267 : static_cast<GByte *>(pData),
1268 1182 : nBlockXSize * nBlockYSize, eDataType);
1269 :
1270 1182 : CPLFree(pabyCData);
1271 :
1272 1182 : return eErr;
1273 : }
1274 :
1275 : // Read uncompressed data directly into the return buffer.
1276 104 : if (nDataSize != -1 &&
1277 104 : (nBlockSize > INT_MAX || static_cast<int>(nBlockSize) > nDataSize))
1278 : {
1279 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size: %d",
1280 0 : static_cast<int>(nBlockSize));
1281 0 : return CE_Failure;
1282 : }
1283 :
1284 104 : if (VSIFReadL(pData, static_cast<size_t>(nBlockSize), 1, fpData) != 1)
1285 : {
1286 0 : memset(pData, 0, nGDALBlockSize);
1287 :
1288 0 : if (fpData != fpExternal)
1289 0 : CPLDebug("HFABand", "Read of %x:%08x bytes at %d on %p failed.\n%s",
1290 0 : static_cast<int>(nBlockSize),
1291 0 : static_cast<int>(nBlockOffset >> 32),
1292 : static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1293 0 : VSIStrerror(errno));
1294 :
1295 0 : return CE_None;
1296 : }
1297 :
1298 : // Byte swap to local byte order if required. It appears that
1299 : // raster data is always stored in Intel byte order in Imagine
1300 : // files.
1301 :
1302 : #ifdef CPL_MSB
1303 : if (HFAGetDataTypeBits(eDataType) == 16)
1304 : {
1305 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1306 : CPL_SWAP16PTR(((unsigned char *)pData) + ii * 2);
1307 : }
1308 : else if (HFAGetDataTypeBits(eDataType) == 32)
1309 : {
1310 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1311 : CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1312 : }
1313 : else if (eDataType == EPT_f64)
1314 : {
1315 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1316 : CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1317 : }
1318 : else if (eDataType == EPT_c64)
1319 : {
1320 : for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1321 : CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1322 : }
1323 : else if (eDataType == EPT_c128)
1324 : {
1325 : for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1326 : CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1327 : }
1328 : #endif // def CPL_MSB
1329 :
1330 104 : return CE_None;
1331 : }
1332 :
1333 : /************************************************************************/
1334 : /* ReAllocBlock() */
1335 : /************************************************************************/
1336 :
1337 17 : void HFABand::ReAllocBlock(int iBlock, int nSize)
1338 : {
1339 : // For compressed files - need to realloc the space for the block.
1340 :
1341 : // TODO: Should check to see if panBlockStart[iBlock] is not zero then do a
1342 : // HFAFreeSpace() but that doesn't exist yet.
1343 : // Instead as in interim measure it will reuse the existing block if
1344 : // the new data will fit in.
1345 17 : if ((panBlockStart[iBlock] != 0) && (nSize <= panBlockSize[iBlock]))
1346 : {
1347 0 : panBlockSize[iBlock] = nSize;
1348 : // fprintf( stderr, "Reusing block %d\n", iBlock );
1349 0 : return;
1350 : }
1351 :
1352 17 : panBlockStart[iBlock] = HFAAllocateSpace(psInfo, nSize);
1353 :
1354 17 : panBlockSize[iBlock] = nSize;
1355 :
1356 : // Need to rewrite this info to the RasterDMS node.
1357 17 : HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
1358 :
1359 17 : if (!poDMS)
1360 : {
1361 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to load RasterDMS");
1362 0 : return;
1363 : }
1364 :
1365 : char szVarName[64];
1366 17 : snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].offset", iBlock);
1367 17 : poDMS->SetIntField(szVarName, static_cast<int>(panBlockStart[iBlock]));
1368 :
1369 17 : snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].size", iBlock);
1370 17 : poDMS->SetIntField(szVarName, panBlockSize[iBlock]);
1371 : }
1372 :
1373 : /************************************************************************/
1374 : /* SetRasterBlock() */
1375 : /************************************************************************/
1376 :
1377 134 : CPLErr HFABand::SetRasterBlock(int nXBlock, int nYBlock, void *pData)
1378 :
1379 : {
1380 134 : if (psInfo->eAccess == HFA_ReadOnly)
1381 : {
1382 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1383 : "Attempt to write block to read-only HFA file failed.");
1384 0 : return CE_Failure;
1385 : }
1386 :
1387 134 : if (LoadBlockInfo() != CE_None)
1388 0 : return CE_Failure;
1389 :
1390 134 : const int iBlock = nXBlock + nYBlock * nBlocksPerRow;
1391 :
1392 : // For now we don't support write invalid uncompressed blocks.
1393 : // To do so we will need logic to make space at the end of the
1394 : // file in the right size.
1395 134 : if ((panBlockFlag[iBlock] & BFLG_VALID) == 0 &&
1396 118 : !(panBlockFlag[iBlock] & BFLG_COMPRESSED) && panBlockStart[iBlock] == 0)
1397 : {
1398 0 : CPLError(CE_Failure, CPLE_AppDefined,
1399 : "Attempt to write to invalid tile with number %d "
1400 : "(X position %d, Y position %d). This operation is "
1401 : "currently unsupported by HFABand::SetRasterBlock().",
1402 : iBlock, nXBlock, nYBlock);
1403 :
1404 0 : return CE_Failure;
1405 : }
1406 :
1407 : // Move to the location that the data sits.
1408 134 : VSILFILE *fpData = nullptr;
1409 134 : vsi_l_offset nBlockOffset = 0;
1410 :
1411 : // Calculate block offset in case we have spill file. Use predefined
1412 : // block map otherwise.
1413 134 : if (fpExternal)
1414 : {
1415 7 : fpData = fpExternal;
1416 7 : nBlockOffset = nBlockStart + nBlockSize * iBlock * nLayerStackCount +
1417 7 : nLayerStackIndex * nBlockSize;
1418 : }
1419 : else
1420 : {
1421 127 : fpData = psInfo->fp;
1422 127 : nBlockOffset = panBlockStart[iBlock];
1423 127 : nBlockSize = panBlockSize[iBlock];
1424 : }
1425 :
1426 : // Compressed Tile Handling.
1427 134 : if (panBlockFlag[iBlock] & BFLG_COMPRESSED)
1428 : {
1429 : // Write compressed data.
1430 : int nInBlockSize = static_cast<int>(
1431 34 : (static_cast<GIntBig>(nBlockXSize) * nBlockYSize *
1432 17 : static_cast<GIntBig>(HFAGetDataTypeBits(eDataType)) +
1433 17 : 7) /
1434 17 : 8);
1435 :
1436 : // Create the compressor object.
1437 17 : HFACompress compress(pData, nInBlockSize, eDataType);
1438 17 : if (compress.getCounts() == nullptr || compress.getValues() == nullptr)
1439 : {
1440 0 : return CE_Failure;
1441 : }
1442 :
1443 : // Compress the data.
1444 17 : if (compress.compressBlock())
1445 : {
1446 : // Get the data out of the object.
1447 15 : GByte *pCounts = compress.getCounts();
1448 15 : GUInt32 nSizeCount = compress.getCountSize();
1449 15 : GByte *pValues = compress.getValues();
1450 15 : GUInt32 nSizeValues = compress.getValueSize();
1451 15 : GUInt32 nMin = compress.getMin();
1452 15 : GUInt32 nNumRuns = compress.getNumRuns();
1453 15 : GByte nNumBits = compress.getNumBits();
1454 :
1455 : // Compensate for the header info.
1456 15 : GUInt32 nDataOffset = nSizeCount + 13;
1457 15 : int nTotalSize = nSizeCount + nSizeValues + 13;
1458 :
1459 : // Allocate space for the compressed block and seek to it.
1460 15 : ReAllocBlock(iBlock, nTotalSize);
1461 :
1462 15 : nBlockOffset = panBlockStart[iBlock];
1463 15 : nBlockSize = panBlockSize[iBlock];
1464 :
1465 : // Seek to offset.
1466 15 : if (VSIFSeekL(fpData, nBlockOffset, SEEK_SET) != 0)
1467 : {
1468 0 : CPLError(CE_Failure, CPLE_FileIO,
1469 : "Seek to %x:%08x on %p failed\n%s",
1470 0 : static_cast<int>(nBlockOffset >> 32),
1471 : static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1472 0 : VSIStrerror(errno));
1473 0 : return CE_Failure;
1474 : }
1475 :
1476 : // Byte swap to local byte order if required. It appears that
1477 : // raster data is always stored in Intel byte order in Imagine
1478 : // files.
1479 :
1480 : #ifdef CPL_MSB
1481 : CPL_SWAP32PTR(&nMin);
1482 : CPL_SWAP32PTR(&nNumRuns);
1483 : CPL_SWAP32PTR(&nDataOffset);
1484 : #endif // def CPL_MSB
1485 :
1486 : // Write out the Minimum value.
1487 15 : bool bRet = VSIFWriteL(&nMin, sizeof(nMin), 1, fpData) > 0;
1488 :
1489 : // The number of runs.
1490 15 : bRet &= VSIFWriteL(&nNumRuns, sizeof(nNumRuns), 1, fpData) > 0;
1491 :
1492 : // The offset to the data.
1493 15 : bRet &=
1494 15 : VSIFWriteL(&nDataOffset, sizeof(nDataOffset), 1, fpData) > 0;
1495 :
1496 : // The number of bits.
1497 15 : bRet &= VSIFWriteL(&nNumBits, sizeof(nNumBits), 1, fpData) > 0;
1498 :
1499 : // The counters - MSB stuff handled in HFACompress.
1500 15 : bRet &= VSIFWriteL(pCounts, nSizeCount, 1, fpData) > 0;
1501 :
1502 : // The values - MSB stuff handled in HFACompress.
1503 15 : bRet &= VSIFWriteL(pValues, nSizeValues, 1, fpData) > 0;
1504 :
1505 15 : if (!bRet)
1506 0 : return CE_Failure;
1507 :
1508 : // Compressed data is freed in the HFACompress destructor.
1509 : }
1510 : else
1511 : {
1512 : // If we have actually made the block bigger - i.e. does not
1513 : // compress well.
1514 2 : panBlockFlag[iBlock] ^= BFLG_COMPRESSED;
1515 : // Alloc more space for the uncompressed block.
1516 2 : ReAllocBlock(iBlock, nInBlockSize);
1517 :
1518 2 : nBlockOffset = panBlockStart[iBlock];
1519 2 : nBlockSize = panBlockSize[iBlock];
1520 :
1521 : // Need to change the RasterDMS entry.
1522 2 : HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
1523 :
1524 2 : if (!poDMS)
1525 : {
1526 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to load RasterDMS");
1527 0 : return CE_Failure;
1528 : }
1529 :
1530 2 : char szVarName[64] = {};
1531 2 : snprintf(szVarName, sizeof(szVarName),
1532 : "blockinfo[%d].compressionType", iBlock);
1533 2 : poDMS->SetIntField(szVarName, 0);
1534 : }
1535 :
1536 : // If the block was previously invalid, mark it as valid now.
1537 17 : if ((panBlockFlag[iBlock] & BFLG_VALID) == 0)
1538 : {
1539 : char szVarName[64];
1540 17 : HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
1541 :
1542 17 : if (!poDMS)
1543 : {
1544 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to load RasterDMS");
1545 0 : return CE_Failure;
1546 : }
1547 :
1548 17 : snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].logvalid",
1549 : iBlock);
1550 17 : poDMS->SetStringField(szVarName, "true");
1551 :
1552 17 : panBlockFlag[iBlock] |= BFLG_VALID;
1553 : }
1554 : }
1555 :
1556 : // Uncompressed TILE handling.
1557 134 : if ((panBlockFlag[iBlock] & BFLG_COMPRESSED) == 0)
1558 : {
1559 :
1560 119 : if (VSIFSeekL(fpData, nBlockOffset, SEEK_SET) != 0)
1561 : {
1562 0 : CPLError(CE_Failure, CPLE_FileIO,
1563 : "Seek to %x:%08x on %p failed\n%s",
1564 0 : static_cast<int>(nBlockOffset >> 32),
1565 : static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1566 0 : VSIStrerror(errno));
1567 0 : return CE_Failure;
1568 : }
1569 :
1570 : // Byte swap to local byte order if required. It appears that
1571 : // raster data is always stored in Intel byte order in Imagine
1572 : // files.
1573 :
1574 : #ifdef CPL_MSB
1575 : if (HFAGetDataTypeBits(eDataType) == 16)
1576 : {
1577 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1578 : CPL_SWAP16PTR(((unsigned char *)pData) + ii * 2);
1579 : }
1580 : else if (HFAGetDataTypeBits(eDataType) == 32)
1581 : {
1582 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1583 : CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1584 : }
1585 : else if (eDataType == EPT_f64)
1586 : {
1587 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1588 : CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1589 : }
1590 : else if (eDataType == EPT_c64)
1591 : {
1592 : for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1593 : CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1594 : }
1595 : else if (eDataType == EPT_c128)
1596 : {
1597 : for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1598 : CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1599 : }
1600 : #endif // def CPL_MSB
1601 :
1602 : // Write uncompressed data.
1603 119 : if (VSIFWriteL(pData, static_cast<size_t>(nBlockSize), 1, fpData) != 1)
1604 : {
1605 0 : CPLError(CE_Failure, CPLE_FileIO,
1606 : "Write of %d bytes at %x:%08x on %p failed.\n%s",
1607 0 : static_cast<int>(nBlockSize),
1608 0 : static_cast<int>(nBlockOffset >> 32),
1609 : static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1610 0 : VSIStrerror(errno));
1611 0 : return CE_Failure;
1612 : }
1613 :
1614 : // If the block was previously invalid, mark it as valid now.
1615 119 : if ((panBlockFlag[iBlock] & BFLG_VALID) == 0)
1616 : {
1617 : char szVarName[64];
1618 101 : HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
1619 101 : if (poDMS == nullptr)
1620 : {
1621 0 : CPLError(CE_Failure, CPLE_AppDefined,
1622 : "Unable to get RasterDMS when trying to mark "
1623 : "block valid.");
1624 0 : return CE_Failure;
1625 : }
1626 101 : snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].logvalid",
1627 : iBlock);
1628 101 : poDMS->SetStringField(szVarName, "true");
1629 :
1630 101 : panBlockFlag[iBlock] |= BFLG_VALID;
1631 : }
1632 : }
1633 : // Swap back, since we don't really have permission to change
1634 : // the callers buffer.
1635 :
1636 : #ifdef CPL_MSB
1637 : if (HFAGetDataTypeBits(eDataType) == 16)
1638 : {
1639 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1640 : CPL_SWAP16PTR(((unsigned char *)pData) + ii * 2);
1641 : }
1642 : else if (HFAGetDataTypeBits(eDataType) == 32)
1643 : {
1644 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1645 : CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1646 : }
1647 : else if (eDataType == EPT_f64)
1648 : {
1649 : for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1650 : CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1651 : }
1652 : else if (eDataType == EPT_c64)
1653 : {
1654 : for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1655 : CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1656 : }
1657 : else if (eDataType == EPT_c128)
1658 : {
1659 : for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1660 : CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1661 : }
1662 : #endif // def CPL_MSB
1663 :
1664 134 : return CE_None;
1665 : }
1666 :
1667 : /************************************************************************/
1668 : /* GetBandName() */
1669 : /* */
1670 : /* Return the Layer Name */
1671 : /************************************************************************/
1672 :
1673 229 : const char *HFABand::GetBandName()
1674 : {
1675 229 : if (strlen(poNode->GetName()) > 0)
1676 229 : return poNode->GetName();
1677 :
1678 0 : for (int iBand = 0; iBand < psInfo->nBands; iBand++)
1679 : {
1680 0 : if (psInfo->papoBand[iBand] == this)
1681 : {
1682 0 : osOverName.Printf("Layer_%d", iBand + 1);
1683 0 : return osOverName;
1684 : }
1685 : }
1686 :
1687 0 : osOverName.Printf("Layer_%x", poNode->GetFilePos());
1688 0 : return osOverName;
1689 : }
1690 :
1691 : /************************************************************************/
1692 : /* SetBandName() */
1693 : /* */
1694 : /* Set the Layer Name */
1695 : /************************************************************************/
1696 :
1697 7 : void HFABand::SetBandName(const char *pszName)
1698 : {
1699 7 : if (psInfo->eAccess == HFA_Update)
1700 : {
1701 7 : poNode->SetName(pszName);
1702 : }
1703 7 : }
1704 :
1705 : /************************************************************************/
1706 : /* SetNoDataValue() */
1707 : /* */
1708 : /* Set the band no-data value */
1709 : /************************************************************************/
1710 :
1711 10 : CPLErr HFABand::SetNoDataValue(double dfValue)
1712 : {
1713 10 : if (psInfo->eAccess != HFA_Update)
1714 0 : return CE_Failure;
1715 :
1716 10 : HFAEntry *poNDNode = poNode->GetNamedChild("Eimg_NonInitializedValue");
1717 :
1718 10 : if (poNDNode == nullptr)
1719 : {
1720 10 : poNDNode = HFAEntry::New(psInfo, "Eimg_NonInitializedValue",
1721 : "Eimg_NonInitializedValue", poNode);
1722 : }
1723 :
1724 10 : poNDNode->MakeData(8 + 12 + 8);
1725 10 : poNDNode->SetPosition();
1726 :
1727 10 : poNDNode->SetIntField("valueBD[-3]", EPT_f64);
1728 10 : poNDNode->SetIntField("valueBD[-2]", 1);
1729 10 : poNDNode->SetIntField("valueBD[-1]", 1);
1730 :
1731 10 : if (poNDNode->SetDoubleField("valueBD[0]", dfValue) == CE_Failure)
1732 0 : return CE_Failure;
1733 :
1734 10 : bNoDataSet = true;
1735 10 : dfNoData = dfValue;
1736 10 : return CE_None;
1737 : }
1738 :
1739 : /************************************************************************/
1740 : /* HFAReadBFUniqueBins() */
1741 : /* */
1742 : /* Attempt to read the bins used for a PCT or RAT from a */
1743 : /* BinFunction node. On failure just return NULL. */
1744 : /************************************************************************/
1745 :
1746 210 : double *HFAReadBFUniqueBins(HFAEntry *poBinFunc, int nPCTColors)
1747 :
1748 : {
1749 : // First confirm this is a "BFUnique" bin function. We don't
1750 : // know what to do with any other types.
1751 : const char *pszBinFunctionType =
1752 210 : poBinFunc->GetStringField("binFunction.type.string");
1753 :
1754 210 : if (pszBinFunctionType == nullptr || !EQUAL(pszBinFunctionType, "BFUnique"))
1755 0 : return nullptr;
1756 :
1757 : // Process dictionary.
1758 : const char *pszDict =
1759 210 : poBinFunc->GetStringField("binFunction.MIFDictionary.string");
1760 210 : if (pszDict == nullptr)
1761 0 : pszDict = poBinFunc->GetStringField("binFunction.MIFDictionary");
1762 210 : if (pszDict == nullptr)
1763 0 : return nullptr;
1764 :
1765 420 : HFADictionary oMiniDict(pszDict);
1766 :
1767 210 : HFAType *poBFUnique = oMiniDict.FindType("BFUnique");
1768 210 : if (poBFUnique == nullptr)
1769 0 : return nullptr;
1770 :
1771 : // Field the MIFObject raw data pointer.
1772 210 : int nMIFObjectSize = 0;
1773 : const GByte *pabyMIFObject =
1774 210 : reinterpret_cast<const GByte *>(poBinFunc->GetStringField(
1775 : "binFunction.MIFObject", nullptr, &nMIFObjectSize));
1776 :
1777 210 : if (pabyMIFObject == nullptr ||
1778 210 : nMIFObjectSize < 24 + static_cast<int>(sizeof(double)) * nPCTColors)
1779 0 : return nullptr;
1780 :
1781 : // Confirm that this is a 64bit floating point basearray.
1782 210 : if (pabyMIFObject[20] != 0x0a || pabyMIFObject[21] != 0x00)
1783 : {
1784 0 : CPLDebug("HFA", "HFAReadPCTBins(): "
1785 : "The basedata does not appear to be EGDA_TYPE_F64.");
1786 0 : return nullptr;
1787 : }
1788 :
1789 : // Decode bins.
1790 : double *padfBins =
1791 210 : static_cast<double *>(CPLCalloc(sizeof(double), nPCTColors));
1792 :
1793 210 : memcpy(padfBins, pabyMIFObject + 24, sizeof(double) * nPCTColors);
1794 :
1795 11925 : for (int i = 0; i < nPCTColors; i++)
1796 : {
1797 : HFAStandard(8, padfBins + i);
1798 : #if DEBUG_VERBOSE
1799 : CPLDebug("HFA", "Bin[%d] = %g", i, padfBins[i]);
1800 : #endif
1801 : }
1802 :
1803 210 : return padfBins;
1804 : }
1805 :
1806 : /************************************************************************/
1807 : /* GetPCT() */
1808 : /* */
1809 : /* Return PCT information, if any exists. */
1810 : /************************************************************************/
1811 :
1812 625 : CPLErr HFABand::GetPCT(int *pnColors, double **ppadfRed, double **ppadfGreen,
1813 : double **ppadfBlue, double **ppadfAlpha,
1814 : double **ppadfBins)
1815 :
1816 : {
1817 625 : *pnColors = 0;
1818 625 : *ppadfRed = nullptr;
1819 625 : *ppadfGreen = nullptr;
1820 625 : *ppadfBlue = nullptr;
1821 625 : *ppadfAlpha = nullptr;
1822 625 : *ppadfBins = nullptr;
1823 :
1824 : // If we haven't already tried to load the colors, do so now.
1825 625 : if (nPCTColors == -1)
1826 : {
1827 :
1828 625 : nPCTColors = 0;
1829 :
1830 625 : HFAEntry *poColumnEntry = poNode->GetNamedChild("Descriptor_Table.Red");
1831 625 : if (poColumnEntry == nullptr)
1832 615 : return CE_Failure;
1833 :
1834 10 : nPCTColors = poColumnEntry->GetIntField("numRows");
1835 10 : if (nPCTColors < 0 || nPCTColors > 65536)
1836 : {
1837 0 : CPLError(CE_Failure, CPLE_AppDefined,
1838 : "Invalid number of colors: %d", nPCTColors);
1839 0 : return CE_Failure;
1840 : }
1841 :
1842 50 : for (int iColumn = 0; iColumn < 4; iColumn++)
1843 : {
1844 40 : apadfPCT[iColumn] = static_cast<double *>(
1845 40 : VSI_MALLOC2_VERBOSE(sizeof(double), nPCTColors));
1846 40 : if (apadfPCT[iColumn] == nullptr)
1847 : {
1848 0 : return CE_Failure;
1849 : }
1850 :
1851 40 : if (iColumn == 0)
1852 : {
1853 10 : poColumnEntry = poNode->GetNamedChild("Descriptor_Table.Red");
1854 : }
1855 30 : else if (iColumn == 1)
1856 : {
1857 10 : poColumnEntry = poNode->GetNamedChild("Descriptor_Table.Green");
1858 : }
1859 20 : else if (iColumn == 2)
1860 : {
1861 10 : poColumnEntry = poNode->GetNamedChild("Descriptor_Table.Blue");
1862 : }
1863 10 : else if (iColumn == 3)
1864 : {
1865 : poColumnEntry =
1866 10 : poNode->GetNamedChild("Descriptor_Table.Opacity");
1867 : }
1868 :
1869 40 : if (poColumnEntry == nullptr)
1870 : {
1871 0 : double *pdCol = apadfPCT[iColumn];
1872 0 : for (int i = 0; i < nPCTColors; i++)
1873 0 : pdCol[i] = 1.0;
1874 : }
1875 : else
1876 : {
1877 80 : if (VSIFSeekL(psInfo->fp,
1878 40 : poColumnEntry->GetIntField("columnDataPtr"),
1879 40 : SEEK_SET) < 0)
1880 : {
1881 0 : CPLError(CE_Failure, CPLE_FileIO,
1882 : "VSIFSeekL() failed in HFABand::GetPCT().");
1883 0 : return CE_Failure;
1884 : }
1885 80 : if (VSIFReadL(apadfPCT[iColumn], sizeof(double), nPCTColors,
1886 40 : psInfo->fp) != static_cast<size_t>(nPCTColors))
1887 : {
1888 0 : CPLError(CE_Failure, CPLE_FileIO,
1889 : "VSIFReadL() failed in HFABand::GetPCT().");
1890 0 : return CE_Failure;
1891 : }
1892 :
1893 11300 : for (int i = 0; i < nPCTColors; i++)
1894 : HFAStandard(8, apadfPCT[iColumn] + i);
1895 : }
1896 : }
1897 :
1898 : // Do we have a custom binning function? If so, try reading it.
1899 : HFAEntry *poBinFunc =
1900 10 : poNode->GetNamedChild("Descriptor_Table.#Bin_Function840#");
1901 :
1902 10 : if (poBinFunc != nullptr)
1903 : {
1904 4 : padfPCTBins = HFAReadBFUniqueBins(poBinFunc, nPCTColors);
1905 : }
1906 : }
1907 :
1908 : // Return the values.
1909 10 : if (nPCTColors == 0)
1910 0 : return CE_Failure;
1911 :
1912 10 : *pnColors = nPCTColors;
1913 10 : *ppadfRed = apadfPCT[0];
1914 10 : *ppadfGreen = apadfPCT[1];
1915 10 : *ppadfBlue = apadfPCT[2];
1916 10 : *ppadfAlpha = apadfPCT[3];
1917 10 : *ppadfBins = padfPCTBins;
1918 :
1919 10 : return CE_None;
1920 : }
1921 :
1922 : /************************************************************************/
1923 : /* SetPCT() */
1924 : /* */
1925 : /* Set the PCT information for this band. */
1926 : /************************************************************************/
1927 :
1928 3 : CPLErr HFABand::SetPCT(int nColors, const double *padfRed,
1929 : const double *padfGreen, const double *padfBlue,
1930 : const double *padfAlpha)
1931 :
1932 : {
1933 : static const char *const apszColNames[4] = {"Red", "Green", "Blue",
1934 : "Opacity"};
1935 : const double *const apadfValues[] = {padfRed, padfGreen, padfBlue,
1936 3 : padfAlpha};
1937 : HFAEntry *poEdsc_Table;
1938 :
1939 : // Do we need to try and clear any existing color table?
1940 3 : if (nColors == 0)
1941 : {
1942 2 : poEdsc_Table = poNode->GetNamedChild("Descriptor_Table");
1943 2 : if (poEdsc_Table == nullptr)
1944 0 : return CE_None;
1945 :
1946 10 : for (int iColumn = 0; iColumn < 4; iColumn++)
1947 : {
1948 : HFAEntry *poEdsc_Column =
1949 8 : poEdsc_Table->GetNamedChild(apszColNames[iColumn]);
1950 8 : if (poEdsc_Column)
1951 8 : poEdsc_Column->RemoveAndDestroy();
1952 : }
1953 :
1954 2 : return CE_None;
1955 : }
1956 :
1957 : // Create the Descriptor table.
1958 1 : poEdsc_Table = poNode->GetNamedChild("Descriptor_Table");
1959 1 : if (poEdsc_Table == nullptr ||
1960 0 : !EQUAL(poEdsc_Table->GetType(), "Edsc_Table"))
1961 : poEdsc_Table =
1962 1 : HFAEntry::New(psInfo, "Descriptor_Table", "Edsc_Table", poNode);
1963 :
1964 1 : poEdsc_Table->SetIntField("numrows", nColors);
1965 :
1966 : // Create the Binning function node. I am not sure that we
1967 : // really need this though.
1968 : HFAEntry *poEdsc_BinFunction =
1969 1 : poEdsc_Table->GetNamedChild("#Bin_Function#");
1970 1 : if (poEdsc_BinFunction == nullptr ||
1971 0 : !EQUAL(poEdsc_BinFunction->GetType(), "Edsc_BinFunction"))
1972 1 : poEdsc_BinFunction = HFAEntry::New(psInfo, "#Bin_Function#",
1973 : "Edsc_BinFunction", poEdsc_Table);
1974 :
1975 : // Because of the BaseData we have to hardcode the size.
1976 1 : poEdsc_BinFunction->MakeData(30);
1977 :
1978 1 : poEdsc_BinFunction->SetIntField("numBins", nColors);
1979 1 : poEdsc_BinFunction->SetStringField("binFunction", "direct");
1980 1 : poEdsc_BinFunction->SetDoubleField("minLimit", 0.0);
1981 1 : poEdsc_BinFunction->SetDoubleField("maxLimit", nColors - 1.0);
1982 :
1983 : // Process each color component.
1984 5 : for (int iColumn = 0; iColumn < 4; iColumn++)
1985 : {
1986 4 : const double *padfValues = apadfValues[iColumn];
1987 4 : const char *pszName = apszColNames[iColumn];
1988 :
1989 : // Create the Edsc_Column.
1990 4 : HFAEntry *poEdsc_Column = poEdsc_Table->GetNamedChild(pszName);
1991 4 : if (poEdsc_Column == nullptr ||
1992 0 : !EQUAL(poEdsc_Column->GetType(), "Edsc_Column"))
1993 : poEdsc_Column =
1994 4 : HFAEntry::New(psInfo, pszName, "Edsc_Column", poEdsc_Table);
1995 :
1996 4 : poEdsc_Column->SetIntField("numRows", nColors);
1997 4 : poEdsc_Column->SetStringField("dataType", "real");
1998 4 : poEdsc_Column->SetIntField("maxNumChars", 0);
1999 :
2000 : // Write the data out.
2001 4 : const auto nOffset = HFAAllocateSpace(psInfo, 8 * nColors);
2002 4 : if (nOffset > static_cast<unsigned>(INT_MAX))
2003 0 : return CE_Failure;
2004 :
2005 4 : poEdsc_Column->SetIntField("columnDataPtr", static_cast<int>(nOffset));
2006 :
2007 : double *padfFileData =
2008 4 : static_cast<double *>(CPLMalloc(nColors * sizeof(double)));
2009 1028 : for (int iColor = 0; iColor < nColors; iColor++)
2010 : {
2011 1024 : padfFileData[iColor] = padfValues[iColor];
2012 : HFAStandard(8, padfFileData + iColor);
2013 : }
2014 8 : const bool bRet = VSIFSeekL(psInfo->fp, nOffset, SEEK_SET) >= 0 &&
2015 4 : VSIFWriteL(padfFileData, 8, nColors, psInfo->fp) ==
2016 4 : static_cast<size_t>(nColors);
2017 4 : CPLFree(padfFileData);
2018 4 : if (!bRet)
2019 0 : return CE_Failure;
2020 : }
2021 :
2022 : // Update the layer type to be thematic.
2023 1 : poNode->SetStringField("layerType", "thematic");
2024 :
2025 1 : return CE_None;
2026 : }
2027 :
2028 : /************************************************************************/
2029 : /* HFAGetOverviewBlockSize() */
2030 : /************************************************************************/
2031 :
2032 12 : static int HFAGetOverviewBlockSize()
2033 : {
2034 12 : const char *pszVal = CPLGetConfigOption("GDAL_HFA_OVR_BLOCKSIZE", "64");
2035 12 : int nOvrBlockSize = atoi(pszVal);
2036 24 : if (nOvrBlockSize < 32 || nOvrBlockSize > 2048 ||
2037 12 : !CPLIsPowerOfTwo(nOvrBlockSize))
2038 : {
2039 0 : CPLErrorOnce(CE_Warning, CPLE_NotSupported,
2040 : "Wrong value for GDAL_HFA_OVR_BLOCKSIZE : %s. "
2041 : "Should be a power of 2 between 32 and 2048. "
2042 : "Defaulting to 64",
2043 : pszVal);
2044 0 : nOvrBlockSize = 64;
2045 : }
2046 :
2047 12 : return nOvrBlockSize;
2048 : }
2049 :
2050 : /************************************************************************/
2051 : /* CreateOverview() */
2052 : /************************************************************************/
2053 :
2054 12 : int HFABand::CreateOverview(int nOverviewLevel, const char *pszResampling)
2055 :
2056 : {
2057 12 : const int nOXSize = DIV_ROUND_UP(psInfo->nXSize, nOverviewLevel);
2058 12 : const int nOYSize = DIV_ROUND_UP(psInfo->nYSize, nOverviewLevel);
2059 :
2060 : // Do we want to use a dependent file (.rrd) for the overviews?
2061 : // Or just create them directly in this file?
2062 12 : HFAInfo_t *psRRDInfo = psInfo;
2063 12 : HFAEntry *poParent = poNode;
2064 :
2065 12 : if (CPLTestBool(CPLGetConfigOption("HFA_USE_RRD", "NO")))
2066 : {
2067 2 : psRRDInfo = HFACreateDependent(psInfo);
2068 2 : if (psRRDInfo == nullptr)
2069 0 : return -1;
2070 :
2071 2 : poParent = psRRDInfo->poRoot->GetNamedChild(GetBandName());
2072 :
2073 : // Need to create layer object.
2074 2 : if (poParent == nullptr)
2075 : {
2076 1 : poParent = HFAEntry::New(psRRDInfo, GetBandName(), "Eimg_Layer",
2077 : psRRDInfo->poRoot);
2078 : }
2079 : }
2080 :
2081 : // What pixel type should we use for the overview. Usually
2082 : // this is the same as the base layer, but when
2083 : // AVERAGE_BIT2GRAYSCALE is in effect we force it to u8 from u1.
2084 12 : EPTType eOverviewDataType = eDataType;
2085 :
2086 12 : if (STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2GR"))
2087 1 : eOverviewDataType = EPT_u8;
2088 :
2089 : // Eventually we need to decide on the whether to use the spill
2090 : // file, primarily on the basis of whether the new overview
2091 : // will drive our .img file size near 4GB. For now, just base
2092 : // it on the config options.
2093 : bool bCreateLargeRaster =
2094 12 : CPLTestBool(CPLGetConfigOption("USE_SPILL", "NO"));
2095 12 : GIntBig nValidFlagsOffset = 0;
2096 12 : GIntBig nDataOffset = 0;
2097 12 : int nOverviewBlockSize = HFAGetOverviewBlockSize();
2098 :
2099 24 : if ((psRRDInfo->nEndOfFile +
2100 24 : (nOXSize * static_cast<double>(nOYSize)) *
2101 12 : (HFAGetDataTypeBits(eOverviewDataType) / 8)) > 2000000000.0)
2102 0 : bCreateLargeRaster = true;
2103 :
2104 12 : if (bCreateLargeRaster)
2105 : {
2106 0 : if (!HFACreateSpillStack(psRRDInfo, nOXSize, nOYSize, 1,
2107 : nOverviewBlockSize, eOverviewDataType,
2108 : &nValidFlagsOffset, &nDataOffset))
2109 : {
2110 0 : return -1;
2111 : }
2112 : }
2113 :
2114 : // Are we compressed? If so, overview should be too (unless
2115 : // HFA_COMPRESS_OVR is defined).
2116 : // Check RasterDMS like HFAGetBandInfo.
2117 12 : bool bCompressionType = false;
2118 : const char *pszCompressOvr =
2119 12 : CPLGetConfigOption("HFA_COMPRESS_OVR", nullptr);
2120 12 : if (pszCompressOvr != nullptr)
2121 : {
2122 0 : bCompressionType = CPLTestBool(pszCompressOvr);
2123 : }
2124 : else
2125 : {
2126 12 : HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
2127 :
2128 12 : if (poDMS != nullptr)
2129 5 : bCompressionType = poDMS->GetIntField("compressionType") != 0;
2130 : }
2131 :
2132 : // Create the layer.
2133 24 : CPLString osLayerName;
2134 12 : osLayerName.Printf("_ss_%d_", nOverviewLevel);
2135 :
2136 12 : if (!HFACreateLayer(
2137 : psRRDInfo, poParent, osLayerName, TRUE, nOverviewBlockSize,
2138 : bCompressionType, bCreateLargeRaster, FALSE, nOXSize, nOYSize,
2139 : eOverviewDataType, nullptr, nValidFlagsOffset, nDataOffset, 1, 0))
2140 0 : return -1;
2141 :
2142 12 : HFAEntry *poOverLayer = poParent->GetNamedChild(osLayerName);
2143 12 : if (poOverLayer == nullptr)
2144 0 : return -1;
2145 :
2146 : // Create RRDNamesList list if it does not yet exist.
2147 12 : HFAEntry *poRRDNamesList = poNode->GetNamedChild("RRDNamesList");
2148 12 : if (poRRDNamesList == nullptr)
2149 : {
2150 : poRRDNamesList =
2151 6 : HFAEntry::New(psInfo, "RRDNamesList", "Eimg_RRDNamesList", poNode);
2152 6 : poRRDNamesList->MakeData(23 + 16 + 8 + 3000); // Hack for growth room.
2153 :
2154 : // We need to hardcode file offset into the data, so locate it now.
2155 6 : poRRDNamesList->SetPosition();
2156 :
2157 6 : poRRDNamesList->SetStringField("algorithm.string",
2158 : "IMAGINE 2X2 Resampling");
2159 : }
2160 :
2161 : // Add new overview layer to RRDNamesList.
2162 12 : int iNextName = poRRDNamesList->GetFieldCount("nameList");
2163 : char szName[50];
2164 24 : CPLString osNodeName;
2165 :
2166 12 : snprintf(szName, sizeof(szName), "nameList[%d].string", iNextName);
2167 :
2168 : osLayerName.Printf("%s(:%s:_ss_%d_)", psRRDInfo->pszFilename, GetBandName(),
2169 12 : nOverviewLevel);
2170 :
2171 : // TODO: Need to add to end of array (that is pretty hard).
2172 12 : if (poRRDNamesList->SetStringField(szName, osLayerName) != CE_None)
2173 : {
2174 1 : poRRDNamesList->MakeData(poRRDNamesList->GetDataSize() + 3000);
2175 1 : if (poRRDNamesList->SetStringField(szName, osLayerName) != CE_None)
2176 0 : return -1;
2177 : }
2178 :
2179 : // Add to the list of overviews for this band.
2180 24 : papoOverviews = static_cast<HFABand **>(
2181 12 : CPLRealloc(papoOverviews, sizeof(void *) * ++nOverviews));
2182 12 : papoOverviews[nOverviews - 1] = new HFABand(psRRDInfo, poOverLayer);
2183 :
2184 : // If there is a nodata value, copy it to the overview band.
2185 12 : if (bNoDataSet)
2186 1 : papoOverviews[nOverviews - 1]->SetNoDataValue(dfNoData);
2187 :
2188 12 : return nOverviews - 1;
2189 : }
|