1 : /******************************************************************************
2 : * $Id: gdal_rpcimdio.cpp 19883 2010-06-17 21:26:06Z rouault $
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Functions for reading RPC and IMD formats, and normalizing.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) HER MAJESTY THE QUEEN IN RIGHT OF CANADA (2008)
10 : * as represented by the Canadian Nuclear Safety Commission
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 : #include "gdal.h"
32 : #include "cpl_string.h"
33 : #include "cplkeywordparser.h"
34 :
35 : CPL_CVSID("$Id: gdal_rpcimdio.cpp 19883 2010-06-17 21:26:06Z rouault $");
36 :
37 : /************************************************************************/
38 : /* GDALLoadRPBFile() */
39 : /************************************************************************/
40 :
41 : static const char *apszRPBMap[] = {
42 : "LINE_OFF", "IMAGE.lineOffset",
43 : "SAMP_OFF", "IMAGE.sampOffset",
44 : "LAT_OFF", "IMAGE.latOffset",
45 : "LONG_OFF", "IMAGE.longOffset",
46 : "HEIGHT_OFF", "IMAGE.heightOffset",
47 : "LINE_SCALE", "IMAGE.lineScale",
48 : "SAMP_SCALE", "IMAGE.sampScale",
49 : "LAT_SCALE", "IMAGE.latScale",
50 : "LONG_SCALE", "IMAGE.longScale",
51 : "HEIGHT_SCALE", "IMAGE.heightScale",
52 : "LINE_NUM_COEFF", "IMAGE.lineNumCoef",
53 : "LINE_DEN_COEFF", "IMAGE.lineDenCoef",
54 : "SAMP_NUM_COEFF", "IMAGE.sampNumCoef",
55 : "SAMP_DEN_COEFF", "IMAGE.sampDenCoef",
56 : NULL, NULL };
57 :
58 : char **CPL_STDCALL GDALLoadRPBFile( const char *pszFilename,
59 4 : char **papszSiblingFiles )
60 :
61 : {
62 : /* -------------------------------------------------------------------- */
63 : /* Try to identify the RPB file in upper or lower case. */
64 : /* -------------------------------------------------------------------- */
65 4 : CPLString osTarget = CPLResetExtension( pszFilename, "RPB" );
66 :
67 : /* Is this already a RPB file ? */
68 4 : if (EQUAL(CPLGetExtension(pszFilename), "RPB"))
69 3 : osTarget = pszFilename;
70 1 : else if( papszSiblingFiles == NULL )
71 : {
72 : VSIStatBufL sStatBuf;
73 :
74 0 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
75 : {
76 0 : osTarget = CPLResetExtension( pszFilename, "rpb" );
77 :
78 0 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
79 0 : return NULL;
80 : }
81 : }
82 : else
83 : {
84 : int iSibling = CSLFindString( papszSiblingFiles,
85 1 : CPLGetFilename(osTarget) );
86 1 : if( iSibling < 0 )
87 1 : return NULL;
88 :
89 0 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
90 0 : osTarget += papszSiblingFiles[iSibling];
91 : }
92 :
93 : /* -------------------------------------------------------------------- */
94 : /* Read file and parse. */
95 : /* -------------------------------------------------------------------- */
96 3 : CPLKeywordParser oParser;
97 :
98 3 : FILE *fp = VSIFOpenL( osTarget, "r" );
99 :
100 3 : if( fp == NULL )
101 0 : return NULL;
102 :
103 3 : if( !oParser.Ingest( fp ) )
104 : {
105 0 : VSIFCloseL( fp );
106 0 : return NULL;
107 : }
108 :
109 3 : VSIFCloseL( fp );
110 :
111 : /* -------------------------------------------------------------------- */
112 : /* Extract RPC information, in a GDAL "standard" metadata format. */
113 : /* -------------------------------------------------------------------- */
114 : int i;
115 3 : char **papszMD = NULL;
116 3 : for( i = 0; apszRPBMap[i] != NULL; i += 2 )
117 : {
118 42 : const char *pszRPBVal = oParser.GetKeyword( apszRPBMap[i+1] );
119 42 : CPLString osAdjVal;
120 :
121 42 : if( pszRPBVal == NULL )
122 : {
123 : CPLError( CE_Failure, CPLE_AppDefined,
124 : "%s file found, but missing %s field (and possibly others).",
125 0 : osTarget.c_str(), apszRPBMap[i+1] );
126 0 : CSLDestroy( papszMD );
127 0 : return NULL;
128 : }
129 :
130 42 : if( strchr(pszRPBVal,',') == NULL )
131 30 : osAdjVal = pszRPBVal;
132 : else
133 : {
134 : // strip out commas and turn newlines into spaces.
135 : int j;
136 :
137 3384 : for( j = 0; pszRPBVal[j] != '\0'; j++ )
138 : {
139 3372 : switch( pszRPBVal[j] )
140 : {
141 : case ',':
142 : case '\n':
143 : case '\r':
144 228 : osAdjVal += ' ';
145 228 : break;
146 :
147 : case '(':
148 : case ')':
149 24 : break;
150 :
151 : default:
152 3120 : osAdjVal += pszRPBVal[j];
153 : }
154 : }
155 : }
156 :
157 42 : papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], osAdjVal );
158 : }
159 :
160 3 : return papszMD;
161 : }
162 :
163 : /************************************************************************/
164 : /* GDALLoadRPCFile() */
165 : /************************************************************************/
166 :
167 : /* Load a GeoEye _rpc.txt file. See ticket http://trac.osgeo.org/gdal/ticket/3639 */
168 :
169 : char **CPL_STDCALL GDALLoadRPCFile( const char *pszFilename,
170 0 : char **papszSiblingFiles )
171 :
172 : {
173 : /* -------------------------------------------------------------------- */
174 : /* Try to identify the RPC file in upper or lower case. */
175 : /* -------------------------------------------------------------------- */
176 0 : CPLString osTarget;
177 :
178 : /* Is this already a _RPC.TXT file ? */
179 0 : if (strlen(pszFilename) > 8 && EQUAL(pszFilename + strlen(pszFilename) - 8, "_RPC.TXT"))
180 0 : osTarget = pszFilename;
181 : else
182 : {
183 0 : CPLString osSrcPath = pszFilename;
184 0 : CPLString soPt(".");
185 0 : size_t found = osSrcPath.rfind(soPt);
186 0 : if (found == CPLString::npos)
187 0 : return NULL;
188 0 : osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.txt");
189 0 : CPLString osTarget = osSrcPath;
190 :
191 0 : if( papszSiblingFiles == NULL )
192 : {
193 : VSIStatBufL sStatBuf;
194 :
195 0 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
196 : {
197 0 : osSrcPath = pszFilename;
198 0 : osSrcPath.replace (found, osSrcPath.size() - found, "_RPC.TXT");
199 0 : osTarget = osSrcPath;
200 :
201 0 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
202 : {
203 0 : osSrcPath = pszFilename;
204 0 : osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.TXT");
205 0 : osTarget = osSrcPath;
206 :
207 0 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
208 : {
209 0 : return NULL;
210 : }
211 : }
212 : }
213 : }
214 : else
215 : {
216 : int iSibling = CSLFindString( papszSiblingFiles,
217 0 : CPLGetFilename(osTarget) );
218 0 : if( iSibling < 0 )
219 0 : return NULL;
220 :
221 0 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
222 0 : osTarget += papszSiblingFiles[iSibling];
223 0 : }
224 : }
225 :
226 : /* -------------------------------------------------------------------- */
227 : /* Read file and parse. */
228 : /* -------------------------------------------------------------------- */
229 0 : char **papszLines = CSLLoad2( osTarget, 100, 100, NULL );
230 0 : if(!papszLines)
231 0 : return NULL;
232 :
233 0 : char **papszMD = NULL;
234 :
235 : /* From LINE_OFF to HEIGHT_SCALE */
236 0 : for(size_t i = 0; i < 19; i += 2 )
237 : {
238 0 : const char *pszRPBVal = CSLFetchNameValue(papszLines, apszRPBMap[i] );
239 0 : if( pszRPBVal == NULL )
240 : {
241 : CPLError( CE_Failure, CPLE_AppDefined,
242 : "%s file found, but missing %s field (and possibly others).",
243 0 : osTarget.c_str(), apszRPBMap[i]);
244 0 : CSLDestroy( papszMD );
245 0 : CSLDestroy( papszLines );
246 0 : return NULL;
247 : }
248 : else
249 : {
250 0 : papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], pszRPBVal );
251 : }
252 : }
253 :
254 : /* For LINE_NUM_COEFF, LINE_DEN_COEFF, SAMP_NUM_COEFF, SAMP_DEN_COEFF */
255 : /* parameters that have 20 values each */
256 0 : for(size_t i = 20; apszRPBMap[i] != NULL; i += 2 )
257 : {
258 0 : CPLString soVal;
259 0 : for(int j = 1; j <= 20; j++)
260 : {
261 0 : CPLString soRPBMapItem;
262 0 : soRPBMapItem.Printf("%s_%d", apszRPBMap[i], j);
263 0 : const char *pszRPBVal = CSLFetchNameValue(papszLines, soRPBMapItem.c_str() );
264 0 : if( pszRPBVal == NULL )
265 : {
266 : CPLError( CE_Failure, CPLE_AppDefined,
267 : "%s file found, but missing %s field (and possibly others).",
268 0 : osTarget.c_str(), soRPBMapItem.c_str() );
269 0 : CSLDestroy( papszMD );
270 0 : CSLDestroy( papszLines );
271 0 : return NULL;
272 : }
273 : else
274 : {
275 0 : soVal += pszRPBVal;
276 0 : soVal += " ";
277 : }
278 : }
279 0 : papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], soVal.c_str() );
280 : }
281 :
282 0 : CSLDestroy( papszLines );
283 0 : return papszMD;
284 : }
285 :
286 : /************************************************************************/
287 : /* GDALWriteRPBFile() */
288 : /************************************************************************/
289 :
290 1 : CPLErr CPL_STDCALL GDALWriteRPBFile( const char *pszFilename, char **papszMD )
291 :
292 : {
293 1 : CPLString osRPBFilename = CPLResetExtension( pszFilename, "RPB" );
294 :
295 :
296 : /* -------------------------------------------------------------------- */
297 : /* Read file and parse. */
298 : /* -------------------------------------------------------------------- */
299 1 : FILE *fp = VSIFOpenL( osRPBFilename, "w" );
300 :
301 1 : if( fp == NULL )
302 : {
303 : CPLError( CE_Failure, CPLE_OpenFailed,
304 : "Unable to create %s for writing.\n%s",
305 0 : osRPBFilename.c_str(), CPLGetLastErrorMsg() );
306 0 : return CE_Failure;
307 : }
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* Write the prefix information. */
311 : /* -------------------------------------------------------------------- */
312 1 : VSIFPrintfL( fp, "%s", "satId = \"QB02\";\n" );
313 1 : VSIFPrintfL( fp, "%s", "bandId = \"P\";\n" );
314 1 : VSIFPrintfL( fp, "%s", "SpecId = \"RPC00B\";\n" );
315 1 : VSIFPrintfL( fp, "%s", "BEGIN_GROUP = IMAGE\n" );
316 1 : VSIFPrintfL( fp, "%s", "\terrBias = 0.0;\n" );
317 1 : VSIFPrintfL( fp, "%s", "\terrRand = 0.0;\n" );
318 :
319 : /* -------------------------------------------------------------------- */
320 : /* Write RPC values from our RPC metadata. */
321 : /* -------------------------------------------------------------------- */
322 : int i;
323 :
324 15 : for( i = 0; apszRPBMap[i] != NULL; i += 2 )
325 : {
326 14 : const char *pszRPBVal = CSLFetchNameValue( papszMD, apszRPBMap[i] );
327 : const char *pszRPBTag;
328 :
329 14 : if( pszRPBVal == NULL )
330 : {
331 : CPLError( CE_Failure, CPLE_AppDefined,
332 : "%s field missing in metadata, %s file not written.",
333 0 : apszRPBMap[i], osRPBFilename.c_str() );
334 0 : VSIFCloseL( fp );
335 0 : VSIUnlink( osRPBFilename );
336 0 : return CE_Failure;
337 : }
338 :
339 14 : pszRPBTag = apszRPBMap[i+1];
340 14 : if( EQUALN(pszRPBTag,"IMAGE.",6) )
341 14 : pszRPBTag += 6;
342 :
343 14 : if( strstr(apszRPBMap[i], "COEF" ) == NULL )
344 : {
345 10 : VSIFPrintfL( fp, "\t%s = %s;\n", pszRPBTag, pszRPBVal );
346 : }
347 : else
348 : {
349 : // Reformat in brackets with commas over multiple lines.
350 :
351 4 : VSIFPrintfL( fp, "\t%s = (\n", pszRPBTag );
352 :
353 : char **papszItems = CSLTokenizeStringComplex( pszRPBVal, " ,",
354 4 : FALSE, FALSE );
355 :
356 4 : if( CSLCount(papszItems) != 20 )
357 : {
358 : CPLError( CE_Failure, CPLE_AppDefined,
359 : "%s field is corrupt (not 20 values), %s file not written.\n%s = %s",
360 : apszRPBMap[i], osRPBFilename.c_str(),
361 0 : apszRPBMap[i], pszRPBVal );
362 0 : VSIFCloseL( fp );
363 0 : VSIUnlink( osRPBFilename );
364 0 : return CE_Failure;
365 : }
366 :
367 : int j;
368 :
369 84 : for( j = 0; j < 20; j++ )
370 : {
371 80 : if( j < 19 )
372 76 : VSIFPrintfL( fp, "\t\t\t%s,\n", papszItems[j] );
373 : else
374 4 : VSIFPrintfL( fp, "\t\t\t%s);\n", papszItems[j] );
375 : }
376 4 : CSLDestroy( papszItems );
377 : }
378 : }
379 :
380 : /* -------------------------------------------------------------------- */
381 : /* Write end part */
382 : /* -------------------------------------------------------------------- */
383 1 : VSIFPrintfL( fp, "%s", "END_GROUP = IMAGE\n" );
384 1 : VSIFPrintfL( fp, "END;\n" );
385 1 : VSIFCloseL( fp );
386 :
387 1 : return CE_None;
388 : }
389 :
390 : /************************************************************************/
391 : /* GDAL_IMD_AA2R() */
392 : /* */
393 : /* Translate AA version IMD file to R version. */
394 : /************************************************************************/
395 :
396 0 : static int GDAL_IMD_AA2R( char ***ppapszIMD )
397 :
398 : {
399 0 : char **papszIMD = *ppapszIMD;
400 :
401 : /* -------------------------------------------------------------------- */
402 : /* Verify that we have a new format file. */
403 : /* -------------------------------------------------------------------- */
404 0 : const char *pszValue = CSLFetchNameValue( papszIMD, "version" );
405 :
406 0 : if( pszValue == NULL )
407 0 : return FALSE;
408 :
409 0 : if( EQUAL(pszValue,"\"R\"") )
410 0 : return TRUE;
411 :
412 0 : if( !EQUAL(pszValue,"\"AA\"") )
413 : {
414 0 : CPLDebug( "IMD", "The file is not the expected 'version = \"AA\"' format.\nProceeding, but file may be corrupted." );
415 : }
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Fix the version line. */
419 : /* -------------------------------------------------------------------- */
420 0 : papszIMD = CSLSetNameValue( papszIMD, "version", "\"R\"" );
421 :
422 : /* -------------------------------------------------------------------- */
423 : /* remove a bunch of fields. */
424 : /* -------------------------------------------------------------------- */
425 : int iKey;
426 :
427 : static const char *apszToRemove[] = {
428 : "productCatalogId",
429 : "childCatalogId",
430 : "productType",
431 : "numberOfLooks",
432 : "effectiveBandwidth",
433 : "mode",
434 : "scanDirection",
435 : "cloudCover",
436 : "productGSD",
437 : NULL };
438 :
439 0 : for( iKey = 0; apszToRemove[iKey] != NULL; iKey++ )
440 : {
441 0 : int iTarget = CSLFindName( papszIMD, apszToRemove[iKey] );
442 0 : if( iTarget != -1 )
443 0 : papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
444 : }
445 :
446 : /* -------------------------------------------------------------------- */
447 : /* Replace various min/mean/max with just the mean. */
448 : /* -------------------------------------------------------------------- */
449 : static const char *keylist[] = {
450 : "CollectedRowGSD",
451 : "CollectedColGSD",
452 : "SunAz",
453 : "SunEl",
454 : "SatAz",
455 : "SatEl",
456 : "InTrackViewAngle",
457 : "CrossTrackViewAngle",
458 : "OffNadirViewAngle",
459 : NULL };
460 :
461 0 : for( iKey = 0; keylist[iKey] != NULL; iKey++ )
462 : {
463 0 : CPLString osTarget;
464 : int iTarget;
465 :
466 0 : osTarget.Printf( "IMAGE_1.min%s", keylist[iKey] );
467 0 : iTarget = CSLFindName( papszIMD, osTarget );
468 0 : if( iTarget != -1 )
469 0 : papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
470 :
471 0 : osTarget.Printf( "IMAGE_1.max%s", keylist[iKey] );
472 0 : iTarget = CSLFindName( papszIMD, osTarget );
473 0 : if( iTarget != -1 )
474 0 : papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
475 :
476 0 : osTarget.Printf( "IMAGE_1.mean%s", keylist[iKey] );
477 0 : iTarget = CSLFindName( papszIMD, osTarget );
478 0 : if( iTarget != -1 )
479 : {
480 0 : CPLString osValue = CSLFetchNameValue( papszIMD, osTarget );
481 0 : CPLString osLine;
482 :
483 : osTarget.Printf( "IMAGE_1.%c%s",
484 : tolower(keylist[iKey][0]),
485 0 : keylist[iKey]+1 );
486 :
487 0 : osLine = osTarget + "=" + osValue;
488 :
489 0 : CPLFree( papszIMD[iTarget] );
490 0 : papszIMD[iTarget] = CPLStrdup(osLine);
491 : }
492 : }
493 :
494 0 : *ppapszIMD = papszIMD;
495 0 : return TRUE;
496 : }
497 :
498 : /************************************************************************/
499 : /* GDALLoadIMDFile() */
500 : /************************************************************************/
501 :
502 : char ** CPL_STDCALL GDALLoadIMDFile( const char *pszFilename,
503 7 : char **papszSiblingFiles )
504 :
505 : {
506 : /* -------------------------------------------------------------------- */
507 : /* Try to identify the IMD file in upper or lower case. */
508 : /* -------------------------------------------------------------------- */
509 7 : CPLString osTarget = CPLResetExtension( pszFilename, "IMD" );
510 :
511 : /* Is this already a IMD file ? */
512 7 : if (EQUAL(CPLGetExtension(pszFilename), "IMD"))
513 6 : osTarget = pszFilename;
514 1 : else if( papszSiblingFiles == NULL )
515 : {
516 : VSIStatBufL sStatBuf;
517 :
518 0 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
519 : {
520 0 : osTarget = CPLResetExtension( pszFilename, "imd" );
521 :
522 0 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
523 0 : return NULL;
524 : }
525 : }
526 : else
527 : {
528 : int iSibling = CSLFindString( papszSiblingFiles,
529 1 : CPLGetFilename(osTarget) );
530 1 : if( iSibling < 0 )
531 0 : return NULL;
532 :
533 1 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
534 1 : osTarget += papszSiblingFiles[iSibling];
535 : }
536 :
537 : /* -------------------------------------------------------------------- */
538 : /* Read file and parse. */
539 : /* -------------------------------------------------------------------- */
540 7 : CPLKeywordParser oParser;
541 :
542 7 : FILE *fp = VSIFOpenL( osTarget, "r" );
543 :
544 7 : if( fp == NULL )
545 0 : return NULL;
546 :
547 7 : if( !oParser.Ingest( fp ) )
548 : {
549 0 : VSIFCloseL( fp );
550 0 : return NULL;
551 : }
552 :
553 7 : VSIFCloseL( fp );
554 :
555 : /* -------------------------------------------------------------------- */
556 : /* Consider version changing. */
557 : /* -------------------------------------------------------------------- */
558 7 : char **papszIMD = CSLDuplicate( oParser.GetAllKeywords() );
559 7 : const char *pszVersion = CSLFetchNameValue( papszIMD, "version" );
560 :
561 7 : if( pszVersion == NULL )
562 : {
563 : /* ? */;
564 : }
565 6 : else if( EQUAL(pszVersion,"\"AA\"") )
566 : {
567 0 : GDAL_IMD_AA2R( &papszIMD );
568 : }
569 :
570 7 : return papszIMD;
571 : }
572 :
573 : /************************************************************************/
574 : /* GDALWriteIMDMultiLine() */
575 : /* */
576 : /* Write a value that is split over multiple lines. */
577 : /************************************************************************/
578 :
579 4 : static void GDALWriteIMDMultiLine( FILE *fp, const char *pszValue )
580 :
581 : {
582 : char **papszItems = CSLTokenizeStringComplex( pszValue, "(,) ",
583 4 : FALSE, FALSE );
584 4 : int nItemCount = CSLCount(papszItems);
585 : int i;
586 :
587 4 : VSIFPrintfL( fp, "(\n" );
588 :
589 40 : for( i = 0; i < nItemCount; i++ )
590 : {
591 36 : if( i == nItemCount-1 )
592 4 : VSIFPrintfL( fp, "\t%s );\n", papszItems[i] );
593 : else
594 32 : VSIFPrintfL( fp, "\t%s,\n", papszItems[i] );
595 : }
596 4 : CSLDestroy( papszItems );
597 4 : }
598 :
599 : /************************************************************************/
600 : /* GDALWriteIMDFile() */
601 : /************************************************************************/
602 :
603 2 : CPLErr CPL_STDCALL GDALWriteIMDFile( const char *pszFilename, char **papszMD )
604 :
605 : {
606 2 : CPLString osRPBFilename = CPLResetExtension( pszFilename, "IMD" );
607 :
608 :
609 : /* -------------------------------------------------------------------- */
610 : /* Read file and parse. */
611 : /* -------------------------------------------------------------------- */
612 2 : FILE *fp = VSIFOpenL( osRPBFilename, "w" );
613 :
614 2 : if( fp == NULL )
615 : {
616 : CPLError( CE_Failure, CPLE_OpenFailed,
617 : "Unable to create %s for writing.\n%s",
618 0 : osRPBFilename.c_str(), CPLGetLastErrorMsg() );
619 0 : return CE_Failure;
620 : }
621 :
622 : /* ==================================================================== */
623 : /* -------------------------------------------------------------------- */
624 : /* Loop through all values writing. */
625 : /* -------------------------------------------------------------------- */
626 : /* ==================================================================== */
627 : int iKey;
628 2 : CPLString osCurSection;
629 :
630 176 : for( iKey = 0; papszMD[iKey] != NULL; iKey++ )
631 : {
632 174 : char *pszRawKey = NULL;
633 174 : const char *pszValue = CPLParseNameValue( papszMD[iKey], &pszRawKey );
634 174 : CPLString osKeySection, osKeyItem;
635 174 : char *pszDot = strchr(pszRawKey,'.');
636 :
637 : /* -------------------------------------------------------------------- */
638 : /* Split stuff like BAND_P.ULLon into section and item. */
639 : /* -------------------------------------------------------------------- */
640 174 : if( pszDot == NULL )
641 : {
642 28 : osKeyItem = pszRawKey;
643 : }
644 : else
645 : {
646 146 : osKeyItem = pszDot+1;
647 146 : *pszDot = '\0';
648 146 : osKeySection = pszRawKey;
649 : }
650 174 : CPLFree( pszRawKey );
651 :
652 : /* -------------------------------------------------------------------- */
653 : /* Close and/or start sections as needed. */
654 : /* -------------------------------------------------------------------- */
655 174 : if( osCurSection.size() && !EQUAL(osCurSection,osKeySection) )
656 4 : VSIFPrintfL( fp, "END_GROUP = %s\n", osCurSection.c_str() );
657 :
658 174 : if( osKeySection.size() && !EQUAL(osCurSection,osKeySection) )
659 6 : VSIFPrintfL( fp, "BEGIN_GROUP = %s\n", osKeySection.c_str() );
660 :
661 174 : osCurSection = osKeySection;
662 :
663 : /* -------------------------------------------------------------------- */
664 : /* Print out simple item. */
665 : /* -------------------------------------------------------------------- */
666 174 : if( osCurSection.size() )
667 146 : VSIFPrintfL( fp, "\t%s = ", osKeyItem.c_str() );
668 : else
669 28 : VSIFPrintfL( fp, "%s = ", osKeyItem.c_str() );
670 :
671 174 : if( pszValue[0] != '(' )
672 170 : VSIFPrintfL( fp, "%s;\n", pszValue );
673 : else
674 4 : GDALWriteIMDMultiLine( fp, pszValue );
675 : }
676 :
677 : /* -------------------------------------------------------------------- */
678 : /* Close off. */
679 : /* -------------------------------------------------------------------- */
680 2 : if( osCurSection.size() )
681 2 : VSIFPrintfL( fp, "END_GROUP = %s\n", osCurSection.c_str() );
682 :
683 2 : VSIFPrintfL( fp, "END;\n" );
684 :
685 2 : VSIFCloseL( fp );
686 :
687 2 : return CE_None;
688 : }
|