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 22 : NASAKeywordHandler::NASAKeywordHandler()
66 :
67 : {
68 22 : papszKeywordList = NULL;
69 22 : }
70 :
71 : /************************************************************************/
72 : /* ~NASAKeywordHandler() */
73 : /************************************************************************/
74 :
75 22 : NASAKeywordHandler::~NASAKeywordHandler()
76 :
77 : {
78 22 : CSLDestroy( papszKeywordList );
79 22 : papszKeywordList = NULL;
80 22 : }
81 :
82 : /************************************************************************/
83 : /* Ingest() */
84 : /************************************************************************/
85 :
86 13 : int NASAKeywordHandler::Ingest( FILE *fp, int nOffset )
87 :
88 : {
89 : /* -------------------------------------------------------------------- */
90 : /* Read in buffer till we find END all on it's own line. */
91 : /* -------------------------------------------------------------------- */
92 13 : if( VSIFSeekL( fp, nOffset, SEEK_SET ) != 0 )
93 0 : return FALSE;
94 :
95 101 : for( ; TRUE; )
96 : {
97 : const char *pszCheck;
98 : char szChunk[513];
99 :
100 114 : int nBytesRead = VSIFReadL( szChunk, 1, 512, fp );
101 :
102 114 : szChunk[nBytesRead] = '\0';
103 114 : osHeaderText += szChunk;
104 :
105 114 : if( nBytesRead < 512 )
106 6 : break;
107 :
108 108 : if( osHeaderText.size() > 520 )
109 95 : pszCheck = osHeaderText.c_str() + (osHeaderText.size() - 520);
110 : else
111 13 : pszCheck = szChunk;
112 :
113 108 : 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 7 : break;
118 : }
119 :
120 13 : pszHeaderNext = osHeaderText.c_str();
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Process name/value pairs, keeping track of a "path stack". */
124 : /* -------------------------------------------------------------------- */
125 13 : return ReadGroup( "" );
126 : }
127 :
128 : /************************************************************************/
129 : /* ReadGroup() */
130 : /************************************************************************/
131 :
132 75 : int NASAKeywordHandler::ReadGroup( const char *pszPathPrefix )
133 :
134 : {
135 75 : CPLString osName, osValue;
136 :
137 1007 : for( ; TRUE; )
138 : {
139 1082 : if( !ReadPair( osName, osValue ) )
140 0 : return FALSE;
141 :
142 1082 : if( EQUAL(osName,"OBJECT") || EQUAL(osName,"GROUP") )
143 : {
144 62 : if( !ReadGroup( (CPLString(pszPathPrefix) + osValue + ".").c_str() ) )
145 0 : return FALSE;
146 : }
147 1020 : else if( EQUAL(osName,"END")
148 : || EQUAL(osName,"END_GROUP" )
149 : || EQUAL(osName,"END_OBJECT" ) )
150 : {
151 75 : return TRUE;
152 : }
153 : else
154 : {
155 945 : osName = pszPathPrefix + osName;
156 : papszKeywordList = CSLSetNameValue( papszKeywordList,
157 945 : 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 1082 : int NASAKeywordHandler::ReadPair( CPLString &osName, CPLString &osValue )
171 :
172 : {
173 1082 : osName = "";
174 2164 : osValue = "";
175 :
176 1082 : if( !ReadWord( osName ) )
177 0 : return FALSE;
178 :
179 1082 : SkipWhite();
180 :
181 1082 : if( EQUAL(osName,"END") )
182 13 : return TRUE;
183 :
184 1069 : 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 1046 : pszHeaderNext++;
194 :
195 1046 : SkipWhite();
196 :
197 1046 : osValue = "";
198 :
199 : // Handle value lists like: Name = (Red, Red)
200 1046 : if( *pszHeaderNext == '(' )
201 : {
202 54 : CPLString osWord;
203 :
204 292 : while( ReadWord( osWord ) )
205 : {
206 238 : SkipWhite();
207 :
208 238 : osValue += osWord;
209 238 : if( osWord[strlen(osWord)-1] == ')' )
210 54 : break;
211 54 : }
212 : }
213 :
214 : // Handle value lists like: Name = {Red, Red}
215 992 : else if( *pszHeaderNext == '{' )
216 : {
217 2 : CPLString osWord;
218 :
219 16 : while( ReadWord( osWord ) )
220 : {
221 14 : SkipWhite();
222 :
223 14 : osValue += osWord;
224 14 : if( osWord[strlen(osWord)-1] == '}' )
225 2 : break;
226 2 : }
227 : }
228 :
229 : else // Handle more normal "single word" values.
230 : {
231 990 : if( !ReadWord( osValue ) )
232 0 : return FALSE;
233 :
234 : }
235 :
236 1046 : SkipWhite();
237 :
238 : // No units keyword?
239 1046 : if( *pszHeaderNext != '<' )
240 926 : return TRUE;
241 :
242 : // Append units keyword. For lines that like like this:
243 : // MAP_RESOLUTION = 4.0 <PIXEL/DEGREE>
244 :
245 120 : CPLString osWord;
246 :
247 120 : osValue += " ";
248 :
249 240 : while( ReadWord( osWord ) )
250 : {
251 120 : SkipWhite();
252 :
253 120 : osValue += osWord;
254 120 : if( osWord[strlen(osWord)-1] == '>' )
255 120 : break;
256 : }
257 :
258 120 : return TRUE;
259 : }
260 :
261 : /************************************************************************/
262 : /* ReadWord() */
263 : /* Returns TRUE on success */
264 : /************************************************************************/
265 :
266 2444 : int NASAKeywordHandler::ReadWord( CPLString &osWord )
267 :
268 : {
269 2444 : osWord = "";
270 :
271 2444 : SkipWhite();
272 :
273 4888 : 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 2444 : if( *pszHeaderNext == '"' )
282 : {
283 240 : osWord += *(pszHeaderNext++);
284 4803 : while( *pszHeaderNext != '"' )
285 : {
286 4323 : if( *pszHeaderNext == '\0' )
287 0 : return FALSE;
288 4323 : if( *pszHeaderNext == '\n' )
289 : {
290 18 : osWord += "\\n";
291 18 : pszHeaderNext++;
292 18 : continue;
293 : }
294 4305 : if( *pszHeaderNext == '\r' )
295 : {
296 16 : osWord += "\\r";
297 16 : pszHeaderNext++;
298 16 : continue;
299 : }
300 4289 : osWord += *(pszHeaderNext++);
301 : }
302 240 : osWord += *(pszHeaderNext++);
303 240 : 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 2204 : if( *pszHeaderNext == '\'' )
313 : {
314 0 : osWord += *(pszHeaderNext++);
315 0 : while( *pszHeaderNext != '\'' )
316 : {
317 0 : if( *pszHeaderNext == '\0' )
318 0 : return FALSE;
319 :
320 0 : osWord += *(pszHeaderNext++);
321 : }
322 0 : osWord += *(pszHeaderNext++);
323 0 : 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 29189 : while( *pszHeaderNext != '\0'
334 : && *pszHeaderNext != '='
335 : && !isspace((unsigned char)*pszHeaderNext) )
336 : {
337 24781 : osWord += *pszHeaderNext;
338 24781 : pszHeaderNext++;
339 :
340 24781 : if( *pszHeaderNext == '-'
341 : && (pszHeaderNext[1] == 10 || pszHeaderNext[1] == 13) )
342 : {
343 0 : pszHeaderNext += 2;
344 0 : SkipWhite();
345 : }
346 : }
347 :
348 2204 : return TRUE;
349 : }
350 :
351 : /************************************************************************/
352 : /* SkipWhite() */
353 : /* Skip white spaces and C style comments */
354 : /************************************************************************/
355 :
356 23384 : void NASAKeywordHandler::SkipWhite()
357 :
358 : {
359 17394 : for( ; TRUE; )
360 : {
361 : // Skip C style comments
362 23384 : if( *pszHeaderNext == '/' && pszHeaderNext[1] == '*' )
363 : {
364 136 : pszHeaderNext += 2;
365 :
366 7287 : while( *pszHeaderNext != '\0'
367 : && (*pszHeaderNext != '*'
368 : || pszHeaderNext[1] != '/' ) )
369 : {
370 7015 : pszHeaderNext++;
371 : }
372 :
373 136 : pszHeaderNext += 2;
374 136 : continue;
375 : }
376 :
377 : // Skip # style comments
378 23248 : if( (*pszHeaderNext == 10 || *pszHeaderNext == 13 ||
379 : *pszHeaderNext == ' ' || *pszHeaderNext == '\t' )
380 : && pszHeaderNext[1] == '#' )
381 : {
382 4 : pszHeaderNext += 2;
383 :
384 : // consume till end of line.
385 216 : while( *pszHeaderNext != '\0'
386 : && *pszHeaderNext != 10
387 : && *pszHeaderNext != 13 )
388 : {
389 208 : pszHeaderNext++;
390 : }
391 4 : continue;
392 : }
393 :
394 : // Skip white space (newline, space, tab, etc )
395 23244 : if( isspace( (unsigned char)*pszHeaderNext ) )
396 : {
397 17254 : pszHeaderNext++;
398 17254 : continue;
399 : }
400 :
401 : // not white space, return.
402 : return;
403 : }
404 : }
405 :
406 : /************************************************************************/
407 : /* GetKeyword() */
408 : /************************************************************************/
409 :
410 : const char *NASAKeywordHandler::GetKeyword( const char *pszPath,
411 461 : const char *pszDefault )
412 :
413 : {
414 : const char *pszResult;
415 :
416 461 : pszResult = CSLFetchNameValue( papszKeywordList, pszPath );
417 461 : if( pszResult == NULL )
418 162 : return pszDefault;
419 : else
420 299 : return pszResult;
421 : }
422 :
|