1 : /******************************************************************************
2 : * $Id: pdsdataset.cpp 12658 2007-11-07 23:14:33Z warmerdam $
3 : *
4 : * Project: PDS Driver; Planetary Data System Format
5 : * Purpose: Implementation of NASAKeywordHandler - a class to read
6 : * keyword data from PDS, ISIS2 and ISIS3 data products.
7 : * Author: Frank Warmerdam <warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2006, Frank Warmerdam <warmerdam@pobox.com>
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 : * Object Description Language (ODL) is used to encode data labels for PDS
31 : * and other NASA data systems. Refer to Chapter 12 of "PDS Standards
32 : * Reference" at http://pds.jpl.nasa.gov/tools/standards-reference.shtml for
33 : * further details about ODL.
34 : *
35 : * This is also known as PVL (Parameter Value Language) which is written
36 : * about at http://www.orrery.us/node/44 where it notes:
37 : *
38 : * The PVL syntax that the PDS uses is specified by the Consultative Committee
39 : * for Space Data Systems in their Blue Book publication: "Parameter Value
40 : * Language Specification (CCSD0006 and CCSD0008)", June 2000
41 : * [CCSDS 641.0-B-2], and Green Book publication: "Parameter Value Language -
42 : * A Tutorial", June 2000 [CCSDS 641.0-G-2]. PVL has also been accepted by the
43 : * International Standards Organization (ISO), as a Final Draft International
44 : * Standard (ISO 14961:2002) keyword value type language for naming and
45 : * expressing data values.
46 : * --
47 : * also of interest, on PDS ODL:
48 : * http://pds.jpl.nasa.gov/documents/sr/Chapter12.pdf
49 : *
50 : ****************************************************************************/
51 :
52 : #include "cpl_string.h"
53 : #include "nasakeywordhandler.h"
54 :
55 : /************************************************************************/
56 : /* ==================================================================== */
57 : /* NASAKeywordHandler */
58 : /* ==================================================================== */
59 : /************************************************************************/
60 :
61 : /************************************************************************/
62 : /* NASAKeywordHandler() */
63 : /************************************************************************/
64 :
65 350 : NASAKeywordHandler::NASAKeywordHandler()
66 :
67 : {
68 350 : papszKeywordList = NULL;
69 350 : }
70 :
71 : /************************************************************************/
72 : /* ~NASAKeywordHandler() */
73 : /************************************************************************/
74 :
75 350 : NASAKeywordHandler::~NASAKeywordHandler()
76 :
77 : {
78 350 : CSLDestroy( papszKeywordList );
79 350 : papszKeywordList = NULL;
80 350 : }
81 :
82 : /************************************************************************/
83 : /* Ingest() */
84 : /************************************************************************/
85 :
86 124 : int NASAKeywordHandler::Ingest( VSILFILE *fp, int nOffset )
87 :
88 : {
89 : /* -------------------------------------------------------------------- */
90 : /* Read in buffer till we find END all on it's own line. */
91 : /* -------------------------------------------------------------------- */
92 124 : if( VSIFSeekL( fp, nOffset, SEEK_SET ) != 0 )
93 0 : return FALSE;
94 :
95 356 : for( ; TRUE; )
96 : {
97 : const char *pszCheck;
98 : char szChunk[513];
99 :
100 480 : int nBytesRead = VSIFReadL( szChunk, 1, 512, fp );
101 :
102 480 : szChunk[nBytesRead] = '\0';
103 480 : osHeaderText += szChunk;
104 :
105 480 : if( nBytesRead < 512 )
106 14 : break;
107 :
108 466 : if( osHeaderText.size() > 520 )
109 342 : pszCheck = osHeaderText.c_str() + (osHeaderText.size() - 520);
110 : else
111 124 : pszCheck = szChunk;
112 :
113 466 : if( strstr(pszCheck,"\r\nEND\r\n") != NULL
114 : || strstr(pszCheck,"\nEND\n") != NULL
115 : || strstr(pszCheck,"\r\nEnd\r\n") != NULL
116 : || strstr(pszCheck,"\nEnd\n") != NULL )
117 110 : break;
118 : }
119 :
120 124 : pszHeaderNext = osHeaderText.c_str();
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Process name/value pairs, keeping track of a "path stack". */
124 : /* -------------------------------------------------------------------- */
125 124 : return ReadGroup( "" );
126 : }
127 :
128 : /************************************************************************/
129 : /* ReadGroup() */
130 : /************************************************************************/
131 :
132 372 : int NASAKeywordHandler::ReadGroup( const char *pszPathPrefix )
133 :
134 : {
135 372 : CPLString osName, osValue;
136 :
137 4338 : for( ; TRUE; )
138 : {
139 4710 : if( !ReadPair( osName, osValue ) )
140 0 : return FALSE;
141 :
142 4710 : if( EQUAL(osName,"OBJECT") || EQUAL(osName,"GROUP") )
143 : {
144 248 : if( !ReadGroup( (CPLString(pszPathPrefix) + osValue + ".").c_str() ) )
145 0 : return FALSE;
146 : }
147 4462 : else if( EQUAL(osName,"END")
148 : || EQUAL(osName,"END_GROUP" )
149 : || EQUAL(osName,"END_OBJECT" ) )
150 : {
151 372 : return TRUE;
152 : }
153 : else
154 : {
155 4090 : osName = pszPathPrefix + osName;
156 : papszKeywordList = CSLSetNameValue( papszKeywordList,
157 4090 : osName, osValue );
158 : }
159 0 : }
160 : }
161 :
162 : /************************************************************************/
163 : /* ReadPair() */
164 : /* */
165 : /* Read a name/value pair from the input stream. Strip off */
166 : /* white space, ignore comments, split on '='. */
167 : /* Returns TRUE on success. */
168 : /************************************************************************/
169 :
170 4710 : int NASAKeywordHandler::ReadPair( CPLString &osName, CPLString &osValue )
171 :
172 : {
173 4710 : osName = "";
174 9420 : osValue = "";
175 :
176 4710 : if( !ReadWord( osName ) )
177 0 : return FALSE;
178 :
179 4710 : SkipWhite();
180 :
181 4710 : if( EQUAL(osName,"END") )
182 124 : return TRUE;
183 :
184 4586 : if( *pszHeaderNext != '=' )
185 : {
186 : // ISIS3 does not have anything after the end group/object keyword.
187 46 : if( EQUAL(osName,"End_Group") || EQUAL(osName,"End_Object") )
188 46 : return TRUE;
189 : else
190 0 : return FALSE;
191 : }
192 :
193 4540 : pszHeaderNext++;
194 :
195 4540 : SkipWhite();
196 :
197 4540 : osValue = "";
198 :
199 : // Handle value lists like: Name = (Red, Red)
200 4540 : if( *pszHeaderNext == '(' )
201 : {
202 384 : CPLString osWord;
203 :
204 384 : while( ReadWord( osWord ) )
205 : {
206 1022 : SkipWhite();
207 :
208 1022 : osValue += osWord;
209 1022 : if( osWord[strlen(osWord)-1] == ')' )
210 384 : break;
211 384 : }
212 : }
213 :
214 : // Handle value lists like: Name = {Red, Red}
215 4156 : else if( *pszHeaderNext == '{' )
216 : {
217 8 : CPLString osWord;
218 :
219 8 : while( ReadWord( osWord ) )
220 : {
221 46 : SkipWhite();
222 :
223 46 : osValue += osWord;
224 46 : if( osWord[strlen(osWord)-1] == '}' )
225 8 : break;
226 8 : }
227 : }
228 :
229 : else // Handle more normal "single word" values.
230 : {
231 4148 : if( !ReadWord( osValue ) )
232 0 : return FALSE;
233 :
234 : }
235 :
236 4540 : SkipWhite();
237 :
238 : // No units keyword?
239 4540 : if( *pszHeaderNext != '<' )
240 4260 : return TRUE;
241 :
242 : // Append units keyword. For lines that like like this:
243 : // MAP_RESOLUTION = 4.0 <PIXEL/DEGREE>
244 :
245 280 : CPLString osWord;
246 :
247 280 : osValue += " ";
248 :
249 560 : while( ReadWord( osWord ) )
250 : {
251 280 : SkipWhite();
252 :
253 280 : osValue += osWord;
254 280 : if( osWord[strlen(osWord)-1] == '>' )
255 280 : break;
256 : }
257 :
258 280 : return TRUE;
259 : }
260 :
261 : /************************************************************************/
262 : /* ReadWord() */
263 : /* Returns TRUE on success */
264 : /************************************************************************/
265 :
266 10206 : int NASAKeywordHandler::ReadWord( CPLString &osWord )
267 :
268 : {
269 10206 : osWord = "";
270 :
271 10206 : SkipWhite();
272 :
273 20412 : if( !(*pszHeaderNext != '\0'
274 : && *pszHeaderNext != '='
275 : && !isspace((unsigned char)*pszHeaderNext)) )
276 0 : return FALSE;
277 :
278 : /* Extract a text string delimited by '\"' */
279 : /* Convert newlines (CR or LF) within quotes. While text strings
280 : support them as per ODL, the keyword list doesn't want them */
281 10206 : if( *pszHeaderNext == '"' )
282 : {
283 916 : osWord += *(pszHeaderNext++);
284 16386 : while( *pszHeaderNext != '"' )
285 : {
286 14554 : if( *pszHeaderNext == '\0' )
287 0 : return FALSE;
288 14554 : if( *pszHeaderNext == '\n' )
289 : {
290 72 : osWord += "\\n";
291 72 : pszHeaderNext++;
292 72 : continue;
293 : }
294 14482 : if( *pszHeaderNext == '\r' )
295 : {
296 68 : osWord += "\\r";
297 68 : pszHeaderNext++;
298 68 : continue;
299 : }
300 14414 : osWord += *(pszHeaderNext++);
301 : }
302 916 : osWord += *(pszHeaderNext++);
303 916 : return TRUE;
304 : }
305 :
306 : /* Extract a symbol string */
307 : /* These are expected to not have
308 : '\'' (delimiters),
309 : format effectors (should fit on a single line) or
310 : control characters.
311 : */
312 9290 : if( *pszHeaderNext == '\'' )
313 : {
314 8 : osWord += *(pszHeaderNext++);
315 40 : while( *pszHeaderNext != '\'' )
316 : {
317 24 : if( *pszHeaderNext == '\0' )
318 0 : return FALSE;
319 :
320 24 : osWord += *(pszHeaderNext++);
321 : }
322 8 : osWord += *(pszHeaderNext++);
323 8 : return TRUE;
324 : }
325 :
326 : /*
327 : * Extract normal text. Terminated by '=' or whitespace.
328 : *
329 : * A special exception is that a line may terminate with a '-'
330 : * which is taken as a line extender, and we suck up white space to new
331 : * text.
332 : */
333 109550 : while( *pszHeaderNext != '\0'
334 : && *pszHeaderNext != '='
335 : && !isspace((unsigned char)*pszHeaderNext) )
336 : {
337 90986 : osWord += *pszHeaderNext;
338 90986 : pszHeaderNext++;
339 :
340 91242 : if( *pszHeaderNext == '-'
341 256 : && (pszHeaderNext[1] == 10 || pszHeaderNext[1] == 13) )
342 : {
343 0 : pszHeaderNext += 2;
344 0 : SkipWhite();
345 : }
346 : }
347 :
348 9282 : return TRUE;
349 : }
350 :
351 : /************************************************************************/
352 : /* SkipWhite() */
353 : /* Skip white spaces and C style comments */
354 : /************************************************************************/
355 :
356 123098 : void NASAKeywordHandler::SkipWhite()
357 :
358 : {
359 97754 : for( ; TRUE; )
360 : {
361 : // Skip C style comments
362 123098 : if( *pszHeaderNext == '/' && pszHeaderNext[1] == '*' )
363 : {
364 760 : pszHeaderNext += 2;
365 :
366 29066 : while( *pszHeaderNext != '\0'
367 : && (*pszHeaderNext != '*'
368 986 : || pszHeaderNext[1] != '/' ) )
369 : {
370 26560 : pszHeaderNext++;
371 : }
372 :
373 760 : pszHeaderNext += 2;
374 :
375 : // consume till end of line.
376 : // reduce sensibility to a label error
377 1520 : while( *pszHeaderNext != '\0'
378 : && *pszHeaderNext != 10
379 : && *pszHeaderNext != 13 )
380 : {
381 0 : pszHeaderNext++;
382 : }
383 760 : continue;
384 : }
385 :
386 : // Skip # style comments
387 219332 : if( (*pszHeaderNext == 10 || *pszHeaderNext == 13 ||
388 : *pszHeaderNext == ' ' || *pszHeaderNext == '\t' )
389 96994 : && pszHeaderNext[1] == '#' )
390 : {
391 8 : pszHeaderNext += 2;
392 :
393 : // consume till end of line.
394 432 : while( *pszHeaderNext != '\0'
395 : && *pszHeaderNext != 10
396 : && *pszHeaderNext != 13 )
397 : {
398 416 : pszHeaderNext++;
399 : }
400 8 : continue;
401 : }
402 :
403 : // Skip white space (newline, space, tab, etc )
404 122330 : if( isspace( (unsigned char)*pszHeaderNext ) )
405 : {
406 96986 : pszHeaderNext++;
407 96986 : continue;
408 : }
409 :
410 : // not white space, return.
411 : return;
412 : }
413 : }
414 :
415 : /************************************************************************/
416 : /* GetKeyword() */
417 : /************************************************************************/
418 :
419 3678 : const char *NASAKeywordHandler::GetKeyword( const char *pszPath,
420 : const char *pszDefault )
421 :
422 : {
423 : const char *pszResult;
424 :
425 3678 : pszResult = CSLFetchNameValue( papszKeywordList, pszPath );
426 3678 : if( pszResult == NULL )
427 1550 : return pszDefault;
428 : else
429 2128 : return pszResult;
430 : }
431 :
432 : /************************************************************************/
433 : /* GetKeywordList() */
434 : /************************************************************************/
435 :
436 0 : char **NASAKeywordHandler::GetKeywordList()
437 : {
438 0 : return papszKeywordList;
439 : }
440 :
|