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