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