1 : /******************************************************************************
2 : * $Id: hfaopen.cpp 18895 2010-02-23 19:30:01Z warmerdam $
3 : *
4 : * Project: Erdas Imagine (.img) Translator
5 : * Purpose: Supporting functions for HFA (.img) ... main (C callable) API
6 : * that is not dependent on GDAL (just CPL).
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 1999, Intergraph Corporation
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ******************************************************************************
30 : *
31 : * hfaopen.cpp
32 : *
33 : * Supporting routines for reading Erdas Imagine (.imf) Heirarchical
34 : * File Architecture files. This is intended to be a library independent
35 : * of the GDAL core, but dependent on the Common Portability Library.
36 : *
37 : */
38 :
39 : #include "hfa_p.h"
40 : #include "cpl_conv.h"
41 : #include <limits.h>
42 :
43 : CPL_CVSID("$Id: hfaopen.cpp 18895 2010-02-23 19:30:01Z warmerdam $");
44 :
45 :
46 : static const char *apszAuxMetadataItems[] = {
47 :
48 : // node/entry field_name metadata_key type
49 :
50 : "Statistics", "dminimum", "STATISTICS_MINIMUM", "Esta_Statistics",
51 : "Statistics", "dmaximum", "STATISTICS_MAXIMUM", "Esta_Statistics",
52 : "Statistics", "dmean", "STATISTICS_MEAN", "Esta_Statistics",
53 : "Statistics", "dmedian", "STATISTICS_MEDIAN", "Esta_Statistics",
54 : "Statistics", "dmode", "STATISTICS_MODE", "Esta_Statistics",
55 : "Statistics", "dstddev", "STATISTICS_STDDEV", "Esta_Statistics",
56 : "HistogramParameters", "lBinFunction.numBins", "STATISTICS_HISTONUMBINS","Eimg_StatisticsParameters830",
57 : "HistogramParameters", "dBinFunction.minLimit", "STATISTICS_HISTOMIN", "Eimg_StatisticsParameters830",
58 : "HistogramParameters", "dBinFunction.maxLimit", "STATISTICS_HISTOMAX", "Eimg_StatisticsParameters830",
59 : "StatisticsParameters", "lSkipFactorX", "STATISTICS_SKIPFACTORX", "",
60 : "StatisticsParameters", "lSkipFactorY", "STATISTICS_SKIPFACTORY", "",
61 : "StatisticsParameters", "dExcludedValues", "STATISTICS_EXCLUDEDVALUES","",
62 : "", "elayerType", "LAYER_TYPE", "",
63 : NULL
64 : };
65 :
66 :
67 527 : const char ** GetHFAAuxMetaDataList()
68 : {
69 527 : return apszAuxMetadataItems;
70 : }
71 :
72 :
73 : /************************************************************************/
74 : /* HFAGetDictionary() */
75 : /************************************************************************/
76 :
77 317 : static char * HFAGetDictionary( HFAHandle hHFA )
78 :
79 : {
80 317 : int nDictMax = 100;
81 317 : char *pszDictionary = (char *) CPLMalloc(nDictMax);
82 317 : int nDictSize = 0;
83 :
84 317 : VSIFSeekL( hHFA->fp, hHFA->nDictionaryPos, SEEK_SET );
85 :
86 1169775 : while( TRUE )
87 : {
88 1170092 : if( nDictSize >= nDictMax-1 )
89 : {
90 1575 : nDictMax = nDictSize * 2 + 100;
91 1575 : pszDictionary = (char *) CPLRealloc(pszDictionary, nDictMax );
92 : }
93 :
94 1170092 : if( VSIFReadL( pszDictionary + nDictSize, 1, 1, hHFA->fp ) < 1
95 : || pszDictionary[nDictSize] == '\0'
96 : || (nDictSize > 2 && pszDictionary[nDictSize-2] == ','
97 : && pszDictionary[nDictSize-1] == '.') )
98 317 : break;
99 :
100 1169775 : nDictSize++;
101 : }
102 :
103 317 : pszDictionary[nDictSize] = '\0';
104 :
105 :
106 317 : return( pszDictionary );
107 : }
108 :
109 : /************************************************************************/
110 : /* HFAOpen() */
111 : /************************************************************************/
112 :
113 317 : HFAHandle HFAOpen( const char * pszFilename, const char * pszAccess )
114 :
115 : {
116 : FILE *fp;
117 : char szHeader[16];
118 : HFAInfo_t *psInfo;
119 : GUInt32 nHeaderPos;
120 :
121 : /* -------------------------------------------------------------------- */
122 : /* Open the file. */
123 : /* -------------------------------------------------------------------- */
124 521 : if( EQUAL(pszAccess,"r") || EQUAL(pszAccess,"rb" ) )
125 204 : fp = VSIFOpenL( pszFilename, "rb" );
126 : else
127 113 : fp = VSIFOpenL( pszFilename, "r+b" );
128 :
129 : /* should this be changed to use some sort of CPLFOpen() which will
130 : set the error? */
131 317 : if( fp == NULL )
132 : {
133 : CPLError( CE_Failure, CPLE_OpenFailed,
134 : "File open of %s failed.",
135 0 : pszFilename );
136 :
137 0 : return NULL;
138 : }
139 :
140 : /* -------------------------------------------------------------------- */
141 : /* Read and verify the header. */
142 : /* -------------------------------------------------------------------- */
143 317 : if( VSIFReadL( szHeader, 16, 1, fp ) < 1 )
144 : {
145 : CPLError( CE_Failure, CPLE_AppDefined,
146 : "Attempt to read 16 byte header failed for\n%s.",
147 0 : pszFilename );
148 :
149 0 : return NULL;
150 : }
151 :
152 317 : if( !EQUALN(szHeader,"EHFA_HEADER_TAG",15) )
153 : {
154 : CPLError( CE_Failure, CPLE_AppDefined,
155 : "File %s is not an Imagine HFA file ... header wrong.",
156 0 : pszFilename );
157 :
158 0 : return NULL;
159 : }
160 :
161 : /* -------------------------------------------------------------------- */
162 : /* Create the HFAInfo_t */
163 : /* -------------------------------------------------------------------- */
164 317 : psInfo = (HFAInfo_t *) CPLCalloc(sizeof(HFAInfo_t),1);
165 :
166 317 : psInfo->pszFilename = CPLStrdup(CPLGetFilename(pszFilename));
167 317 : psInfo->pszPath = CPLStrdup(CPLGetPath(pszFilename));
168 317 : psInfo->fp = fp;
169 521 : if( EQUAL(pszAccess,"r") || EQUAL(pszAccess,"rb" ) )
170 204 : psInfo->eAccess = HFA_ReadOnly;
171 : else
172 113 : psInfo->eAccess = HFA_Update;
173 317 : psInfo->bTreeDirty = FALSE;
174 :
175 : /* -------------------------------------------------------------------- */
176 : /* Where is the header? */
177 : /* -------------------------------------------------------------------- */
178 317 : VSIFReadL( &nHeaderPos, sizeof(GInt32), 1, fp );
179 : HFAStandard( 4, &nHeaderPos );
180 :
181 : /* -------------------------------------------------------------------- */
182 : /* Read the header. */
183 : /* -------------------------------------------------------------------- */
184 317 : VSIFSeekL( fp, nHeaderPos, SEEK_SET );
185 :
186 317 : VSIFReadL( &(psInfo->nVersion), sizeof(GInt32), 1, fp );
187 : HFAStandard( 4, &(psInfo->nVersion) );
188 :
189 317 : VSIFReadL( szHeader, 4, 1, fp ); /* skip freeList */
190 :
191 317 : VSIFReadL( &(psInfo->nRootPos), sizeof(GInt32), 1, fp );
192 : HFAStandard( 4, &(psInfo->nRootPos) );
193 :
194 317 : VSIFReadL( &(psInfo->nEntryHeaderLength), sizeof(GInt16), 1, fp );
195 : HFAStandard( 2, &(psInfo->nEntryHeaderLength) );
196 :
197 317 : VSIFReadL( &(psInfo->nDictionaryPos), sizeof(GInt32), 1, fp );
198 : HFAStandard( 4, &(psInfo->nDictionaryPos) );
199 :
200 : /* -------------------------------------------------------------------- */
201 : /* Collect file size. */
202 : /* -------------------------------------------------------------------- */
203 317 : VSIFSeekL( fp, 0, SEEK_END );
204 317 : psInfo->nEndOfFile = (GUInt32) VSIFTellL( fp );
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Instantiate the root entry. */
208 : /* -------------------------------------------------------------------- */
209 317 : psInfo->poRoot = new HFAEntry( psInfo, psInfo->nRootPos, NULL, NULL );
210 :
211 : /* -------------------------------------------------------------------- */
212 : /* Read the dictionary */
213 : /* -------------------------------------------------------------------- */
214 317 : psInfo->pszDictionary = HFAGetDictionary( psInfo );
215 634 : psInfo->poDictionary = new HFADictionary( psInfo->pszDictionary );
216 :
217 : /* -------------------------------------------------------------------- */
218 : /* Collect band definitions. */
219 : /* -------------------------------------------------------------------- */
220 317 : HFAParseBandInfo( psInfo );
221 :
222 317 : return psInfo;
223 : }
224 :
225 : /************************************************************************/
226 : /* HFACreateDependent() */
227 : /* */
228 : /* Create a .rrd file for the named file if it does not exist, */
229 : /* or return the existing dependent if it already exists. */
230 : /************************************************************************/
231 :
232 1 : HFAInfo_t *HFACreateDependent( HFAInfo_t *psBase )
233 :
234 : {
235 1 : if( psBase->psDependent != NULL )
236 0 : return psBase->psDependent;
237 :
238 : /* -------------------------------------------------------------------- */
239 : /* Create desired RRD filename. */
240 : /* -------------------------------------------------------------------- */
241 1 : CPLString oBasename = CPLGetBasename( psBase->pszFilename );
242 : CPLString oRRDFilename =
243 1 : CPLFormFilename( psBase->pszPath, oBasename, "rrd" );
244 :
245 : /* -------------------------------------------------------------------- */
246 : /* Does this file already exist? If so, re-use it. */
247 : /* -------------------------------------------------------------------- */
248 1 : FILE *fp = VSIFOpenL( oRRDFilename, "rb" );
249 1 : if( fp != NULL )
250 : {
251 0 : VSIFCloseL( fp );
252 0 : psBase->psDependent = HFAOpen( oRRDFilename, "rb" );
253 : }
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* Otherwise create it now. */
257 : /* -------------------------------------------------------------------- */
258 : HFAInfo_t *psDep;
259 1 : psDep = psBase->psDependent = HFACreateLL( oRRDFilename );
260 :
261 : /* -------------------------------------------------------------------- */
262 : /* Add the DependentFile node with the pointer back to the */
263 : /* parent. When working from an .aux file we really want the */
264 : /* .rrd to point back to the original file, not the .aux file. */
265 : /* -------------------------------------------------------------------- */
266 1 : HFAEntry *poEntry = psBase->poRoot->GetNamedChild("DependentFile");
267 1 : const char *pszDependentFile = NULL;
268 1 : if( poEntry != NULL )
269 0 : pszDependentFile = poEntry->GetStringField( "dependent.string" );
270 1 : if( pszDependentFile == NULL )
271 1 : pszDependentFile = psBase->pszFilename;
272 :
273 : HFAEntry *poDF = new HFAEntry( psDep, "DependentFile",
274 1 : "Eimg_DependentFile", psDep->poRoot );
275 :
276 1 : poDF->MakeData( strlen(pszDependentFile) + 50 );
277 1 : poDF->SetPosition();
278 1 : poDF->SetStringField( "dependent.string", pszDependentFile );
279 :
280 1 : return psDep;
281 : }
282 :
283 : /************************************************************************/
284 : /* HFAGetDependent() */
285 : /************************************************************************/
286 :
287 15 : HFAInfo_t *HFAGetDependent( HFAInfo_t *psBase, const char *pszFilename )
288 :
289 : {
290 15 : if( EQUAL(pszFilename,psBase->pszFilename) )
291 9 : return psBase;
292 :
293 6 : if( psBase->psDependent != NULL )
294 : {
295 1 : if( EQUAL(pszFilename,psBase->psDependent->pszFilename) )
296 1 : return psBase->psDependent;
297 : else
298 0 : return NULL;
299 : }
300 :
301 : /* -------------------------------------------------------------------- */
302 : /* Try to open the dependent file. */
303 : /* -------------------------------------------------------------------- */
304 : char *pszDependent;
305 : FILE *fp;
306 5 : const char* pszMode = psBase->eAccess == HFA_Update ? "r+b" : "rb";
307 :
308 : pszDependent = CPLStrdup(
309 5 : CPLFormFilename( psBase->pszPath, pszFilename, NULL ) );
310 :
311 5 : fp = VSIFOpenL( pszDependent, pszMode );
312 5 : if( fp != NULL )
313 : {
314 3 : VSIFCloseL( fp );
315 3 : psBase->psDependent = HFAOpen( pszDependent, pszMode );
316 : }
317 :
318 5 : CPLFree( pszDependent );
319 :
320 5 : return psBase->psDependent;
321 : }
322 :
323 :
324 : /************************************************************************/
325 : /* HFAParseBandInfo() */
326 : /* */
327 : /* This is used by HFAOpen() and HFACreate() to initialize the */
328 : /* band structures. */
329 : /************************************************************************/
330 :
331 421 : CPLErr HFAParseBandInfo( HFAInfo_t *psInfo )
332 :
333 : {
334 : HFAEntry *poNode;
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Find the first band node. */
338 : /* -------------------------------------------------------------------- */
339 421 : psInfo->nBands = 0;
340 421 : poNode = psInfo->poRoot->GetChild();
341 1988 : while( poNode != NULL )
342 : {
343 1146 : if( EQUAL(poNode->GetType(),"Eimg_Layer")
344 : && poNode->GetIntField("width") > 0
345 : && poNode->GetIntField("height") > 0 )
346 : {
347 651 : if( psInfo->nBands == 0 )
348 : {
349 413 : psInfo->nXSize = poNode->GetIntField("width");
350 413 : psInfo->nYSize = poNode->GetIntField("height");
351 : }
352 238 : else if( poNode->GetIntField("width") != psInfo->nXSize
353 : || poNode->GetIntField("height") != psInfo->nYSize )
354 : {
355 0 : return CE_Failure;
356 : }
357 :
358 : psInfo->papoBand = (HFABand **)
359 : CPLRealloc(psInfo->papoBand,
360 651 : sizeof(HFABand *) * (psInfo->nBands+1));
361 651 : psInfo->papoBand[psInfo->nBands] = new HFABand( psInfo, poNode );
362 651 : if (psInfo->papoBand[psInfo->nBands]->nWidth == 0)
363 : {
364 0 : delete psInfo->papoBand[psInfo->nBands];
365 0 : return CE_Failure;
366 : }
367 651 : psInfo->nBands++;
368 : }
369 :
370 1146 : poNode = poNode->GetNext();
371 : }
372 :
373 421 : return CE_None;
374 : }
375 :
376 : /************************************************************************/
377 : /* HFAClose() */
378 : /************************************************************************/
379 :
380 422 : void HFAClose( HFAHandle hHFA )
381 :
382 : {
383 : int i;
384 :
385 422 : if( hHFA->bTreeDirty || hHFA->poDictionary->bDictionaryTextDirty )
386 210 : HFAFlush( hHFA );
387 :
388 422 : if( hHFA->psDependent != NULL )
389 3 : HFAClose( hHFA->psDependent );
390 :
391 422 : delete hHFA->poRoot;
392 :
393 422 : VSIFCloseL( hHFA->fp );
394 :
395 422 : if( hHFA->poDictionary != NULL )
396 422 : delete hHFA->poDictionary;
397 :
398 422 : CPLFree( hHFA->pszDictionary );
399 422 : CPLFree( hHFA->pszFilename );
400 422 : CPLFree( hHFA->pszIGEFilename );
401 422 : CPLFree( hHFA->pszPath );
402 :
403 1073 : for( i = 0; i < hHFA->nBands; i++ )
404 : {
405 651 : delete hHFA->papoBand[i];
406 : }
407 :
408 422 : CPLFree( hHFA->papoBand );
409 :
410 422 : if( hHFA->pProParameters != NULL )
411 : {
412 : Eprj_ProParameters *psProParms = (Eprj_ProParameters *)
413 36 : hHFA->pProParameters;
414 :
415 36 : CPLFree( psProParms->proExeName );
416 36 : CPLFree( psProParms->proName );
417 36 : CPLFree( psProParms->proSpheroid.sphereName );
418 :
419 36 : CPLFree( psProParms );
420 : }
421 :
422 422 : if( hHFA->pDatum != NULL )
423 : {
424 36 : CPLFree( ((Eprj_Datum *) hHFA->pDatum)->datumname );
425 36 : CPLFree( ((Eprj_Datum *) hHFA->pDatum)->gridname );
426 36 : CPLFree( hHFA->pDatum );
427 : }
428 :
429 422 : if( hHFA->pMapInfo != NULL )
430 : {
431 122 : CPLFree( ((Eprj_MapInfo *) hHFA->pMapInfo)->proName );
432 122 : CPLFree( ((Eprj_MapInfo *) hHFA->pMapInfo)->units );
433 122 : CPLFree( hHFA->pMapInfo );
434 : }
435 :
436 422 : CPLFree( hHFA );
437 422 : }
438 :
439 : /************************************************************************/
440 : /* HFARemove() */
441 : /* Used from HFADelete() function. */
442 : /************************************************************************/
443 :
444 0 : CPLErr HFARemove( const char *pszFilename )
445 :
446 : {
447 : VSIStatBufL sStat;
448 :
449 0 : if( VSIStatL( pszFilename, &sStat ) == 0 && VSI_ISREG( sStat.st_mode ) )
450 : {
451 0 : if( VSIUnlink( pszFilename ) == 0 )
452 0 : return CE_None;
453 : else
454 : {
455 : CPLError( CE_Failure, CPLE_AppDefined,
456 0 : "Attempt to unlink %s failed.\n", pszFilename );
457 0 : return CE_Failure;
458 : }
459 : }
460 : else
461 : {
462 : CPLError( CE_Failure, CPLE_AppDefined,
463 0 : "Unable to delete %s, not a file.\n", pszFilename );
464 0 : return CE_Failure;
465 : }
466 : }
467 :
468 : /************************************************************************/
469 : /* HFADelete() */
470 : /************************************************************************/
471 :
472 0 : CPLErr HFADelete( const char *pszFilename )
473 :
474 : {
475 0 : HFAInfo_t *psInfo = HFAOpen( pszFilename, "rb" );
476 0 : HFAEntry *poDMS = NULL;
477 0 : HFAEntry *poLayer = NULL;
478 0 : HFAEntry *poNode = NULL;
479 :
480 0 : if( psInfo != NULL )
481 : {
482 0 : poNode = psInfo->poRoot->GetChild();
483 0 : while( ( poNode != NULL ) && ( poLayer == NULL ) )
484 : {
485 0 : if( EQUAL(poNode->GetType(),"Eimg_Layer") )
486 : {
487 0 : poLayer = poNode;
488 : }
489 0 : poNode = poNode->GetNext();
490 : }
491 :
492 0 : if( poLayer != NULL )
493 0 : poDMS = poLayer->GetNamedChild( "ExternalRasterDMS" );
494 :
495 0 : if ( poDMS )
496 : {
497 : const char *pszRawFilename =
498 0 : poDMS->GetStringField( "fileName.string" );
499 :
500 0 : if( pszRawFilename != NULL )
501 : HFARemove( CPLFormFilename( psInfo->pszPath,
502 0 : pszRawFilename, NULL ) );
503 : }
504 :
505 0 : HFAClose( psInfo );
506 : }
507 0 : return HFARemove( pszFilename );
508 : }
509 :
510 : /************************************************************************/
511 : /* HFAGetRasterInfo() */
512 : /************************************************************************/
513 :
514 : CPLErr HFAGetRasterInfo( HFAHandle hHFA, int * pnXSize, int * pnYSize,
515 314 : int * pnBands )
516 :
517 : {
518 314 : if( pnXSize != NULL )
519 314 : *pnXSize = hHFA->nXSize;
520 314 : if( pnYSize != NULL )
521 314 : *pnYSize = hHFA->nYSize;
522 314 : if( pnBands != NULL )
523 314 : *pnBands = hHFA->nBands;
524 314 : return CE_None;
525 : }
526 :
527 : /************************************************************************/
528 : /* HFAGetBandInfo() */
529 : /************************************************************************/
530 :
531 : CPLErr HFAGetBandInfo( HFAHandle hHFA, int nBand, int * pnDataType,
532 : int * pnBlockXSize, int * pnBlockYSize,
533 500 : int *pnCompressionType )
534 :
535 : {
536 500 : if( nBand < 0 || nBand > hHFA->nBands )
537 : {
538 0 : CPLAssert( FALSE );
539 0 : return CE_Failure;
540 : }
541 :
542 500 : HFABand *poBand = hHFA->papoBand[nBand-1];
543 :
544 500 : if( pnDataType != NULL )
545 500 : *pnDataType = poBand->nDataType;
546 :
547 500 : if( pnBlockXSize != NULL )
548 500 : *pnBlockXSize = poBand->nBlockXSize;
549 :
550 500 : if( pnBlockYSize != NULL )
551 500 : *pnBlockYSize = poBand->nBlockYSize;
552 :
553 : /* -------------------------------------------------------------------- */
554 : /* Get compression code from RasterDMS. */
555 : /* -------------------------------------------------------------------- */
556 500 : if( pnCompressionType != NULL )
557 : {
558 : HFAEntry *poDMS;
559 :
560 500 : *pnCompressionType = 0;
561 :
562 500 : poDMS = poBand->poNode->GetNamedChild( "RasterDMS" );
563 :
564 500 : if( poDMS != NULL )
565 445 : *pnCompressionType = poDMS->GetIntField( "compressionType" );
566 : }
567 :
568 500 : return( CE_None );
569 : }
570 :
571 : /************************************************************************/
572 : /* HFAGetBandNoData() */
573 : /* */
574 : /* returns TRUE if value is set, otherwise FALSE. */
575 : /************************************************************************/
576 :
577 153 : int HFAGetBandNoData( HFAHandle hHFA, int nBand, double *pdfNoData )
578 :
579 : {
580 153 : if( nBand < 0 || nBand > hHFA->nBands )
581 : {
582 0 : CPLAssert( FALSE );
583 0 : return CE_Failure;
584 : }
585 :
586 153 : HFABand *poBand = hHFA->papoBand[nBand-1];
587 :
588 153 : *pdfNoData = poBand->dfNoData;
589 153 : return poBand->bNoDataSet;
590 : }
591 :
592 : /************************************************************************/
593 : /* HFASetBandNoData() */
594 : /* */
595 : /* attempts to set a no-data value on the given band */
596 : /************************************************************************/
597 :
598 6 : CPLErr HFASetBandNoData( HFAHandle hHFA, int nBand, double dfValue )
599 :
600 : {
601 6 : if ( nBand < 0 || nBand > hHFA->nBands )
602 : {
603 0 : CPLAssert( FALSE );
604 0 : return CE_Failure;
605 : }
606 :
607 6 : HFABand *poBand = hHFA->papoBand[nBand - 1];
608 :
609 6 : return poBand->SetNoDataValue( dfValue );
610 : }
611 :
612 : /************************************************************************/
613 : /* HFAGetOverviewCount() */
614 : /************************************************************************/
615 :
616 16 : int HFAGetOverviewCount( HFAHandle hHFA, int nBand )
617 :
618 : {
619 : HFABand *poBand;
620 :
621 16 : if( nBand < 0 || nBand > hHFA->nBands )
622 : {
623 0 : CPLAssert( FALSE );
624 0 : return CE_Failure;
625 : }
626 :
627 16 : poBand = hHFA->papoBand[nBand-1];
628 16 : poBand->LoadOverviews();
629 :
630 16 : return poBand->nOverviews;
631 : }
632 :
633 : /************************************************************************/
634 : /* HFAGetOverviewInfo() */
635 : /************************************************************************/
636 :
637 : CPLErr HFAGetOverviewInfo( HFAHandle hHFA, int nBand, int iOverview,
638 : int * pnXSize, int * pnYSize,
639 : int * pnBlockXSize, int * pnBlockYSize,
640 19 : int * pnHFADataType )
641 :
642 : {
643 : HFABand *poBand;
644 :
645 19 : if( nBand < 0 || nBand > hHFA->nBands )
646 : {
647 0 : CPLAssert( FALSE );
648 0 : return CE_Failure;
649 : }
650 :
651 19 : poBand = hHFA->papoBand[nBand-1];
652 19 : poBand->LoadOverviews();
653 :
654 19 : if( iOverview < 0 || iOverview >= poBand->nOverviews )
655 : {
656 0 : CPLAssert( FALSE );
657 0 : return CE_Failure;
658 : }
659 19 : poBand = poBand->papoOverviews[iOverview];
660 :
661 19 : if( pnXSize != NULL )
662 19 : *pnXSize = poBand->nWidth;
663 :
664 19 : if( pnYSize != NULL )
665 19 : *pnYSize = poBand->nHeight;
666 :
667 19 : if( pnBlockXSize != NULL )
668 19 : *pnBlockXSize = poBand->nBlockXSize;
669 :
670 19 : if( pnBlockYSize != NULL )
671 19 : *pnBlockYSize = poBand->nBlockYSize;
672 :
673 19 : if( pnHFADataType != NULL )
674 19 : *pnHFADataType = poBand->nDataType;
675 :
676 19 : return( CE_None );
677 : }
678 :
679 : /************************************************************************/
680 : /* HFAGetRasterBlock() */
681 : /************************************************************************/
682 :
683 : CPLErr HFAGetRasterBlock( HFAHandle hHFA, int nBand,
684 0 : int nXBlock, int nYBlock, void * pData )
685 :
686 : {
687 0 : return HFAGetRasterBlockEx(hHFA, nBand, nXBlock, nYBlock, pData, -1);
688 : }
689 :
690 : /************************************************************************/
691 : /* HFAGetRasterBlockEx() */
692 : /************************************************************************/
693 :
694 : CPLErr HFAGetRasterBlockEx( HFAHandle hHFA, int nBand,
695 356 : int nXBlock, int nYBlock, void * pData, int nDataSize )
696 :
697 : {
698 356 : if( nBand < 1 || nBand > hHFA->nBands )
699 0 : return CE_Failure;
700 :
701 356 : return( hHFA->papoBand[nBand-1]->GetRasterBlock(nXBlock,nYBlock,pData,nDataSize) );
702 : }
703 :
704 : /************************************************************************/
705 : /* HFAGetOverviewRasterBlock() */
706 : /************************************************************************/
707 :
708 : CPLErr HFAGetOverviewRasterBlock( HFAHandle hHFA, int nBand, int iOverview,
709 0 : int nXBlock, int nYBlock, void * pData )
710 :
711 : {
712 0 : return HFAGetOverviewRasterBlockEx(hHFA, nBand, iOverview, nXBlock, nYBlock, pData, -1);
713 : }
714 :
715 : /************************************************************************/
716 : /* HFAGetOverviewRasterBlockEx() */
717 : /************************************************************************/
718 :
719 : CPLErr HFAGetOverviewRasterBlockEx( HFAHandle hHFA, int nBand, int iOverview,
720 13 : int nXBlock, int nYBlock, void * pData, int nDataSize )
721 :
722 : {
723 13 : if( nBand < 1 || nBand > hHFA->nBands )
724 0 : return CE_Failure;
725 :
726 13 : if( iOverview < 0 || iOverview >= hHFA->papoBand[nBand-1]->nOverviews )
727 0 : return CE_Failure;
728 :
729 : return( hHFA->papoBand[nBand-1]->papoOverviews[iOverview]->
730 13 : GetRasterBlock(nXBlock,nYBlock,pData, nDataSize) );
731 : }
732 :
733 : /************************************************************************/
734 : /* HFASetRasterBlock() */
735 : /************************************************************************/
736 :
737 : CPLErr HFASetRasterBlock( HFAHandle hHFA, int nBand,
738 112 : int nXBlock, int nYBlock, void * pData )
739 :
740 : {
741 112 : if( nBand < 1 || nBand > hHFA->nBands )
742 0 : return CE_Failure;
743 :
744 112 : return( hHFA->papoBand[nBand-1]->SetRasterBlock(nXBlock,nYBlock,pData) );
745 : }
746 :
747 : /************************************************************************/
748 : /* HFASetRasterBlock() */
749 : /************************************************************************/
750 :
751 : CPLErr HFASetOverviewRasterBlock( HFAHandle hHFA, int nBand, int iOverview,
752 9 : int nXBlock, int nYBlock, void * pData )
753 :
754 : {
755 9 : if( nBand < 1 || nBand > hHFA->nBands )
756 0 : return CE_Failure;
757 :
758 9 : if( iOverview < 0 || iOverview >= hHFA->papoBand[nBand-1]->nOverviews )
759 0 : return CE_Failure;
760 :
761 : return( hHFA->papoBand[nBand-1]->papoOverviews[iOverview]->
762 9 : SetRasterBlock(nXBlock,nYBlock,pData) );
763 : }
764 :
765 : /************************************************************************/
766 : /* HFAGetBandName() */
767 : /************************************************************************/
768 :
769 129 : const char * HFAGetBandName( HFAHandle hHFA, int nBand )
770 : {
771 129 : if( nBand < 1 || nBand > hHFA->nBands )
772 0 : return "";
773 :
774 129 : return( hHFA->papoBand[nBand-1]->GetBandName() );
775 : }
776 :
777 : /************************************************************************/
778 : /* HFASetBandName() */
779 : /************************************************************************/
780 :
781 3 : void HFASetBandName( HFAHandle hHFA, int nBand, const char *pszName )
782 : {
783 3 : if( nBand < 1 || nBand > hHFA->nBands )
784 0 : return;
785 :
786 3 : hHFA->papoBand[nBand-1]->SetBandName( pszName );
787 : }
788 :
789 : /************************************************************************/
790 : /* HFAGetDataTypeBits() */
791 : /************************************************************************/
792 :
793 2724 : int HFAGetDataTypeBits( int nDataType )
794 :
795 : {
796 2724 : switch( nDataType )
797 : {
798 : case EPT_u1:
799 29 : return 1;
800 :
801 : case EPT_u2:
802 0 : return 2;
803 :
804 : case EPT_u4:
805 0 : return 4;
806 :
807 : case EPT_u8:
808 : case EPT_s8:
809 887 : return 8;
810 :
811 : case EPT_u16:
812 : case EPT_s16:
813 272 : return 16;
814 :
815 : case EPT_u32:
816 : case EPT_s32:
817 : case EPT_f32:
818 315 : return 32;
819 :
820 : case EPT_f64:
821 : case EPT_c64:
822 1133 : return 64;
823 :
824 : case EPT_c128:
825 88 : return 128;
826 : }
827 :
828 0 : return 0;
829 : }
830 :
831 : /************************************************************************/
832 : /* HFAGetDataTypeName() */
833 : /************************************************************************/
834 :
835 0 : const char *HFAGetDataTypeName( int nDataType )
836 :
837 : {
838 0 : switch( nDataType )
839 : {
840 : case EPT_u1:
841 0 : return "u1";
842 :
843 : case EPT_u2:
844 0 : return "u2";
845 :
846 : case EPT_u4:
847 0 : return "u4";
848 :
849 : case EPT_u8:
850 0 : return "u8";
851 :
852 : case EPT_s8:
853 0 : return "s8";
854 :
855 : case EPT_u16:
856 0 : return "u16";
857 :
858 : case EPT_s16:
859 0 : return "s16";
860 :
861 : case EPT_u32:
862 0 : return "u32";
863 :
864 : case EPT_s32:
865 0 : return "s32";
866 :
867 : case EPT_f32:
868 0 : return "f32";
869 :
870 : case EPT_f64:
871 0 : return "f64";
872 :
873 : case EPT_c64:
874 0 : return "c64";
875 :
876 : case EPT_c128:
877 0 : return "c128";
878 :
879 : default:
880 0 : return "unknown";
881 : }
882 : }
883 :
884 : /************************************************************************/
885 : /* HFAGetMapInfo() */
886 : /************************************************************************/
887 :
888 555 : const Eprj_MapInfo *HFAGetMapInfo( HFAHandle hHFA )
889 :
890 : {
891 : HFAEntry *poMIEntry;
892 : Eprj_MapInfo *psMapInfo;
893 :
894 555 : if( hHFA->nBands < 1 )
895 0 : return NULL;
896 :
897 : /* -------------------------------------------------------------------- */
898 : /* Do we already have it? */
899 : /* -------------------------------------------------------------------- */
900 555 : if( hHFA->pMapInfo != NULL )
901 57 : return( (Eprj_MapInfo *) hHFA->pMapInfo );
902 :
903 : /* -------------------------------------------------------------------- */
904 : /* Get the HFA node. If we don't find it under the usual name */
905 : /* we search for any node of the right type (#3338). */
906 : /* -------------------------------------------------------------------- */
907 498 : poMIEntry = hHFA->papoBand[0]->poNode->GetNamedChild( "Map_Info" );
908 498 : if( poMIEntry == NULL )
909 : {
910 : HFAEntry *poChild;
911 1296 : for( poChild = hHFA->papoBand[0]->poNode->GetChild();
912 : poChild != NULL && poMIEntry == NULL;
913 : poChild = poChild->GetNext() )
914 : {
915 920 : if( EQUAL(poChild->GetType(),"Eprj_MapInfo") )
916 0 : poMIEntry = poChild;
917 : }
918 : }
919 :
920 498 : if( poMIEntry == NULL )
921 : {
922 376 : return NULL;
923 : }
924 :
925 : /* -------------------------------------------------------------------- */
926 : /* Allocate the structure. */
927 : /* -------------------------------------------------------------------- */
928 122 : psMapInfo = (Eprj_MapInfo *) CPLCalloc(sizeof(Eprj_MapInfo),1);
929 :
930 : /* -------------------------------------------------------------------- */
931 : /* Fetch the fields. */
932 : /* -------------------------------------------------------------------- */
933 : CPLErr eErr;
934 :
935 122 : psMapInfo->proName = CPLStrdup(poMIEntry->GetStringField("proName"));
936 :
937 : psMapInfo->upperLeftCenter.x =
938 122 : poMIEntry->GetDoubleField("upperLeftCenter.x");
939 : psMapInfo->upperLeftCenter.y =
940 122 : poMIEntry->GetDoubleField("upperLeftCenter.y");
941 :
942 : psMapInfo->lowerRightCenter.x =
943 122 : poMIEntry->GetDoubleField("lowerRightCenter.x");
944 : psMapInfo->lowerRightCenter.y =
945 122 : poMIEntry->GetDoubleField("lowerRightCenter.y");
946 :
947 : psMapInfo->pixelSize.width =
948 122 : poMIEntry->GetDoubleField("pixelSize.width",&eErr);
949 : psMapInfo->pixelSize.height =
950 122 : poMIEntry->GetDoubleField("pixelSize.height",&eErr);
951 :
952 : // The following is basically a hack to get files with
953 : // non-standard MapInfo's that misname the pixelSize fields. (#3338)
954 122 : if( eErr != CE_None )
955 : {
956 : psMapInfo->pixelSize.width =
957 0 : poMIEntry->GetDoubleField("pixelSize.x");
958 : psMapInfo->pixelSize.height =
959 0 : poMIEntry->GetDoubleField("pixelSize.y");
960 : }
961 :
962 122 : psMapInfo->units = CPLStrdup(poMIEntry->GetStringField("units"));
963 :
964 122 : hHFA->pMapInfo = (void *) psMapInfo;
965 :
966 122 : return psMapInfo;
967 : }
968 :
969 : /************************************************************************/
970 : /* HFAInvGeoTransform() */
971 : /************************************************************************/
972 :
973 6 : static int HFAInvGeoTransform( double *gt_in, double *gt_out )
974 :
975 : {
976 : double det, inv_det;
977 :
978 : /* we assume a 3rd row that is [1 0 0] */
979 :
980 : /* Compute determinate */
981 :
982 6 : det = gt_in[1] * gt_in[5] - gt_in[2] * gt_in[4];
983 :
984 6 : if( fabs(det) < 0.000000000000001 )
985 0 : return 0;
986 :
987 6 : inv_det = 1.0 / det;
988 :
989 : /* compute adjoint, and devide by determinate */
990 :
991 6 : gt_out[1] = gt_in[5] * inv_det;
992 6 : gt_out[4] = -gt_in[4] * inv_det;
993 :
994 6 : gt_out[2] = -gt_in[2] * inv_det;
995 6 : gt_out[5] = gt_in[1] * inv_det;
996 :
997 6 : gt_out[0] = ( gt_in[2] * gt_in[3] - gt_in[0] * gt_in[5]) * inv_det;
998 6 : gt_out[3] = (-gt_in[1] * gt_in[3] + gt_in[0] * gt_in[4]) * inv_det;
999 :
1000 6 : return 1;
1001 : }
1002 :
1003 : /************************************************************************/
1004 : /* HFAGetGeoTransform() */
1005 : /************************************************************************/
1006 :
1007 311 : int HFAGetGeoTransform( HFAHandle hHFA, double *padfGeoTransform )
1008 :
1009 : {
1010 311 : const Eprj_MapInfo *psMapInfo = HFAGetMapInfo( hHFA );
1011 :
1012 311 : padfGeoTransform[0] = 0.0;
1013 311 : padfGeoTransform[1] = 1.0;
1014 311 : padfGeoTransform[2] = 0.0;
1015 311 : padfGeoTransform[3] = 0.0;
1016 311 : padfGeoTransform[4] = 0.0;
1017 311 : padfGeoTransform[5] = 1.0;
1018 :
1019 : /* -------------------------------------------------------------------- */
1020 : /* Simple (north up) MapInfo approach. */
1021 : /* -------------------------------------------------------------------- */
1022 311 : if( psMapInfo != NULL )
1023 : {
1024 : padfGeoTransform[0] = psMapInfo->upperLeftCenter.x
1025 122 : - psMapInfo->pixelSize.width*0.5;
1026 122 : padfGeoTransform[1] = psMapInfo->pixelSize.width;
1027 122 : padfGeoTransform[2] = 0.0;
1028 122 : if( psMapInfo->upperLeftCenter.y >= psMapInfo->lowerRightCenter.y )
1029 122 : padfGeoTransform[5] = - psMapInfo->pixelSize.height;
1030 : else
1031 0 : padfGeoTransform[5] = psMapInfo->pixelSize.height;
1032 :
1033 : padfGeoTransform[3] = psMapInfo->upperLeftCenter.y
1034 122 : - padfGeoTransform[5]*0.5;
1035 122 : padfGeoTransform[4] = 0.0;
1036 :
1037 : // special logic to fixup odd angular units.
1038 122 : if( EQUAL(psMapInfo->units,"ds") )
1039 : {
1040 0 : padfGeoTransform[0] /= 3600.0;
1041 0 : padfGeoTransform[1] /= 3600.0;
1042 0 : padfGeoTransform[2] /= 3600.0;
1043 0 : padfGeoTransform[3] /= 3600.0;
1044 0 : padfGeoTransform[4] /= 3600.0;
1045 0 : padfGeoTransform[5] /= 3600.0;
1046 : }
1047 :
1048 122 : return TRUE;
1049 : }
1050 :
1051 : /* -------------------------------------------------------------------- */
1052 : /* Try for a MapToPixelXForm affine polynomial supporting */
1053 : /* rotated and sheared affine transformations. */
1054 : /* -------------------------------------------------------------------- */
1055 189 : if( hHFA->nBands == 0 )
1056 0 : return FALSE;
1057 :
1058 : HFAEntry *poXForm0 =
1059 189 : hHFA->papoBand[0]->poNode->GetNamedChild( "MapToPixelXForm.XForm0" );
1060 :
1061 189 : if( poXForm0 == NULL )
1062 183 : return FALSE;
1063 :
1064 6 : if( poXForm0->GetIntField( "order" ) != 1
1065 : || poXForm0->GetIntField( "numdimtransform" ) != 2
1066 : || poXForm0->GetIntField( "numdimpolynomial" ) != 2
1067 : || poXForm0->GetIntField( "termcount" ) != 3 )
1068 1 : return FALSE;
1069 :
1070 : // Verify that there aren't any further xform steps.
1071 5 : if( hHFA->papoBand[0]->poNode->GetNamedChild( "MapToPixelXForm.XForm1" )
1072 : != NULL )
1073 1 : return FALSE;
1074 :
1075 : // we should check that the exponent list is 0 0 1 0 0 1 but
1076 : // we don't because we are lazy
1077 :
1078 : // fetch geotransform values.
1079 : double adfXForm[6];
1080 :
1081 4 : adfXForm[0] = poXForm0->GetDoubleField( "polycoefvector[0]" );
1082 4 : adfXForm[1] = poXForm0->GetDoubleField( "polycoefmtx[0]" );
1083 4 : adfXForm[4] = poXForm0->GetDoubleField( "polycoefmtx[1]" );
1084 4 : adfXForm[3] = poXForm0->GetDoubleField( "polycoefvector[1]" );
1085 4 : adfXForm[2] = poXForm0->GetDoubleField( "polycoefmtx[2]" );
1086 4 : adfXForm[5] = poXForm0->GetDoubleField( "polycoefmtx[3]" );
1087 :
1088 : // invert
1089 :
1090 4 : HFAInvGeoTransform( adfXForm, padfGeoTransform );
1091 :
1092 : // Adjust origin from center of top left pixel to top left corner
1093 : // of top left pixel.
1094 :
1095 4 : padfGeoTransform[0] -= padfGeoTransform[1] * 0.5;
1096 4 : padfGeoTransform[0] -= padfGeoTransform[2] * 0.5;
1097 4 : padfGeoTransform[3] -= padfGeoTransform[4] * 0.5;
1098 4 : padfGeoTransform[3] -= padfGeoTransform[5] * 0.5;
1099 :
1100 4 : return TRUE;
1101 : }
1102 :
1103 : /************************************************************************/
1104 : /* HFASetMapInfo() */
1105 : /************************************************************************/
1106 :
1107 68 : CPLErr HFASetMapInfo( HFAHandle hHFA, const Eprj_MapInfo *poMapInfo )
1108 :
1109 : {
1110 : /* -------------------------------------------------------------------- */
1111 : /* Loop over bands, setting information on each one. */
1112 : /* -------------------------------------------------------------------- */
1113 172 : for( int iBand = 0; iBand < hHFA->nBands; iBand++ )
1114 : {
1115 : HFAEntry *poMIEntry;
1116 :
1117 : /* -------------------------------------------------------------------- */
1118 : /* Create a new Map_Info if there isn't one present already. */
1119 : /* -------------------------------------------------------------------- */
1120 104 : poMIEntry = hHFA->papoBand[iBand]->poNode->GetNamedChild( "Map_Info" );
1121 104 : if( poMIEntry == NULL )
1122 : {
1123 : poMIEntry = new HFAEntry( hHFA, "Map_Info", "Eprj_MapInfo",
1124 104 : hHFA->papoBand[iBand]->poNode );
1125 : }
1126 :
1127 104 : poMIEntry->MarkDirty();
1128 :
1129 : /* -------------------------------------------------------------------- */
1130 : /* Ensure we have enough space for all the data. */
1131 : /* -------------------------------------------------------------------- */
1132 : int nSize;
1133 : GByte *pabyData;
1134 :
1135 : nSize = 48 + 40
1136 : + strlen(poMapInfo->proName) + 1
1137 104 : + strlen(poMapInfo->units) + 1;
1138 :
1139 104 : pabyData = poMIEntry->MakeData( nSize );
1140 104 : memset( pabyData, 0, nSize );
1141 :
1142 104 : poMIEntry->SetPosition();
1143 :
1144 : /* -------------------------------------------------------------------- */
1145 : /* Write the various fields. */
1146 : /* -------------------------------------------------------------------- */
1147 104 : poMIEntry->SetStringField( "proName", poMapInfo->proName );
1148 :
1149 : poMIEntry->SetDoubleField( "upperLeftCenter.x",
1150 104 : poMapInfo->upperLeftCenter.x );
1151 : poMIEntry->SetDoubleField( "upperLeftCenter.y",
1152 104 : poMapInfo->upperLeftCenter.y );
1153 :
1154 : poMIEntry->SetDoubleField( "lowerRightCenter.x",
1155 104 : poMapInfo->lowerRightCenter.x );
1156 : poMIEntry->SetDoubleField( "lowerRightCenter.y",
1157 104 : poMapInfo->lowerRightCenter.y );
1158 :
1159 : poMIEntry->SetDoubleField( "pixelSize.width",
1160 104 : poMapInfo->pixelSize.width );
1161 : poMIEntry->SetDoubleField( "pixelSize.height",
1162 104 : poMapInfo->pixelSize.height );
1163 :
1164 104 : poMIEntry->SetStringField( "units", poMapInfo->units );
1165 : }
1166 :
1167 68 : return CE_None;
1168 : }
1169 :
1170 : /************************************************************************/
1171 : /* HFAGetPEString() */
1172 : /* */
1173 : /* Some files have a ProjectionX node contining the ESRI style */
1174 : /* PE_STRING. This function allows fetching from it. */
1175 : /************************************************************************/
1176 :
1177 311 : char *HFAGetPEString( HFAHandle hHFA )
1178 :
1179 : {
1180 311 : if( hHFA->nBands == 0 )
1181 0 : return NULL;
1182 :
1183 : /* -------------------------------------------------------------------- */
1184 : /* Get the HFA node. */
1185 : /* -------------------------------------------------------------------- */
1186 : HFAEntry *poProX;
1187 :
1188 311 : poProX = hHFA->papoBand[0]->poNode->GetNamedChild( "ProjectionX" );
1189 311 : if( poProX == NULL )
1190 244 : return NULL;
1191 :
1192 67 : const char *pszType = poProX->GetStringField( "projection.type.string" );
1193 67 : if( pszType == NULL || !EQUAL(pszType,"PE_COORDSYS") )
1194 0 : return NULL;
1195 :
1196 : /* -------------------------------------------------------------------- */
1197 : /* Use a gross hack to scan ahead to the actual projection */
1198 : /* string. We do it this way because we don't have general */
1199 : /* handling for MIFObjects. */
1200 : /* -------------------------------------------------------------------- */
1201 67 : GByte *pabyData = poProX->GetData();
1202 67 : int nDataSize = poProX->GetDataSize();
1203 :
1204 6298 : while( nDataSize > 10
1205 : && !EQUALN((const char *) pabyData,"PE_COORDSYS,.",13) ) {
1206 6164 : pabyData++;
1207 6164 : nDataSize--;
1208 : }
1209 :
1210 67 : if( nDataSize < 31 )
1211 0 : return NULL;
1212 :
1213 : /* -------------------------------------------------------------------- */
1214 : /* Skip ahead to the actual string. */
1215 : /* -------------------------------------------------------------------- */
1216 67 : pabyData += 30;
1217 67 : nDataSize -= 30;
1218 :
1219 67 : return CPLStrdup( (const char *) pabyData );
1220 : }
1221 :
1222 : /************************************************************************/
1223 : /* HFASetPEString() */
1224 : /************************************************************************/
1225 :
1226 57 : CPLErr HFASetPEString( HFAHandle hHFA, const char *pszPEString )
1227 :
1228 : {
1229 : /* -------------------------------------------------------------------- */
1230 : /* Loop over bands, setting information on each one. */
1231 : /* -------------------------------------------------------------------- */
1232 : int iBand;
1233 :
1234 150 : for( iBand = 0; iBand < hHFA->nBands; iBand++ )
1235 : {
1236 : HFAEntry *poProX;
1237 :
1238 : /* -------------------------------------------------------------------- */
1239 : /* Verify we don't already have the node, since update-in-place */
1240 : /* is likely to be more complicated. */
1241 : /* -------------------------------------------------------------------- */
1242 93 : poProX = hHFA->papoBand[iBand]->poNode->GetNamedChild( "ProjectionX" );
1243 :
1244 : /* -------------------------------------------------------------------- */
1245 : /* Create the node. */
1246 : /* -------------------------------------------------------------------- */
1247 93 : if( poProX == NULL )
1248 : {
1249 : poProX = new HFAEntry( hHFA, "ProjectionX","Eprj_MapProjection842",
1250 93 : hHFA->papoBand[iBand]->poNode );
1251 186 : if( poProX == NULL || poProX->GetTypeObject() == NULL )
1252 0 : return CE_Failure;
1253 : }
1254 :
1255 : /* -------------------------------------------------------------------- */
1256 : /* Prepare the data area with some extra space just in case. */
1257 : /* -------------------------------------------------------------------- */
1258 93 : GByte *pabyData = poProX->MakeData( 700 + strlen(pszPEString) );
1259 93 : if( !pabyData )
1260 0 : return CE_Failure;
1261 :
1262 93 : memset( pabyData, 0, 250+strlen(pszPEString) );
1263 :
1264 93 : poProX->SetPosition();
1265 :
1266 93 : poProX->SetStringField( "projection.type.string", "PE_COORDSYS" );
1267 : poProX->SetStringField( "projection.MIFDictionary.string",
1268 93 : "{0:pcstring,}Emif_String,{1:x{0:pcstring,}Emif_String,coordSys,}PE_COORDSYS,." );
1269 :
1270 : /* -------------------------------------------------------------------- */
1271 : /* Use a gross hack to scan ahead to the actual projection */
1272 : /* string. We do it this way because we don't have general */
1273 : /* handling for MIFObjects. */
1274 : /* -------------------------------------------------------------------- */
1275 93 : pabyData = poProX->GetData();
1276 93 : int nDataSize = poProX->GetDataSize();
1277 93 : GUInt32 iOffset = poProX->GetDataPos();
1278 : GUInt32 nSize;
1279 :
1280 8742 : while( nDataSize > 10
1281 : && !EQUALN((const char *) pabyData,"PE_COORDSYS,.",13) ) {
1282 8556 : pabyData++;
1283 8556 : nDataSize--;
1284 8556 : iOffset++;
1285 : }
1286 :
1287 93 : CPLAssert( nDataSize > (int) strlen(pszPEString) + 10 );
1288 :
1289 93 : pabyData += 14;
1290 93 : iOffset += 14;
1291 :
1292 : /* -------------------------------------------------------------------- */
1293 : /* Set the size and offset of the mifobject. */
1294 : /* -------------------------------------------------------------------- */
1295 93 : iOffset += 8;
1296 :
1297 93 : nSize = strlen(pszPEString) + 9;
1298 :
1299 : HFAStandard( 4, &nSize );
1300 93 : memcpy( pabyData, &nSize, 4 );
1301 93 : pabyData += 4;
1302 :
1303 : HFAStandard( 4, &iOffset );
1304 93 : memcpy( pabyData, &iOffset, 4 );
1305 93 : pabyData += 4;
1306 :
1307 : /* -------------------------------------------------------------------- */
1308 : /* Set the size and offset of the string value. */
1309 : /* -------------------------------------------------------------------- */
1310 93 : nSize = strlen(pszPEString) + 1;
1311 :
1312 : HFAStandard( 4, &nSize );
1313 93 : memcpy( pabyData, &nSize, 4 );
1314 93 : pabyData += 4;
1315 :
1316 93 : iOffset = 8;
1317 : HFAStandard( 4, &iOffset );
1318 93 : memcpy( pabyData, &iOffset, 4 );
1319 93 : pabyData += 4;
1320 :
1321 : /* -------------------------------------------------------------------- */
1322 : /* Place the string itself. */
1323 : /* -------------------------------------------------------------------- */
1324 93 : memcpy( pabyData, pszPEString, strlen(pszPEString)+1 );
1325 :
1326 93 : poProX->SetStringField( "title.string", "PE" );
1327 : }
1328 :
1329 57 : return CE_None;
1330 : }
1331 :
1332 : /************************************************************************/
1333 : /* HFAGetProParameters() */
1334 : /************************************************************************/
1335 :
1336 244 : const Eprj_ProParameters *HFAGetProParameters( HFAHandle hHFA )
1337 :
1338 : {
1339 : HFAEntry *poMIEntry;
1340 : Eprj_ProParameters *psProParms;
1341 : int i;
1342 :
1343 244 : if( hHFA->nBands < 1 )
1344 0 : return NULL;
1345 :
1346 : /* -------------------------------------------------------------------- */
1347 : /* Do we already have it? */
1348 : /* -------------------------------------------------------------------- */
1349 244 : if( hHFA->pProParameters != NULL )
1350 0 : return( (Eprj_ProParameters *) hHFA->pProParameters );
1351 :
1352 : /* -------------------------------------------------------------------- */
1353 : /* Get the HFA node. */
1354 : /* -------------------------------------------------------------------- */
1355 244 : poMIEntry = hHFA->papoBand[0]->poNode->GetNamedChild( "Projection" );
1356 244 : if( poMIEntry == NULL )
1357 208 : return NULL;
1358 :
1359 : /* -------------------------------------------------------------------- */
1360 : /* Allocate the structure. */
1361 : /* -------------------------------------------------------------------- */
1362 36 : psProParms = (Eprj_ProParameters *)CPLCalloc(sizeof(Eprj_ProParameters),1);
1363 :
1364 : /* -------------------------------------------------------------------- */
1365 : /* Fetch the fields. */
1366 : /* -------------------------------------------------------------------- */
1367 36 : psProParms->proType = (Eprj_ProType) poMIEntry->GetIntField("proType");
1368 36 : psProParms->proNumber = poMIEntry->GetIntField("proNumber");
1369 36 : psProParms->proExeName =CPLStrdup(poMIEntry->GetStringField("proExeName"));
1370 36 : psProParms->proName = CPLStrdup(poMIEntry->GetStringField("proName"));
1371 36 : psProParms->proZone = poMIEntry->GetIntField("proZone");
1372 :
1373 576 : for( i = 0; i < 15; i++ )
1374 : {
1375 : char szFieldName[40];
1376 :
1377 540 : sprintf( szFieldName, "proParams[%d]", i );
1378 540 : psProParms->proParams[i] = poMIEntry->GetDoubleField(szFieldName);
1379 : }
1380 :
1381 : psProParms->proSpheroid.sphereName =
1382 36 : CPLStrdup(poMIEntry->GetStringField("proSpheroid.sphereName"));
1383 36 : psProParms->proSpheroid.a = poMIEntry->GetDoubleField("proSpheroid.a");
1384 36 : psProParms->proSpheroid.b = poMIEntry->GetDoubleField("proSpheroid.b");
1385 : psProParms->proSpheroid.eSquared =
1386 36 : poMIEntry->GetDoubleField("proSpheroid.eSquared");
1387 : psProParms->proSpheroid.radius =
1388 36 : poMIEntry->GetDoubleField("proSpheroid.radius");
1389 :
1390 36 : hHFA->pProParameters = (void *) psProParms;
1391 :
1392 36 : return psProParms;
1393 : }
1394 :
1395 : /************************************************************************/
1396 : /* HFASetProParameters() */
1397 : /************************************************************************/
1398 :
1399 54 : CPLErr HFASetProParameters( HFAHandle hHFA, const Eprj_ProParameters *poPro )
1400 :
1401 : {
1402 : /* -------------------------------------------------------------------- */
1403 : /* Loop over bands, setting information on each one. */
1404 : /* -------------------------------------------------------------------- */
1405 144 : for( int iBand = 0; iBand < hHFA->nBands; iBand++ )
1406 : {
1407 : HFAEntry *poMIEntry;
1408 :
1409 : /* -------------------------------------------------------------------- */
1410 : /* Create a new Projection if there isn't one present already. */
1411 : /* -------------------------------------------------------------------- */
1412 90 : poMIEntry = hHFA->papoBand[iBand]->poNode->GetNamedChild("Projection");
1413 90 : if( poMIEntry == NULL )
1414 : {
1415 : poMIEntry = new HFAEntry( hHFA, "Projection","Eprj_ProParameters",
1416 90 : hHFA->papoBand[iBand]->poNode );
1417 : }
1418 :
1419 90 : poMIEntry->MarkDirty();
1420 :
1421 : /* -------------------------------------------------------------------- */
1422 : /* Ensure we have enough space for all the data. */
1423 : /* -------------------------------------------------------------------- */
1424 : int nSize;
1425 : GByte *pabyData;
1426 :
1427 : nSize = 34 + 15 * 8
1428 : + 8 + strlen(poPro->proName) + 1
1429 90 : + 32 + 8 + strlen(poPro->proSpheroid.sphereName) + 1;
1430 :
1431 90 : if( poPro->proExeName != NULL )
1432 0 : nSize += strlen(poPro->proExeName) + 1;
1433 :
1434 90 : pabyData = poMIEntry->MakeData( nSize );
1435 90 : poMIEntry->SetPosition();
1436 :
1437 : /* -------------------------------------------------------------------- */
1438 : /* Write the various fields. */
1439 : /* -------------------------------------------------------------------- */
1440 90 : poMIEntry->SetIntField( "proType", poPro->proType );
1441 :
1442 90 : poMIEntry->SetIntField( "proNumber", poPro->proNumber );
1443 :
1444 90 : poMIEntry->SetStringField( "proExeName", poPro->proExeName );
1445 90 : poMIEntry->SetStringField( "proName", poPro->proName );
1446 90 : poMIEntry->SetIntField( "proZone", poPro->proZone );
1447 90 : poMIEntry->SetDoubleField( "proParams[0]", poPro->proParams[0] );
1448 90 : poMIEntry->SetDoubleField( "proParams[1]", poPro->proParams[1] );
1449 90 : poMIEntry->SetDoubleField( "proParams[2]", poPro->proParams[2] );
1450 90 : poMIEntry->SetDoubleField( "proParams[3]", poPro->proParams[3] );
1451 90 : poMIEntry->SetDoubleField( "proParams[4]", poPro->proParams[4] );
1452 90 : poMIEntry->SetDoubleField( "proParams[5]", poPro->proParams[5] );
1453 90 : poMIEntry->SetDoubleField( "proParams[6]", poPro->proParams[6] );
1454 90 : poMIEntry->SetDoubleField( "proParams[7]", poPro->proParams[7] );
1455 90 : poMIEntry->SetDoubleField( "proParams[8]", poPro->proParams[8] );
1456 90 : poMIEntry->SetDoubleField( "proParams[9]", poPro->proParams[9] );
1457 90 : poMIEntry->SetDoubleField( "proParams[10]", poPro->proParams[10] );
1458 90 : poMIEntry->SetDoubleField( "proParams[11]", poPro->proParams[11] );
1459 90 : poMIEntry->SetDoubleField( "proParams[12]", poPro->proParams[12] );
1460 90 : poMIEntry->SetDoubleField( "proParams[13]", poPro->proParams[13] );
1461 90 : poMIEntry->SetDoubleField( "proParams[14]", poPro->proParams[14] );
1462 : poMIEntry->SetStringField( "proSpheroid.sphereName",
1463 90 : poPro->proSpheroid.sphereName );
1464 : poMIEntry->SetDoubleField( "proSpheroid.a",
1465 90 : poPro->proSpheroid.a );
1466 : poMIEntry->SetDoubleField( "proSpheroid.b",
1467 90 : poPro->proSpheroid.b );
1468 : poMIEntry->SetDoubleField( "proSpheroid.eSquared",
1469 90 : poPro->proSpheroid.eSquared );
1470 : poMIEntry->SetDoubleField( "proSpheroid.radius",
1471 90 : poPro->proSpheroid.radius );
1472 : }
1473 :
1474 54 : return CE_None;
1475 : }
1476 :
1477 : /************************************************************************/
1478 : /* HFAGetDatum() */
1479 : /************************************************************************/
1480 :
1481 244 : const Eprj_Datum *HFAGetDatum( HFAHandle hHFA )
1482 :
1483 : {
1484 : HFAEntry *poMIEntry;
1485 : Eprj_Datum *psDatum;
1486 : int i;
1487 :
1488 244 : if( hHFA->nBands < 1 )
1489 0 : return NULL;
1490 :
1491 : /* -------------------------------------------------------------------- */
1492 : /* Do we already have it? */
1493 : /* -------------------------------------------------------------------- */
1494 244 : if( hHFA->pDatum != NULL )
1495 0 : return( (Eprj_Datum *) hHFA->pDatum );
1496 :
1497 : /* -------------------------------------------------------------------- */
1498 : /* Get the HFA node. */
1499 : /* -------------------------------------------------------------------- */
1500 244 : poMIEntry = hHFA->papoBand[0]->poNode->GetNamedChild( "Projection.Datum" );
1501 244 : if( poMIEntry == NULL )
1502 208 : return NULL;
1503 :
1504 : /* -------------------------------------------------------------------- */
1505 : /* Allocate the structure. */
1506 : /* -------------------------------------------------------------------- */
1507 36 : psDatum = (Eprj_Datum *) CPLCalloc(sizeof(Eprj_Datum),1);
1508 :
1509 : /* -------------------------------------------------------------------- */
1510 : /* Fetch the fields. */
1511 : /* -------------------------------------------------------------------- */
1512 36 : psDatum->datumname = CPLStrdup(poMIEntry->GetStringField("datumname"));
1513 36 : psDatum->type = (Eprj_DatumType) poMIEntry->GetIntField("type");
1514 :
1515 288 : for( i = 0; i < 7; i++ )
1516 : {
1517 : char szFieldName[30];
1518 :
1519 252 : sprintf( szFieldName, "params[%d]", i );
1520 252 : psDatum->params[i] = poMIEntry->GetDoubleField(szFieldName);
1521 : }
1522 :
1523 36 : psDatum->gridname = CPLStrdup(poMIEntry->GetStringField("gridname"));
1524 :
1525 36 : hHFA->pDatum = (void *) psDatum;
1526 :
1527 36 : return psDatum;
1528 : }
1529 :
1530 : /************************************************************************/
1531 : /* HFASetDatum() */
1532 : /************************************************************************/
1533 :
1534 54 : CPLErr HFASetDatum( HFAHandle hHFA, const Eprj_Datum *poDatum )
1535 :
1536 : {
1537 : /* -------------------------------------------------------------------- */
1538 : /* Loop over bands, setting information on each one. */
1539 : /* -------------------------------------------------------------------- */
1540 144 : for( int iBand = 0; iBand < hHFA->nBands; iBand++ )
1541 : {
1542 90 : HFAEntry *poDatumEntry=NULL, *poProParms;
1543 :
1544 : /* -------------------------------------------------------------------- */
1545 : /* Create a new Projection if there isn't one present already. */
1546 : /* -------------------------------------------------------------------- */
1547 : poProParms =
1548 90 : hHFA->papoBand[iBand]->poNode->GetNamedChild("Projection");
1549 90 : if( poProParms == NULL )
1550 : {
1551 : CPLError( CE_Failure, CPLE_AppDefined,
1552 0 : "Can't add Eprj_Datum with no Eprj_ProjParameters." );
1553 0 : return CE_Failure;
1554 : }
1555 :
1556 90 : poDatumEntry = poProParms->GetNamedChild("Datum");
1557 90 : if( poDatumEntry == NULL )
1558 : {
1559 : poDatumEntry = new HFAEntry( hHFA, "Datum","Eprj_Datum",
1560 90 : poProParms );
1561 : }
1562 :
1563 90 : poDatumEntry->MarkDirty();
1564 :
1565 : /* -------------------------------------------------------------------- */
1566 : /* Ensure we have enough space for all the data. */
1567 : /* -------------------------------------------------------------------- */
1568 : int nSize;
1569 : GByte *pabyData;
1570 :
1571 90 : nSize = 26 + strlen(poDatum->datumname) + 1 + 7*8;
1572 :
1573 90 : if( poDatum->gridname != NULL )
1574 19 : nSize += strlen(poDatum->gridname) + 1;
1575 :
1576 90 : pabyData = poDatumEntry->MakeData( nSize );
1577 90 : poDatumEntry->SetPosition();
1578 :
1579 : /* -------------------------------------------------------------------- */
1580 : /* Write the various fields. */
1581 : /* -------------------------------------------------------------------- */
1582 90 : poDatumEntry->SetStringField( "datumname", poDatum->datumname );
1583 90 : poDatumEntry->SetIntField( "type", poDatum->type );
1584 :
1585 90 : poDatumEntry->SetDoubleField( "params[0]", poDatum->params[0] );
1586 90 : poDatumEntry->SetDoubleField( "params[1]", poDatum->params[1] );
1587 90 : poDatumEntry->SetDoubleField( "params[2]", poDatum->params[2] );
1588 90 : poDatumEntry->SetDoubleField( "params[3]", poDatum->params[3] );
1589 90 : poDatumEntry->SetDoubleField( "params[4]", poDatum->params[4] );
1590 90 : poDatumEntry->SetDoubleField( "params[5]", poDatum->params[5] );
1591 90 : poDatumEntry->SetDoubleField( "params[6]", poDatum->params[6] );
1592 :
1593 90 : poDatumEntry->SetStringField( "gridname", poDatum->gridname );
1594 : }
1595 :
1596 54 : return CE_None;
1597 : }
1598 :
1599 : /************************************************************************/
1600 : /* HFAGetPCT() */
1601 : /* */
1602 : /* Read the PCT from a band, if it has one. */
1603 : /************************************************************************/
1604 :
1605 : CPLErr HFAGetPCT( HFAHandle hHFA, int nBand, int *pnColors,
1606 : double **ppadfRed, double **ppadfGreen,
1607 : double **ppadfBlue , double **ppadfAlpha,
1608 481 : double **ppadfBins )
1609 :
1610 : {
1611 481 : if( nBand < 1 || nBand > hHFA->nBands )
1612 0 : return CE_Failure;
1613 :
1614 : return( hHFA->papoBand[nBand-1]->GetPCT( pnColors, ppadfRed,
1615 : ppadfGreen, ppadfBlue,
1616 481 : ppadfAlpha, ppadfBins ) );
1617 : }
1618 :
1619 : /************************************************************************/
1620 : /* HFASetPCT() */
1621 : /* */
1622 : /* Set the PCT on a band. */
1623 : /************************************************************************/
1624 :
1625 : CPLErr HFASetPCT( HFAHandle hHFA, int nBand, int nColors,
1626 : double *padfRed, double *padfGreen, double *padfBlue,
1627 3 : double *padfAlpha )
1628 :
1629 : {
1630 3 : if( nBand < 1 || nBand > hHFA->nBands )
1631 0 : return CE_Failure;
1632 :
1633 : return( hHFA->papoBand[nBand-1]->SetPCT( nColors, padfRed,
1634 3 : padfGreen, padfBlue, padfAlpha ) );
1635 : }
1636 :
1637 : /************************************************************************/
1638 : /* HFAGetDataRange() */
1639 : /************************************************************************/
1640 :
1641 : CPLErr HFAGetDataRange( HFAHandle hHFA, int nBand,
1642 0 : double * pdfMin, double *pdfMax )
1643 :
1644 : {
1645 : HFAEntry *poBinInfo;
1646 :
1647 0 : if( nBand < 1 || nBand > hHFA->nBands )
1648 0 : return CE_Failure;
1649 :
1650 0 : poBinInfo = hHFA->papoBand[nBand-1]->poNode->GetNamedChild("Statistics" );
1651 :
1652 0 : if( poBinInfo == NULL )
1653 0 : return( CE_Failure );
1654 :
1655 0 : *pdfMin = poBinInfo->GetDoubleField( "minimum" );
1656 0 : *pdfMax = poBinInfo->GetDoubleField( "maximum" );
1657 :
1658 0 : if( *pdfMax > *pdfMin )
1659 0 : return CE_None;
1660 : else
1661 0 : return CE_Failure;
1662 : }
1663 :
1664 : /************************************************************************/
1665 : /* HFADumpNode() */
1666 : /************************************************************************/
1667 :
1668 : static void HFADumpNode( HFAEntry *poEntry, int nIndent, int bVerbose,
1669 0 : FILE * fp )
1670 :
1671 : {
1672 : static char szSpaces[256];
1673 : int i;
1674 :
1675 0 : for( i = 0; i < nIndent*2; i++ )
1676 0 : szSpaces[i] = ' ';
1677 0 : szSpaces[nIndent*2] = '\0';
1678 :
1679 : fprintf( fp, "%s%s(%s) @ %d + %d @ %d\n", szSpaces,
1680 : poEntry->GetName(), poEntry->GetType(),
1681 : poEntry->GetFilePos(),
1682 0 : poEntry->GetDataSize(), poEntry->GetDataPos() );
1683 :
1684 0 : if( bVerbose )
1685 : {
1686 0 : strcat( szSpaces, "+ " );
1687 0 : poEntry->DumpFieldValues( fp, szSpaces );
1688 0 : fprintf( fp, "\n" );
1689 : }
1690 :
1691 0 : if( poEntry->GetChild() != NULL )
1692 0 : HFADumpNode( poEntry->GetChild(), nIndent+1, bVerbose, fp );
1693 :
1694 0 : if( poEntry->GetNext() != NULL )
1695 0 : HFADumpNode( poEntry->GetNext(), nIndent, bVerbose, fp );
1696 0 : }
1697 :
1698 : /************************************************************************/
1699 : /* HFADumpTree() */
1700 : /* */
1701 : /* Dump the tree of information in a HFA file. */
1702 : /************************************************************************/
1703 :
1704 0 : void HFADumpTree( HFAHandle hHFA, FILE * fpOut )
1705 :
1706 : {
1707 0 : HFADumpNode( hHFA->poRoot, 0, TRUE, fpOut );
1708 0 : }
1709 :
1710 : /************************************************************************/
1711 : /* HFADumpDictionary() */
1712 : /* */
1713 : /* Dump the dictionary (in raw, and parsed form) to the named */
1714 : /* device. */
1715 : /************************************************************************/
1716 :
1717 0 : void HFADumpDictionary( HFAHandle hHFA, FILE * fpOut )
1718 :
1719 : {
1720 0 : fprintf( fpOut, "%s\n", hHFA->pszDictionary );
1721 :
1722 0 : hHFA->poDictionary->Dump( fpOut );
1723 0 : }
1724 :
1725 : /************************************************************************/
1726 : /* HFAStandard() */
1727 : /* */
1728 : /* Swap byte order on MSB systems. */
1729 : /************************************************************************/
1730 :
1731 : #ifdef CPL_MSB
1732 : void HFAStandard( int nBytes, void * pData )
1733 :
1734 : {
1735 : int i;
1736 : GByte *pabyData = (GByte *) pData;
1737 :
1738 : for( i = nBytes/2-1; i >= 0; i-- )
1739 : {
1740 : GByte byTemp;
1741 :
1742 : byTemp = pabyData[i];
1743 : pabyData[i] = pabyData[nBytes-i-1];
1744 : pabyData[nBytes-i-1] = byTemp;
1745 : }
1746 : }
1747 : #endif
1748 :
1749 : /* ==================================================================== */
1750 : /* Default data dictionary. Emitted verbatim into the imagine */
1751 : /* file. */
1752 : /* ==================================================================== */
1753 :
1754 : static const char *aszDefaultDD[] = {
1755 : "{1:lversion,1:LfreeList,1:LrootEntryPtr,1:sentryHeaderLength,1:LdictionaryPtr,}Ehfa_File,{1:Lnext,1:Lprev,1:Lparent,1:Lchild,1:Ldata,1:ldataSize,64:cname,32:ctype,1:tmodTime,}Ehfa_Entry,{16:clabel,1:LheaderPtr,}Ehfa_HeaderTag,{1:LfreeList,1:lfreeSize,}Ehfa_FreeListNode,{1:lsize,1:Lptr,}Ehfa_Data,{1:lwidth,1:lheight,1:e3:thematic,athematic,fft of real-valued data,layerType,",
1756 : "1:e13:u1,u2,u4,u8,s8,u16,s16,u32,s32,f32,f64,c64,c128,pixelType,1:lblockWidth,1:lblockHeight,}Eimg_Layer,{1:lwidth,1:lheight,1:e3:thematic,athematic,fft of real-valued data,layerType,1:e13:u1,u2,u4,u8,s8,u16,s16,u32,s32,f32,f64,c64,c128,pixelType,1:lblockWidth,1:lblockHeight,}Eimg_Layer_SubSample,{1:e2:raster,vector,type,1:LdictionaryPtr,}Ehfa_Layer,{1:LspaceUsedForRasterData,}ImgFormatInfo831,{1:sfileCode,1:Loffset,1:lsize,1:e2:false,true,logvalid,",
1757 : "1:e2:no compression,ESRI GRID compression,compressionType,}Edms_VirtualBlockInfo,{1:lmin,1:lmax,}Edms_FreeIDList,{1:lnumvirtualblocks,1:lnumobjectsperblock,1:lnextobjectnum,1:e2:no compression,RLC compression,compressionType,0:poEdms_VirtualBlockInfo,blockinfo,0:poEdms_FreeIDList,freelist,1:tmodTime,}Edms_State,{0:pcstring,}Emif_String,{1:oEmif_String,fileName,2:LlayerStackValidFlagsOffset,2:LlayerStackDataOffset,1:LlayerStackCount,1:LlayerStackIndex,}ImgExternalRaster,{1:oEmif_String,algorithm,0:poEmif_String,nameList,}Eimg_RRDNamesList,{1:oEmif_String,projection,1:oEmif_String,units,}Eimg_MapInformation,",
1758 : "{1:oEmif_String,dependent,}Eimg_DependentFile,{1:oEmif_String,ImageLayerName,}Eimg_DependentLayerName,{1:lnumrows,1:lnumcolumns,1:e13:EGDA_TYPE_U1,EGDA_TYPE_U2,EGDA_TYPE_U4,EGDA_TYPE_U8,EGDA_TYPE_S8,EGDA_TYPE_U16,EGDA_TYPE_S16,EGDA_TYPE_U32,EGDA_TYPE_S32,EGDA_TYPE_F32,EGDA_TYPE_F64,EGDA_TYPE_C64,EGDA_TYPE_C128,datatype,1:e4:EGDA_SCALAR_OBJECT,EGDA_TABLE_OBJECT,EGDA_MATRIX_OBJECT,EGDA_RASTER_OBJECT,objecttype,}Egda_BaseData,{1:*bvalueBD,}Eimg_NonInitializedValue,{1:dx,1:dy,}Eprj_Coordinate,{1:dwidth,1:dheight,}Eprj_Size,{0:pcproName,1:*oEprj_Coordinate,upperLeftCenter,",
1759 : "1:*oEprj_Coordinate,lowerRightCenter,1:*oEprj_Size,pixelSize,0:pcunits,}Eprj_MapInfo,{0:pcdatumname,1:e3:EPRJ_DATUM_PARAMETRIC,EPRJ_DATUM_GRID,EPRJ_DATUM_REGRESSION,type,0:pdparams,0:pcgridname,}Eprj_Datum,{0:pcsphereName,1:da,1:db,1:deSquared,1:dradius,}Eprj_Spheroid,{1:e2:EPRJ_INTERNAL,EPRJ_EXTERNAL,proType,1:lproNumber,0:pcproExeName,0:pcproName,1:lproZone,0:pdproParams,1:*oEprj_Spheroid,proSpheroid,}Eprj_ProParameters,{1:dminimum,1:dmaximum,1:dmean,1:dmedian,1:dmode,1:dstddev,}Esta_Statistics,{1:lnumBins,1:e4:direct,linear,logarithmic,explicit,binFunctionType,1:dminLimit,1:dmaxLimit,1:*bbinLimits,}Edsc_BinFunction,{0:poEmif_String,LayerNames,1:*bExcludedValues,1:oEmif_String,AOIname,",
1760 : "1:lSkipFactorX,1:lSkipFactorY,1:*oEdsc_BinFunction,BinFunction,}Eimg_StatisticsParameters830,{1:lnumrows,}Edsc_Table,{1:lnumRows,1:LcolumnDataPtr,1:e4:integer,real,complex,string,dataType,1:lmaxNumChars,}Edsc_Column,{1:lposition,0:pcname,1:e2:EMSC_FALSE,EMSC_TRUE,editable,1:e3:LEFT,CENTER,RIGHT,alignment,0:pcformat,1:e3:DEFAULT,APPLY,AUTO-APPLY,formulamode,0:pcformula,1:dcolumnwidth,0:pcunits,1:e5:NO_COLOR,RED,GREEN,BLUE,COLOR,colorflag,0:pcgreenname,0:pcbluename,}Eded_ColumnAttributes_1,{1:lversion,1:lnumobjects,1:e2:EAOI_UNION,EAOI_INTERSECTION,operation,}Eaoi_AreaOfInterest,",
1761 : "{1:x{0:pcstring,}Emif_String,type,1:x{0:pcstring,}Emif_String,MIFDictionary,0:pCMIFObject,}Emif_MIFObject,",
1762 : "{1:x{1:x{0:pcstring,}Emif_String,type,1:x{0:pcstring,}Emif_String,MIFDictionary,0:pCMIFObject,}Emif_MIFObject,projection,1:x{0:pcstring,}Emif_String,title,}Eprj_MapProjection842,",
1763 : "{0:poEmif_String,titleList,}Exfr_GenericXFormHeader,{1:lorder,1:lnumdimtransform,1:lnumdimpolynomial,1:ltermcount,0:plexponentlist,1:*bpolycoefmtx,1:*bpolycoefvector,}Efga_Polynomial,",
1764 : ".",
1765 : NULL
1766 : };
1767 :
1768 :
1769 :
1770 : /************************************************************************/
1771 : /* HFACreateLL() */
1772 : /* */
1773 : /* Low level creation of an Imagine file. Writes out the */
1774 : /* Ehfa_HeaderTag, dictionary and Ehfa_File. */
1775 : /************************************************************************/
1776 :
1777 105 : HFAHandle HFACreateLL( const char * pszFilename )
1778 :
1779 : {
1780 : FILE *fp;
1781 : HFAInfo_t *psInfo;
1782 :
1783 : /* -------------------------------------------------------------------- */
1784 : /* Create the file in the file system. */
1785 : /* -------------------------------------------------------------------- */
1786 105 : fp = VSIFOpenL( pszFilename, "w+b" );
1787 105 : if( fp == NULL )
1788 : {
1789 : CPLError( CE_Failure, CPLE_OpenFailed,
1790 : "Creation of file %s failed.",
1791 0 : pszFilename );
1792 0 : return NULL;
1793 : }
1794 :
1795 : /* -------------------------------------------------------------------- */
1796 : /* Create the HFAInfo_t */
1797 : /* -------------------------------------------------------------------- */
1798 105 : psInfo = (HFAInfo_t *) CPLCalloc(sizeof(HFAInfo_t),1);
1799 :
1800 105 : psInfo->fp = fp;
1801 105 : psInfo->eAccess = HFA_Update;
1802 105 : psInfo->nXSize = 0;
1803 105 : psInfo->nYSize = 0;
1804 105 : psInfo->nBands = 0;
1805 105 : psInfo->papoBand = NULL;
1806 105 : psInfo->pMapInfo = NULL;
1807 105 : psInfo->pDatum = NULL;
1808 105 : psInfo->pProParameters = NULL;
1809 105 : psInfo->bTreeDirty = FALSE;
1810 105 : psInfo->pszFilename = CPLStrdup(CPLGetFilename(pszFilename));
1811 105 : psInfo->pszPath = CPLStrdup(CPLGetPath(pszFilename));
1812 :
1813 : /* -------------------------------------------------------------------- */
1814 : /* Write out the Ehfa_HeaderTag */
1815 : /* -------------------------------------------------------------------- */
1816 : GInt32 nHeaderPos;
1817 :
1818 105 : VSIFWriteL( (void *) "EHFA_HEADER_TAG", 1, 16, fp );
1819 :
1820 105 : nHeaderPos = 20;
1821 : HFAStandard( 4, &nHeaderPos );
1822 105 : VSIFWriteL( &nHeaderPos, 4, 1, fp );
1823 :
1824 : /* -------------------------------------------------------------------- */
1825 : /* Write the Ehfa_File node, locked in at offset 20. */
1826 : /* -------------------------------------------------------------------- */
1827 105 : GInt32 nVersion = 1, nFreeList = 0, nRootEntry = 0;
1828 105 : GInt16 nEntryHeaderLength = 128;
1829 105 : GInt32 nDictionaryPtr = 38;
1830 :
1831 105 : psInfo->nEntryHeaderLength = nEntryHeaderLength;
1832 105 : psInfo->nRootPos = 0;
1833 105 : psInfo->nDictionaryPos = nDictionaryPtr;
1834 105 : psInfo->nVersion = nVersion;
1835 :
1836 : HFAStandard( 4, &nVersion );
1837 : HFAStandard( 4, &nFreeList );
1838 : HFAStandard( 4, &nRootEntry );
1839 : HFAStandard( 2, &nEntryHeaderLength );
1840 : HFAStandard( 4, &nDictionaryPtr );
1841 :
1842 105 : VSIFWriteL( &nVersion, 4, 1, fp );
1843 105 : VSIFWriteL( &nFreeList, 4, 1, fp );
1844 105 : VSIFWriteL( &nRootEntry, 4, 1, fp );
1845 105 : VSIFWriteL( &nEntryHeaderLength, 2, 1, fp );
1846 105 : VSIFWriteL( &nDictionaryPtr, 4, 1, fp );
1847 :
1848 : /* -------------------------------------------------------------------- */
1849 : /* Write the dictionary, locked in at location 38. Note that */
1850 : /* we jump through a bunch of hoops to operate on the */
1851 : /* dictionary in chunks because some compiles (such as VC++) */
1852 : /* don't allow particularly large static strings. */
1853 : /* -------------------------------------------------------------------- */
1854 105 : int nDictLen = 0, iChunk;
1855 :
1856 1155 : for( iChunk = 0; aszDefaultDD[iChunk] != NULL; iChunk++ )
1857 1050 : nDictLen += strlen(aszDefaultDD[iChunk]);
1858 :
1859 105 : psInfo->pszDictionary = (char *) CPLMalloc(nDictLen+1);
1860 105 : psInfo->pszDictionary[0] = '\0';
1861 :
1862 1155 : for( iChunk = 0; aszDefaultDD[iChunk] != NULL; iChunk++ )
1863 1050 : strcat( psInfo->pszDictionary, aszDefaultDD[iChunk] );
1864 :
1865 : VSIFWriteL( (void *) psInfo->pszDictionary, 1,
1866 105 : strlen(psInfo->pszDictionary)+1, fp );
1867 :
1868 105 : psInfo->poDictionary = new HFADictionary( psInfo->pszDictionary );
1869 :
1870 105 : psInfo->nEndOfFile = (GUInt32) VSIFTellL( fp );
1871 :
1872 : /* -------------------------------------------------------------------- */
1873 : /* Create a root entry. */
1874 : /* -------------------------------------------------------------------- */
1875 210 : psInfo->poRoot = new HFAEntry( psInfo, "root", "root", NULL );
1876 :
1877 : /* -------------------------------------------------------------------- */
1878 : /* If an .ige or .rrd file exists with the same base name, */
1879 : /* delete them. (#1784) */
1880 : /* -------------------------------------------------------------------- */
1881 105 : CPLString osExtension = CPLGetExtension(pszFilename);
1882 210 : if( !EQUAL(osExtension,"rrd") && !EQUAL(osExtension,"aux") )
1883 : {
1884 102 : CPLString osPath = CPLGetPath( pszFilename );
1885 102 : CPLString osBasename = CPLGetBasename( pszFilename );
1886 : VSIStatBufL sStatBuf;
1887 102 : CPLString osSupFile = CPLFormCIFilename( osPath, osBasename, "rrd" );
1888 :
1889 102 : if( VSIStatL( osSupFile, &sStatBuf ) == 0 )
1890 0 : VSIUnlink( osSupFile );
1891 :
1892 102 : osSupFile = CPLFormCIFilename( osPath, osBasename, "ige" );
1893 :
1894 102 : if( VSIStatL( osSupFile, &sStatBuf ) == 0 )
1895 7 : VSIUnlink( osSupFile );
1896 : }
1897 :
1898 105 : return psInfo;
1899 : }
1900 :
1901 : /************************************************************************/
1902 : /* HFAAllocateSpace() */
1903 : /* */
1904 : /* Return an area in the file to the caller to write the */
1905 : /* requested number of bytes. Currently this is always at the */
1906 : /* end of the file, but eventually we might actually keep track */
1907 : /* of free space. The HFAInfo_t's concept of file size is */
1908 : /* updated, even if nothing ever gets written to this region. */
1909 : /* */
1910 : /* Returns the offset to the requested space, or zero one */
1911 : /* failure. */
1912 : /************************************************************************/
1913 :
1914 1901 : GUInt32 HFAAllocateSpace( HFAInfo_t *psInfo, GUInt32 nBytes )
1915 :
1916 : {
1917 : /* should check if this will wrap over 2GB limit */
1918 :
1919 1901 : psInfo->nEndOfFile += nBytes;
1920 1901 : return psInfo->nEndOfFile - nBytes;
1921 : }
1922 :
1923 : /************************************************************************/
1924 : /* HFAFlush() */
1925 : /* */
1926 : /* Write out any dirty tree information to disk, putting the */
1927 : /* disk file in a consistent state. */
1928 : /************************************************************************/
1929 :
1930 210 : CPLErr HFAFlush( HFAHandle hHFA )
1931 :
1932 : {
1933 : CPLErr eErr;
1934 :
1935 210 : if( !hHFA->bTreeDirty && !hHFA->poDictionary->bDictionaryTextDirty )
1936 0 : return CE_None;
1937 :
1938 210 : CPLAssert( hHFA->poRoot != NULL );
1939 :
1940 : /* -------------------------------------------------------------------- */
1941 : /* Flush HFAEntry tree to disk. */
1942 : /* -------------------------------------------------------------------- */
1943 210 : if( hHFA->bTreeDirty )
1944 : {
1945 209 : eErr = hHFA->poRoot->FlushToDisk();
1946 209 : if( eErr != CE_None )
1947 0 : return eErr;
1948 :
1949 209 : hHFA->bTreeDirty = FALSE;
1950 : }
1951 :
1952 : /* -------------------------------------------------------------------- */
1953 : /* Flush Dictionary to disk. */
1954 : /* -------------------------------------------------------------------- */
1955 210 : GUInt32 nNewDictionaryPos = hHFA->nDictionaryPos;
1956 :
1957 210 : if( hHFA->poDictionary->bDictionaryTextDirty )
1958 : {
1959 1 : VSIFSeekL( hHFA->fp, 0, SEEK_END );
1960 1 : nNewDictionaryPos = (GUInt32) VSIFTellL( hHFA->fp );
1961 : VSIFWriteL( hHFA->poDictionary->osDictionaryText.c_str(),
1962 : strlen(hHFA->poDictionary->osDictionaryText.c_str()) + 1,
1963 1 : 1, hHFA->fp );
1964 1 : hHFA->poDictionary->bDictionaryTextDirty = FALSE;
1965 : }
1966 :
1967 : /* -------------------------------------------------------------------- */
1968 : /* do we need to update the Ehfa_File pointer to the root node? */
1969 : /* -------------------------------------------------------------------- */
1970 210 : if( hHFA->nRootPos != hHFA->poRoot->GetFilePos()
1971 : || nNewDictionaryPos != hHFA->nDictionaryPos )
1972 : {
1973 : GUInt32 nOffset;
1974 : GUInt32 nHeaderPos;
1975 :
1976 106 : VSIFSeekL( hHFA->fp, 16, SEEK_SET );
1977 106 : VSIFReadL( &nHeaderPos, sizeof(GInt32), 1, hHFA->fp );
1978 : HFAStandard( 4, &nHeaderPos );
1979 :
1980 106 : nOffset = hHFA->nRootPos = hHFA->poRoot->GetFilePos();
1981 : HFAStandard( 4, &nOffset );
1982 106 : VSIFSeekL( hHFA->fp, nHeaderPos+8, SEEK_SET );
1983 106 : VSIFWriteL( &nOffset, 4, 1, hHFA->fp );
1984 :
1985 106 : nOffset = hHFA->nDictionaryPos = nNewDictionaryPos;
1986 : HFAStandard( 4, &nOffset );
1987 106 : VSIFSeekL( hHFA->fp, nHeaderPos+14, SEEK_SET );
1988 106 : VSIFWriteL( &nOffset, 4, 1, hHFA->fp );
1989 : }
1990 :
1991 210 : return CE_None;
1992 : }
1993 :
1994 : /************************************************************************/
1995 : /* HFACreateLayer() */
1996 : /* */
1997 : /* Create a layer object, and corresponding RasterDMS. */
1998 : /* Suitable for use with primary layers, and overviews. */
1999 : /************************************************************************/
2000 :
2001 : int
2002 : HFACreateLayer( HFAHandle psInfo, HFAEntry *poParent,
2003 : const char *pszLayerName,
2004 : int bOverview, int nBlockSize,
2005 : int bCreateCompressed, int bCreateLargeRaster,
2006 : int bDependentLayer,
2007 : int nXSize, int nYSize, int nDataType,
2008 : char **papszOptions,
2009 :
2010 : // these are only related to external (large) files
2011 : GIntBig nStackValidFlagsOffset,
2012 : GIntBig nStackDataOffset,
2013 176 : int nStackCount, int nStackIndex )
2014 :
2015 : {
2016 :
2017 : HFAEntry *poEimg_Layer;
2018 : const char *pszLayerType;
2019 :
2020 176 : if( bOverview )
2021 6 : pszLayerType = "Eimg_Layer_SubSample";
2022 : else
2023 170 : pszLayerType = "Eimg_Layer";
2024 :
2025 176 : if (nBlockSize <= 0)
2026 : {
2027 0 : CPLError(CE_Failure, CPLE_IllegalArg, "HFACreateLayer : nBlockXSize < 0");
2028 0 : return FALSE;
2029 : }
2030 :
2031 : /* -------------------------------------------------------------------- */
2032 : /* Work out some details about the tiling scheme. */
2033 : /* -------------------------------------------------------------------- */
2034 : int nBlocksPerRow, nBlocksPerColumn, nBlocks, nBytesPerBlock;
2035 :
2036 176 : nBlocksPerRow = (nXSize + nBlockSize - 1) / nBlockSize;
2037 176 : nBlocksPerColumn = (nYSize + nBlockSize - 1) / nBlockSize;
2038 176 : nBlocks = nBlocksPerRow * nBlocksPerColumn;
2039 : nBytesPerBlock = (nBlockSize * nBlockSize
2040 176 : * HFAGetDataTypeBits(nDataType) + 7) / 8;
2041 :
2042 : /* -------------------------------------------------------------------- */
2043 : /* Create the Eimg_Layer for the band. */
2044 : /* -------------------------------------------------------------------- */
2045 : poEimg_Layer =
2046 176 : new HFAEntry( psInfo, pszLayerName, pszLayerType, poParent );
2047 :
2048 176 : poEimg_Layer->SetIntField( "width", nXSize );
2049 176 : poEimg_Layer->SetIntField( "height", nYSize );
2050 176 : poEimg_Layer->SetStringField( "layerType", "athematic" );
2051 176 : poEimg_Layer->SetIntField( "pixelType", nDataType );
2052 176 : poEimg_Layer->SetIntField( "blockWidth", nBlockSize );
2053 176 : poEimg_Layer->SetIntField( "blockHeight", nBlockSize );
2054 :
2055 : /* -------------------------------------------------------------------- */
2056 : /* Create the RasterDMS (block list). This is a complex type */
2057 : /* with pointers, and variable size. We set the superstructure */
2058 : /* ourselves rather than trying to have the HFA type management */
2059 : /* system do it for us (since this would be hard to implement). */
2060 : /* -------------------------------------------------------------------- */
2061 500 : if ( !bCreateLargeRaster && !bDependentLayer )
2062 : {
2063 : int nDmsSize;
2064 : HFAEntry *poEdms_State;
2065 : GByte *pabyData;
2066 :
2067 : poEdms_State =
2068 161 : new HFAEntry( psInfo, "RasterDMS", "Edms_State", poEimg_Layer );
2069 :
2070 161 : nDmsSize = 14 * nBlocks + 38;
2071 161 : pabyData = poEdms_State->MakeData( nDmsSize );
2072 :
2073 : /* set some simple values */
2074 161 : poEdms_State->SetIntField( "numvirtualblocks", nBlocks );
2075 : poEdms_State->SetIntField( "numobjectsperblock",
2076 161 : nBlockSize*nBlockSize );
2077 : poEdms_State->SetIntField( "nextobjectnum",
2078 161 : nBlockSize*nBlockSize*nBlocks );
2079 :
2080 : /* Is file compressed or not? */
2081 161 : if( bCreateCompressed )
2082 : {
2083 12 : poEdms_State->SetStringField( "compressionType", "RLC compression" );
2084 : }
2085 : else
2086 : {
2087 149 : poEdms_State->SetStringField( "compressionType", "no compression" );
2088 : }
2089 :
2090 : /* we need to hardcode file offset into the data, so locate it now */
2091 161 : poEdms_State->SetPosition();
2092 :
2093 : /* Set block info headers */
2094 : GUInt32 nValue;
2095 :
2096 : /* blockinfo count */
2097 161 : nValue = nBlocks;
2098 : HFAStandard( 4, &nValue );
2099 161 : memcpy( pabyData + 14, &nValue, 4 );
2100 :
2101 : /* blockinfo position */
2102 161 : nValue = poEdms_State->GetDataPos() + 22;
2103 : HFAStandard( 4, &nValue );
2104 161 : memcpy( pabyData + 18, &nValue, 4 );
2105 :
2106 : /* Set each blockinfo */
2107 558 : for( int iBlock = 0; iBlock < nBlocks; iBlock++ )
2108 : {
2109 : GInt16 nValue16;
2110 397 : int nOffset = 22 + 14 * iBlock;
2111 :
2112 : /* fileCode */
2113 397 : nValue16 = 0;
2114 : HFAStandard( 2, &nValue16 );
2115 397 : memcpy( pabyData + nOffset, &nValue16, 2 );
2116 :
2117 : /* offset */
2118 397 : if( bCreateCompressed )
2119 : {
2120 : /* flag it with zero offset - will allocate space when we compress it */
2121 12 : nValue = 0;
2122 : }
2123 : else
2124 : {
2125 385 : nValue = HFAAllocateSpace( psInfo, nBytesPerBlock );
2126 : }
2127 : HFAStandard( 4, &nValue );
2128 397 : memcpy( pabyData + nOffset + 2, &nValue, 4 );
2129 :
2130 : /* size */
2131 397 : if( bCreateCompressed )
2132 : {
2133 : /* flag it with zero size - don't know until we compress it */
2134 12 : nValue = 0;
2135 : }
2136 : else
2137 : {
2138 385 : nValue = nBytesPerBlock;
2139 : }
2140 : HFAStandard( 4, &nValue );
2141 397 : memcpy( pabyData + nOffset + 6, &nValue, 4 );
2142 :
2143 : /* logValid (false) */
2144 397 : nValue16 = 0;
2145 : HFAStandard( 2, &nValue16 );
2146 397 : memcpy( pabyData + nOffset + 10, &nValue16, 2 );
2147 :
2148 : /* compressionType */
2149 397 : if( bCreateCompressed )
2150 12 : nValue16 = 1;
2151 : else
2152 385 : nValue16 = 0;
2153 :
2154 : HFAStandard( 2, &nValue16 );
2155 397 : memcpy( pabyData + nOffset + 12, &nValue16, 2 );
2156 : }
2157 :
2158 : }
2159 : /* -------------------------------------------------------------------- */
2160 : /* Create ExternalRasterDMS object. */
2161 : /* -------------------------------------------------------------------- */
2162 15 : else if( bCreateLargeRaster )
2163 : {
2164 : HFAEntry *poEdms_State;
2165 :
2166 : poEdms_State =
2167 : new HFAEntry( psInfo, "ExternalRasterDMS",
2168 13 : "ImgExternalRaster", poEimg_Layer );
2169 13 : poEdms_State->MakeData( 8 + strlen(psInfo->pszIGEFilename) + 1 + 6 * 4 );
2170 :
2171 : poEdms_State->SetStringField( "fileName.string",
2172 13 : psInfo->pszIGEFilename );
2173 :
2174 : poEdms_State->SetIntField( "layerStackValidFlagsOffset[0]",
2175 13 : (int) (nStackValidFlagsOffset & 0xFFFFFFFF));
2176 : poEdms_State->SetIntField( "layerStackValidFlagsOffset[1]",
2177 13 : (int) (nStackValidFlagsOffset >> 32) );
2178 :
2179 : poEdms_State->SetIntField( "layerStackDataOffset[0]",
2180 13 : (int) (nStackDataOffset & 0xFFFFFFFF) );
2181 : poEdms_State->SetIntField( "layerStackDataOffset[1]",
2182 13 : (int) (nStackDataOffset >> 32 ) );
2183 13 : poEdms_State->SetIntField( "layerStackCount", nStackCount );
2184 13 : poEdms_State->SetIntField( "layerStackIndex", nStackIndex );
2185 : }
2186 :
2187 : /* -------------------------------------------------------------------- */
2188 : /* Dependent... */
2189 : /* -------------------------------------------------------------------- */
2190 2 : else if( bDependentLayer )
2191 : {
2192 : HFAEntry *poDepLayerName;
2193 :
2194 : poDepLayerName =
2195 : new HFAEntry( psInfo, "DependentLayerName",
2196 2 : "Eimg_DependentLayerName", poEimg_Layer );
2197 2 : poDepLayerName->MakeData( 8 + strlen(pszLayerName) + 2 );
2198 :
2199 : poDepLayerName->SetStringField( "ImageLayerName.string",
2200 2 : pszLayerName );
2201 : }
2202 :
2203 : /* -------------------------------------------------------------------- */
2204 : /* Create the Ehfa_Layer. */
2205 : /* -------------------------------------------------------------------- */
2206 : HFAEntry *poEhfa_Layer;
2207 : GUInt32 nLDict;
2208 : char szLDict[128], chBandType;
2209 :
2210 176 : if( nDataType == EPT_u1 )
2211 2 : chBandType = '1';
2212 174 : else if( nDataType == EPT_u2 )
2213 0 : chBandType = '2';
2214 174 : else if( nDataType == EPT_u4 )
2215 0 : chBandType = '4';
2216 174 : else if( nDataType == EPT_u8 )
2217 69 : chBandType = 'c';
2218 105 : else if( nDataType == EPT_s8 )
2219 0 : chBandType = 'C';
2220 105 : else if( nDataType == EPT_u16 )
2221 19 : chBandType = 's';
2222 86 : else if( nDataType == EPT_s16 )
2223 11 : chBandType = 'S';
2224 75 : else if( nDataType == EPT_u32 )
2225 : // for some reason erdas imagine expects an L for unsinged 32 bit ints
2226 : // otherwise it gives strange "out of memory errors"
2227 11 : chBandType = 'L';
2228 64 : else if( nDataType == EPT_s32 )
2229 13 : chBandType = 'L';
2230 51 : else if( nDataType == EPT_f32 )
2231 11 : chBandType = 'f';
2232 40 : else if( nDataType == EPT_f64 )
2233 18 : chBandType = 'd';
2234 22 : else if( nDataType == EPT_c64 )
2235 11 : chBandType = 'm';
2236 11 : else if( nDataType == EPT_c128 )
2237 11 : chBandType = 'M';
2238 : else
2239 : {
2240 0 : CPLAssert( FALSE );
2241 0 : chBandType = 'c';
2242 : }
2243 :
2244 : // the first value in the entry below gives the number of pixels within a block
2245 176 : sprintf( szLDict, "{%d:%cdata,}RasterDMS,.", nBlockSize*nBlockSize, chBandType );
2246 :
2247 : poEhfa_Layer = new HFAEntry( psInfo, "Ehfa_Layer", "Ehfa_Layer",
2248 176 : poEimg_Layer );
2249 176 : poEhfa_Layer->MakeData();
2250 176 : poEhfa_Layer->SetPosition();
2251 176 : nLDict = HFAAllocateSpace( psInfo, strlen(szLDict) + 1 );
2252 :
2253 176 : poEhfa_Layer->SetStringField( "type", "raster" );
2254 176 : poEhfa_Layer->SetIntField( "dictionaryPtr", nLDict );
2255 :
2256 176 : VSIFSeekL( psInfo->fp, nLDict, SEEK_SET );
2257 176 : VSIFWriteL( (void *) szLDict, strlen(szLDict) + 1, 1, psInfo->fp );
2258 :
2259 176 : return TRUE;
2260 : }
2261 :
2262 :
2263 : /************************************************************************/
2264 : /* HFACreate() */
2265 : /************************************************************************/
2266 :
2267 : HFAHandle HFACreate( const char * pszFilename,
2268 : int nXSize, int nYSize, int nBands,
2269 104 : int nDataType, char ** papszOptions )
2270 :
2271 : {
2272 : HFAHandle psInfo;
2273 104 : int nBlockSize = 64;
2274 104 : const char * pszValue = CSLFetchNameValue( papszOptions, "BLOCKSIZE" );
2275 :
2276 104 : if ( pszValue != NULL )
2277 : {
2278 0 : nBlockSize = atoi( pszValue );
2279 : // check for sane values
2280 0 : if ( ( nBlockSize < 32 ) || (nBlockSize > 2048) )
2281 : {
2282 0 : nBlockSize = 64;
2283 : }
2284 : }
2285 : int bCreateLargeRaster = CSLFetchBoolean(papszOptions,"USE_SPILL",
2286 104 : FALSE);
2287 : int bCreateCompressed =
2288 : CSLFetchBoolean(papszOptions,"COMPRESS", FALSE)
2289 104 : || CSLFetchBoolean(papszOptions,"COMPRESSED", FALSE);
2290 104 : int bCreateAux = CSLFetchBoolean(papszOptions,"AUX", FALSE);
2291 :
2292 104 : char *pszFullFilename = NULL, *pszRawFilename = NULL;
2293 :
2294 : /* -------------------------------------------------------------------- */
2295 : /* Create the low level structure. */
2296 : /* -------------------------------------------------------------------- */
2297 104 : psInfo = HFACreateLL( pszFilename );
2298 104 : if( psInfo == NULL )
2299 0 : return NULL;
2300 :
2301 : /* -------------------------------------------------------------------- */
2302 : /* Create the DependentFile node if requested. */
2303 : /* -------------------------------------------------------------------- */
2304 : const char *pszDependentFile =
2305 104 : CSLFetchNameValue( papszOptions, "DEPENDENT_FILE" );
2306 :
2307 104 : if( pszDependentFile != NULL )
2308 : {
2309 : HFAEntry *poDF = new HFAEntry( psInfo, "DependentFile",
2310 2 : "Eimg_DependentFile", psInfo->poRoot );
2311 :
2312 2 : poDF->MakeData( strlen(pszDependentFile) + 50 );
2313 2 : poDF->SetPosition();
2314 2 : poDF->SetStringField( "dependent.string", pszDependentFile );
2315 : }
2316 :
2317 : /* -------------------------------------------------------------------- */
2318 : /* Work out some details about the tiling scheme. */
2319 : /* -------------------------------------------------------------------- */
2320 : int nBlocksPerRow, nBlocksPerColumn, nBlocks, nBytesPerBlock;
2321 :
2322 104 : nBlocksPerRow = (nXSize + nBlockSize - 1) / nBlockSize;
2323 104 : nBlocksPerColumn = (nYSize + nBlockSize - 1) / nBlockSize;
2324 104 : nBlocks = nBlocksPerRow * nBlocksPerColumn;
2325 : nBytesPerBlock = (nBlockSize * nBlockSize
2326 104 : * HFAGetDataTypeBits(nDataType) + 7) / 8;
2327 :
2328 : CPLDebug( "HFACreate", "Blocks per row %d, blocks per column %d, "
2329 : "total number of blocks %d, bytes per block %d.",
2330 104 : nBlocksPerRow, nBlocksPerColumn, nBlocks, nBytesPerBlock );
2331 :
2332 : /* -------------------------------------------------------------------- */
2333 : /* Check whether we should create external large file with */
2334 : /* image. We create a spill file if the amount of imagery is */
2335 : /* close to 2GB. We don't check the amount of auxilary */
2336 : /* information, so in theory if there were an awful lot of */
2337 : /* non-imagery data our approximate size could be smaller than */
2338 : /* the file will actually we be. We leave room for 10MB of */
2339 : /* auxilary data. */
2340 : /* We can also force spill file creation using option */
2341 : /* SPILL_FILE=YES. */
2342 : /* -------------------------------------------------------------------- */
2343 : double dfApproxSize = (double)nBytesPerBlock * (double)nBlocks *
2344 104 : (double)nBands + 10000000.0;
2345 :
2346 104 : if( dfApproxSize > 2147483648.0 && !bCreateAux )
2347 0 : bCreateLargeRaster = TRUE;
2348 :
2349 : // erdas imagine creates this entry even if an external spill file is used
2350 104 : if( !bCreateAux )
2351 : {
2352 : HFAEntry *poImgFormat;
2353 : poImgFormat = new HFAEntry( psInfo, "IMGFormatInfo",
2354 102 : "ImgFormatInfo831", psInfo->poRoot );
2355 102 : poImgFormat->MakeData();
2356 102 : if ( bCreateLargeRaster )
2357 : {
2358 7 : poImgFormat->SetIntField( "spaceUsedForRasterData", 0 );
2359 7 : bCreateCompressed = FALSE; // Can't be compressed if we are creating a spillfile
2360 : }
2361 : else
2362 : {
2363 : poImgFormat->SetIntField( "spaceUsedForRasterData",
2364 95 : nBytesPerBlock*nBlocks*nBands );
2365 : }
2366 : }
2367 :
2368 : /* -------------------------------------------------------------------- */
2369 : /* Create external file and write its header. */
2370 : /* -------------------------------------------------------------------- */
2371 104 : GIntBig nValidFlagsOffset = 0, nDataOffset = 0;
2372 :
2373 104 : if( bCreateLargeRaster )
2374 : {
2375 7 : if( !HFACreateSpillStack( psInfo, nXSize, nYSize, nBands,
2376 : nBlockSize, nDataType,
2377 : &nValidFlagsOffset, &nDataOffset ) )
2378 : {
2379 0 : CPLFree( pszRawFilename );
2380 0 : CPLFree( pszFullFilename );
2381 0 : return NULL;
2382 : }
2383 : }
2384 :
2385 : /* ==================================================================== */
2386 : /* Create each band (layer) */
2387 : /* ==================================================================== */
2388 : int iBand;
2389 :
2390 274 : for( iBand = 0; iBand < nBands; iBand++ )
2391 : {
2392 : char szName[128];
2393 :
2394 170 : sprintf( szName, "Layer_%d", iBand + 1 );
2395 :
2396 170 : if( !HFACreateLayer( psInfo, psInfo->poRoot, szName, FALSE, nBlockSize,
2397 : bCreateCompressed, bCreateLargeRaster, bCreateAux,
2398 : nXSize, nYSize, nDataType, papszOptions,
2399 : nValidFlagsOffset, nDataOffset,
2400 : nBands, iBand ) )
2401 : {
2402 0 : HFAClose( psInfo );
2403 0 : return NULL;
2404 : }
2405 : }
2406 :
2407 : /* -------------------------------------------------------------------- */
2408 : /* Initialize the band information. */
2409 : /* -------------------------------------------------------------------- */
2410 104 : HFAParseBandInfo( psInfo );
2411 :
2412 104 : return psInfo;
2413 : }
2414 :
2415 : /************************************************************************/
2416 : /* HFACreateOverview() */
2417 : /* */
2418 : /* Create an overview layer object for a band. */
2419 : /************************************************************************/
2420 :
2421 6 : int HFACreateOverview( HFAHandle hHFA, int nBand, int nOverviewLevel )
2422 :
2423 : {
2424 6 : if( nBand < 1 || nBand > hHFA->nBands )
2425 0 : return -1;
2426 : else
2427 : {
2428 6 : HFABand *poBand = hHFA->papoBand[nBand-1];
2429 6 : return poBand->CreateOverview( nOverviewLevel );
2430 : }
2431 : }
2432 :
2433 : /************************************************************************/
2434 : /* HFAGetMetadata() */
2435 : /* */
2436 : /* Read metadata structured in a table called GDAL_MetaData. */
2437 : /************************************************************************/
2438 :
2439 792 : char ** HFAGetMetadata( HFAHandle hHFA, int nBand )
2440 :
2441 : {
2442 : HFAEntry *poTable;
2443 :
2444 1273 : if( nBand > 0 && nBand <= hHFA->nBands )
2445 481 : poTable = hHFA->papoBand[nBand - 1]->poNode->GetChild();
2446 311 : else if( nBand == 0 )
2447 311 : poTable = hHFA->poRoot->GetChild();
2448 : else
2449 0 : return NULL;
2450 :
2451 792 : for( ; poTable != NULL && !EQUAL(poTable->GetName(),"GDAL_MetaData");
2452 : poTable = poTable->GetNext() ) {}
2453 :
2454 792 : if( poTable == NULL || !EQUAL(poTable->GetType(),"Edsc_Table") )
2455 722 : return NULL;
2456 :
2457 70 : if( poTable->GetIntField( "numRows" ) != 1 )
2458 : {
2459 : CPLDebug( "HFADataset", "GDAL_MetaData.numRows = %d, expected 1!",
2460 0 : poTable->GetIntField( "numRows" ) );
2461 0 : return NULL;
2462 : }
2463 :
2464 : /* -------------------------------------------------------------------- */
2465 : /* Loop over each column. Each column will be one metadata */
2466 : /* entry, with the title being the key, and the row value being */
2467 : /* the value. There is only ever one row in GDAL_MetaData */
2468 : /* tables. */
2469 : /* -------------------------------------------------------------------- */
2470 : HFAEntry *poColumn;
2471 70 : char **papszMD = NULL;
2472 :
2473 212 : for( poColumn = poTable->GetChild();
2474 : poColumn != NULL;
2475 : poColumn = poColumn->GetNext() )
2476 : {
2477 : const char *pszValue;
2478 : int columnDataPtr;
2479 :
2480 : // Skip the #Bin_Function# entry.
2481 142 : if( EQUALN(poColumn->GetName(),"#",1) )
2482 70 : continue;
2483 :
2484 72 : pszValue = poColumn->GetStringField( "dataType" );
2485 72 : if( pszValue == NULL || !EQUAL(pszValue,"string") )
2486 0 : continue;
2487 :
2488 72 : columnDataPtr = poColumn->GetIntField( "columnDataPtr" );
2489 72 : if( columnDataPtr == 0 )
2490 0 : continue;
2491 :
2492 : /* -------------------------------------------------------------------- */
2493 : /* read up to nMaxNumChars bytes from the indicated location. */
2494 : /* allocate required space temporarily */
2495 : /* nMaxNumChars should have been set by GDAL orginally so we should*/
2496 : /* trust it, but who knows... */
2497 : /* -------------------------------------------------------------------- */
2498 72 : int nMaxNumChars = poColumn->GetIntField( "maxNumChars" );
2499 :
2500 72 : if( nMaxNumChars == 0 )
2501 : {
2502 0 : papszMD = CSLSetNameValue( papszMD, poColumn->GetName(), "" );
2503 : }
2504 : else
2505 : {
2506 72 : char *pszMDValue = (char*) VSIMalloc(nMaxNumChars);
2507 72 : if (pszMDValue == NULL)
2508 : {
2509 : CPLError(CE_Failure, CPLE_OutOfMemory,
2510 0 : "HFAGetMetadata : Out of memory while allocating %d bytes", nMaxNumChars);
2511 0 : continue;
2512 : }
2513 :
2514 72 : if( VSIFSeekL( hHFA->fp, columnDataPtr, SEEK_SET ) != 0 )
2515 0 : continue;
2516 :
2517 72 : int nMDBytes = VSIFReadL( pszMDValue, 1, nMaxNumChars, hHFA->fp );
2518 72 : if( nMDBytes == 0 )
2519 : {
2520 0 : CPLFree( pszMDValue );
2521 0 : continue;
2522 : }
2523 :
2524 72 : pszMDValue[nMaxNumChars-1] = '\0';
2525 :
2526 : papszMD = CSLSetNameValue( papszMD, poColumn->GetName(),
2527 72 : pszMDValue );
2528 72 : CPLFree( pszMDValue );
2529 : }
2530 : }
2531 :
2532 70 : return papszMD;
2533 : }
2534 :
2535 : /************************************************************************/
2536 : /* HFASetGDALMetadata() */
2537 : /* */
2538 : /* This function is used to set metadata in a table called */
2539 : /* GDAL_MetaData. It is called by HFASetMetadata() for all */
2540 : /* metadata items that aren't some specific supported */
2541 : /* information (like histogram or stats info). */
2542 : /************************************************************************/
2543 :
2544 : static CPLErr
2545 44 : HFASetGDALMetadata( HFAHandle hHFA, int nBand, char **papszMD )
2546 :
2547 : {
2548 44 : if( papszMD == NULL )
2549 0 : return CE_None;
2550 :
2551 : HFAEntry *poNode;
2552 :
2553 46 : if( nBand > 0 && nBand <= hHFA->nBands )
2554 2 : poNode = hHFA->papoBand[nBand - 1]->poNode;
2555 42 : else if( nBand == 0 )
2556 42 : poNode = hHFA->poRoot;
2557 : else
2558 0 : return CE_Failure;
2559 :
2560 : /* -------------------------------------------------------------------- */
2561 : /* Create the Descriptor table. */
2562 : /* Check we have no table with this name already */
2563 : /* -------------------------------------------------------------------- */
2564 44 : HFAEntry *poEdsc_Table = poNode->GetNamedChild( "GDAL_MetaData" );
2565 :
2566 44 : if( poEdsc_Table == NULL || !EQUAL(poEdsc_Table->GetType(),"Edsc_Table") )
2567 : poEdsc_Table = new HFAEntry( hHFA, "GDAL_MetaData", "Edsc_Table",
2568 43 : poNode );
2569 :
2570 44 : poEdsc_Table->SetIntField( "numrows", 1 );
2571 :
2572 : /* -------------------------------------------------------------------- */
2573 : /* Create the Binning function node. I am not sure that we */
2574 : /* really need this though. */
2575 : /* Check it doesn't exist already */
2576 : /* -------------------------------------------------------------------- */
2577 : HFAEntry *poEdsc_BinFunction =
2578 44 : poEdsc_Table->GetNamedChild( "#Bin_Function#" );
2579 :
2580 44 : if( poEdsc_BinFunction == NULL
2581 : || !EQUAL(poEdsc_BinFunction->GetType(),"Edsc_BinFunction") )
2582 : poEdsc_BinFunction = new HFAEntry( hHFA, "#Bin_Function#",
2583 43 : "Edsc_BinFunction", poEdsc_Table );
2584 :
2585 : // Because of the BaseData we have to hardcode the size.
2586 44 : poEdsc_BinFunction->MakeData( 30 );
2587 :
2588 44 : poEdsc_BinFunction->SetIntField( "numBins", 1 );
2589 44 : poEdsc_BinFunction->SetStringField( "binFunction", "direct" );
2590 44 : poEdsc_BinFunction->SetDoubleField( "minLimit", 0.0 );
2591 44 : poEdsc_BinFunction->SetDoubleField( "maxLimit", 0.0 );
2592 :
2593 : /* -------------------------------------------------------------------- */
2594 : /* Process each metadata item as a separate column. */
2595 : /* -------------------------------------------------------------------- */
2596 89 : for( int iColumn = 0; papszMD[iColumn] != NULL; iColumn++ )
2597 : {
2598 : HFAEntry *poEdsc_Column;
2599 45 : char *pszKey = NULL;
2600 : const char *pszValue;
2601 :
2602 45 : pszValue = CPLParseNameValue( papszMD[iColumn], &pszKey );
2603 45 : if( pszValue == NULL )
2604 0 : continue;
2605 :
2606 : /* -------------------------------------------------------------------- */
2607 : /* Create the Edsc_Column. */
2608 : /* Check it doesn't exist already */
2609 : /* -------------------------------------------------------------------- */
2610 45 : poEdsc_Column = poEdsc_Table->GetNamedChild(pszKey);
2611 :
2612 45 : if( poEdsc_Column == NULL
2613 : || !EQUAL(poEdsc_Column->GetType(),"Edsc_Column") )
2614 : poEdsc_Column = new HFAEntry( hHFA, pszKey, "Edsc_Column",
2615 44 : poEdsc_Table );
2616 :
2617 45 : poEdsc_Column->SetIntField( "numRows", 1 );
2618 45 : poEdsc_Column->SetStringField( "dataType", "string" );
2619 45 : poEdsc_Column->SetIntField( "maxNumChars", strlen(pszValue)+1 );
2620 :
2621 : /* -------------------------------------------------------------------- */
2622 : /* Write the data out. */
2623 : /* -------------------------------------------------------------------- */
2624 45 : int nOffset = HFAAllocateSpace( hHFA, strlen(pszValue)+1);
2625 :
2626 45 : poEdsc_Column->SetIntField( "columnDataPtr", nOffset );
2627 :
2628 45 : VSIFSeekL( hHFA->fp, nOffset, SEEK_SET );
2629 45 : VSIFWriteL( (void *) pszValue, 1, strlen(pszValue)+1, hHFA->fp );
2630 :
2631 45 : CPLFree( pszKey );
2632 : }
2633 :
2634 44 : return CE_Failure;
2635 : }
2636 :
2637 : /************************************************************************/
2638 : /* HFASetMetadata() */
2639 : /************************************************************************/
2640 :
2641 46 : CPLErr HFASetMetadata( HFAHandle hHFA, int nBand, char **papszMD )
2642 :
2643 : {
2644 46 : char **papszGDALMD = NULL;
2645 :
2646 46 : if( CSLCount(papszMD) == 0 )
2647 0 : return CE_None;
2648 :
2649 : HFAEntry *poNode;
2650 :
2651 50 : if( nBand > 0 && nBand <= hHFA->nBands )
2652 4 : poNode = hHFA->papoBand[nBand - 1]->poNode;
2653 42 : else if( nBand == 0 )
2654 42 : poNode = hHFA->poRoot;
2655 : else
2656 0 : return CE_Failure;
2657 :
2658 : /* -------------------------------------------------------------------- */
2659 : /* Check if the Metadata is an "known" entity which should be */
2660 : /* stored in a better place. */
2661 : /* -------------------------------------------------------------------- */
2662 46 : char * pszBinValues = NULL;
2663 46 : int bCreatedHistogramParameters = FALSE;
2664 46 : int bCreatedStatistics = FALSE;
2665 46 : const char ** pszAuxMetaData = GetHFAAuxMetaDataList();
2666 : // check each metadata item
2667 120 : for( int iColumn = 0; papszMD[iColumn] != NULL; iColumn++ )
2668 : {
2669 74 : char *pszKey = NULL;
2670 : const char *pszValue;
2671 :
2672 74 : pszValue = CPLParseNameValue( papszMD[iColumn], &pszKey );
2673 74 : if( pszValue == NULL )
2674 0 : continue;
2675 :
2676 : // know look if its known
2677 : int i;
2678 853 : for( i = 0; pszAuxMetaData[i] != NULL; i += 4 )
2679 : {
2680 806 : if ( EQUALN( pszAuxMetaData[i + 2], pszKey, strlen(pszKey) ) )
2681 27 : break;
2682 : }
2683 74 : if ( pszAuxMetaData[i] != NULL )
2684 : {
2685 : // found one, get the right entry
2686 : HFAEntry *poEntry;
2687 :
2688 27 : if( strlen(pszAuxMetaData[i]) > 0 )
2689 24 : poEntry = poNode->GetNamedChild( pszAuxMetaData[i] );
2690 : else
2691 3 : poEntry = poNode;
2692 :
2693 27 : if( poEntry == NULL && strlen(pszAuxMetaData[i+3]) > 0 )
2694 : {
2695 : // child does not yet exist --> create it
2696 : poEntry = new HFAEntry( hHFA, pszAuxMetaData[i], pszAuxMetaData[i+3],
2697 4 : poNode );
2698 :
2699 4 : if ( EQUALN( "Statistics", pszAuxMetaData[i], 10 ) )
2700 2 : bCreatedStatistics = TRUE;
2701 :
2702 4 : if( EQUALN( "HistogramParameters", pszAuxMetaData[i], 19 ) )
2703 : {
2704 : // this is a bit nasty I need to set the string field for the object
2705 : // first because the SetStringField sets the count for the object
2706 : // BinFunction to the length of the string
2707 2 : poEntry->MakeData( 70 );
2708 2 : poEntry->SetStringField( "BinFunction.binFunctionType", "linear" );
2709 :
2710 2 : bCreatedHistogramParameters = TRUE;
2711 : }
2712 : }
2713 27 : if ( poEntry == NULL )
2714 : {
2715 6 : CPLFree( pszKey );
2716 6 : continue;
2717 : }
2718 :
2719 21 : const char *pszFieldName = pszAuxMetaData[i+1] + 1;
2720 21 : switch( pszAuxMetaData[i+1][0] )
2721 : {
2722 : case 'd':
2723 : {
2724 16 : double dfValue = atof( pszValue );
2725 16 : poEntry->SetDoubleField( pszFieldName, dfValue );
2726 : }
2727 16 : break;
2728 : case 'i':
2729 : case 'l':
2730 : {
2731 2 : int nValue = atoi( pszValue );
2732 2 : poEntry->SetIntField( pszFieldName, nValue );
2733 : }
2734 2 : break;
2735 : case 's':
2736 : case 'e':
2737 : {
2738 3 : poEntry->SetStringField( pszFieldName, pszValue );
2739 : }
2740 3 : break;
2741 : default:
2742 0 : CPLAssert( FALSE );
2743 : }
2744 : }
2745 47 : else if ( EQUALN( "STATISTICS_HISTOBINVALUES", pszKey, strlen(pszKey) ) )
2746 : {
2747 2 : pszBinValues = strdup( pszValue );
2748 : }
2749 : else
2750 45 : papszGDALMD = CSLAddString( papszGDALMD, papszMD[iColumn] );
2751 :
2752 68 : CPLFree( pszKey );
2753 : }
2754 :
2755 : /* -------------------------------------------------------------------- */
2756 : /* Special case to write out the histogram. */
2757 : /* -------------------------------------------------------------------- */
2758 46 : if ( pszBinValues != NULL )
2759 : {
2760 2 : HFAEntry * poEntry = poNode->GetNamedChild( "HistogramParameters" );
2761 2 : if ( poEntry != NULL && bCreatedHistogramParameters )
2762 : {
2763 : // if this node exists we have added Histogram data -- complete with some defaults
2764 2 : poEntry->SetIntField( "SkipFactorX", 1 );
2765 2 : poEntry->SetIntField( "SkipFactorY", 1 );
2766 :
2767 2 : int nNumBins = poEntry->GetIntField( "BinFunction.numBins" );
2768 2 : double dMinLimit = poEntry->GetDoubleField( "BinFunction.minLimit" );
2769 2 : double dMaxLimit = poEntry->GetDoubleField( "BinFunction.maxLimit" );
2770 :
2771 : // fill the descriptor table - check it isn't there already
2772 2 : poEntry = poNode->GetNamedChild( "Descriptor_Table" );
2773 2 : if( poEntry == NULL || !EQUAL(poEntry->GetType(),"Edsc_Table") )
2774 2 : poEntry = new HFAEntry( hHFA, "Descriptor_Table", "Edsc_Table", poNode );
2775 :
2776 2 : poEntry->SetIntField( "numRows", nNumBins );
2777 :
2778 : // bin function
2779 2 : HFAEntry * poBinFunc = poEntry->GetNamedChild( "#Bin_Function#" );
2780 2 : if( poBinFunc == NULL || !EQUAL(poBinFunc->GetType(),"Edsc_BinFunction") )
2781 2 : poBinFunc = new HFAEntry( hHFA, "#Bin_Function#", "Edsc_BinFunction", poEntry );
2782 :
2783 2 : poBinFunc->MakeData( 30 );
2784 2 : poBinFunc->SetIntField( "numBins", nNumBins );
2785 2 : poBinFunc->SetDoubleField( "minLimit", dMinLimit );
2786 2 : poBinFunc->SetDoubleField( "maxLimit", dMaxLimit );
2787 2 : poBinFunc->SetStringField( "binFunctionType", "linear" ); // we use always a linear
2788 :
2789 : // we need a child named histogram
2790 2 : HFAEntry * poHisto = poEntry->GetNamedChild( "Histogram" );
2791 2 : if( poHisto == NULL || !EQUAL(poHisto->GetType(),"Edsc_Column") )
2792 2 : poHisto = new HFAEntry( hHFA, "Histogram", "Edsc_Column", poEntry );
2793 :
2794 2 : poHisto->SetIntField( "numRows", nNumBins );
2795 : // allocate space for the bin values
2796 2 : GUInt32 nOffset = HFAAllocateSpace( hHFA, nNumBins*4 );
2797 2 : poHisto->SetIntField( "columnDataPtr", nOffset );
2798 2 : poHisto->SetStringField( "dataType", "integer" );
2799 2 : poHisto->SetIntField( "maxNumChars", 0 );
2800 : // write out histogram data
2801 2 : char * pszWork = pszBinValues;
2802 503 : for ( int nBin = 0; nBin < nNumBins; ++nBin )
2803 : {
2804 501 : char * pszEnd = strchr( pszWork, '|' );
2805 501 : if ( pszEnd != NULL )
2806 : {
2807 501 : *pszEnd = 0;
2808 501 : VSIFSeekL( hHFA->fp, nOffset + 4*nBin, SEEK_SET );
2809 501 : int nValue = atoi( pszWork );
2810 : HFAStandard( 4, &nValue );
2811 :
2812 501 : VSIFWriteL( (void *)&nValue, 1, 4, hHFA->fp );
2813 501 : pszWork = pszEnd + 1;
2814 : }
2815 : }
2816 : }
2817 2 : free( pszBinValues );
2818 : }
2819 :
2820 : /* -------------------------------------------------------------------- */
2821 : /* If we created a statistics node then try to create a */
2822 : /* StatisticsParameters node too. */
2823 : /* -------------------------------------------------------------------- */
2824 46 : if( bCreatedStatistics )
2825 : {
2826 : HFAEntry *poEntry =
2827 : new HFAEntry( hHFA, "StatisticsParameters",
2828 2 : "Eimg_StatisticsParameters830", poNode );
2829 :
2830 2 : poEntry->MakeData( 70 );
2831 : //poEntry->SetStringField( "BinFunction.binFunctionType", "linear" );
2832 :
2833 2 : poEntry->SetIntField( "SkipFactorX", 1 );
2834 2 : poEntry->SetIntField( "SkipFactorY", 1 );
2835 : }
2836 :
2837 : /* -------------------------------------------------------------------- */
2838 : /* Write out metadata items without a special place. */
2839 : /* -------------------------------------------------------------------- */
2840 46 : if( CSLCount( papszGDALMD) != 0 )
2841 : {
2842 44 : CPLErr eErr = HFASetGDALMetadata( hHFA, nBand, papszGDALMD );
2843 :
2844 44 : CSLDestroy( papszGDALMD );
2845 44 : return eErr;
2846 : }
2847 : else
2848 2 : return CE_Failure;
2849 : }
2850 :
2851 : /************************************************************************/
2852 : /* HFACreateSpillStack() */
2853 : /* */
2854 : /* Create a new stack of raster layers in the spill (.ige) */
2855 : /* file. Create the spill file if it didn't exist before. */
2856 : /************************************************************************/
2857 :
2858 : int HFACreateSpillStack( HFAInfo_t *psInfo, int nXSize, int nYSize,
2859 : int nLayers, int nBlockSize, int nDataType,
2860 : GIntBig *pnValidFlagsOffset,
2861 7 : GIntBig *pnDataOffset )
2862 :
2863 : {
2864 : /* -------------------------------------------------------------------- */
2865 : /* Form .ige filename. */
2866 : /* -------------------------------------------------------------------- */
2867 : char *pszFullFilename;
2868 :
2869 7 : if (nBlockSize <= 0)
2870 : {
2871 0 : CPLError(CE_Failure, CPLE_IllegalArg, "HFACreateSpillStack : nBlockXSize < 0");
2872 0 : return FALSE;
2873 : }
2874 :
2875 7 : if( psInfo->pszIGEFilename == NULL )
2876 : {
2877 7 : if( EQUAL(CPLGetExtension(psInfo->pszFilename),"rrd") )
2878 : psInfo->pszIGEFilename =
2879 0 : CPLStrdup( CPLResetExtension( psInfo->pszFilename, "rde" ) );
2880 7 : else if( EQUAL(CPLGetExtension(psInfo->pszFilename),"aux") )
2881 : psInfo->pszIGEFilename =
2882 0 : CPLStrdup( CPLResetExtension( psInfo->pszFilename, "axe" ) );
2883 : else
2884 : psInfo->pszIGEFilename =
2885 7 : CPLStrdup( CPLResetExtension( psInfo->pszFilename, "ige" ) );
2886 : }
2887 :
2888 : pszFullFilename =
2889 7 : CPLStrdup( CPLFormFilename( psInfo->pszPath, psInfo->pszIGEFilename, NULL ) );
2890 :
2891 : /* -------------------------------------------------------------------- */
2892 : /* Try and open it. If we fail, create it and write the magic */
2893 : /* header. */
2894 : /* -------------------------------------------------------------------- */
2895 : static const char *pszMagick = "ERDAS_IMG_EXTERNAL_RASTER";
2896 : FILE *fpVSIL;
2897 :
2898 7 : fpVSIL = VSIFOpenL( pszFullFilename, "r+b" );
2899 7 : if( fpVSIL == NULL )
2900 : {
2901 7 : fpVSIL = VSIFOpenL( pszFullFilename, "w+" );
2902 7 : if( fpVSIL == NULL )
2903 : {
2904 : CPLError( CE_Failure, CPLE_OpenFailed,
2905 : "Failed to create spill file %s.\n%s",
2906 0 : psInfo->pszIGEFilename, VSIStrerror( errno ) );
2907 0 : return FALSE;
2908 : }
2909 :
2910 7 : VSIFWriteL( (void *) pszMagick, 1, strlen(pszMagick)+1, fpVSIL );
2911 : }
2912 :
2913 7 : CPLFree( pszFullFilename );
2914 :
2915 : /* -------------------------------------------------------------------- */
2916 : /* Work out some details about the tiling scheme. */
2917 : /* -------------------------------------------------------------------- */
2918 : int nBlocksPerRow, nBlocksPerColumn, nBlocks, nBytesPerBlock;
2919 : int nBytesPerRow, nBlockMapSize, iFlagsSize;
2920 :
2921 7 : nBlocksPerRow = (nXSize + nBlockSize - 1) / nBlockSize;
2922 7 : nBlocksPerColumn = (nYSize + nBlockSize - 1) / nBlockSize;
2923 7 : nBlocks = nBlocksPerRow * nBlocksPerColumn;
2924 : nBytesPerBlock = (nBlockSize * nBlockSize
2925 7 : * HFAGetDataTypeBits(nDataType) + 7) / 8;
2926 :
2927 7 : nBytesPerRow = ( nBlocksPerRow + 7 ) / 8;
2928 7 : nBlockMapSize = nBytesPerRow * nBlocksPerColumn;
2929 7 : iFlagsSize = nBlockMapSize + 20;
2930 :
2931 : /* -------------------------------------------------------------------- */
2932 : /* Write stack prefix information. */
2933 : /* -------------------------------------------------------------------- */
2934 : GByte bUnknown;
2935 : GInt32 nValue32;
2936 :
2937 7 : VSIFSeekL( fpVSIL, 0, SEEK_END );
2938 :
2939 7 : bUnknown = 1;
2940 7 : VSIFWriteL( &bUnknown, 1, 1, fpVSIL );
2941 7 : nValue32 = nLayers;
2942 : HFAStandard( 4, &nValue32 );
2943 7 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2944 7 : nValue32 = nXSize;
2945 : HFAStandard( 4, &nValue32 );
2946 7 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2947 7 : nValue32 = nYSize;
2948 : HFAStandard( 4, &nValue32 );
2949 7 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2950 7 : nValue32 = nBlockSize;
2951 : HFAStandard( 4, &nValue32 );
2952 7 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2953 7 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2954 7 : bUnknown = 3;
2955 7 : VSIFWriteL( &bUnknown, 1, 1, fpVSIL );
2956 7 : bUnknown = 0;
2957 7 : VSIFWriteL( &bUnknown, 1, 1, fpVSIL );
2958 :
2959 : /* -------------------------------------------------------------------- */
2960 : /* Write out ValidFlags section(s). */
2961 : /* -------------------------------------------------------------------- */
2962 : unsigned char *pabyBlockMap;
2963 : int iBand;
2964 :
2965 7 : *pnValidFlagsOffset = VSIFTellL( fpVSIL );
2966 :
2967 7 : pabyBlockMap = (unsigned char *) VSIMalloc( nBlockMapSize );
2968 7 : if (pabyBlockMap == NULL)
2969 : {
2970 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "HFACreateSpillStack : Out of memory");
2971 0 : VSIFCloseL( fpVSIL );
2972 0 : return FALSE;
2973 : }
2974 :
2975 7 : memset( pabyBlockMap, 0xff, nBlockMapSize );
2976 20 : for ( iBand = 0; iBand < nLayers; iBand++ )
2977 : {
2978 : int i, iRemainder;
2979 :
2980 13 : nValue32 = 1; // Unknown
2981 : HFAStandard( 4, &nValue32 );
2982 13 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2983 13 : nValue32 = 0; // Unknown
2984 13 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2985 13 : nValue32 = nBlocksPerColumn;
2986 : HFAStandard( 4, &nValue32 );
2987 13 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2988 13 : nValue32 = nBlocksPerRow;
2989 : HFAStandard( 4, &nValue32 );
2990 13 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2991 13 : nValue32 = 0x30000; // Unknown
2992 : HFAStandard( 4, &nValue32 );
2993 13 : VSIFWriteL( &nValue32, 4, 1, fpVSIL );
2994 :
2995 13 : iRemainder = nBlocksPerRow % 8;
2996 : CPLDebug( "HFACreate",
2997 : "Block map size %d, bytes per row %d, remainder %d.",
2998 13 : nBlockMapSize, nBytesPerRow, iRemainder );
2999 13 : if ( iRemainder )
3000 : {
3001 26 : for ( i = nBytesPerRow - 1; i < nBlockMapSize; i+=nBytesPerRow )
3002 13 : pabyBlockMap[i] = (GByte) ((1<<iRemainder) - 1);
3003 : }
3004 :
3005 13 : VSIFWriteL( pabyBlockMap, 1, nBlockMapSize, fpVSIL );
3006 : }
3007 7 : CPLFree(pabyBlockMap);
3008 7 : pabyBlockMap = NULL;
3009 :
3010 : /* -------------------------------------------------------------------- */
3011 : /* Extend the file to account for all the imagery space. */
3012 : /* -------------------------------------------------------------------- */
3013 : GIntBig nTileDataSize = ((GIntBig) nBytesPerBlock)
3014 7 : * nBlocksPerRow * nBlocksPerColumn * nLayers;
3015 :
3016 7 : *pnDataOffset = VSIFTellL( fpVSIL );
3017 :
3018 7 : if( VSIFSeekL( fpVSIL, nTileDataSize - 1 + *pnDataOffset, SEEK_SET ) != 0
3019 : || VSIFWriteL( (void *) "", 1, 1, fpVSIL ) != 1 )
3020 : {
3021 : CPLError( CE_Failure, CPLE_FileIO,
3022 : "Failed to extend %s to full size (%g bytes),\n"
3023 : "likely out of disk space.\n%s",
3024 : psInfo->pszIGEFilename,
3025 : (double) nTileDataSize - 1 + *pnDataOffset,
3026 0 : VSIStrerror( errno ) );
3027 :
3028 0 : VSIFCloseL( fpVSIL );
3029 0 : return FALSE;
3030 : }
3031 :
3032 7 : VSIFCloseL( fpVSIL );
3033 :
3034 7 : return TRUE;
3035 : }
3036 :
3037 : /************************************************************************/
3038 : /* HFAReadAndValidatePoly() */
3039 : /************************************************************************/
3040 :
3041 : static int HFAReadAndValidatePoly( HFAEntry *poTarget,
3042 : const char *pszName,
3043 3 : Efga_Polynomial *psRetPoly )
3044 :
3045 : {
3046 3 : CPLString osFldName;
3047 :
3048 3 : memset( psRetPoly, 0, sizeof(Efga_Polynomial) );
3049 :
3050 3 : osFldName.Printf( "%sorder", pszName );
3051 3 : psRetPoly->order = poTarget->GetIntField(osFldName);
3052 :
3053 3 : if( psRetPoly->order < 1 || psRetPoly->order > 3 )
3054 0 : return FALSE;
3055 :
3056 : /* -------------------------------------------------------------------- */
3057 : /* Validate that things are in a "well known" form. */
3058 : /* -------------------------------------------------------------------- */
3059 : int numdimtransform, numdimpolynomial, termcount;
3060 :
3061 3 : osFldName.Printf( "%snumdimtransform", pszName );
3062 3 : numdimtransform = poTarget->GetIntField(osFldName);
3063 :
3064 3 : osFldName.Printf( "%snumdimpolynomial", pszName );
3065 3 : numdimpolynomial = poTarget->GetIntField(osFldName);
3066 :
3067 3 : osFldName.Printf( "%stermcount", pszName );
3068 3 : termcount = poTarget->GetIntField(osFldName);
3069 :
3070 3 : if( numdimtransform != 2 || numdimpolynomial != 2 )
3071 0 : return FALSE;
3072 :
3073 3 : if( (psRetPoly->order == 1 && termcount != 3)
3074 : || (psRetPoly->order == 2 && termcount != 6)
3075 : || (psRetPoly->order == 3 && termcount != 10) )
3076 0 : return FALSE;
3077 :
3078 : // we don't check the exponent organization for now. Hopefully
3079 : // it is always standard.
3080 :
3081 : /* -------------------------------------------------------------------- */
3082 : /* Get coefficients. */
3083 : /* -------------------------------------------------------------------- */
3084 : int i;
3085 :
3086 43 : for( i = 0; i < termcount*2 - 2; i++ )
3087 : {
3088 40 : osFldName.Printf( "%spolycoefmtx[%d]", pszName, i );
3089 40 : psRetPoly->polycoefmtx[i] = poTarget->GetDoubleField(osFldName);
3090 : }
3091 :
3092 9 : for( i = 0; i < 2; i++ )
3093 : {
3094 6 : osFldName.Printf( "%spolycoefvector[%d]", pszName, i );
3095 6 : psRetPoly->polycoefvector[i] = poTarget->GetDoubleField(osFldName);
3096 : }
3097 :
3098 3 : return TRUE;
3099 : }
3100 :
3101 : /************************************************************************/
3102 : /* HFAReadXFormStack() */
3103 : /************************************************************************/
3104 :
3105 :
3106 : int HFAReadXFormStack( HFAHandle hHFA,
3107 : Efga_Polynomial **ppasPolyListForward,
3108 185 : Efga_Polynomial **ppasPolyListReverse )
3109 :
3110 : {
3111 185 : if( hHFA->nBands == 0 )
3112 0 : return 0;
3113 :
3114 : /* -------------------------------------------------------------------- */
3115 : /* Get the HFA node. */
3116 : /* -------------------------------------------------------------------- */
3117 : HFAEntry *poXFormHeader;
3118 :
3119 185 : poXFormHeader = hHFA->papoBand[0]->poNode->GetNamedChild( "MapToPixelXForm" );
3120 185 : if( poXFormHeader == NULL )
3121 183 : return 0;
3122 :
3123 : /* -------------------------------------------------------------------- */
3124 : /* Loop over children, collecting XForms. */
3125 : /* -------------------------------------------------------------------- */
3126 : HFAEntry *poXForm;
3127 2 : int nStepCount = 0;
3128 2 : *ppasPolyListForward = NULL;
3129 2 : *ppasPolyListReverse = NULL;
3130 :
3131 5 : for( poXForm = poXFormHeader->GetChild();
3132 : poXForm != NULL;
3133 : poXForm = poXForm->GetNext() )
3134 : {
3135 3 : int bSuccess = FALSE;
3136 : Efga_Polynomial sForward, sReverse;
3137 :
3138 3 : if( EQUAL(poXForm->GetType(),"Efga_Polynomial") )
3139 : {
3140 : bSuccess =
3141 1 : HFAReadAndValidatePoly( poXForm, "", &sForward );
3142 :
3143 1 : if( bSuccess )
3144 : {
3145 : double adfGT[6], adfInvGT[6];
3146 :
3147 1 : adfGT[0] = sForward.polycoefvector[0];
3148 1 : adfGT[1] = sForward.polycoefmtx[0];
3149 1 : adfGT[2] = sForward.polycoefmtx[2];
3150 1 : adfGT[3] = sForward.polycoefvector[1];
3151 1 : adfGT[4] = sForward.polycoefmtx[1];
3152 1 : adfGT[5] = sForward.polycoefmtx[3];
3153 :
3154 1 : bSuccess = HFAInvGeoTransform( adfGT, adfInvGT );
3155 :
3156 1 : memset( &sReverse, 0, sizeof(sReverse) );
3157 :
3158 1 : sReverse.order = sForward.order;
3159 1 : sReverse.polycoefvector[0] = adfInvGT[0];
3160 1 : sReverse.polycoefmtx[0] = adfInvGT[1];
3161 1 : sReverse.polycoefmtx[2] = adfInvGT[2];
3162 1 : sReverse.polycoefvector[1] = adfInvGT[3];
3163 1 : sReverse.polycoefmtx[1] = adfInvGT[4];
3164 1 : sReverse.polycoefmtx[3] = adfInvGT[5];
3165 : }
3166 : }
3167 2 : else if( EQUAL(poXForm->GetType(),"GM_PolyPair") )
3168 : {
3169 : bSuccess =
3170 1 : HFAReadAndValidatePoly( poXForm, "forward.", &sForward );
3171 : bSuccess = bSuccess &&
3172 1 : HFAReadAndValidatePoly( poXForm, "reverse.", &sReverse );
3173 : }
3174 :
3175 3 : if( bSuccess )
3176 : {
3177 2 : nStepCount++;
3178 : *ppasPolyListForward = (Efga_Polynomial *)
3179 : CPLRealloc( *ppasPolyListForward,
3180 2 : sizeof(Efga_Polynomial) * nStepCount);
3181 : memcpy( *ppasPolyListForward + nStepCount - 1,
3182 2 : &sForward, sizeof(sForward) );
3183 :
3184 : *ppasPolyListReverse = (Efga_Polynomial *)
3185 : CPLRealloc( *ppasPolyListReverse,
3186 2 : sizeof(Efga_Polynomial) * nStepCount);
3187 : memcpy( *ppasPolyListReverse + nStepCount - 1,
3188 2 : &sReverse, sizeof(sReverse) );
3189 : }
3190 : }
3191 :
3192 2 : return nStepCount;
3193 : }
3194 :
3195 : /************************************************************************/
3196 : /* HFAEvaluateXFormStack() */
3197 : /************************************************************************/
3198 :
3199 : int HFAEvaluateXFormStack( int nStepCount, int bForward,
3200 : Efga_Polynomial *pasPolyList,
3201 36 : double *pdfX, double *pdfY )
3202 :
3203 : {
3204 : int iStep;
3205 :
3206 108 : for( iStep = 0; iStep < nStepCount; iStep++ )
3207 : {
3208 : double dfXOut, dfYOut;
3209 : Efga_Polynomial *psStep;
3210 :
3211 72 : if( bForward )
3212 0 : psStep = pasPolyList + iStep;
3213 : else
3214 72 : psStep = pasPolyList + nStepCount - iStep - 1;
3215 :
3216 72 : if( psStep->order == 1 )
3217 : {
3218 : dfXOut = psStep->polycoefvector[0]
3219 : + psStep->polycoefmtx[0] * *pdfX
3220 36 : + psStep->polycoefmtx[2] * *pdfY;
3221 :
3222 : dfYOut = psStep->polycoefvector[1]
3223 : + psStep->polycoefmtx[1] * *pdfX
3224 36 : + psStep->polycoefmtx[3] * *pdfY;
3225 :
3226 36 : *pdfX = dfXOut;
3227 36 : *pdfY = dfYOut;
3228 : }
3229 36 : else if( psStep->order == 2 )
3230 : {
3231 : dfXOut = psStep->polycoefvector[0]
3232 : + psStep->polycoefmtx[0] * *pdfX
3233 : + psStep->polycoefmtx[2] * *pdfY
3234 : + psStep->polycoefmtx[4] * *pdfX * *pdfX
3235 : + psStep->polycoefmtx[6] * *pdfX * *pdfY
3236 0 : + psStep->polycoefmtx[8] * *pdfY * *pdfY;
3237 : dfYOut = psStep->polycoefvector[1]
3238 : + psStep->polycoefmtx[1] * *pdfX
3239 : + psStep->polycoefmtx[3] * *pdfY
3240 : + psStep->polycoefmtx[5] * *pdfX * *pdfX
3241 : + psStep->polycoefmtx[7] * *pdfX * *pdfY
3242 0 : + psStep->polycoefmtx[9] * *pdfY * *pdfY;
3243 :
3244 0 : *pdfX = dfXOut;
3245 0 : *pdfY = dfYOut;
3246 : }
3247 36 : else if( psStep->order == 3 )
3248 : {
3249 : dfXOut = psStep->polycoefvector[0]
3250 : + psStep->polycoefmtx[ 0] * *pdfX
3251 : + psStep->polycoefmtx[ 2] * *pdfY
3252 : + psStep->polycoefmtx[ 4] * *pdfX * *pdfX
3253 : + psStep->polycoefmtx[ 6] * *pdfX * *pdfY
3254 : + psStep->polycoefmtx[ 8] * *pdfY * *pdfY
3255 : + psStep->polycoefmtx[10] * *pdfX * *pdfX * *pdfX
3256 : + psStep->polycoefmtx[12] * *pdfX * *pdfX * *pdfY
3257 : + psStep->polycoefmtx[14] * *pdfX * *pdfY * *pdfY
3258 36 : + psStep->polycoefmtx[16] * *pdfY * *pdfY * *pdfY;
3259 : dfYOut = psStep->polycoefvector[1]
3260 : + psStep->polycoefmtx[ 1] * *pdfX
3261 : + psStep->polycoefmtx[ 3] * *pdfY
3262 : + psStep->polycoefmtx[ 5] * *pdfX * *pdfX
3263 : + psStep->polycoefmtx[ 7] * *pdfX * *pdfY
3264 : + psStep->polycoefmtx[ 9] * *pdfY * *pdfY
3265 : + psStep->polycoefmtx[11] * *pdfX * *pdfX * *pdfX
3266 : + psStep->polycoefmtx[13] * *pdfX * *pdfX * *pdfY
3267 : + psStep->polycoefmtx[15] * *pdfX * *pdfY * *pdfY
3268 36 : + psStep->polycoefmtx[17] * *pdfY * *pdfY * *pdfY;
3269 :
3270 36 : *pdfX = dfXOut;
3271 36 : *pdfY = dfYOut;
3272 : }
3273 : else
3274 0 : return FALSE;
3275 : }
3276 :
3277 36 : return TRUE;
3278 : }
3279 :
3280 : /************************************************************************/
3281 : /* HFAWriteXFormStack() */
3282 : /************************************************************************/
3283 :
3284 : CPLErr HFAWriteXFormStack( HFAHandle hHFA, int nBand, int nXFormCount,
3285 : Efga_Polynomial **ppasPolyListForward,
3286 2 : Efga_Polynomial **ppasPolyListReverse )
3287 :
3288 : {
3289 2 : if( nXFormCount == 0 )
3290 0 : return CE_None;
3291 :
3292 2 : if( ppasPolyListForward[0]->order != 1 )
3293 : {
3294 : CPLError( CE_Failure, CPLE_AppDefined,
3295 0 : "For now HFAWriteXFormStack() only supports order 1 polynomials" );
3296 0 : return CE_Failure;
3297 : }
3298 :
3299 2 : if( nBand < 0 || nBand > hHFA->nBands )
3300 0 : return CE_Failure;
3301 :
3302 : /* -------------------------------------------------------------------- */
3303 : /* If no band number is provided, operate on all bands. */
3304 : /* -------------------------------------------------------------------- */
3305 2 : if( nBand == 0 )
3306 : {
3307 1 : CPLErr eErr = CE_None;
3308 :
3309 2 : for( nBand = 1; nBand <= hHFA->nBands; nBand++ )
3310 : {
3311 : eErr = HFAWriteXFormStack( hHFA, nBand, nXFormCount,
3312 : ppasPolyListForward,
3313 1 : ppasPolyListReverse );
3314 1 : if( eErr != CE_None )
3315 0 : return eErr;
3316 : }
3317 :
3318 1 : return eErr;
3319 : }
3320 :
3321 : /* -------------------------------------------------------------------- */
3322 : /* Fetch our band node. */
3323 : /* -------------------------------------------------------------------- */
3324 1 : HFAEntry *poBandNode = hHFA->papoBand[nBand-1]->poNode;
3325 : HFAEntry *poXFormHeader;
3326 :
3327 1 : poXFormHeader = poBandNode->GetNamedChild( "MapToPixelXForm" );
3328 1 : if( poXFormHeader == NULL )
3329 : {
3330 : poXFormHeader = new HFAEntry( hHFA, "MapToPixelXForm",
3331 1 : "Exfr_GenericXFormHeader", poBandNode );
3332 1 : poXFormHeader->MakeData( 23 );
3333 1 : poXFormHeader->SetPosition();
3334 1 : poXFormHeader->SetStringField( "titleList.string", "Affine" );
3335 : }
3336 :
3337 : /* -------------------------------------------------------------------- */
3338 : /* Loop over XForms. */
3339 : /* -------------------------------------------------------------------- */
3340 2 : for( int iXForm = 0; iXForm < nXFormCount; iXForm++ )
3341 : {
3342 1 : Efga_Polynomial *psForward = *ppasPolyListForward + iXForm;
3343 1 : CPLString osXFormName;
3344 1 : osXFormName.Printf( "XForm%d", iXForm );
3345 :
3346 1 : HFAEntry *poXForm = poXFormHeader->GetNamedChild( osXFormName );
3347 :
3348 1 : if( poXForm == NULL )
3349 : {
3350 : poXForm = new HFAEntry( hHFA, osXFormName, "Efga_Polynomial",
3351 1 : poXFormHeader );
3352 1 : poXForm->MakeData( 136 );
3353 1 : poXForm->SetPosition();
3354 : }
3355 :
3356 1 : poXForm->SetIntField( "order", 1 );
3357 1 : poXForm->SetIntField( "numdimtransform", 2 );
3358 1 : poXForm->SetIntField( "numdimpolynomial", 2 );
3359 1 : poXForm->SetIntField( "termcount", 3 );
3360 1 : poXForm->SetIntField( "exponentlist[0]", 0 );
3361 1 : poXForm->SetIntField( "exponentlist[1]", 0 );
3362 1 : poXForm->SetIntField( "exponentlist[2]", 1 );
3363 1 : poXForm->SetIntField( "exponentlist[3]", 0 );
3364 1 : poXForm->SetIntField( "exponentlist[4]", 0 );
3365 1 : poXForm->SetIntField( "exponentlist[5]", 1 );
3366 :
3367 1 : poXForm->SetIntField( "polycoefmtx[-3]", EPT_f64 );
3368 1 : poXForm->SetIntField( "polycoefmtx[-2]", 2 );
3369 1 : poXForm->SetIntField( "polycoefmtx[-1]", 2 );
3370 : poXForm->SetDoubleField( "polycoefmtx[0]",
3371 1 : psForward->polycoefmtx[0] );
3372 : poXForm->SetDoubleField( "polycoefmtx[1]",
3373 1 : psForward->polycoefmtx[1] );
3374 : poXForm->SetDoubleField( "polycoefmtx[2]",
3375 1 : psForward->polycoefmtx[2] );
3376 : poXForm->SetDoubleField( "polycoefmtx[3]",
3377 1 : psForward->polycoefmtx[3] );
3378 :
3379 1 : poXForm->SetIntField( "polycoefvector[-3]", EPT_f64 );
3380 1 : poXForm->SetIntField( "polycoefvector[-2]", 1 );
3381 1 : poXForm->SetIntField( "polycoefvector[-1]", 2 );
3382 : poXForm->SetDoubleField( "polycoefvector[0]",
3383 1 : psForward->polycoefvector[0] );
3384 : poXForm->SetDoubleField( "polycoefvector[1]",
3385 1 : psForward->polycoefvector[1] );
3386 : }
3387 :
3388 1 : return CE_None;
3389 : }
3390 :
3391 : /************************************************************************/
3392 : /* HFAReadCameraModel() */
3393 : /************************************************************************/
3394 :
3395 311 : char **HFAReadCameraModel( HFAHandle hHFA )
3396 :
3397 : {
3398 311 : if( hHFA->nBands == 0 )
3399 0 : return NULL;
3400 :
3401 : /* -------------------------------------------------------------------- */
3402 : /* Get the camera model node, and confirm it's type. */
3403 : /* -------------------------------------------------------------------- */
3404 : HFAEntry *poXForm;
3405 :
3406 : poXForm =
3407 311 : hHFA->papoBand[0]->poNode->GetNamedChild( "MapToPixelXForm.XForm0" );
3408 311 : if( poXForm == NULL )
3409 305 : return NULL;
3410 :
3411 6 : if( !EQUAL(poXForm->GetType(),"Camera_ModelX") )
3412 5 : return NULL;
3413 :
3414 : /* -------------------------------------------------------------------- */
3415 : /* Convert the values to metadata. */
3416 : /* -------------------------------------------------------------------- */
3417 : const char *pszValue;
3418 : int i;
3419 1 : char **papszMD = NULL;
3420 : static const char *apszFields[] = {
3421 : "direction", "refType", "demsource", "PhotoDirection", "RotationSystem",
3422 : "demfilename", "demzunits",
3423 : "forSrcAffine[0]", "forSrcAffine[1]", "forSrcAffine[2]",
3424 : "forSrcAffine[3]", "forSrcAffine[4]", "forSrcAffine[5]",
3425 : "forDstAffine[0]", "forDstAffine[1]", "forDstAffine[2]",
3426 : "forDstAffine[3]", "forDstAffine[4]", "forDstAffine[5]",
3427 : "invSrcAffine[0]", "invSrcAffine[1]", "invSrcAffine[2]",
3428 : "invSrcAffine[3]", "invSrcAffine[4]", "invSrcAffine[5]",
3429 : "invDstAffine[0]", "invDstAffine[1]", "invDstAffine[2]",
3430 : "invDstAffine[3]", "invDstAffine[4]", "invDstAffine[5]",
3431 : "z_mean", "lat0", "lon0",
3432 : "coeffs[0]", "coeffs[1]", "coeffs[2]",
3433 : "coeffs[3]", "coeffs[4]", "coeffs[5]",
3434 : "coeffs[6]", "coeffs[7]", "coeffs[8]",
3435 : "LensDistortion[0]", "LensDistortion[1]", "LensDistortion[2]",
3436 : NULL };
3437 :
3438 47 : for( i = 0; apszFields[i] != NULL; i++ )
3439 : {
3440 46 : pszValue = poXForm->GetStringField( apszFields[i] );
3441 46 : if( pszValue == NULL )
3442 1 : pszValue = "";
3443 :
3444 46 : papszMD = CSLSetNameValue( papszMD, apszFields[i], pszValue );
3445 : }
3446 :
3447 : /* -------------------------------------------------------------------- */
3448 : /* Create a pseudo-entry for the MIFObject with the */
3449 : /* outputProjection. */
3450 : /* -------------------------------------------------------------------- */
3451 1 : HFAEntry *poProjInfo = HFAEntry::BuildEntryFromMIFObject( poXForm, "outputProjection" );
3452 1 : if (poProjInfo)
3453 : {
3454 : /* -------------------------------------------------------------------- */
3455 : /* Fetch the datum. */
3456 : /* -------------------------------------------------------------------- */
3457 : Eprj_Datum sDatum;
3458 :
3459 1 : memset( &sDatum, 0, sizeof(sDatum));
3460 :
3461 : sDatum.datumname =
3462 1 : (char *) poProjInfo->GetStringField("earthModel.datum.datumname");
3463 : sDatum.type = (Eprj_DatumType) poProjInfo->GetIntField(
3464 1 : "earthModel.datum.type");
3465 :
3466 8 : for( i = 0; i < 7; i++ )
3467 : {
3468 : char szFieldName[60];
3469 :
3470 7 : sprintf( szFieldName, "earthModel.datum.params[%d]", i );
3471 7 : sDatum.params[i] = poProjInfo->GetDoubleField(szFieldName);
3472 : }
3473 :
3474 : sDatum.gridname = (char *)
3475 1 : poProjInfo->GetStringField("earthModel.datum.gridname");
3476 :
3477 : /* -------------------------------------------------------------------- */
3478 : /* Fetch the projection parameters. */
3479 : /* -------------------------------------------------------------------- */
3480 : Eprj_ProParameters sPro;
3481 :
3482 1 : memset( &sPro, 0, sizeof(sPro) );
3483 :
3484 1 : sPro.proType = (Eprj_ProType) poProjInfo->GetIntField("projectionObject.proType");
3485 1 : sPro.proNumber = poProjInfo->GetIntField("projectionObject.proNumber");
3486 1 : sPro.proExeName = (char *) poProjInfo->GetStringField("projectionObject.proExeName");
3487 1 : sPro.proName = (char *) poProjInfo->GetStringField("projectionObject.proName");
3488 1 : sPro.proZone = poProjInfo->GetIntField("projectionObject.proZone");
3489 :
3490 16 : for( i = 0; i < 15; i++ )
3491 : {
3492 : char szFieldName[40];
3493 :
3494 15 : sprintf( szFieldName, "projectionObject.proParams[%d]", i );
3495 15 : sPro.proParams[i] = poProjInfo->GetDoubleField(szFieldName);
3496 : }
3497 :
3498 : /* -------------------------------------------------------------------- */
3499 : /* Fetch the spheroid. */
3500 : /* -------------------------------------------------------------------- */
3501 : sPro.proSpheroid.sphereName = (char *)
3502 1 : poProjInfo->GetStringField("earthModel.proSpheroid.sphereName");
3503 1 : sPro.proSpheroid.a = poProjInfo->GetDoubleField("earthModel.proSpheroid.a");
3504 1 : sPro.proSpheroid.b = poProjInfo->GetDoubleField("earthModel.proSpheroid.b");
3505 : sPro.proSpheroid.eSquared =
3506 1 : poProjInfo->GetDoubleField("earthModel.proSpheroid.eSquared");
3507 : sPro.proSpheroid.radius =
3508 1 : poProjInfo->GetDoubleField("earthModel.proSpheroid.radius");
3509 :
3510 : /* -------------------------------------------------------------------- */
3511 : /* Fetch the projection info. */
3512 : /* -------------------------------------------------------------------- */
3513 : char *pszProjection;
3514 :
3515 : // poProjInfo->DumpFieldValues( stdout, "" );
3516 :
3517 1 : pszProjection = HFAPCSStructToWKT( &sDatum, &sPro, NULL, NULL );
3518 :
3519 1 : if( pszProjection )
3520 : {
3521 : papszMD =
3522 1 : CSLSetNameValue( papszMD, "outputProjection", pszProjection );
3523 1 : CPLFree( pszProjection );
3524 : }
3525 :
3526 1 : delete poProjInfo;
3527 : }
3528 :
3529 : /* -------------------------------------------------------------------- */
3530 : /* Fetch the horizontal units. */
3531 : /* -------------------------------------------------------------------- */
3532 1 : pszValue = poXForm->GetStringField( "outputHorizontalUnits.string" );
3533 1 : if( pszValue == NULL )
3534 0 : pszValue = "";
3535 :
3536 1 : papszMD = CSLSetNameValue( papszMD, "outputHorizontalUnits", pszValue );
3537 :
3538 : /* -------------------------------------------------------------------- */
3539 : /* Fetch the elevationinfo. */
3540 : /* -------------------------------------------------------------------- */
3541 1 : HFAEntry *poElevInfo = HFAEntry::BuildEntryFromMIFObject( poXForm, "outputElevationInfo" );
3542 1 : if ( poElevInfo )
3543 : {
3544 : //poElevInfo->DumpFieldValues( stdout, "" );
3545 :
3546 1 : if( poElevInfo->GetDataSize() != 0 )
3547 : {
3548 : static const char *apszEFields[] = {
3549 : "verticalDatum.datumname",
3550 : "verticalDatum.type",
3551 : "elevationUnit",
3552 : "elevationType",
3553 : NULL };
3554 :
3555 5 : for( i = 0; apszEFields[i] != NULL; i++ )
3556 : {
3557 4 : pszValue = poElevInfo->GetStringField( apszEFields[i] );
3558 4 : if( pszValue == NULL )
3559 0 : pszValue = "";
3560 :
3561 4 : papszMD = CSLSetNameValue( papszMD, apszEFields[i], pszValue );
3562 : }
3563 : }
3564 :
3565 1 : delete poElevInfo;
3566 : }
3567 :
3568 1 : return papszMD;
3569 : }
3570 :
3571 : /************************************************************************/
3572 : /* HFASetGeoTransform() */
3573 : /* */
3574 : /* Set a MapInformation and XForm block. Allows for rotated */
3575 : /* and shared geotransforms. */
3576 : /************************************************************************/
3577 :
3578 : CPLErr HFASetGeoTransform( HFAHandle hHFA,
3579 : const char *pszProName,
3580 : const char *pszUnits,
3581 1 : double *padfGeoTransform )
3582 :
3583 : {
3584 : /* -------------------------------------------------------------------- */
3585 : /* Write MapInformation. */
3586 : /* -------------------------------------------------------------------- */
3587 : int nBand;
3588 :
3589 2 : for( nBand = 1; nBand <= hHFA->nBands; nBand++ )
3590 : {
3591 1 : HFAEntry *poBandNode = hHFA->papoBand[nBand-1]->poNode;
3592 :
3593 1 : HFAEntry *poMI = poBandNode->GetNamedChild( "MapInformation" );
3594 1 : if( poMI == NULL )
3595 : {
3596 : poMI = new HFAEntry( hHFA, "MapInformation",
3597 1 : "Eimg_MapInformation", poBandNode );
3598 1 : poMI->MakeData( 18 + strlen(pszProName) + strlen(pszUnits) );
3599 1 : poMI->SetPosition();
3600 : }
3601 :
3602 1 : poMI->SetStringField( "projection.string", pszProName );
3603 1 : poMI->SetStringField( "units.string", pszUnits );
3604 : }
3605 :
3606 : /* -------------------------------------------------------------------- */
3607 : /* Write XForm. */
3608 : /* -------------------------------------------------------------------- */
3609 : Efga_Polynomial sForward, sReverse;
3610 : double adfAdjTransform[6], adfRevTransform[6];
3611 :
3612 : // Offset by half pixel.
3613 :
3614 1 : memcpy( adfAdjTransform, padfGeoTransform, sizeof(double) * 6 );
3615 1 : adfAdjTransform[0] += adfAdjTransform[1] * 0.5;
3616 1 : adfAdjTransform[0] += adfAdjTransform[2] * 0.5;
3617 1 : adfAdjTransform[3] += adfAdjTransform[4] * 0.5;
3618 1 : adfAdjTransform[3] += adfAdjTransform[5] * 0.5;
3619 :
3620 : // Invert
3621 1 : HFAInvGeoTransform( adfAdjTransform, adfRevTransform );
3622 :
3623 : // Assign to polynomial object.
3624 :
3625 1 : sForward.order = 1;
3626 1 : sForward.polycoefvector[0] = adfRevTransform[0];
3627 1 : sForward.polycoefmtx[0] = adfRevTransform[1];
3628 1 : sForward.polycoefmtx[1] = adfRevTransform[4];
3629 1 : sForward.polycoefvector[1] = adfRevTransform[3];
3630 1 : sForward.polycoefmtx[2] = adfRevTransform[2];
3631 1 : sForward.polycoefmtx[3] = adfRevTransform[5];
3632 :
3633 1 : sReverse = sForward;
3634 1 : Efga_Polynomial *psForward=&sForward, *psReverse=&sReverse;
3635 :
3636 1 : return HFAWriteXFormStack( hHFA, 0, 1, &psForward, &psReverse );
3637 : }
|