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