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