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