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 190 : NASAKeywordHandler::NASAKeywordHandler()
66 :
67 : {
68 190 : papszKeywordList = NULL;
69 190 : }
70 :
71 : /************************************************************************/
72 : /* ~NASAKeywordHandler() */
73 : /************************************************************************/
74 :
75 190 : NASAKeywordHandler::~NASAKeywordHandler()
76 :
77 : {
78 190 : CSLDestroy( papszKeywordList );
79 190 : papszKeywordList = NULL;
80 190 : }
81 :
82 : /************************************************************************/
83 : /* Ingest() */
84 : /************************************************************************/
85 :
86 62 : 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 62 : if( VSIFSeekL( fp, nOffset, SEEK_SET ) != 0 )
93 0 : return FALSE;
94 :
95 178 : for( ; TRUE; )
96 : {
97 : const char *pszCheck;
98 : char szChunk[513];
99 :
100 240 : int nBytesRead = VSIFReadL( szChunk, 1, 512, fp );
101 :
102 240 : szChunk[nBytesRead] = '\0';
103 240 : osHeaderText += szChunk;
104 :
105 240 : if( nBytesRead < 512 )
106 7 : break;
107 :
108 233 : if( osHeaderText.size() > 520 )
109 171 : pszCheck = osHeaderText.c_str() + (osHeaderText.size() - 520);
110 : else
111 62 : pszCheck = szChunk;
112 :
113 233 : 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 55 : break;
118 : }
119 :
120 62 : pszHeaderNext = osHeaderText.c_str();
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Process name/value pairs, keeping track of a "path stack". */
124 : /* -------------------------------------------------------------------- */
125 62 : return ReadGroup( "" );
126 : }
127 :
128 : /************************************************************************/
129 : /* ReadGroup() */
130 : /************************************************************************/
131 :
132 186 : int NASAKeywordHandler::ReadGroup( const char *pszPathPrefix )
133 :
134 : {
135 186 : CPLString osName, osValue;
136 :
137 2169 : for( ; TRUE; )
138 : {
139 2355 : if( !ReadPair( osName, osValue ) )
140 0 : return FALSE;
141 :
142 2355 : if( EQUAL(osName,"OBJECT") || EQUAL(osName,"GROUP") )
143 : {
144 124 : if( !ReadGroup( (CPLString(pszPathPrefix) + osValue + ".").c_str() ) )
145 0 : return FALSE;
146 : }
147 2231 : else if( EQUAL(osName,"END")
148 : || EQUAL(osName,"END_GROUP" )
149 : || EQUAL(osName,"END_OBJECT" ) )
150 : {
151 186 : return TRUE;
152 : }
153 : else
154 : {
155 2045 : osName = pszPathPrefix + osName;
156 : papszKeywordList = CSLSetNameValue( papszKeywordList,
157 2045 : 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 2355 : int NASAKeywordHandler::ReadPair( CPLString &osName, CPLString &osValue )
171 :
172 : {
173 2355 : osName = "";
174 4710 : osValue = "";
175 :
176 2355 : if( !ReadWord( osName ) )
177 0 : return FALSE;
178 :
179 2355 : SkipWhite();
180 :
181 2355 : if( EQUAL(osName,"END") )
182 62 : return TRUE;
183 :
184 2293 : if( *pszHeaderNext != '=' )
185 : {
186 : // ISIS3 does not have anything after the end group/object keyword.
187 23 : if( EQUAL(osName,"End_Group") || EQUAL(osName,"End_Object") )
188 23 : return TRUE;
189 : else
190 0 : return FALSE;
191 : }
192 :
193 2270 : pszHeaderNext++;
194 :
195 2270 : SkipWhite();
196 :
197 2270 : osValue = "";
198 :
199 : // Handle value lists like: Name = (Red, Red)
200 2270 : if( *pszHeaderNext == '(' )
201 : {
202 192 : CPLString osWord;
203 :
204 192 : while( ReadWord( osWord ) )
205 : {
206 511 : SkipWhite();
207 :
208 511 : osValue += osWord;
209 511 : if( osWord[strlen(osWord)-1] == ')' )
210 192 : break;
211 192 : }
212 : }
213 :
214 : // Handle value lists like: Name = {Red, Red}
215 2078 : else if( *pszHeaderNext == '{' )
216 : {
217 4 : CPLString osWord;
218 :
219 4 : while( ReadWord( osWord ) )
220 : {
221 23 : SkipWhite();
222 :
223 23 : osValue += osWord;
224 23 : if( osWord[strlen(osWord)-1] == '}' )
225 4 : break;
226 4 : }
227 : }
228 :
229 : else // Handle more normal "single word" values.
230 : {
231 2074 : if( !ReadWord( osValue ) )
232 0 : return FALSE;
233 :
234 : }
235 :
236 2270 : SkipWhite();
237 :
238 : // No units keyword?
239 2270 : if( *pszHeaderNext != '<' )
240 2130 : return TRUE;
241 :
242 : // Append units keyword. For lines that like like this:
243 : // MAP_RESOLUTION = 4.0 <PIXEL/DEGREE>
244 :
245 140 : CPLString osWord;
246 :
247 140 : osValue += " ";
248 :
249 280 : while( ReadWord( osWord ) )
250 : {
251 140 : SkipWhite();
252 :
253 140 : osValue += osWord;
254 140 : if( osWord[strlen(osWord)-1] == '>' )
255 140 : break;
256 : }
257 :
258 140 : return TRUE;
259 : }
260 :
261 : /************************************************************************/
262 : /* ReadWord() */
263 : /* Returns TRUE on success */
264 : /************************************************************************/
265 :
266 5103 : int NASAKeywordHandler::ReadWord( CPLString &osWord )
267 :
268 : {
269 5103 : osWord = "";
270 :
271 5103 : SkipWhite();
272 :
273 10206 : 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 5103 : if( *pszHeaderNext == '"' )
282 : {
283 458 : osWord += *(pszHeaderNext++);
284 8193 : while( *pszHeaderNext != '"' )
285 : {
286 7277 : if( *pszHeaderNext == '\0' )
287 0 : return FALSE;
288 7277 : if( *pszHeaderNext == '\n' )
289 : {
290 36 : osWord += "\\n";
291 36 : pszHeaderNext++;
292 36 : continue;
293 : }
294 7241 : if( *pszHeaderNext == '\r' )
295 : {
296 34 : osWord += "\\r";
297 34 : pszHeaderNext++;
298 34 : continue;
299 : }
300 7207 : osWord += *(pszHeaderNext++);
301 : }
302 458 : osWord += *(pszHeaderNext++);
303 458 : 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 4645 : if( *pszHeaderNext == '\'' )
313 : {
314 4 : osWord += *(pszHeaderNext++);
315 20 : while( *pszHeaderNext != '\'' )
316 : {
317 12 : if( *pszHeaderNext == '\0' )
318 0 : return FALSE;
319 :
320 12 : osWord += *(pszHeaderNext++);
321 : }
322 4 : osWord += *(pszHeaderNext++);
323 4 : 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 54775 : while( *pszHeaderNext != '\0'
334 : && *pszHeaderNext != '='
335 : && !isspace((unsigned char)*pszHeaderNext) )
336 : {
337 45493 : osWord += *pszHeaderNext;
338 45493 : pszHeaderNext++;
339 :
340 45621 : if( *pszHeaderNext == '-'
341 128 : && (pszHeaderNext[1] == 10 || pszHeaderNext[1] == 13) )
342 : {
343 0 : pszHeaderNext += 2;
344 0 : SkipWhite();
345 : }
346 : }
347 :
348 4641 : return TRUE;
349 : }
350 :
351 : /************************************************************************/
352 : /* SkipWhite() */
353 : /* Skip white spaces and C style comments */
354 : /************************************************************************/
355 :
356 61549 : void NASAKeywordHandler::SkipWhite()
357 :
358 : {
359 48877 : for( ; TRUE; )
360 : {
361 : // Skip C style comments
362 61549 : if( *pszHeaderNext == '/' && pszHeaderNext[1] == '*' )
363 : {
364 380 : pszHeaderNext += 2;
365 :
366 14533 : while( *pszHeaderNext != '\0'
367 : && (*pszHeaderNext != '*'
368 493 : || pszHeaderNext[1] != '/' ) )
369 : {
370 13280 : pszHeaderNext++;
371 : }
372 :
373 380 : pszHeaderNext += 2;
374 :
375 : // consume till end of line.
376 : // reduce sensibility to a label error
377 760 : while( *pszHeaderNext != '\0'
378 : && *pszHeaderNext != 10
379 : && *pszHeaderNext != 13 )
380 : {
381 0 : pszHeaderNext++;
382 : }
383 380 : continue;
384 : }
385 :
386 : // Skip # style comments
387 109666 : if( (*pszHeaderNext == 10 || *pszHeaderNext == 13 ||
388 : *pszHeaderNext == ' ' || *pszHeaderNext == '\t' )
389 48497 : && pszHeaderNext[1] == '#' )
390 : {
391 4 : pszHeaderNext += 2;
392 :
393 : // consume till end of line.
394 216 : while( *pszHeaderNext != '\0'
395 : && *pszHeaderNext != 10
396 : && *pszHeaderNext != 13 )
397 : {
398 208 : pszHeaderNext++;
399 : }
400 4 : continue;
401 : }
402 :
403 : // Skip white space (newline, space, tab, etc )
404 61165 : if( isspace( (unsigned char)*pszHeaderNext ) )
405 : {
406 48493 : pszHeaderNext++;
407 48493 : continue;
408 : }
409 :
410 : // not white space, return.
411 : return;
412 : }
413 : }
414 :
415 : /************************************************************************/
416 : /* GetKeyword() */
417 : /************************************************************************/
418 :
419 1839 : const char *NASAKeywordHandler::GetKeyword( const char *pszPath,
420 : const char *pszDefault )
421 :
422 : {
423 : const char *pszResult;
424 :
425 1839 : pszResult = CSLFetchNameValue( papszKeywordList, pszPath );
426 1839 : if( pszResult == NULL )
427 775 : return pszDefault;
428 : else
429 1064 : return pszResult;
430 : }
431 :
432 : /************************************************************************/
433 : /* GetKeywordList() */
434 : /************************************************************************/
435 :
436 0 : char **NASAKeywordHandler::GetKeywordList()
437 : {
438 0 : return papszKeywordList;
439 : }
440 :
|