1 : /**********************************************************************
2 : * $Id: gmlhandler.cpp 13760 2008-02-11 17:48:30Z warmerdam $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Implementation of NASHandler class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include <ctype.h>
31 : #include "nasreaderp.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_string.h"
34 :
35 : #define MAX_TOKEN_SIZE 1000
36 :
37 : /************************************************************************/
38 : /* NASHandler() */
39 : /************************************************************************/
40 :
41 2 : NASHandler::NASHandler( NASReader *poReader )
42 :
43 : {
44 2 : m_poReader = poReader;
45 2 : m_pszCurField = NULL;
46 2 : m_pszGeometry = NULL;
47 2 : m_nGeomAlloc = m_nGeomLen = 0;
48 2 : }
49 :
50 : /************************************************************************/
51 : /* ~NASHandler() */
52 : /************************************************************************/
53 :
54 2 : NASHandler::~NASHandler()
55 :
56 : {
57 2 : CPLFree( m_pszCurField );
58 2 : CPLFree( m_pszGeometry );
59 2 : }
60 :
61 :
62 : /************************************************************************/
63 : /* startElement() */
64 : /************************************************************************/
65 :
66 : void NASHandler::startElement(const XMLCh* const uri,
67 : const XMLCh* const localname,
68 : const XMLCh* const qname,
69 1041361 : const Attributes& attrs )
70 :
71 : {
72 : char szElementName[MAX_TOKEN_SIZE];
73 1041361 : GMLReadState *poState = m_poReader->GetState();
74 :
75 1041361 : tr_strcpy( szElementName, localname );
76 :
77 : /* -------------------------------------------------------------------- */
78 : /* If we are in the midst of collecting a feature attribute */
79 : /* value, then this must be a complex attribute which we don't */
80 : /* try to collect for now, so just terminate the field */
81 : /* collection. */
82 : /* -------------------------------------------------------------------- */
83 1041361 : if( m_pszCurField != NULL )
84 : {
85 0 : CPLFree( m_pszCurField );
86 0 : m_pszCurField = NULL;
87 : }
88 :
89 : /* -------------------------------------------------------------------- */
90 : /* If we are collecting geometry, or if we determine this is a */
91 : /* geometry element then append to the geometry info. */
92 : /* -------------------------------------------------------------------- */
93 1041361 : if( m_pszGeometry != NULL
94 : || IsGeometryElement( szElementName ) )
95 : {
96 864543 : int nLNLen = tr_strlen( localname );
97 :
98 : /* should save attributes too! */
99 :
100 864543 : if( m_pszGeometry == NULL )
101 12559 : m_nGeometryDepth = poState->m_nPathLength;
102 :
103 864543 : if( m_nGeomLen + nLNLen + 4 > m_nGeomAlloc )
104 : {
105 12635 : m_nGeomAlloc = (int) (m_nGeomAlloc * 1.3 + nLNLen + 1000);
106 : m_pszGeometry = (char *)
107 12635 : CPLRealloc( m_pszGeometry, m_nGeomAlloc);
108 : }
109 :
110 864543 : strcpy( m_pszGeometry+m_nGeomLen, "<" );
111 864543 : tr_strcpy( m_pszGeometry+m_nGeomLen+1, localname );
112 864543 : strcat( m_pszGeometry+m_nGeomLen+nLNLen+1, ">" );
113 864543 : m_nGeomLen += strlen(m_pszGeometry+m_nGeomLen);
114 : }
115 :
116 : /* -------------------------------------------------------------------- */
117 : /* Is it a feature? If so push a whole new state, and return. */
118 : /* -------------------------------------------------------------------- */
119 176818 : else if( m_poReader->IsFeatureElement( szElementName ) )
120 : {
121 16647 : m_poReader->PushFeature( szElementName, attrs );
122 16647 : return;
123 : }
124 :
125 : /* -------------------------------------------------------------------- */
126 : /* If it is (or at least potentially is) a simple attribute, */
127 : /* then start collecting it. */
128 : /* -------------------------------------------------------------------- */
129 160171 : else if( m_poReader->IsAttributeElement( szElementName ) )
130 : {
131 63073 : CPLFree( m_pszCurField );
132 63073 : m_pszCurField = CPLStrdup("");
133 :
134 : // Capture href as OB property.
135 63073 : m_poReader->CheckForRelations( szElementName, attrs );
136 : }
137 :
138 : /* -------------------------------------------------------------------- */
139 : /* Push the element onto the current state's path. */
140 : /* -------------------------------------------------------------------- */
141 1024714 : poState->PushPath( szElementName );
142 : }
143 :
144 : /************************************************************************/
145 : /* endElement() */
146 : /************************************************************************/
147 : void NASHandler::endElement(const XMLCh* const uri,
148 : const XMLCh* const localname,
149 1041358 : const XMLCh* const qname )
150 :
151 : {
152 : char szElementName[MAX_TOKEN_SIZE];
153 1041358 : GMLReadState *poState = m_poReader->GetState();
154 :
155 1041358 : tr_strcpy( szElementName, localname );
156 :
157 : /* -------------------------------------------------------------------- */
158 : /* Is this closing off an attribute value? We assume so if */
159 : /* we are collecting an attribute value and got to this point. */
160 : /* We don't bother validating that the closing tag matches the */
161 : /* opening tag. */
162 : /* -------------------------------------------------------------------- */
163 1041358 : if( m_pszCurField != NULL )
164 : {
165 63073 : CPLAssert( poState->m_poFeature != NULL );
166 :
167 63073 : m_poReader->SetFeatureProperty( poState->m_pszPath, m_pszCurField );
168 63073 : CPLFree( m_pszCurField );
169 63073 : m_pszCurField = NULL;
170 : }
171 :
172 : /* -------------------------------------------------------------------- */
173 : /* If we are collecting Geometry than store it, and consider if */
174 : /* this is the end of the geometry. */
175 : /* -------------------------------------------------------------------- */
176 1041358 : if( m_pszGeometry != NULL )
177 : {
178 864543 : int nLNLen = tr_strlen( localname );
179 :
180 : /* should save attributes too! */
181 :
182 864543 : if( m_nGeomLen + nLNLen + 4 > m_nGeomAlloc )
183 : {
184 2 : m_nGeomAlloc = (int) (m_nGeomAlloc * 1.3 + nLNLen + 1000);
185 : m_pszGeometry = (char *)
186 2 : CPLRealloc( m_pszGeometry, m_nGeomAlloc);
187 : }
188 :
189 864543 : strcat( m_pszGeometry+m_nGeomLen, "</" );
190 864543 : tr_strcpy( m_pszGeometry+m_nGeomLen+2, localname );
191 864543 : strcat( m_pszGeometry+m_nGeomLen+nLNLen+2, ">" );
192 864543 : m_nGeomLen += strlen(m_pszGeometry+m_nGeomLen);
193 :
194 864543 : if( poState->m_nPathLength == m_nGeometryDepth+1 )
195 : {
196 12559 : if( poState->m_poFeature != NULL )
197 12559 : poState->m_poFeature->SetGeometryDirectly( m_pszGeometry );
198 : else
199 0 : CPLFree( m_pszGeometry );
200 :
201 12559 : m_pszGeometry = NULL;
202 12559 : m_nGeomAlloc = m_nGeomLen = 0;
203 : }
204 : }
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* If we are collecting a feature, and this element tag matches */
208 : /* element name for the class, then we have finished the */
209 : /* feature, and we pop the feature read state. */
210 : /* -------------------------------------------------------------------- */
211 1041358 : if( poState->m_poFeature != NULL
212 : && EQUAL(szElementName,
213 : poState->m_poFeature->GetClass()->GetElementName()) )
214 : {
215 16647 : m_poReader->PopState();
216 : }
217 :
218 : /* -------------------------------------------------------------------- */
219 : /* Otherwise, we just pop the element off the local read states */
220 : /* element stack. */
221 : /* -------------------------------------------------------------------- */
222 : else
223 : {
224 1024711 : if( EQUAL(szElementName,poState->GetLastComponent()) )
225 1024711 : poState->PopPath();
226 : else
227 : {
228 0 : CPLAssert( FALSE );
229 : }
230 : }
231 1041358 : }
232 :
233 : /************************************************************************/
234 : /* characters() */
235 : /************************************************************************/
236 :
237 : #if XERCES_VERSION_MAJOR >= 3
238 : void NASHandler::characters( const XMLCh *const chars_in,
239 : const XMLSize_t length )
240 : #else
241 : void NASHandler::characters(const XMLCh* const chars_in,
242 2079791 : const unsigned int length )
243 : #endif
244 :
245 : {
246 2079791 : const XMLCh *chars = chars_in;
247 :
248 2079791 : if( m_pszCurField != NULL )
249 : {
250 59401 : int nCurFieldLength = strlen(m_pszCurField);
251 :
252 118802 : while( *chars == ' ' || *chars == 10 || *chars == 13 || *chars == '\t')
253 0 : chars++;
254 :
255 59401 : char *pszTranslated = tr_strdup(chars);
256 :
257 59401 : if( m_pszCurField == NULL )
258 : {
259 0 : m_pszCurField = pszTranslated;
260 0 : nCurFieldLength = strlen(m_pszCurField);
261 : }
262 : else
263 : {
264 : m_pszCurField = (char *)
265 : CPLRealloc( m_pszCurField,
266 59401 : nCurFieldLength+strlen(pszTranslated)+1 );
267 59401 : strcpy( m_pszCurField + nCurFieldLength, pszTranslated );
268 59401 : CPLFree( pszTranslated );
269 : }
270 : }
271 2020390 : else if( m_pszGeometry != NULL )
272 : {
273 : // Ignore white space
274 36830384 : while( *chars == ' ' || *chars == 10 || *chars == 13 || *chars == '\t')
275 33397330 : chars++;
276 :
277 1716527 : int nCharsLen = tr_strlen(chars);
278 :
279 1716527 : if( m_nGeomLen + nCharsLen*4 + 4 > m_nGeomAlloc )
280 : {
281 11807 : m_nGeomAlloc = (int) (m_nGeomAlloc * 1.3 + nCharsLen*4 + 1000);
282 : m_pszGeometry = (char *)
283 11807 : CPLRealloc( m_pszGeometry, m_nGeomAlloc);
284 : }
285 :
286 1716527 : tr_strcpy( m_pszGeometry+m_nGeomLen, chars );
287 1716527 : m_nGeomLen += strlen(m_pszGeometry+m_nGeomLen);
288 : }
289 2079791 : }
290 :
291 : /************************************************************************/
292 : /* fatalError() */
293 : /************************************************************************/
294 :
295 0 : void NASHandler::fatalError( const SAXParseException &exception)
296 :
297 : {
298 : char *pszErrorMessage;
299 :
300 0 : pszErrorMessage = tr_strdup( exception.getMessage() );
301 : CPLError( CE_Failure, CPLE_AppDefined,
302 : "XML Parsing Error: %s\n",
303 0 : pszErrorMessage );
304 :
305 0 : CPLFree( pszErrorMessage );
306 0 : }
307 :
308 : /************************************************************************/
309 : /* IsGeometryElement() */
310 : /************************************************************************/
311 :
312 189377 : int NASHandler::IsGeometryElement( const char *pszElement )
313 :
314 : {
315 : return strcmp(pszElement,"Polygon") == 0
316 : || strcmp(pszElement,"MultiPolygon") == 0
317 : || strcmp(pszElement,"MultiPoint") == 0
318 : || strcmp(pszElement,"MultiLineString") == 0
319 : || strcmp(pszElement,"MultiSurface") == 0
320 : || strcmp(pszElement,"GeometryCollection") == 0
321 : || strcmp(pszElement,"Point") == 0
322 : || strcmp(pszElement,"Curve") == 0
323 : || strcmp(pszElement,"Surface") == 0
324 : || strcmp(pszElement,"PolygonPatch") == 0
325 189377 : || strcmp(pszElement,"LineString") == 0;
326 : }
|