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