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 40 : CPLKeywordParser::CPLKeywordParser()
49 :
50 : {
51 40 : papszKeywordList = NULL;
52 40 : }
53 :
54 : /************************************************************************/
55 : /* ~CPLKeywordParser() */
56 : /************************************************************************/
57 :
58 40 : CPLKeywordParser::~CPLKeywordParser()
59 :
60 : {
61 40 : CSLDestroy( papszKeywordList );
62 40 : papszKeywordList = NULL;
63 40 : }
64 :
65 : /************************************************************************/
66 : /* Ingest() */
67 : /************************************************************************/
68 :
69 152 : int CPLKeywordParser::Ingest( VSILFILE *fp )
70 :
71 : {
72 : /* -------------------------------------------------------------------- */
73 : /* Read in buffer till we find END all on it's own line. */
74 : /* -------------------------------------------------------------------- */
75 112 : for( ; TRUE; )
76 : {
77 : const char *pszCheck;
78 : char szChunk[513];
79 :
80 152 : int nBytesRead = VSIFReadL( szChunk, 1, 512, fp );
81 :
82 152 : szChunk[nBytesRead] = '\0';
83 152 : osHeaderText += szChunk;
84 :
85 152 : if( nBytesRead < 512 )
86 40 : break;
87 :
88 112 : if( osHeaderText.size() > 520 )
89 80 : pszCheck = osHeaderText.c_str() + (osHeaderText.size() - 520);
90 : else
91 32 : pszCheck = szChunk;
92 :
93 112 : if( strstr(pszCheck,"\r\nEND;\r\n") != NULL
94 : || strstr(pszCheck,"\nEND;\n") != NULL )
95 0 : break;
96 : }
97 :
98 40 : pszHeaderNext = osHeaderText.c_str();
99 :
100 : /* -------------------------------------------------------------------- */
101 : /* Process name/value pairs, keeping track of a "path stack". */
102 : /* -------------------------------------------------------------------- */
103 40 : return ReadGroup( "" );
104 : }
105 :
106 : /************************************************************************/
107 : /* ReadGroup() */
108 : /************************************************************************/
109 :
110 104 : int CPLKeywordParser::ReadGroup( const char *pszPathPrefix )
111 :
112 : {
113 104 : CPLString osName, osValue;
114 :
115 1796 : for( ; TRUE; )
116 : {
117 1900 : if( !ReadPair( osName, osValue ) )
118 0 : return FALSE;
119 :
120 1900 : if( EQUAL(osName,"BEGIN_GROUP") )
121 : {
122 64 : if( !ReadGroup( (CPLString(pszPathPrefix) + osValue + ".").c_str() ) )
123 0 : return FALSE;
124 : }
125 1836 : else if( EQUALN(osName,"END",3) )
126 : {
127 104 : return TRUE;
128 : }
129 : else
130 : {
131 1732 : osName = pszPathPrefix + osName;
132 : papszKeywordList = CSLSetNameValue( papszKeywordList,
133 1732 : 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 1900 : int CPLKeywordParser::ReadPair( CPLString &osName, CPLString &osValue )
146 :
147 : {
148 1900 : osName = "";
149 3800 : osValue = "";
150 :
151 1900 : if( !ReadWord( osName ) )
152 0 : return FALSE;
153 :
154 1900 : SkipWhite();
155 :
156 1900 : if( EQUAL(osName,"END") )
157 40 : return TRUE;
158 :
159 1860 : 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 1860 : pszHeaderNext++;
169 :
170 1860 : SkipWhite();
171 :
172 1860 : osValue = "";
173 :
174 : // Handle value lists like: Name = (Red, Red)
175 : // or list of lists like : TLCList = ( (0, 0.000000), (8299, 4.811014) );
176 1860 : if( *pszHeaderNext == '(' )
177 : {
178 96 : CPLString osWord;
179 96 : int nDepth = 0;
180 96 : const char* pszLastPos = pszHeaderNext;
181 :
182 1792 : while( ReadWord( osWord ) && pszLastPos != pszHeaderNext)
183 : {
184 1696 : SkipWhite();
185 1696 : pszLastPos = pszHeaderNext;
186 :
187 1696 : osValue += osWord;
188 1696 : const char* pszIter = osWord.c_str();
189 1696 : int bInQuote = FALSE;
190 24480 : while(*pszIter != '\0')
191 : {
192 21184 : if (*pszIter == '"')
193 0 : bInQuote = !bInQuote;
194 21184 : else if (!bInQuote)
195 : {
196 21184 : if (*pszIter == '(')
197 96 : nDepth ++;
198 21088 : else if (*pszIter == ')')
199 : {
200 96 : nDepth --;
201 96 : if (nDepth == 0)
202 96 : break;
203 : }
204 : }
205 21088 : pszIter ++;
206 : }
207 1696 : if (*pszIter == ')' && nDepth == 0)
208 96 : break;
209 96 : }
210 : }
211 :
212 : else // Handle more normal "single word" values.
213 : {
214 1764 : if( !ReadWord( osValue ) )
215 0 : return FALSE;
216 :
217 : }
218 :
219 1860 : SkipWhite();
220 :
221 : // No units keyword?
222 1860 : if( *pszHeaderNext != '<' )
223 1860 : 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 5360 : int CPLKeywordParser::ReadWord( CPLString &osWord )
249 :
250 : {
251 5360 : osWord = "";
252 :
253 5360 : SkipWhite();
254 :
255 5360 : if( pszHeaderNext == '\0' )
256 0 : return FALSE;
257 :
258 61644 : while( *pszHeaderNext != '\0'
259 : && *pszHeaderNext != '='
260 : && *pszHeaderNext != ';'
261 : && !isspace((unsigned char)*pszHeaderNext) )
262 : {
263 50924 : if( *pszHeaderNext == '"' )
264 : {
265 404 : osWord += *(pszHeaderNext++);
266 3032 : while( *pszHeaderNext != '"' )
267 : {
268 2224 : if( *pszHeaderNext == '\0' )
269 0 : return FALSE;
270 :
271 2224 : osWord += *(pszHeaderNext++);
272 : }
273 404 : osWord += *(pszHeaderNext++);
274 : }
275 50520 : 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 50520 : osWord += *pszHeaderNext;
290 50520 : pszHeaderNext++;
291 : }
292 : }
293 :
294 5360 : if( *pszHeaderNext == ';' )
295 1736 : pszHeaderNext++;
296 :
297 5360 : return TRUE;
298 : }
299 :
300 : /************************************************************************/
301 : /* SkipWhite() */
302 : /************************************************************************/
303 :
304 26404 : void CPLKeywordParser::SkipWhite()
305 :
306 : {
307 13728 : for( ; TRUE; )
308 : {
309 : // Skip white space (newline, space, tab, etc )
310 26404 : if( isspace( (unsigned char)*pszHeaderNext ) )
311 : {
312 13728 : pszHeaderNext++;
313 13728 : continue;
314 : }
315 :
316 : // Skip C style comments
317 12676 : 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 12676 : 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 224 : const char *CPLKeywordParser::GetKeyword( const char *pszPath,
357 : const char *pszDefault )
358 :
359 : {
360 : const char *pszResult;
361 :
362 224 : pszResult = CSLFetchNameValue( papszKeywordList, pszPath );
363 224 : if( pszResult == NULL )
364 0 : return pszDefault;
365 : else
366 224 : return pszResult;
367 : }
368 :
|