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