1 : /******************************************************************************
2 : * $Id: cplkeywordparser.cpp 20996 2010-10-28 18:38:15Z rouault $
3 : *
4 : * Project: Common Portability Library
5 : * Purpose: Implementation of CPLKeywordParser - a class for parsing
6 : * the keyword format used for files like QuickBird .RPB files.
7 : * This is a slight variation on the NASAKeywordParser used for
8 : * the PDS/ISIS2/ISIS3 formats.
9 : * Author: Frank Warmerdam <warmerdam@pobox.com
10 : *
11 : ******************************************************************************
12 : * Copyright (c) 2008, Frank Warmerdam <warmerdam@pobox.com>
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining a
15 : * copy of this software and associated documentation files (the "Software"),
16 : * to deal in the Software without restriction, including without limitation
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 : * and/or sell copies of the Software, and to permit persons to whom the
19 : * Software is furnished to do so, subject to the following conditions:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 : * DEALINGS IN THE SOFTWARE.
31 : ****************************************************************************/
32 :
33 : #include "cpl_string.h"
34 : #include "cplkeywordparser.h"
35 :
36 : CPL_CVSID("$Id");
37 :
38 : /************************************************************************/
39 : /* ==================================================================== */
40 : /* CPLKeywordParser */
41 : /* ==================================================================== */
42 : /************************************************************************/
43 :
44 : /************************************************************************/
45 : /* CPLKeywordParser() */
46 : /************************************************************************/
47 :
48 20 : CPLKeywordParser::CPLKeywordParser()
49 :
50 : {
51 20 : papszKeywordList = NULL;
52 20 : }
53 :
54 : /************************************************************************/
55 : /* ~CPLKeywordParser() */
56 : /************************************************************************/
57 :
58 20 : CPLKeywordParser::~CPLKeywordParser()
59 :
60 : {
61 20 : CSLDestroy( papszKeywordList );
62 20 : papszKeywordList = NULL;
63 20 : }
64 :
65 : /************************************************************************/
66 : /* Ingest() */
67 : /************************************************************************/
68 :
69 76 : int CPLKeywordParser::Ingest( VSILFILE *fp )
70 :
71 : {
72 : /* -------------------------------------------------------------------- */
73 : /* Read in buffer till we find END all on it's own line. */
74 : /* -------------------------------------------------------------------- */
75 56 : for( ; TRUE; )
76 : {
77 : const char *pszCheck;
78 : char szChunk[513];
79 :
80 76 : int nBytesRead = VSIFReadL( szChunk, 1, 512, fp );
81 :
82 76 : szChunk[nBytesRead] = '\0';
83 76 : osHeaderText += szChunk;
84 :
85 76 : if( nBytesRead < 512 )
86 20 : break;
87 :
88 56 : if( osHeaderText.size() > 520 )
89 40 : pszCheck = osHeaderText.c_str() + (osHeaderText.size() - 520);
90 : else
91 16 : pszCheck = szChunk;
92 :
93 56 : if( strstr(pszCheck,"\r\nEND;\r\n") != NULL
94 : || strstr(pszCheck,"\nEND;\n") != NULL )
95 0 : break;
96 : }
97 :
98 20 : pszHeaderNext = osHeaderText.c_str();
99 :
100 : /* -------------------------------------------------------------------- */
101 : /* Process name/value pairs, keeping track of a "path stack". */
102 : /* -------------------------------------------------------------------- */
103 20 : return ReadGroup( "" );
104 : }
105 :
106 : /************************************************************************/
107 : /* ReadGroup() */
108 : /************************************************************************/
109 :
110 52 : int CPLKeywordParser::ReadGroup( const char *pszPathPrefix )
111 :
112 : {
113 52 : CPLString osName, osValue;
114 :
115 898 : for( ; TRUE; )
116 : {
117 950 : if( !ReadPair( osName, osValue ) )
118 0 : return FALSE;
119 :
120 950 : if( EQUAL(osName,"BEGIN_GROUP") )
121 : {
122 32 : if( !ReadGroup( (CPLString(pszPathPrefix) + osValue + ".").c_str() ) )
123 0 : return FALSE;
124 : }
125 918 : else if( EQUALN(osName,"END",3) )
126 : {
127 52 : return TRUE;
128 : }
129 : else
130 : {
131 866 : osName = pszPathPrefix + osName;
132 : papszKeywordList = CSLSetNameValue( papszKeywordList,
133 866 : osName, osValue );
134 : }
135 0 : }
136 : }
137 :
138 : /************************************************************************/
139 : /* ReadPair() */
140 : /* */
141 : /* Read a name/value pair from the input stream. Strip off */
142 : /* white space, ignore comments, split on '='. */
143 : /************************************************************************/
144 :
145 950 : int CPLKeywordParser::ReadPair( CPLString &osName, CPLString &osValue )
146 :
147 : {
148 950 : osName = "";
149 1900 : osValue = "";
150 :
151 950 : if( !ReadWord( osName ) )
152 0 : return FALSE;
153 :
154 950 : SkipWhite();
155 :
156 950 : if( EQUAL(osName,"END") )
157 20 : return TRUE;
158 :
159 930 : if( *pszHeaderNext != '=' )
160 : {
161 : // ISIS3 does not have anything after the end group/object keyword.
162 0 : if( EQUAL(osName,"End_Group") || EQUAL(osName,"End_Object") )
163 0 : return TRUE;
164 : else
165 0 : return FALSE;
166 : }
167 :
168 930 : pszHeaderNext++;
169 :
170 930 : SkipWhite();
171 :
172 930 : osValue = "";
173 :
174 : // Handle value lists like: Name = (Red, Red)
175 : // or list of lists like : TLCList = ( (0, 0.000000), (8299, 4.811014) );
176 930 : if( *pszHeaderNext == '(' )
177 : {
178 48 : CPLString osWord;
179 48 : int nDepth = 0;
180 48 : const char* pszLastPos = pszHeaderNext;
181 :
182 896 : while( ReadWord( osWord ) && pszLastPos != pszHeaderNext)
183 : {
184 848 : SkipWhite();
185 848 : pszLastPos = pszHeaderNext;
186 :
187 848 : osValue += osWord;
188 848 : const char* pszIter = osWord.c_str();
189 848 : int bInQuote = FALSE;
190 12240 : while(*pszIter != '\0')
191 : {
192 10592 : if (*pszIter == '"')
193 0 : bInQuote = !bInQuote;
194 10592 : else if (!bInQuote)
195 : {
196 10592 : if (*pszIter == '(')
197 48 : nDepth ++;
198 10544 : else if (*pszIter == ')')
199 : {
200 48 : nDepth --;
201 48 : if (nDepth == 0)
202 48 : break;
203 : }
204 : }
205 10544 : pszIter ++;
206 : }
207 848 : if (*pszIter == ')' && nDepth == 0)
208 48 : break;
209 48 : }
210 : }
211 :
212 : else // Handle more normal "single word" values.
213 : {
214 882 : if( !ReadWord( osValue ) )
215 0 : return FALSE;
216 :
217 : }
218 :
219 930 : SkipWhite();
220 :
221 : // No units keyword?
222 930 : if( *pszHeaderNext != '<' )
223 930 : return TRUE;
224 :
225 : // Append units keyword. For lines that like like this:
226 : // MAP_RESOLUTION = 4.0 <PIXEL/DEGREE>
227 :
228 0 : CPLString osWord;
229 :
230 0 : osValue += " ";
231 :
232 0 : while( ReadWord( osWord ) )
233 : {
234 0 : SkipWhite();
235 :
236 0 : osValue += osWord;
237 0 : if( osWord[strlen(osWord)-1] == '>' )
238 0 : break;
239 : }
240 :
241 0 : return TRUE;
242 : }
243 :
244 : /************************************************************************/
245 : /* ReadWord() */
246 : /************************************************************************/
247 :
248 2680 : int CPLKeywordParser::ReadWord( CPLString &osWord )
249 :
250 : {
251 2680 : osWord = "";
252 :
253 2680 : SkipWhite();
254 :
255 2680 : if( pszHeaderNext == '\0' )
256 0 : return FALSE;
257 :
258 30822 : while( *pszHeaderNext != '\0'
259 : && *pszHeaderNext != '='
260 : && *pszHeaderNext != ';'
261 : && !isspace((unsigned char)*pszHeaderNext) )
262 : {
263 25462 : if( *pszHeaderNext == '"' )
264 : {
265 202 : osWord += *(pszHeaderNext++);
266 1516 : while( *pszHeaderNext != '"' )
267 : {
268 1112 : if( *pszHeaderNext == '\0' )
269 0 : return FALSE;
270 :
271 1112 : osWord += *(pszHeaderNext++);
272 : }
273 202 : osWord += *(pszHeaderNext++);
274 : }
275 25260 : else if( *pszHeaderNext == '\'' )
276 : {
277 0 : osWord += *(pszHeaderNext++);
278 0 : while( *pszHeaderNext != '\'' )
279 : {
280 0 : if( *pszHeaderNext == '\0' )
281 0 : return FALSE;
282 :
283 0 : osWord += *(pszHeaderNext++);
284 : }
285 0 : osWord += *(pszHeaderNext++);
286 : }
287 : else
288 : {
289 25260 : osWord += *pszHeaderNext;
290 25260 : pszHeaderNext++;
291 : }
292 : }
293 :
294 2680 : if( *pszHeaderNext == ';' )
295 868 : pszHeaderNext++;
296 :
297 2680 : return TRUE;
298 : }
299 :
300 : /************************************************************************/
301 : /* SkipWhite() */
302 : /************************************************************************/
303 :
304 13202 : void CPLKeywordParser::SkipWhite()
305 :
306 : {
307 6864 : for( ; TRUE; )
308 : {
309 : // Skip white space (newline, space, tab, etc )
310 13202 : if( isspace( (unsigned char)*pszHeaderNext ) )
311 : {
312 6864 : pszHeaderNext++;
313 6864 : continue;
314 : }
315 :
316 : // Skip C style comments
317 6338 : if( *pszHeaderNext == '/' && pszHeaderNext[1] == '*' )
318 : {
319 0 : pszHeaderNext += 2;
320 :
321 0 : while( *pszHeaderNext != '\0'
322 : && (*pszHeaderNext != '*'
323 0 : || pszHeaderNext[1] != '/' ) )
324 : {
325 0 : pszHeaderNext++;
326 : }
327 :
328 0 : pszHeaderNext += 2;
329 0 : continue;
330 : }
331 :
332 : // Skip # style comments
333 6338 : if( *pszHeaderNext == '#' )
334 : {
335 0 : pszHeaderNext += 1;
336 :
337 : // consume till end of line.
338 0 : while( *pszHeaderNext != '\0'
339 : && *pszHeaderNext != 10
340 : && *pszHeaderNext != 13 )
341 : {
342 0 : pszHeaderNext++;
343 : }
344 0 : continue;
345 : }
346 :
347 : // not white space, return.
348 : return;
349 : }
350 : }
351 :
352 : /************************************************************************/
353 : /* GetKeyword() */
354 : /************************************************************************/
355 :
356 112 : const char *CPLKeywordParser::GetKeyword( const char *pszPath,
357 : const char *pszDefault )
358 :
359 : {
360 : const char *pszResult;
361 :
362 112 : pszResult = CSLFetchNameValue( papszKeywordList, pszPath );
363 112 : if( pszResult == NULL )
364 0 : return pszDefault;
365 : else
366 112 : return pszResult;
367 : }
368 :
|