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