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