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