1 : /******************************************************************************
2 : * $Id: ogr2gmlgeometry.cpp 18025 2009-11-14 19:09:50Z rouault $
3 : *
4 : * Project: GML Translator
5 : * Purpose: Code to translate OGRGeometry to GML string representation.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
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 : * Independent Security Audit 2003/04/17 Andrey Kiselev:
31 : * Completed audit of this module. All functions may be used without buffer
32 : * overflows and stack corruptions if caller could be trusted.
33 : *
34 : * Security Audit 2003/03/28 warmerda:
35 : * Completed security audit. I believe that this module may be safely used
36 : * to generate GML from arbitrary but well formed OGRGeomety objects that
37 : * come from a potentially hostile source, but through a trusted OGR importer
38 : * without compromising the system.
39 : *
40 : */
41 :
42 : #include "cpl_minixml.h"
43 : #include "ogr_geometry.h"
44 : #include "ogr_api.h"
45 : #include "ogr_p.h"
46 : #include "cpl_error.h"
47 : #include "cpl_conv.h"
48 :
49 : /************************************************************************/
50 : /* MakeGMLCoordinate() */
51 : /************************************************************************/
52 :
53 157 : static void MakeGMLCoordinate( char *pszTarget,
54 : double x, double y, double z, int b3D )
55 :
56 : {
57 157 : OGRMakeWktCoordinate( pszTarget, x, y, z, b3D ? 3 : 2 );
58 4110 : while( *pszTarget != '\0' )
59 : {
60 3796 : if( *pszTarget == ' ' )
61 180 : *pszTarget = ',';
62 3796 : pszTarget++;
63 : }
64 :
65 : #ifdef notdef
66 : if( !b3D )
67 : {
68 : if( x == (int) x && y == (int) y )
69 : sprintf( pszTarget, "%d,%d", (int) x, (int) y );
70 : else if( fabs(x) < 370 && fabs(y) < 370 )
71 : sprintf( pszTarget, "%.16g,%.16g", x, y );
72 : else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0 )
73 : sprintf( pszTarget, "%.16g,%.16g", x, y );
74 : else
75 : sprintf( pszTarget, "%.3f,%.3f", x, y );
76 : }
77 : else
78 : {
79 : if( x == (int) x && y == (int) y && z == (int) z )
80 : sprintf( pszTarget, "%d,%d,%d", (int) x, (int) y, (int) z );
81 : else if( fabs(x) < 370 && fabs(y) < 370 )
82 : sprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
83 : else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0
84 : || fabs(z) > 100000000.0 )
85 : sprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
86 : else
87 : sprintf( pszTarget, "%.3f,%.3f,%.3f", x, y, z );
88 : }
89 : #endif
90 157 : }
91 :
92 : /************************************************************************/
93 : /* _GrowBuffer() */
94 : /************************************************************************/
95 :
96 489 : static void _GrowBuffer( int nNeeded, char **ppszText, int *pnMaxLength )
97 :
98 : {
99 489 : if( nNeeded+1 >= *pnMaxLength )
100 : {
101 117 : *pnMaxLength = MAX(*pnMaxLength * 2,nNeeded+1);
102 117 : *ppszText = (char *) CPLRealloc(*ppszText, *pnMaxLength);
103 : }
104 489 : }
105 :
106 : /************************************************************************/
107 : /* AppendString() */
108 : /************************************************************************/
109 :
110 276 : static void AppendString( char **ppszText, int *pnLength, int *pnMaxLength,
111 : const char *pszTextToAppend )
112 :
113 : {
114 : _GrowBuffer( *pnLength + strlen(pszTextToAppend) + 1,
115 276 : ppszText, pnMaxLength );
116 :
117 276 : strcat( *ppszText + *pnLength, pszTextToAppend );
118 276 : *pnLength += strlen( *ppszText + *pnLength );
119 276 : }
120 :
121 :
122 : /************************************************************************/
123 : /* AppendCoordinateList() */
124 : /************************************************************************/
125 :
126 28 : static void AppendCoordinateList( OGRLineString *poLine,
127 : char **ppszText, int *pnLength,
128 : int *pnMaxLength )
129 :
130 : {
131 : char szCoordinate[256];
132 28 : int b3D = (poLine->getGeometryType() & wkb25DBit);
133 :
134 28 : *pnLength += strlen(*ppszText + *pnLength);
135 28 : _GrowBuffer( *pnLength + 20, ppszText, pnMaxLength );
136 :
137 28 : strcat( *ppszText + *pnLength, "<gml:coordinates>" );
138 28 : *pnLength += strlen(*ppszText + *pnLength);
139 :
140 :
141 164 : for( int iPoint = 0; iPoint < poLine->getNumPoints(); iPoint++ )
142 : {
143 : MakeGMLCoordinate( szCoordinate,
144 : poLine->getX(iPoint),
145 : poLine->getY(iPoint),
146 : poLine->getZ(iPoint),
147 136 : b3D );
148 : _GrowBuffer( *pnLength + strlen(szCoordinate)+1,
149 136 : ppszText, pnMaxLength );
150 :
151 136 : if( iPoint != 0 )
152 108 : strcat( *ppszText + *pnLength, " " );
153 :
154 136 : strcat( *ppszText + *pnLength, szCoordinate );
155 136 : *pnLength += strlen(*ppszText + *pnLength);
156 : }
157 :
158 28 : _GrowBuffer( *pnLength + 20, ppszText, pnMaxLength );
159 28 : strcat( *ppszText + *pnLength, "</gml:coordinates>" );
160 28 : *pnLength += strlen(*ppszText + *pnLength);
161 28 : }
162 :
163 : /************************************************************************/
164 : /* OGR2GMLGeometryAppend() */
165 : /************************************************************************/
166 :
167 70 : static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
168 : char **ppszText, int *pnLength,
169 : int *pnMaxLength,
170 : int bIsSubGeometry )
171 :
172 : {
173 :
174 : /* -------------------------------------------------------------------- */
175 : /* Check for Spatial Reference System attached to given geometry */
176 : /* -------------------------------------------------------------------- */
177 :
178 : // Buffer for srsName attribute (srsName="...")
179 70 : char szSrsName[30] = { 0 };
180 70 : int nSrsNameLength = 0;
181 :
182 70 : const OGRSpatialReference* poSRS = NULL;
183 70 : poSRS = poGeometry->getSpatialReference();
184 :
185 70 : if( NULL != poSRS && !bIsSubGeometry )
186 : {
187 8 : const char* pszAuthName = NULL;
188 8 : const char* pszAuthCode = NULL;
189 8 : const char* pszTarget = NULL;
190 :
191 8 : if (poSRS->IsProjected())
192 0 : pszTarget = "PROJCS";
193 : else
194 8 : pszTarget = "GEOGCS";
195 :
196 8 : pszAuthName = poSRS->GetAuthorityName( pszTarget );
197 8 : if( NULL != pszAuthName )
198 : {
199 8 : if( EQUAL( pszAuthName, "EPSG" ) )
200 : {
201 8 : pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
202 8 : if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
203 : {
204 : sprintf( szSrsName, " srsName=\"%s:%s\"",
205 8 : pszAuthName, pszAuthCode );
206 :
207 8 : nSrsNameLength = strlen(szSrsName);
208 : }
209 : }
210 : }
211 : }
212 :
213 : /* -------------------------------------------------------------------- */
214 : /* 2D Point */
215 : /* -------------------------------------------------------------------- */
216 70 : if( poGeometry->getGeometryType() == wkbPoint )
217 : {
218 : char szCoordinate[256];
219 17 : OGRPoint *poPoint = (OGRPoint *) poGeometry;
220 :
221 : MakeGMLCoordinate( szCoordinate,
222 17 : poPoint->getX(), poPoint->getY(), 0.0, FALSE );
223 :
224 : _GrowBuffer( *pnLength + strlen(szCoordinate) + 60 + nSrsNameLength,
225 17 : ppszText, pnMaxLength );
226 :
227 : sprintf( *ppszText + *pnLength,
228 : "<gml:Point%s><gml:coordinates>%s</gml:coordinates></gml:Point>",
229 17 : szSrsName, szCoordinate );
230 :
231 17 : *pnLength += strlen( *ppszText + *pnLength );
232 : }
233 : /* -------------------------------------------------------------------- */
234 : /* 3D Point */
235 : /* -------------------------------------------------------------------- */
236 53 : else if( poGeometry->getGeometryType() == wkbPoint25D )
237 : {
238 : char szCoordinate[256];
239 4 : OGRPoint *poPoint = (OGRPoint *) poGeometry;
240 :
241 : MakeGMLCoordinate( szCoordinate,
242 : poPoint->getX(), poPoint->getY(), poPoint->getZ(),
243 4 : TRUE );
244 :
245 : _GrowBuffer( *pnLength + strlen(szCoordinate) + 70 + nSrsNameLength,
246 4 : ppszText, pnMaxLength );
247 :
248 : sprintf( *ppszText + *pnLength,
249 : "<gml:Point%s><gml:coordinates>%s</gml:coordinates></gml:Point>",
250 4 : szSrsName, szCoordinate );
251 :
252 4 : *pnLength += strlen( *ppszText + *pnLength );
253 : }
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* LineString and LinearRing */
257 : /* -------------------------------------------------------------------- */
258 75 : else if( poGeometry->getGeometryType() == wkbLineString
259 26 : || poGeometry->getGeometryType() == wkbLineString25D )
260 : {
261 28 : int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING");
262 :
263 : // Buffer for tag name + srsName attribute if set
264 28 : const size_t nLineTagLength = 16;
265 28 : char* pszLineTagName = NULL;
266 28 : pszLineTagName = (char *) CPLMalloc( nLineTagLength + nSrsNameLength + 1 );
267 :
268 28 : if( bRing )
269 : {
270 13 : sprintf( pszLineTagName, "<gml:LinearRing%s>", szSrsName );
271 :
272 : AppendString( ppszText, pnLength, pnMaxLength,
273 13 : pszLineTagName );
274 : }
275 : else
276 : {
277 15 : sprintf( pszLineTagName, "<gml:LineString%s>", szSrsName );
278 :
279 : AppendString( ppszText, pnLength, pnMaxLength,
280 15 : pszLineTagName );
281 : }
282 :
283 : // FREE TAG BUFFER
284 28 : CPLFree( pszLineTagName );
285 :
286 : AppendCoordinateList( (OGRLineString *) poGeometry,
287 28 : ppszText, pnLength, pnMaxLength );
288 :
289 28 : if( bRing )
290 : AppendString( ppszText, pnLength, pnMaxLength,
291 13 : "</gml:LinearRing>" );
292 : else
293 : AppendString( ppszText, pnLength, pnMaxLength,
294 15 : "</gml:LineString>" );
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Polygon */
299 : /* -------------------------------------------------------------------- */
300 33 : else if( poGeometry->getGeometryType() == wkbPolygon
301 12 : || poGeometry->getGeometryType() == wkbPolygon25D )
302 : {
303 11 : OGRPolygon *poPolygon = (OGRPolygon *) poGeometry;
304 :
305 : // Buffer for polygon tag name + srsName attribute if set
306 11 : const size_t nPolyTagLength = 13;
307 11 : char* pszPolyTagName = NULL;
308 11 : pszPolyTagName = (char *) CPLMalloc( nPolyTagLength + nSrsNameLength + 1 );
309 :
310 : // Compose Polygon tag with or without srsName attribute
311 11 : sprintf( pszPolyTagName, "<gml:Polygon%s>", szSrsName );
312 :
313 : AppendString( ppszText, pnLength, pnMaxLength,
314 11 : pszPolyTagName );
315 :
316 : // FREE TAG BUFFER
317 11 : CPLFree( pszPolyTagName );
318 :
319 : // Don't add srsName to polygon rings
320 :
321 11 : if( poPolygon->getExteriorRing() != NULL )
322 : {
323 : AppendString( ppszText, pnLength, pnMaxLength,
324 11 : "<gml:outerBoundaryIs>" );
325 :
326 11 : if( !OGR2GMLGeometryAppend( poPolygon->getExteriorRing(),
327 : ppszText, pnLength, pnMaxLength,
328 : TRUE ) )
329 : {
330 0 : return FALSE;
331 : }
332 :
333 : AppendString( ppszText, pnLength, pnMaxLength,
334 11 : "</gml:outerBoundaryIs>" );
335 : }
336 :
337 13 : for( int iRing = 0; iRing < poPolygon->getNumInteriorRings(); iRing++ )
338 : {
339 2 : OGRLinearRing *poRing = poPolygon->getInteriorRing(iRing);
340 :
341 : AppendString( ppszText, pnLength, pnMaxLength,
342 2 : "<gml:innerBoundaryIs>" );
343 :
344 2 : if( !OGR2GMLGeometryAppend( poRing, ppszText, pnLength,
345 : pnMaxLength, TRUE ) )
346 0 : return FALSE;
347 :
348 : AppendString( ppszText, pnLength, pnMaxLength,
349 2 : "</gml:innerBoundaryIs>" );
350 : }
351 :
352 : AppendString( ppszText, pnLength, pnMaxLength,
353 11 : "</gml:Polygon>" );
354 : }
355 :
356 : /* -------------------------------------------------------------------- */
357 : /* MultiPolygon */
358 : /* -------------------------------------------------------------------- */
359 27 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon
360 8 : || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString
361 6 : || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint
362 3 : || wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection )
363 : {
364 10 : OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
365 : int iMember;
366 10 : const char *pszElemClose = NULL;
367 10 : const char *pszMemberElem = NULL;
368 :
369 : // Buffer for opening tag + srsName attribute
370 10 : char* pszElemOpen = NULL;
371 :
372 10 : if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon )
373 : {
374 2 : pszElemOpen = (char *) CPLMalloc( 13 + nSrsNameLength + 1 );
375 2 : sprintf( pszElemOpen, "MultiPolygon%s>", szSrsName );
376 :
377 2 : pszElemClose = "MultiPolygon>";
378 2 : pszMemberElem = "polygonMember>";
379 : }
380 8 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString )
381 : {
382 2 : pszElemOpen = (char *) CPLMalloc( 16 + nSrsNameLength + 1 );
383 2 : sprintf( pszElemOpen, "MultiLineString%s>", szSrsName );
384 :
385 2 : pszElemClose = "MultiLineString>";
386 2 : pszMemberElem = "lineStringMember>";
387 : }
388 6 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint )
389 : {
390 3 : pszElemOpen = (char *) CPLMalloc( 11 + nSrsNameLength + 1 );
391 3 : sprintf( pszElemOpen, "MultiPoint%s>", szSrsName );
392 :
393 3 : pszElemClose = "MultiPoint>";
394 3 : pszMemberElem = "pointMember>";
395 : }
396 : else
397 : {
398 3 : pszElemOpen = (char *) CPLMalloc( 19 + nSrsNameLength + 1 );
399 3 : sprintf( pszElemOpen, "GeometryCollection%s>", szSrsName );
400 :
401 3 : pszElemClose = "GeometryCollection>";
402 3 : pszMemberElem = "geometryMember>";
403 : }
404 :
405 10 : AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
406 10 : AppendString( ppszText, pnLength, pnMaxLength, pszElemOpen );
407 :
408 43 : for( iMember = 0; iMember < poGC->getNumGeometries(); iMember++)
409 : {
410 33 : OGRGeometry *poMember = poGC->getGeometryRef( iMember );
411 :
412 33 : AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
413 33 : AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );
414 :
415 33 : if( !OGR2GMLGeometryAppend( poMember,
416 : ppszText, pnLength, pnMaxLength,
417 : TRUE ) )
418 : {
419 0 : return FALSE;
420 : }
421 :
422 33 : AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
423 33 : AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );
424 : }
425 :
426 10 : AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
427 10 : AppendString( ppszText, pnLength, pnMaxLength, pszElemClose );
428 :
429 : // FREE TAG BUFFER
430 10 : CPLFree( pszElemOpen );
431 : }
432 : else
433 : {
434 0 : return FALSE;
435 : }
436 :
437 70 : return TRUE;
438 : }
439 :
440 : /************************************************************************/
441 : /* OGR_G_ExportEnvelopeToGMLTree() */
442 : /* */
443 : /* Export the envelope of a geometry as a gml:Box. */
444 : /************************************************************************/
445 :
446 0 : CPLXMLNode *OGR_G_ExportEnvelopeToGMLTree( OGRGeometryH hGeometry )
447 :
448 : {
449 : CPLXMLNode *psBox, *psCoord;
450 0 : OGREnvelope sEnvelope;
451 : char szCoordinate[256];
452 : char *pszY;
453 :
454 0 : memset( &sEnvelope, 0, sizeof(sEnvelope) );
455 0 : ((OGRGeometry *) hGeometry)->getEnvelope( &sEnvelope );
456 :
457 0 : if( sEnvelope.MinX == 0 && sEnvelope.MaxX == 0
458 : && sEnvelope.MaxX == 0 && sEnvelope.MaxY == 0 )
459 : {
460 : /* there is apparently a special way of representing a null box
461 : geometry ... we should use it here eventually. */
462 :
463 0 : return NULL;
464 : }
465 :
466 0 : psBox = CPLCreateXMLNode( NULL, CXT_Element, "gml:Box" );
467 :
468 : /* -------------------------------------------------------------------- */
469 : /* Add minxy coordinate. */
470 : /* -------------------------------------------------------------------- */
471 0 : psCoord = CPLCreateXMLNode( psBox, CXT_Element, "gml:coord" );
472 :
473 : MakeGMLCoordinate( szCoordinate, sEnvelope.MinX, sEnvelope.MinY, 0.0,
474 0 : FALSE );
475 0 : pszY = strstr(szCoordinate,",") + 1;
476 0 : pszY[-1] = '\0';
477 :
478 0 : CPLCreateXMLElementAndValue( psCoord, "gml:X", szCoordinate );
479 0 : CPLCreateXMLElementAndValue( psCoord, "gml:Y", pszY );
480 :
481 : /* -------------------------------------------------------------------- */
482 : /* Add maxxy coordinate. */
483 : /* -------------------------------------------------------------------- */
484 0 : psCoord = CPLCreateXMLNode( psBox, CXT_Element, "gml:coord" );
485 :
486 : MakeGMLCoordinate( szCoordinate, sEnvelope.MaxX, sEnvelope.MaxY, 0.0,
487 0 : FALSE );
488 0 : pszY = strstr(szCoordinate,",") + 1;
489 0 : pszY[-1] = '\0';
490 :
491 0 : CPLCreateXMLElementAndValue( psCoord, "gml:X", szCoordinate );
492 0 : CPLCreateXMLElementAndValue( psCoord, "gml:Y", pszY );
493 :
494 0 : return psBox;
495 : }
496 :
497 : /************************************************************************/
498 : /* OGR_G_ExportToGMLTree() */
499 : /************************************************************************/
500 :
501 0 : CPLXMLNode *OGR_G_ExportToGMLTree( OGRGeometryH hGeometry )
502 :
503 : {
504 : char *pszText;
505 : CPLXMLNode *psTree;
506 :
507 0 : pszText = OGR_G_ExportToGML( hGeometry );
508 0 : if( pszText == NULL )
509 0 : return NULL;
510 :
511 0 : psTree = CPLParseXMLString( pszText );
512 :
513 0 : CPLFree( pszText );
514 :
515 0 : return psTree;
516 : }
517 :
518 : /************************************************************************/
519 : /* OGR_G_ExportToGML() */
520 : /************************************************************************/
521 :
522 24 : char *OGR_G_ExportToGML( OGRGeometryH hGeometry )
523 :
524 : {
525 : char *pszText;
526 24 : int nLength = 0, nMaxLength = 1;
527 :
528 24 : if( hGeometry == NULL )
529 0 : return CPLStrdup( "" );
530 :
531 24 : pszText = (char *) CPLMalloc(nMaxLength);
532 24 : pszText[0] = '\0';
533 :
534 24 : if( !OGR2GMLGeometryAppend( (OGRGeometry *) hGeometry, &pszText,
535 : &nLength, &nMaxLength, FALSE ))
536 : {
537 0 : CPLFree( pszText );
538 0 : return NULL;
539 : }
540 : else
541 24 : return pszText;
542 : }
|