1 : /******************************************************************************
2 : * $Id: hugefileresolver.cpp 23675 2012-01-01 16:09:45Z rouault $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Implementation of GMLReader::HugeFileResolver() method.
6 : * Author: Alessandro Furieri, a.furitier@lqt.it
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, Alessandro Furieri
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 : * Contributor: Alessandro Furieri, a.furieri@lqt.it
31 : * This module implents GML_SKIP_RESOLVE_ELEMS HUGE
32 : * Developed for Faunalia ( http://www.faunalia.it) with funding from
33 : * Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE
34 : *
35 : ****************************************************************************/
36 :
37 : #include "gmlreader.h"
38 : #include "cpl_error.h"
39 :
40 : #include "gmlreaderp.h"
41 : #include "gmlutils.h"
42 : #include "cpl_conv.h"
43 : #include "ogr_p.h"
44 : #include "cpl_string.h"
45 : #include "cpl_http.h"
46 :
47 : #include <stack>
48 :
49 : CPL_CVSID("$Id: hugefileresolver.cpp 23675 2012-01-01 16:09:45Z rouault $");
50 :
51 : /****************************************************/
52 : /* SQLite is absolutely required in order to */
53 : /* support the HUGE xlink:href resolver */
54 : /****************************************************/
55 :
56 : #ifdef HAVE_SQLITE
57 : #include <sqlite3.h>
58 : #endif
59 :
60 : /* sqlite3_clear_bindings() isn't available in old versions of */
61 : /* sqlite3 */
62 : #if defined(HAVE_SQLITE) && SQLITE_VERSION_NUMBER >= 3006000
63 :
64 : /* an internal helper struct supporting GML tags <Edge> */
65 : struct huge_tag
66 : {
67 : CPLString *gmlTagValue;
68 : CPLString *gmlId;
69 : CPLString *gmlNodeFrom;
70 : CPLString *gmlNodeTo;
71 : int bIsNodeFromHref;
72 : int bIsNodeToHref;
73 : int bHasCoords;
74 : int bHasZ;
75 : double xNodeFrom;
76 : double yNodeFrom;
77 : double zNodeFrom;
78 : double xNodeTo;
79 : double yNodeTo;
80 : double zNodeTo;
81 : struct huge_tag *pNext;
82 : };
83 :
84 : /* an internal helper struct supporting GML tags xlink:href */
85 : struct huge_href
86 : {
87 : CPLString *gmlId;
88 : CPLString *gmlText;
89 : const CPLXMLNode *psParent;
90 : const CPLXMLNode *psNode;
91 : int bIsDirectedEdge;
92 : char cOrientation;
93 : struct huge_href *pNext;
94 : };
95 :
96 : /* an internal helper struct supporying GML rewriting */
97 : struct huge_child
98 : {
99 : CPLXMLNode *psChild;
100 : struct huge_href *pItem;
101 : struct huge_child *pNext;
102 : };
103 :
104 : /* an internal helper struct supporting GML rewriting */
105 : struct huge_parent
106 : {
107 : CPLXMLNode *psParent;
108 : struct huge_child *pFirst;
109 : struct huge_child *pLast;
110 : struct huge_parent *pNext;
111 : };
112 :
113 : /*
114 : / an internal helper struct supporting GML
115 : / resolver for Huge Files (based on SQLite)
116 : */
117 : struct huge_helper
118 : {
119 : sqlite3 *hDB;
120 : sqlite3_stmt *hNodes;
121 : sqlite3_stmt *hEdges;
122 : CPLString *nodeSrs;
123 : struct huge_tag *pFirst;
124 : struct huge_tag *pLast;
125 : struct huge_href *pFirstHref;
126 : struct huge_href *pLastHref;
127 : struct huge_parent *pFirstParent;
128 : struct huge_parent *pLastParent;
129 : };
130 :
131 2 : static int gmlHugeFileSQLiteInit( struct huge_helper *helper )
132 : {
133 : /* attempting to create SQLite tables */
134 : const char *osCommand;
135 2 : char *pszErrMsg = NULL;
136 : int rc;
137 2 : sqlite3 *hDB = helper->hDB;
138 : sqlite3_stmt *hStmt;
139 :
140 : /* DB table: NODES */
141 : osCommand = "CREATE TABLE nodes ("
142 : " gml_id VARCHAR PRIMARY KEY, "
143 : " x DOUBLE, "
144 : " y DOUBLE, "
145 2 : " z DOUBLE)";
146 2 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
147 2 : if( rc != SQLITE_OK )
148 : {
149 : CPLError( CE_Failure, CPLE_AppDefined,
150 : "Unable to create table nodes: %s",
151 0 : pszErrMsg );
152 0 : sqlite3_free( pszErrMsg );
153 0 : return FALSE;
154 : }
155 :
156 : /* DB table: GML_EDGES */
157 : osCommand = "CREATE TABLE gml_edges ("
158 : " gml_id VARCHAR PRIMARY KEY, "
159 : " gml_string BLOB, "
160 : " gml_resolved BLOB, "
161 : " node_from_id TEXT, "
162 : " node_from_x DOUBLE, "
163 : " node_from_y DOUBLE, "
164 : " node_from_z DOUBLE, "
165 : " node_to_id TEXT, "
166 : " node_to_x DOUBLE, "
167 : " node_to_y DOUBLE, "
168 2 : " node_to_z DOUBLE)";
169 2 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
170 2 : if( rc != SQLITE_OK )
171 : {
172 : CPLError( CE_Failure, CPLE_AppDefined,
173 : "Unable to create table gml_edges: %s",
174 0 : pszErrMsg );
175 0 : sqlite3_free( pszErrMsg );
176 0 : return FALSE;
177 : }
178 :
179 : /* DB table: NODES / Insert cursor */
180 : osCommand = "INSERT OR IGNORE INTO nodes (gml_id, x, y, z) "
181 2 : "VALUES (?, ?, ?, ?)";
182 2 : rc = sqlite3_prepare( hDB, osCommand, -1, &hStmt, NULL );
183 2 : if( rc != SQLITE_OK )
184 : {
185 : CPLError( CE_Failure, CPLE_AppDefined,
186 0 : "Unable to create INSERT stmt for: nodes" );
187 0 : return FALSE;
188 : }
189 2 : helper->hNodes = hStmt;
190 :
191 : /* DB table: GML_EDGES / Insert cursor */
192 : osCommand = "INSERT INTO gml_edges "
193 : "(gml_id, gml_string, gml_resolved, "
194 : "node_from_id, node_from_x, node_from_y, "
195 : "node_from_z, node_to_id, node_to_x, "
196 : "node_to_y, node_to_z) "
197 2 : "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
198 2 : rc = sqlite3_prepare( hDB, osCommand, -1, &hStmt, NULL );
199 2 : if( rc != SQLITE_OK )
200 : {
201 : CPLError( CE_Failure, CPLE_AppDefined,
202 0 : "Unable to create INSERT stmt for: gml_edges" );
203 0 : return FALSE;
204 : }
205 2 : helper->hEdges = hStmt;
206 :
207 : /* starting a TRANSACTION */
208 2 : rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
209 2 : if( rc != SQLITE_OK )
210 : {
211 : CPLError( CE_Failure, CPLE_AppDefined,
212 : "Unable to perform BEGIN TRANSACTION: %s",
213 0 : pszErrMsg );
214 0 : sqlite3_free( pszErrMsg );
215 0 : return FALSE;
216 : }
217 :
218 2 : return TRUE;
219 : }
220 :
221 70 : static int gmlHugeResolveEdgeNodes( const CPLXMLNode *psNode,
222 : const char *pszFromId,
223 : const char *pszToId )
224 : {
225 : /* resolves an Edge definition */
226 70 : CPLXMLNode *psDirNode_1 = NULL;
227 70 : CPLXMLNode *psDirNode_2 = NULL;
228 70 : CPLXMLNode *psOldNode_1 = NULL;
229 70 : CPLXMLNode *psOldNode_2 = NULL;
230 70 : CPLXMLNode *psNewNode_1 = NULL;
231 70 : CPLXMLNode *psNewNode_2 = NULL;
232 70 : int iToBeReplaced = 0;
233 70 : int iReplaced = 0;
234 70 : if( psNode->eType == CXT_Element && EQUAL( psNode->pszValue, "Edge" ) )
235 : ;
236 : else
237 0 : return FALSE;
238 :
239 70 : CPLXMLNode *psChild = psNode->psChild;
240 420 : while( psChild != NULL )
241 : {
242 280 : if( psChild->eType == CXT_Element &&
243 : EQUAL( psChild->pszValue, "directedNode" ) )
244 : {
245 140 : char cOrientation = '+';
246 140 : CPLXMLNode *psOldNode = NULL;
247 140 : CPLXMLNode *psAttr = psChild->psChild;
248 490 : while( psAttr != NULL )
249 : {
250 210 : if( psAttr->eType == CXT_Attribute &&
251 : EQUAL( psAttr->pszValue, "xlink:href" ) )
252 96 : psOldNode = psAttr;
253 210 : if( psAttr->eType == CXT_Attribute &&
254 : EQUAL( psAttr->pszValue, "orientation" ) )
255 : {
256 70 : const CPLXMLNode *psOrientation = psAttr->psChild;
257 70 : if( psOrientation != NULL )
258 : {
259 70 : if( psOrientation->eType == CXT_Text )
260 70 : cOrientation = *(psOrientation->pszValue);
261 : }
262 : }
263 210 : psAttr = psAttr->psNext;
264 : }
265 140 : if( psOldNode != NULL )
266 : {
267 96 : CPLXMLNode *psNewNode = CPLCreateXMLNode(NULL, CXT_Element, "Node");
268 96 : CPLXMLNode *psGMLIdNode = CPLCreateXMLNode(psNewNode, CXT_Attribute, "gml:id");
269 96 : if( cOrientation == '-' )
270 49 : CPLCreateXMLNode(psGMLIdNode, CXT_Text, pszFromId);
271 : else
272 47 : CPLCreateXMLNode(psGMLIdNode, CXT_Text, pszToId);
273 96 : if( iToBeReplaced == 0 )
274 : {
275 70 : psDirNode_1 = psChild;
276 70 : psOldNode_1 = psOldNode;
277 70 : psNewNode_1 = psNewNode;
278 : }
279 : else
280 : {
281 26 : psDirNode_2 = psChild;
282 26 : psOldNode_2 = psOldNode;
283 26 : psNewNode_2 = psNewNode;
284 : }
285 96 : iToBeReplaced++;
286 : }
287 : }
288 280 : psChild = psChild->psNext;
289 : }
290 :
291 : /* rewriting the Edge GML definition */
292 70 : if( psDirNode_1 != NULL)
293 : {
294 70 : if( psOldNode_1 != NULL )
295 : {
296 70 : CPLRemoveXMLChild( psDirNode_1, psOldNode_1 );
297 70 : CPLDestroyXMLNode( psOldNode_1 );
298 70 : if( psNewNode_1 != NULL )
299 : {
300 70 : CPLAddXMLChild( psDirNode_1, psNewNode_1 );
301 70 : iReplaced++;
302 : }
303 : }
304 : }
305 70 : if( psDirNode_2 != NULL)
306 : {
307 26 : if( psOldNode_2 != NULL )
308 : {
309 26 : CPLRemoveXMLChild( psDirNode_2, psOldNode_2 );
310 26 : CPLDestroyXMLNode( psOldNode_2 );
311 26 : if( psNewNode_2 != NULL )
312 : {
313 26 : CPLAddXMLChild( psDirNode_2, psNewNode_2 );
314 26 : iReplaced++;
315 : }
316 : }
317 : }
318 70 : if( iToBeReplaced != iReplaced )
319 0 : return FALSE;
320 70 : return TRUE;
321 : }
322 :
323 2 : static int gmlHugeFileResolveEdges( struct huge_helper *helper )
324 : {
325 : /* identifying any not yet resolved <Edge> GML string */
326 : const char *osCommand;
327 2 : char *pszErrMsg = NULL;
328 : int rc;
329 2 : sqlite3 *hDB = helper->hDB;
330 : sqlite3_stmt *hQueryStmt;
331 : sqlite3_stmt *hUpdateStmt;
332 2 : int iCount = 0;
333 2 : int bError = FALSE;
334 :
335 : /* query cursor */
336 : osCommand = "SELECT e.gml_id, e.gml_string, e.node_from_id, "
337 : "e.node_from_x, e.node_from_y, e.node_from_z, "
338 : "n1.gml_id, n1.x, n1.y, n1.z, e.node_to_id, "
339 : "e.node_to_x, e.node_to_y, e.node_to_z, "
340 : "n2.gml_id, n2.x, n2.y, n2.z "
341 : "FROM gml_edges AS e "
342 : "LEFT JOIN nodes AS n1 ON (n1.gml_id = e.node_from_id) "
343 2 : "LEFT JOIN nodes AS n2 ON (n2.gml_id = e.node_to_id)";
344 2 : rc = sqlite3_prepare( hDB, osCommand, -1, &hQueryStmt, NULL );
345 2 : if( rc != SQLITE_OK )
346 : {
347 : CPLError( CE_Failure, CPLE_AppDefined,
348 0 : "Unable to create QUERY stmt for Edge resolver" );
349 0 : return FALSE;
350 : }
351 :
352 : /* update cursor */
353 : osCommand = "UPDATE gml_edges "
354 : "SET gml_resolved = ?, "
355 : "gml_string = NULL "
356 2 : "WHERE gml_id = ?";
357 2 : rc = sqlite3_prepare( hDB, osCommand, -1, &hUpdateStmt, NULL );
358 2 : if( rc != SQLITE_OK )
359 : {
360 : CPLError( CE_Failure, CPLE_AppDefined,
361 0 : "Unable to create UPDATE stmt for resolved Edges" );
362 0 : sqlite3_finalize ( hQueryStmt );
363 0 : return FALSE;
364 : }
365 :
366 : /* starting a TRANSACTION */
367 2 : rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
368 2 : if( rc != SQLITE_OK )
369 : {
370 : CPLError( CE_Failure, CPLE_AppDefined,
371 : "Unable to perform BEGIN TRANSACTION: %s",
372 0 : pszErrMsg );
373 0 : sqlite3_free( pszErrMsg );
374 0 : sqlite3_finalize ( hQueryStmt );
375 0 : sqlite3_finalize ( hUpdateStmt );
376 0 : return FALSE;
377 : }
378 :
379 : /* looping on the QUERY result-set */
380 81 : while ( TRUE )
381 : {
382 : const char *pszGmlId;
383 83 : const char *pszGmlString = NULL;
384 : int bIsGmlStringNull;
385 83 : const char *pszFromId = NULL;
386 : int bIsFromIdNull;
387 83 : double xFrom = 0.0;
388 : int bIsXFromNull;
389 83 : double yFrom = 0.0;
390 : int bIsYFromNull;
391 83 : double zFrom = 0.0;
392 : int bIsZFromNull;
393 83 : const char *pszNodeFromId = NULL;
394 : int bIsNodeFromIdNull;
395 83 : double xNodeFrom = 0.0;
396 : int bIsXNodeFromNull;
397 83 : double yNodeFrom = 0.0;
398 : int bIsYNodeFromNull;
399 83 : double zNodeFrom = 0.0;
400 : int bIsZNodeFromNull;
401 83 : const char *pszToId = NULL;
402 : int bIsToIdNull;
403 83 : double xTo = 0.0;
404 : int bIsXToNull;
405 83 : double yTo = 0.0;
406 : int bIsYToNull;
407 83 : double zTo = 0.0;
408 : int bIsZToNull;
409 83 : const char *pszNodeToId = NULL;
410 : int bIsNodeToIdNull;
411 83 : double xNodeTo = 0.0;
412 : int bIsXNodeToNull;
413 83 : double yNodeTo = 0.0;
414 : int bIsYNodeToNull;
415 83 : double zNodeTo = 0.0;
416 : int bIsZNodeToNull;
417 :
418 83 : rc = sqlite3_step( hQueryStmt );
419 83 : if( rc == SQLITE_DONE )
420 : break;
421 81 : else if( rc == SQLITE_ROW )
422 : {
423 81 : bError = FALSE;
424 81 : pszGmlId = (const char *) sqlite3_column_text( hQueryStmt, 0 );
425 81 : if( sqlite3_column_type( hQueryStmt, 1 ) == SQLITE_NULL )
426 11 : bIsGmlStringNull = TRUE;
427 : else
428 : {
429 70 : pszGmlString = (const char *) sqlite3_column_blob( hQueryStmt, 1 );
430 70 : bIsGmlStringNull = FALSE;
431 : }
432 81 : if( sqlite3_column_type( hQueryStmt, 2 ) == SQLITE_NULL )
433 0 : bIsFromIdNull = TRUE;
434 : else
435 : {
436 81 : pszFromId = (const char *) sqlite3_column_text( hQueryStmt, 2 );
437 81 : bIsFromIdNull = FALSE;
438 : }
439 81 : if( sqlite3_column_type( hQueryStmt, 3 ) == SQLITE_NULL )
440 0 : bIsXFromNull = TRUE;
441 : else
442 : {
443 81 : xFrom = sqlite3_column_double( hQueryStmt, 3 );
444 81 : bIsXFromNull = FALSE;
445 : }
446 81 : if( sqlite3_column_type( hQueryStmt, 4 ) == SQLITE_NULL )
447 0 : bIsYFromNull = TRUE;
448 : else
449 : {
450 81 : yFrom = sqlite3_column_double( hQueryStmt, 4 );
451 81 : bIsYFromNull = FALSE;
452 : }
453 81 : if( sqlite3_column_type( hQueryStmt, 5 ) == SQLITE_NULL )
454 81 : bIsZFromNull = TRUE;
455 : else
456 : {
457 0 : zFrom = sqlite3_column_double( hQueryStmt, 5 );
458 0 : bIsZFromNull = FALSE;
459 : }
460 81 : if( sqlite3_column_type( hQueryStmt, 6 ) == SQLITE_NULL )
461 0 : bIsNodeFromIdNull = TRUE;
462 : else
463 : {
464 81 : pszNodeFromId = (const char *) sqlite3_column_text( hQueryStmt, 6 );
465 81 : bIsNodeFromIdNull = FALSE;
466 : }
467 81 : if( sqlite3_column_type( hQueryStmt, 7 ) == SQLITE_NULL )
468 0 : bIsXNodeFromNull = TRUE;
469 : else
470 : {
471 81 : xNodeFrom = sqlite3_column_double( hQueryStmt, 7 );
472 81 : bIsXNodeFromNull = FALSE;
473 : }
474 81 : if( sqlite3_column_type( hQueryStmt, 8 ) == SQLITE_NULL )
475 0 : bIsYNodeFromNull = TRUE;
476 : else
477 : {
478 81 : yNodeFrom = sqlite3_column_double( hQueryStmt, 8 );
479 81 : bIsYNodeFromNull = FALSE;
480 : }
481 81 : if( sqlite3_column_type( hQueryStmt, 9 ) == SQLITE_NULL )
482 81 : bIsZNodeFromNull = TRUE;
483 : else
484 : {
485 0 : zNodeFrom = sqlite3_column_double( hQueryStmt, 9 );
486 0 : bIsZNodeFromNull = FALSE;
487 : }
488 81 : if( sqlite3_column_type( hQueryStmt, 10 ) == SQLITE_NULL )
489 0 : bIsToIdNull = TRUE;
490 : else
491 : {
492 81 : pszToId = (const char *) sqlite3_column_text( hQueryStmt, 10 );
493 81 : bIsToIdNull = FALSE;
494 : }
495 81 : if( sqlite3_column_type( hQueryStmt, 11 ) == SQLITE_NULL )
496 0 : bIsXToNull = TRUE;
497 : else
498 : {
499 81 : xTo = sqlite3_column_double( hQueryStmt, 11 );
500 81 : bIsXToNull = FALSE;
501 : }
502 81 : if( sqlite3_column_type( hQueryStmt, 12 ) == SQLITE_NULL )
503 0 : bIsYToNull = TRUE;
504 : else
505 : {
506 81 : yTo = sqlite3_column_double( hQueryStmt, 12 );
507 81 : bIsYToNull = FALSE;
508 : }
509 81 : if( sqlite3_column_type( hQueryStmt, 13 ) == SQLITE_NULL )
510 81 : bIsZToNull = TRUE;
511 : else
512 : {
513 0 : zTo = sqlite3_column_double( hQueryStmt, 13 );
514 0 : bIsZToNull = FALSE;
515 : }
516 81 : if( sqlite3_column_type( hQueryStmt, 14 ) == SQLITE_NULL )
517 0 : bIsNodeToIdNull = TRUE;
518 : else
519 : {
520 81 : pszNodeToId = (const char *) sqlite3_column_text( hQueryStmt, 14 );
521 81 : bIsNodeToIdNull = FALSE;
522 : }
523 81 : if( sqlite3_column_type( hQueryStmt, 15 ) == SQLITE_NULL )
524 0 : bIsXNodeToNull = TRUE;
525 : else
526 : {
527 81 : xNodeTo = sqlite3_column_double( hQueryStmt, 15 );
528 81 : bIsXNodeToNull = FALSE;
529 : }
530 81 : if( sqlite3_column_type( hQueryStmt, 16 ) == SQLITE_NULL )
531 0 : bIsYNodeToNull = TRUE;
532 : else
533 : {
534 81 : yNodeTo = sqlite3_column_double( hQueryStmt, 16 );
535 81 : bIsYNodeToNull = FALSE;
536 : }
537 81 : if( sqlite3_column_type( hQueryStmt, 17 ) == SQLITE_NULL )
538 81 : bIsZNodeToNull = TRUE;
539 : else
540 : {
541 0 : zNodeTo = sqlite3_column_double( hQueryStmt, 17 );
542 0 : bIsZNodeToNull = FALSE;
543 : }
544 :
545 : /* checking for consistency */
546 81 : if( bIsFromIdNull == TRUE || bIsXFromNull == TRUE ||
547 : bIsYFromNull == TRUE )
548 : {
549 0 : bError = TRUE;
550 : CPLError( CE_Failure, CPLE_AppDefined,
551 : "Edge gml:id=\"%s\": invalid Node-from",
552 0 : pszGmlId );
553 : }
554 : else
555 : {
556 81 : if( bIsNodeFromIdNull == TRUE )
557 : {
558 0 : bError = TRUE;
559 : CPLError( CE_Failure, CPLE_AppDefined,
560 : "Edge gml:id=\"%s\": undeclared Node gml:id=\"%s\"",
561 0 : pszGmlId, pszFromId );
562 : }
563 81 : else if( bIsXNodeFromNull == TRUE || bIsYNodeFromNull == TRUE )
564 : {
565 0 : bError = TRUE;
566 : CPLError( CE_Failure, CPLE_AppDefined,
567 : "Edge gml:id=\"%s\": unknown coords for Node gml:id=\"%s\"",
568 0 : pszGmlId, pszFromId );
569 : }
570 81 : else if( xFrom != xNodeFrom || yFrom != yNodeFrom )
571 : {
572 0 : bError = TRUE;
573 : CPLError( CE_Failure, CPLE_AppDefined,
574 : "Edge gml:id=\"%s\": mismatching coords for Node gml:id=\"%s\"",
575 0 : pszGmlId, pszFromId );
576 : }
577 : else
578 : {
579 81 : if( bIsZFromNull == TRUE && bIsZNodeFromNull == TRUE )
580 : ;
581 0 : else if( bIsZFromNull == TRUE || bIsZNodeFromNull == TRUE )
582 : {
583 0 : bError = TRUE;
584 : CPLError( CE_Failure, CPLE_AppDefined,
585 : "Edge gml:id=\"%s\": mismatching 2D/3D for Node gml:id=\"%s\"",
586 0 : pszGmlId, pszFromId );
587 : }
588 0 : else if( zFrom != zNodeFrom )
589 : {
590 0 : bError = TRUE;
591 : CPLError( CE_Failure, CPLE_AppDefined,
592 : "Edge gml:id=\"%s\": mismatching Z coord for Node gml:id=\"%s\"",
593 0 : pszGmlId, pszFromId );
594 : }
595 : }
596 : }
597 81 : if( bIsToIdNull == TRUE || bIsXToNull == TRUE ||
598 : bIsYToNull == TRUE )
599 : {
600 0 : bError = TRUE;
601 : CPLError( CE_Failure, CPLE_AppDefined,
602 : "Edge gml:id=\"%s\": invalid Node-to",
603 0 : pszGmlId );
604 : }
605 : else
606 : {
607 81 : if( bIsNodeToIdNull == TRUE )
608 : {
609 0 : bError = TRUE;
610 : CPLError( CE_Failure, CPLE_AppDefined,
611 : "Edge gml:id=\"%s\": undeclared Node gml:id=\"%s\"",
612 0 : pszGmlId, pszToId );
613 : }
614 81 : else if( bIsXNodeToNull == TRUE || bIsYNodeToNull == TRUE )
615 : {
616 0 : bError = TRUE;
617 : CPLError( CE_Failure, CPLE_AppDefined,
618 : "Edge gml:id=\"%s\": unknown coords for Node gml:id=\"%s\"",
619 0 : pszGmlId, pszToId );
620 : }
621 81 : else if( xTo != xNodeTo || yTo != yNodeTo )
622 : {
623 0 : bError = TRUE;
624 : CPLError( CE_Failure, CPLE_AppDefined,
625 : "Edge gml:id=\"%s\": mismatching coords for Node gml:id=\"%s\"",
626 0 : pszGmlId, pszToId );
627 : }
628 : else
629 : {
630 81 : if( bIsZToNull == TRUE && bIsZNodeToNull == TRUE )
631 : ;
632 0 : else if( bIsZToNull == TRUE || bIsZNodeToNull == TRUE )
633 : {
634 0 : bError = TRUE;
635 : CPLError( CE_Failure, CPLE_AppDefined,
636 : "Edge gml:id=\"%s\": mismatching 2D/3D for Node gml:id=\"%s\"",
637 0 : pszGmlId, pszToId );
638 : }
639 0 : else if( zTo != zNodeTo )
640 : {
641 0 : bError = TRUE;
642 : CPLError( CE_Failure, CPLE_AppDefined,
643 : "Edge gml:id=\"%s\": mismatching Z coord for Node gml:id=\"%s\"",
644 0 : pszGmlId, pszToId );
645 : }
646 : }
647 : }
648 :
649 : /* updating the resolved Node */
650 81 : if( bError == FALSE && bIsGmlStringNull == FALSE &&
651 : bIsFromIdNull == FALSE && bIsToIdNull == FALSE )
652 : {
653 70 : CPLXMLNode *psNode = CPLParseXMLString( pszGmlString );
654 70 : if( psNode != NULL )
655 : {
656 70 : if( gmlHugeResolveEdgeNodes( psNode, pszFromId,
657 : pszToId ) == TRUE )
658 : {
659 70 : char * gmlText = CPLSerializeXMLTree(psNode);
660 70 : sqlite3_reset ( hUpdateStmt );
661 70 : sqlite3_clear_bindings ( hUpdateStmt );
662 : sqlite3_bind_blob( hUpdateStmt, 1, gmlText,
663 70 : strlen(gmlText), SQLITE_STATIC );
664 : sqlite3_bind_text( hUpdateStmt, 2, pszGmlId, -1,
665 70 : SQLITE_STATIC );
666 70 : rc = sqlite3_step( hUpdateStmt );
667 70 : if( rc != SQLITE_OK && rc != SQLITE_DONE )
668 : {
669 : CPLError( CE_Failure, CPLE_AppDefined,
670 : "UPDATE resoved Edge \"%s\" sqlite3_step() failed:\n %s",
671 0 : pszGmlId, sqlite3_errmsg(hDB) );
672 : }
673 70 : CPLFree( gmlText );
674 70 : iCount++;
675 70 : if( (iCount % 1024) == 1023 )
676 : {
677 : /* committing the current TRANSACTION */
678 : rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL,
679 0 : &pszErrMsg );
680 0 : if( rc != SQLITE_OK )
681 : {
682 : CPLError( CE_Failure, CPLE_AppDefined,
683 : "Unable to perform COMMIT TRANSACTION: %s",
684 0 : pszErrMsg );
685 0 : sqlite3_free( pszErrMsg );
686 0 : return FALSE;
687 : }
688 : /* restarting a new TRANSACTION */
689 0 : rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
690 0 : if( rc != SQLITE_OK )
691 : {
692 : CPLError( CE_Failure, CPLE_AppDefined,
693 : "Unable to perform BEGIN TRANSACTION: %s",
694 0 : pszErrMsg );
695 0 : sqlite3_free( pszErrMsg );
696 0 : sqlite3_finalize ( hQueryStmt );
697 0 : sqlite3_finalize ( hUpdateStmt );
698 0 : return FALSE;
699 : }
700 : }
701 : }
702 70 : CPLDestroyXMLNode( psNode );
703 : }
704 : }
705 : }
706 : else
707 : {
708 : CPLError( CE_Failure, CPLE_AppDefined,
709 : "Edge resolver QUERY: sqlite3_step(%s)",
710 0 : sqlite3_errmsg(hDB) );
711 0 : sqlite3_finalize ( hQueryStmt );
712 0 : sqlite3_finalize ( hUpdateStmt );
713 0 : return FALSE;
714 : }
715 : }
716 2 : sqlite3_finalize ( hQueryStmt );
717 2 : sqlite3_finalize ( hUpdateStmt );
718 :
719 : /* committing the current TRANSACTION */
720 2 : rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL, &pszErrMsg );
721 2 : if( rc != SQLITE_OK )
722 : {
723 : CPLError( CE_Failure, CPLE_AppDefined,
724 : "Unable to perform COMMIT TRANSACTION: %s",
725 0 : pszErrMsg );
726 0 : sqlite3_free( pszErrMsg );
727 0 : return FALSE;
728 : }
729 2 : if( bError == TRUE )
730 0 : return FALSE;
731 2 : return TRUE;
732 : }
733 :
734 72 : static int gmlHugeFileSQLiteInsert( struct huge_helper *helper )
735 : {
736 : /* inserting any appropriate row into the SQLite DB */
737 : int rc;
738 : struct huge_tag *pItem;
739 :
740 : /* looping on GML tags */
741 72 : pItem = helper->pFirst;
742 225 : while ( pItem != NULL )
743 : {
744 81 : if( pItem->bHasCoords == TRUE )
745 : {
746 81 : if( pItem->gmlNodeFrom != NULL )
747 : {
748 81 : sqlite3_reset ( helper->hNodes );
749 81 : sqlite3_clear_bindings ( helper->hNodes );
750 : sqlite3_bind_text( helper->hNodes, 1,
751 : pItem->gmlNodeFrom->c_str(), -1,
752 81 : SQLITE_STATIC );
753 81 : sqlite3_bind_double ( helper->hNodes, 2, pItem->xNodeFrom );
754 81 : sqlite3_bind_double ( helper->hNodes, 3, pItem->yNodeFrom );
755 81 : if( pItem->bHasZ == TRUE )
756 0 : sqlite3_bind_double ( helper->hNodes, 4, pItem->zNodeFrom );
757 81 : sqlite3_bind_null ( helper->hNodes, 5 );
758 81 : rc = sqlite3_step( helper->hNodes );
759 81 : if( rc != SQLITE_OK && rc != SQLITE_DONE )
760 : {
761 : CPLError( CE_Failure, CPLE_AppDefined,
762 : "sqlite3_step() failed:\n %s",
763 0 : sqlite3_errmsg(helper->hDB) );
764 0 : return FALSE;
765 : }
766 : }
767 81 : if( pItem->gmlNodeTo != NULL )
768 : {
769 81 : sqlite3_reset ( helper->hNodes );
770 81 : sqlite3_clear_bindings ( helper->hNodes );
771 : sqlite3_bind_text( helper->hNodes, 1, pItem->gmlNodeTo->c_str(),
772 81 : -1, SQLITE_STATIC );
773 81 : sqlite3_bind_double ( helper->hNodes, 2, pItem->xNodeTo );
774 81 : sqlite3_bind_double ( helper->hNodes, 3, pItem->yNodeTo );
775 81 : if ( pItem->bHasZ == TRUE )
776 0 : sqlite3_bind_double ( helper->hNodes, 4, pItem->zNodeTo );
777 81 : sqlite3_bind_null ( helper->hNodes, 5 );
778 81 : rc = sqlite3_step( helper->hNodes );
779 81 : if( rc != SQLITE_OK && rc != SQLITE_DONE )
780 : {
781 : CPLError( CE_Failure, CPLE_AppDefined,
782 : "sqlite3_step() failed:\n %s",
783 0 : sqlite3_errmsg(helper->hDB) );
784 0 : return FALSE;
785 : }
786 : }
787 : }
788 :
789 : /* gml:id */
790 81 : sqlite3_reset( helper->hEdges );
791 81 : sqlite3_clear_bindings( helper->hEdges );
792 : sqlite3_bind_text( helper->hEdges, 1, pItem->gmlId->c_str(), -1,
793 81 : SQLITE_STATIC );
794 92 : if( pItem->bIsNodeFromHref == FALSE && pItem->bIsNodeToHref == FALSE )
795 : {
796 11 : sqlite3_bind_null( helper->hEdges, 2 );
797 : sqlite3_bind_blob( helper->hEdges, 3, pItem->gmlTagValue->c_str(),
798 : strlen( pItem->gmlTagValue->c_str() ),
799 11 : SQLITE_STATIC );
800 : }
801 : else
802 : {
803 : sqlite3_bind_blob( helper->hEdges, 2, pItem->gmlTagValue->c_str(),
804 : strlen( pItem->gmlTagValue->c_str() ),
805 70 : SQLITE_STATIC );
806 70 : sqlite3_bind_null( helper->hEdges, 3 );
807 : }
808 81 : if( pItem->gmlNodeFrom != NULL )
809 : sqlite3_bind_text( helper->hEdges, 4, pItem->gmlNodeFrom->c_str(),
810 81 : -1, SQLITE_STATIC );
811 : else
812 0 : sqlite3_bind_null( helper->hEdges, 4 );
813 81 : if( pItem->bHasCoords == TRUE )
814 : {
815 81 : sqlite3_bind_double( helper->hEdges, 5, pItem->xNodeFrom );
816 81 : sqlite3_bind_double( helper->hEdges, 6, pItem->yNodeFrom );
817 81 : if( pItem->bHasZ == TRUE )
818 0 : sqlite3_bind_double( helper->hEdges, 7, pItem->zNodeFrom );
819 : else
820 81 : sqlite3_bind_null( helper->hEdges, 7 );
821 : }
822 : else
823 : {
824 0 : sqlite3_bind_null( helper->hEdges, 5 );
825 0 : sqlite3_bind_null( helper->hEdges, 6 );
826 0 : sqlite3_bind_null( helper->hEdges, 7 );
827 : }
828 81 : if( pItem->gmlNodeTo != NULL )
829 : sqlite3_bind_text( helper->hEdges, 8, pItem->gmlNodeTo->c_str(),
830 81 : -1, SQLITE_STATIC );
831 : else
832 0 : sqlite3_bind_null( helper->hEdges, 8 );
833 81 : if( pItem->bHasCoords == TRUE )
834 : {
835 81 : sqlite3_bind_double( helper->hEdges, 9, pItem->xNodeTo );
836 81 : sqlite3_bind_double( helper->hEdges, 10, pItem->yNodeTo );
837 81 : if( pItem->bHasZ == TRUE )
838 0 : sqlite3_bind_double( helper->hEdges, 11, pItem->zNodeTo );
839 : else
840 81 : sqlite3_bind_null( helper->hEdges, 11 );
841 : }
842 : else
843 : {
844 0 : sqlite3_bind_null( helper->hEdges, 9 );
845 0 : sqlite3_bind_null( helper->hEdges, 10 );
846 0 : sqlite3_bind_null( helper->hEdges, 11 );
847 : }
848 81 : rc = sqlite3_step( helper->hEdges );
849 81 : if( rc != SQLITE_OK && rc != SQLITE_DONE )
850 : {
851 : CPLError( CE_Failure, CPLE_AppDefined,
852 : "sqlite3_step() failed:\n %s",
853 0 : sqlite3_errmsg(helper->hDB) );
854 0 : return FALSE;
855 : }
856 81 : pItem = pItem->pNext;
857 : }
858 72 : return TRUE;
859 : }
860 :
861 72 : static void gmlHugeFileReset( struct huge_helper *helper )
862 : {
863 : /* resetting an empty helper struct */
864 : struct huge_tag *pNext;
865 72 : struct huge_tag *p = helper->pFirst;
866 :
867 : /* cleaning any previous item */
868 225 : while( p != NULL )
869 : {
870 81 : pNext = p->pNext;
871 81 : if( p->gmlTagValue != NULL )
872 81 : delete p->gmlTagValue;
873 81 : if( p->gmlId != NULL )
874 81 : delete p->gmlId;
875 81 : if( p->gmlNodeFrom != NULL )
876 81 : delete p->gmlNodeFrom;
877 81 : if( p->gmlNodeTo != NULL )
878 81 : delete p->gmlNodeTo;
879 81 : delete p;
880 81 : p = pNext;
881 : }
882 72 : helper->pFirst = NULL;
883 72 : helper->pLast = NULL;
884 72 : }
885 :
886 14 : static void gmlHugeFileHrefReset( struct huge_helper *helper )
887 : {
888 : /* resetting an empty helper struct */
889 : struct huge_href *pNext;
890 14 : struct huge_href *p = helper->pFirstHref;
891 :
892 : /* cleaning any previous item */
893 151 : while( p != NULL )
894 : {
895 123 : pNext = p->pNext;
896 123 : if( p->gmlId != NULL )
897 123 : delete p->gmlId;
898 123 : if( p->gmlText != NULL )
899 123 : delete p->gmlText;
900 123 : delete p;
901 123 : p = pNext;
902 : }
903 14 : helper->pFirstHref = NULL;
904 14 : helper->pLastHref = NULL;
905 14 : }
906 :
907 14 : static int gmlHugeFileHrefCheck( struct huge_helper *helper )
908 : {
909 : /* testing for unresolved items */
910 14 : int bError = FALSE;
911 14 : struct huge_href *p = helper->pFirstHref;
912 151 : while( p != NULL )
913 : {
914 123 : if( p->gmlText == NULL)
915 : {
916 0 : bError = TRUE;
917 : CPLError( CE_Failure, CPLE_AppDefined,
918 : "Edge xlink:href\"%s\": unresolved match",
919 0 : p->gmlId->c_str() );
920 : }
921 123 : p = p->pNext;
922 : }
923 14 : if( bError == TRUE )
924 0 : return FALSE;
925 14 : return TRUE;
926 : }
927 :
928 14 : static void gmlHugeFileRewiterReset( struct huge_helper *helper )
929 : {
930 : /* resetting an empty helper struct */
931 : struct huge_parent *pNext;
932 14 : struct huge_parent *p = helper->pFirstParent;
933 :
934 : /* cleaning any previous item */
935 54 : while( p != NULL )
936 : {
937 26 : pNext = p->pNext;
938 : struct huge_child *pChildNext;
939 26 : struct huge_child *pChild = p->pFirst;
940 216 : while( pChild != NULL )
941 : {
942 164 : pChildNext = pChild->pNext;
943 164 : delete pChild;
944 164 : pChild = pChildNext;
945 : }
946 26 : delete p;
947 26 : p = pNext;
948 : }
949 14 : helper->pFirstParent = NULL;
950 14 : helper->pLastParent = NULL;
951 14 : }
952 :
953 97 : static struct huge_tag *gmlHugeAddToHelper( struct huge_helper *helper,
954 : CPLString *gmlId,
955 : CPLString *gmlFragment )
956 : {
957 : /* adding an item into the linked list */
958 : struct huge_tag *pItem;
959 :
960 : /* checking against duplicates */
961 97 : pItem = helper->pFirst;
962 339 : while( pItem != NULL )
963 : {
964 161 : if( EQUAL( pItem->gmlId->c_str(), gmlId->c_str() ) )
965 16 : return NULL;
966 145 : pItem = pItem->pNext;
967 : }
968 :
969 81 : pItem = new struct huge_tag;
970 81 : pItem->gmlId = gmlId;
971 81 : pItem->gmlTagValue = gmlFragment;
972 81 : pItem->gmlNodeFrom = NULL;
973 81 : pItem->gmlNodeTo = NULL;
974 81 : pItem->bHasCoords = FALSE;
975 81 : pItem->bHasZ = FALSE;
976 81 : pItem->pNext = NULL;
977 :
978 : /* appending the item to the linked list */
979 81 : if ( helper->pFirst == NULL )
980 59 : helper->pFirst = pItem;
981 81 : if ( helper->pLast != NULL )
982 22 : helper->pLast->pNext = pItem;
983 81 : helper->pLast = pItem;
984 81 : return pItem;
985 : }
986 :
987 123 : static void gmlHugeAddPendingToHelper( struct huge_helper *helper,
988 : CPLString *gmlId,
989 : const CPLXMLNode *psParent,
990 : const CPLXMLNode *psNode,
991 : int bIsDirectedEdge,
992 : char cOrientation )
993 : {
994 : /* inserting an item into the linked list */
995 : struct huge_href *pItem;
996 :
997 : /* checking against duplicates */
998 123 : pItem = helper->pFirstHref;
999 820 : while( pItem != NULL )
1000 : {
1001 574 : if( EQUAL( pItem->gmlId->c_str(), gmlId->c_str() ) &&
1002 : pItem->psParent == psParent &&
1003 : pItem->psNode == psNode &&
1004 : pItem->cOrientation == cOrientation &&
1005 : pItem->bIsDirectedEdge == bIsDirectedEdge )
1006 : {
1007 0 : delete gmlId;
1008 0 : return;
1009 : }
1010 574 : pItem = pItem->pNext;
1011 : }
1012 :
1013 123 : pItem = new struct huge_href;
1014 123 : pItem->gmlId = gmlId;
1015 123 : pItem->gmlText = NULL;
1016 123 : pItem->psParent = psParent;
1017 123 : pItem->psNode = psNode;
1018 123 : pItem->bIsDirectedEdge = bIsDirectedEdge;
1019 123 : pItem->cOrientation = cOrientation;
1020 123 : pItem->pNext = NULL;
1021 :
1022 : /* appending the item to the linked list */
1023 123 : if ( helper->pFirstHref == NULL )
1024 14 : helper->pFirstHref = pItem;
1025 123 : if ( helper->pLastHref != NULL )
1026 109 : helper->pLastHref->pNext = pItem;
1027 123 : helper->pLastHref = pItem;
1028 : }
1029 :
1030 97 : static int gmlHugeFindGmlId( const CPLXMLNode *psNode, CPLString **gmlId )
1031 : {
1032 : /* attempting to identify a gml:id value */
1033 97 : *gmlId = NULL;
1034 97 : const CPLXMLNode *psChild = psNode->psChild;
1035 194 : while( psChild != NULL )
1036 : {
1037 97 : if( psChild->eType == CXT_Attribute &&
1038 : EQUAL( psChild->pszValue, "gml:id" ) )
1039 : {
1040 97 : const CPLXMLNode *psIdValue = psChild->psChild;
1041 97 : if( psIdValue != NULL )
1042 : {
1043 97 : if( psIdValue->eType == CXT_Text )
1044 : {
1045 97 : *gmlId = new CPLString(psIdValue->pszValue);
1046 97 : return TRUE;
1047 : }
1048 : }
1049 : }
1050 0 : psChild = psChild->psNext;
1051 : }
1052 0 : return FALSE;
1053 : }
1054 :
1055 81 : static void gmlHugeFileNodeCoords( struct huge_tag *pItem,
1056 : const CPLXMLNode * psNode,
1057 : CPLString **nodeSrs )
1058 : {
1059 : /*
1060 : / this function attempts to set coordinates for <Node> items
1061 : / when required (an <Edge> is expected to be processed)
1062 : */
1063 :
1064 : /* attempting to fetch Node coordinates */
1065 81 : CPLXMLNode *psTopoCurve = CPLCreateXMLNode(NULL, CXT_Element, "TopoCurve");
1066 81 : CPLXMLNode *psDirEdge = CPLCreateXMLNode(psTopoCurve, CXT_Element, "directedEdge");
1067 81 : CPLXMLNode *psEdge = CPLCloneXMLTree((CPLXMLNode *)psNode);
1068 81 : CPLAddXMLChild( psDirEdge, psEdge );
1069 : OGRGeometryCollection *poColl = (OGRGeometryCollection *)
1070 81 : GML2OGRGeometry_XMLNode( psTopoCurve, FALSE );
1071 81 : CPLDestroyXMLNode( psTopoCurve );
1072 81 : if( poColl != NULL )
1073 : {
1074 81 : int iCount = poColl->getNumGeometries();
1075 81 : if( iCount == 1 )
1076 : {
1077 81 : OGRGeometry * poChild = (OGRGeometry*)poColl->getGeometryRef(0);
1078 81 : int type = wkbFlatten( poChild->getGeometryType());
1079 81 : if( type == wkbLineString )
1080 : {
1081 81 : OGRLineString *poLine = (OGRLineString *)poChild;
1082 81 : int iPoints = poLine->getNumPoints();
1083 81 : if( iPoints >= 2 )
1084 : {
1085 81 : pItem->bHasCoords = TRUE;
1086 81 : pItem->xNodeFrom = poLine->getX( 0 );
1087 81 : pItem->yNodeFrom = poLine->getY( 0 );
1088 81 : pItem->xNodeTo = poLine->getX( iPoints - 1 );
1089 81 : pItem->yNodeTo = poLine->getY( iPoints - 1 );
1090 81 : if( poLine->getCoordinateDimension() == 3 )
1091 : {
1092 0 : pItem->zNodeFrom = poLine->getZ( 0 );
1093 0 : pItem->zNodeTo = poLine->getZ( iPoints - 1 );
1094 0 : pItem->bHasZ = TRUE;
1095 : }
1096 : else
1097 81 : pItem->bHasZ = FALSE;
1098 : }
1099 : }
1100 : }
1101 81 : delete poColl;
1102 : }
1103 :
1104 : /* searching the <directedNode> sub-tags */
1105 81 : const CPLXMLNode *psChild = psNode->psChild;
1106 486 : while( psChild != NULL )
1107 : {
1108 324 : if( psChild->eType == CXT_Element &&
1109 : EQUAL( psChild->pszValue, "directedNode" ) )
1110 : {
1111 162 : char cOrientation = '+';
1112 162 : const char *pszGmlId = NULL;
1113 162 : int bIsHref = FALSE;
1114 162 : const CPLXMLNode *psAttr = psChild->psChild;
1115 567 : while( psAttr != NULL )
1116 : {
1117 243 : if( psAttr->eType == CXT_Attribute &&
1118 : EQUAL( psAttr->pszValue, "xlink:href" ) )
1119 : {
1120 96 : const CPLXMLNode *psHref = psAttr->psChild;
1121 96 : if( psHref != NULL )
1122 : {
1123 96 : if( psHref->eType == CXT_Text )
1124 : {
1125 96 : pszGmlId = psHref->pszValue;
1126 96 : bIsHref = TRUE;
1127 : }
1128 : }
1129 : }
1130 243 : if( psAttr->eType == CXT_Attribute &&
1131 : EQUAL( psAttr->pszValue, "orientation" ) )
1132 : {
1133 81 : const CPLXMLNode *psOrientation = psAttr->psChild;
1134 81 : if( psOrientation != NULL )
1135 : {
1136 81 : if( psOrientation->eType == CXT_Text )
1137 : {
1138 81 : cOrientation = *(psOrientation->pszValue);
1139 : }
1140 : }
1141 : }
1142 243 : if( psAttr->eType == CXT_Element &&
1143 : EQUAL( psAttr->pszValue, "Node" ) )
1144 : {
1145 66 : const CPLXMLNode *psId = psAttr->psChild;
1146 198 : while( psId != NULL )
1147 : {
1148 66 : if( psId->eType == CXT_Attribute &&
1149 : EQUAL( psId->pszValue, "gml:id" ) )
1150 : {
1151 66 : const CPLXMLNode *psIdGml = psId->psChild;
1152 66 : if( psIdGml != NULL )
1153 : {
1154 66 : if( psIdGml->eType == CXT_Text )
1155 : {
1156 66 : pszGmlId = psIdGml->pszValue;
1157 66 : bIsHref = FALSE;
1158 : }
1159 : }
1160 : }
1161 66 : psId = psId->psNext;
1162 : }
1163 : }
1164 243 : psAttr = psAttr->psNext;
1165 : }
1166 162 : if( pszGmlId != NULL )
1167 : {
1168 : CPLString* posNode;
1169 162 : if( bIsHref == TRUE )
1170 : {
1171 96 : if (pszGmlId[0] != '#')
1172 : {
1173 : CPLError(CE_Warning, CPLE_NotSupported,
1174 : "Only values of xlink:href element starting with '#' are supported, "
1175 0 : "so %s will not be properly recognized", pszGmlId);
1176 : }
1177 96 : posNode = new CPLString(pszGmlId+1);
1178 : }
1179 : else
1180 66 : posNode = new CPLString(pszGmlId);
1181 162 : if( cOrientation == '-' )
1182 : {
1183 81 : pItem->gmlNodeFrom = posNode;
1184 81 : pItem->bIsNodeFromHref = bIsHref;
1185 : }
1186 : else
1187 : {
1188 81 : pItem->gmlNodeTo = posNode;
1189 81 : pItem->bIsNodeToHref = bIsHref;
1190 : }
1191 162 : pszGmlId = NULL;
1192 162 : bIsHref = FALSE;
1193 162 : cOrientation = '+';
1194 : }
1195 : }
1196 324 : psChild = psChild->psNext;
1197 : }
1198 81 : }
1199 :
1200 251 : static void gmlHugeFileCheckXrefs( struct huge_helper *helper,
1201 : const CPLXMLNode *psNode )
1202 : {
1203 : /* identifying <Edge> GML nodes */
1204 251 : if( psNode->eType == CXT_Element )
1205 : {
1206 251 : if( EQUAL(psNode->pszValue, "Edge") == TRUE )
1207 : {
1208 97 : CPLString *gmlId = NULL;
1209 97 : if( gmlHugeFindGmlId( psNode, &gmlId ) == TRUE )
1210 : {
1211 97 : char * gmlText = CPLSerializeXMLTree((CPLXMLNode *)psNode);
1212 97 : CPLString *gmlValue = new CPLString(gmlText);
1213 97 : CPLFree( gmlText );
1214 : struct huge_tag *pItem = gmlHugeAddToHelper( helper, gmlId,
1215 97 : gmlValue );
1216 97 : if( pItem != NULL )
1217 81 : gmlHugeFileNodeCoords( pItem, psNode, &(helper->nodeSrs) );
1218 : else
1219 : {
1220 16 : delete gmlId;
1221 16 : delete gmlValue;
1222 : }
1223 : }
1224 : }
1225 : }
1226 :
1227 : /* recursively scanning each Child GML node */
1228 251 : const CPLXMLNode *psChild = psNode->psChild;
1229 1064 : while( psChild != NULL )
1230 : {
1231 562 : if( psChild->eType == CXT_Element )
1232 : {
1233 465 : if( EQUAL(psChild->pszValue, "Edge") == TRUE ||
1234 : EQUAL(psChild->pszValue, "directedEdge") == TRUE )
1235 : {
1236 148 : gmlHugeFileCheckXrefs( helper, psChild );
1237 : }
1238 465 : if( EQUAL(psChild->pszValue, "directedFace") == TRUE )
1239 : {
1240 26 : const CPLXMLNode *psFace = psChild->psChild;
1241 26 : if( psFace != NULL )
1242 : {
1243 26 : if( psFace->eType == CXT_Element &&
1244 : EQUAL(psFace->pszValue, "Face") == TRUE)
1245 : {
1246 24 : const CPLXMLNode *psDirEdge = psFace->psChild;
1247 205 : while (psDirEdge != NULL)
1248 : {
1249 157 : const CPLXMLNode *psEdge = psDirEdge->psChild;
1250 536 : while( psEdge != NULL)
1251 : {
1252 222 : if( psEdge->eType == CXT_Element &&
1253 : EQUAL(psEdge->pszValue, "Edge") == TRUE)
1254 15 : gmlHugeFileCheckXrefs( helper, psEdge );
1255 222 : psEdge = psEdge->psNext;
1256 : }
1257 157 : psDirEdge = psDirEdge->psNext;
1258 : }
1259 : }
1260 : }
1261 : }
1262 : }
1263 562 : psChild = psChild->psNext;
1264 : }
1265 :
1266 : /* recursively scanning each GML of the same level */
1267 251 : const CPLXMLNode *psNext = psNode->psNext;
1268 518 : while( psNext != NULL )
1269 : {
1270 16 : if( psNext->eType == CXT_Element )
1271 : {
1272 16 : if( EQUAL(psNext->pszValue, "Edge") == TRUE ||
1273 : EQUAL(psNext->pszValue, "directedEdge") == TRUE )
1274 : {
1275 16 : gmlHugeFileCheckXrefs( helper, psNext );
1276 : }
1277 : }
1278 16 : psNext = psNext->psNext;
1279 : }
1280 251 : }
1281 :
1282 2 : static void gmlHugeFileCleanUp ( struct huge_helper *helper )
1283 : {
1284 : /* cleaning up any SQLite handle */
1285 2 : if( helper->hNodes != NULL )
1286 0 : sqlite3_finalize ( helper->hNodes );
1287 2 : if( helper->hEdges != NULL )
1288 0 : sqlite3_finalize ( helper->hEdges );
1289 2 : if( helper->hDB != NULL )
1290 2 : sqlite3_close( helper->hDB );
1291 2 : if( helper->nodeSrs != NULL )
1292 0 : delete helper->nodeSrs;
1293 2 : }
1294 :
1295 328 : static void gmlHugeFileCheckPendingHrefs( struct huge_helper *helper,
1296 : const CPLXMLNode *psParent,
1297 : const CPLXMLNode *psNode )
1298 : {
1299 : /* identifying any xlink:href to be replaced */
1300 328 : if( psNode->eType == CXT_Element )
1301 : {
1302 328 : if( EQUAL(psNode->pszValue, "directedEdge") == TRUE )
1303 : {
1304 204 : char cOrientation = '+';
1305 204 : CPLXMLNode *psAttr = psNode->psChild;
1306 680 : while( psAttr != NULL )
1307 : {
1308 272 : if( psAttr->eType == CXT_Attribute &&
1309 : EQUAL( psAttr->pszValue, "orientation" ) )
1310 : {
1311 68 : const CPLXMLNode *psOrientation = psAttr->psChild;
1312 68 : if( psOrientation != NULL )
1313 : {
1314 68 : if( psOrientation->eType == CXT_Text )
1315 68 : cOrientation = *(psOrientation->pszValue);
1316 : }
1317 : }
1318 272 : psAttr = psAttr->psNext;
1319 : }
1320 204 : psAttr = psNode->psChild;
1321 680 : while( psAttr != NULL )
1322 : {
1323 272 : if( psAttr->eType == CXT_Attribute &&
1324 : EQUAL( psAttr->pszValue, "xlink:href" ) )
1325 : {
1326 123 : const CPLXMLNode *pszHref = psAttr->psChild;
1327 123 : if( pszHref != NULL )
1328 : {
1329 123 : if( pszHref->eType == CXT_Text )
1330 : {
1331 123 : if (pszHref->pszValue[0] != '#')
1332 : {
1333 : CPLError(CE_Warning, CPLE_NotSupported,
1334 : "Only values of xlink:href element starting with '#' are supported, "
1335 0 : "so %s will not be properly recognized", pszHref->pszValue);
1336 : }
1337 123 : CPLString *gmlId = new CPLString(pszHref->pszValue+1);
1338 : gmlHugeAddPendingToHelper( helper, gmlId, psParent,
1339 123 : psNode, TRUE, cOrientation );
1340 : }
1341 : }
1342 : }
1343 272 : psAttr = psAttr->psNext;
1344 : }
1345 : }
1346 : }
1347 :
1348 : /* recursively scanning each Child GML node */
1349 328 : const CPLXMLNode *psChild = psNode->psChild;
1350 1212 : while( psChild != NULL )
1351 : {
1352 556 : if( psChild->eType == CXT_Element )
1353 : {
1354 337 : if( EQUAL(psChild->pszValue, "directedEdge") == TRUE ||
1355 : EQUAL(psChild->pszValue, "directedFace") == TRUE ||
1356 : EQUAL(psChild->pszValue, "Face") == TRUE)
1357 : {
1358 256 : gmlHugeFileCheckPendingHrefs( helper, psNode, psChild );
1359 : }
1360 : }
1361 556 : psChild = psChild->psNext;
1362 : }
1363 :
1364 : /* recursively scanning each GML of the same level */
1365 328 : const CPLXMLNode *psNext = psNode->psNext;
1366 1104 : while( psNext != NULL )
1367 : {
1368 448 : if( psNext->eType == CXT_Element )
1369 : {
1370 448 : if( EQUAL(psNext->pszValue, "Face") == TRUE )
1371 : {
1372 0 : gmlHugeFileCheckPendingHrefs( helper, psParent, psNext );
1373 : }
1374 : }
1375 448 : psNext = psNext->psNext;
1376 : }
1377 328 : }
1378 :
1379 123 : static void gmlHugeSetHrefGmlText( struct huge_helper *helper,
1380 : const char *pszGmlId,
1381 : const char *pszGmlText )
1382 : {
1383 : /* setting the GML text for the corresponding gml:id */
1384 123 : struct huge_href *pItem = helper->pFirstHref;
1385 820 : while( pItem != NULL )
1386 : {
1387 697 : if( EQUAL( pItem->gmlId->c_str(), pszGmlId ) == TRUE )
1388 : {
1389 123 : if( pItem->gmlText != NULL)
1390 0 : delete pItem->gmlText;
1391 123 : pItem->gmlText = new CPLString( pszGmlText );
1392 123 : return;
1393 : }
1394 574 : pItem = pItem->pNext;
1395 : }
1396 : }
1397 :
1398 123 : static struct huge_parent *gmlHugeFindParent( struct huge_helper *helper,
1399 : CPLXMLNode *psParent )
1400 : {
1401 : /* inserting a GML Node (parent) to be rewritted */
1402 123 : struct huge_parent *pItem = helper->pFirstParent;
1403 :
1404 : /* checking if already exists */
1405 318 : while( pItem != NULL )
1406 : {
1407 169 : if( pItem->psParent == psParent )
1408 97 : return pItem;
1409 72 : pItem = pItem->pNext;
1410 : }
1411 :
1412 : /* creating a new Parent Node */
1413 26 : pItem = new struct huge_parent;
1414 26 : pItem->psParent = psParent;
1415 26 : pItem->pFirst = NULL;
1416 26 : pItem->pLast = NULL;
1417 26 : pItem->pNext = NULL;
1418 26 : if( helper->pFirstParent == NULL )
1419 14 : helper->pFirstParent = pItem;
1420 26 : if( helper->pLastParent != NULL )
1421 12 : helper->pLastParent->pNext = pItem;
1422 26 : helper->pLastParent = pItem;
1423 :
1424 : /* inserting any Child node into the Parent */
1425 26 : CPLXMLNode *psChild = psParent->psChild;
1426 216 : while( psChild != NULL )
1427 : {
1428 : struct huge_child *pChildItem;
1429 164 : pChildItem = new struct huge_child;
1430 164 : pChildItem->psChild = psChild;
1431 164 : pChildItem->pItem = NULL;
1432 164 : pChildItem->pNext = NULL;
1433 164 : if( pItem->pFirst == NULL )
1434 26 : pItem->pFirst = pChildItem;
1435 164 : if( pItem->pLast != NULL )
1436 138 : pItem->pLast->pNext = pChildItem;
1437 164 : pItem->pLast = pChildItem;
1438 164 : psChild = psChild->psNext;
1439 : }
1440 26 : return pItem;
1441 : }
1442 :
1443 123 : static int gmlHugeSetChild( struct huge_parent *pParent,
1444 : struct huge_href *pItem )
1445 : {
1446 : /* setting a Child Node to be rewritted */
1447 123 : struct huge_child *pChild = pParent->pFirst;
1448 712 : while( pChild != NULL )
1449 : {
1450 589 : if( pChild->psChild == pItem->psNode )
1451 : {
1452 123 : pChild->pItem = pItem;
1453 123 : return TRUE;
1454 : }
1455 466 : pChild = pChild->pNext;
1456 : }
1457 0 : return FALSE;
1458 : }
1459 :
1460 14 : static int gmlHugeResolveEdges( struct huge_helper *helper,
1461 : CPLXMLNode *psNode, sqlite3 *hDB )
1462 : {
1463 : /* resolving GML <Edge> xlink:href */
1464 14 : CPLString osCommand;
1465 : sqlite3_stmt *hStmtEdges;
1466 : int rc;
1467 14 : int bIsComma = FALSE;
1468 14 : int bError = FALSE;
1469 : struct huge_href *pItem;
1470 : struct huge_parent *pParent;
1471 :
1472 : /* query cursor [Edges] */
1473 : osCommand = "SELECT gml_id, gml_resolved "
1474 : "FROM gml_edges "
1475 14 : "WHERE gml_id IN (";
1476 14 : pItem = helper->pFirstHref;
1477 151 : while( pItem != NULL )
1478 : {
1479 123 : if( bIsComma == TRUE )
1480 109 : osCommand += ", ";
1481 : else
1482 14 : bIsComma = TRUE;
1483 123 : osCommand += "'";
1484 123 : osCommand += pItem->gmlId->c_str();
1485 123 : osCommand += "'";
1486 123 : pItem = pItem->pNext;
1487 : }
1488 14 : osCommand += ")";
1489 14 : rc = sqlite3_prepare( hDB, osCommand.c_str(), -1, &hStmtEdges, NULL );
1490 14 : if( rc != SQLITE_OK )
1491 : {
1492 : CPLError( CE_Failure, CPLE_AppDefined,
1493 0 : "Unable to create QUERY stmt for EDGES" );
1494 0 : return FALSE;
1495 : }
1496 123 : while ( TRUE )
1497 : {
1498 137 : rc = sqlite3_step( hStmtEdges );
1499 137 : if( rc == SQLITE_DONE )
1500 14 : break;
1501 123 : if ( rc == SQLITE_ROW )
1502 : {
1503 : const char *pszGmlId;
1504 123 : const char *pszGmlText = NULL;
1505 123 : pszGmlId = (const char *)sqlite3_column_text ( hStmtEdges, 0 );
1506 123 : if( sqlite3_column_type( hStmtEdges, 1 ) != SQLITE_NULL )
1507 123 : pszGmlText = (const char *)sqlite3_column_text ( hStmtEdges, 1 );
1508 123 : gmlHugeSetHrefGmlText( helper, pszGmlId, pszGmlText );
1509 : }
1510 : else
1511 : {
1512 : CPLError( CE_Failure, CPLE_AppDefined,
1513 : "Edge xlink:href QUERY: sqlite3_step(%s)",
1514 0 : sqlite3_errmsg(hDB) );
1515 0 : bError = TRUE;
1516 0 : break;
1517 : }
1518 : }
1519 14 : sqlite3_finalize ( hStmtEdges );
1520 14 : if( bError == TRUE )
1521 0 : return FALSE;
1522 :
1523 : /* indentifying any GML node to be rewritten */
1524 14 : pItem = helper->pFirstHref;
1525 151 : while( pItem != NULL )
1526 : {
1527 123 : if( pItem->gmlText == NULL || pItem->psParent == NULL ||
1528 : pItem->psNode == NULL )
1529 : {
1530 0 : bError = TRUE;
1531 0 : break;
1532 : }
1533 123 : pParent = gmlHugeFindParent( helper, (CPLXMLNode *)pItem->psParent );
1534 123 : if( gmlHugeSetChild( pParent, pItem ) == FALSE )
1535 : {
1536 0 : bError = TRUE;
1537 0 : break;
1538 : }
1539 123 : pItem = pItem->pNext;
1540 : }
1541 :
1542 14 : if( bError == FALSE )
1543 : {
1544 : /* rewriting GML nodes */
1545 14 : pParent = helper->pFirstParent;
1546 54 : while( pParent != NULL )
1547 : {
1548 : struct huge_child *pChild;
1549 :
1550 : /* removing any Child node from the Parent */
1551 26 : pChild = pParent->pFirst;
1552 216 : while( pChild != NULL )
1553 : {
1554 164 : CPLRemoveXMLChild( pParent->psParent, pChild->psChild );
1555 :
1556 : /* destroyng any Child Node to be rewritten */
1557 164 : if( pChild->pItem != NULL )
1558 123 : CPLDestroyXMLNode( pChild->psChild );
1559 164 : pChild = pChild->pNext;
1560 : }
1561 :
1562 : /* rewriting the Parent Node */
1563 26 : pChild = pParent->pFirst;
1564 216 : while( pChild != NULL )
1565 : {
1566 164 : if( pChild->pItem == NULL )
1567 : {
1568 : /* reinserting any untouched Child Node */
1569 41 : CPLAddXMLChild( pParent->psParent, pChild->psChild );
1570 : }
1571 : else
1572 : {
1573 : /* rewriting a Child Node */
1574 123 : CPLXMLNode *psNewNode = CPLCreateXMLNode(NULL, CXT_Element, "directedEdge");
1575 123 : if( pChild->pItem->cOrientation == '-' )
1576 : {
1577 67 : CPLXMLNode *psOrientationNode = CPLCreateXMLNode(psNewNode, CXT_Attribute, "orientation");
1578 67 : CPLCreateXMLNode(psOrientationNode, CXT_Text, "-");
1579 : }
1580 123 : CPLXMLNode *psEdge = CPLParseXMLString(pChild->pItem->gmlText->c_str());
1581 123 : CPLAddXMLChild( psNewNode, psEdge );
1582 123 : CPLAddXMLChild( pParent->psParent, psNewNode );
1583 : }
1584 164 : pChild = pChild->pNext;
1585 : }
1586 26 : pParent = pParent->pNext;
1587 : }
1588 : }
1589 :
1590 : /* resetting the Rewrite Helper to an empty state */
1591 14 : gmlHugeFileRewiterReset( helper );
1592 14 : if( bError == TRUE )
1593 0 : return FALSE;
1594 14 : return TRUE;
1595 : }
1596 :
1597 2 : static int gmlHugeFileWriteResolved ( struct huge_helper *helper,
1598 : const char *pszOutputFilename,
1599 : GMLReader *pReader,
1600 : int *m_bSequentialLayers )
1601 : {
1602 : /* writing the resolved GML file */
1603 : VSILFILE *fp;
1604 : GMLFeature *poFeature;
1605 : const char *osCommand;
1606 : int rc;
1607 2 : sqlite3 *hDB = helper->hDB;
1608 : sqlite3_stmt *hStmtNodes;
1609 2 : int bError = FALSE;
1610 2 : int iOutCount = 0;
1611 :
1612 : /* -------------------------------------------------------------------- */
1613 : /* Opening the resolved GML file */
1614 : /* -------------------------------------------------------------------- */
1615 2 : fp = VSIFOpenL( pszOutputFilename, "w" );
1616 2 : if( fp == NULL )
1617 : {
1618 : CPLError( CE_Failure, CPLE_OpenFailed,
1619 0 : "Failed to open %.500s to write.", pszOutputFilename );
1620 0 : return FALSE;
1621 : }
1622 :
1623 : /* query cursor [Nodes] */
1624 : osCommand = "SELECT gml_id, x, y, z "
1625 2 : "FROM nodes";
1626 2 : rc = sqlite3_prepare( hDB, osCommand, -1, &hStmtNodes, NULL );
1627 2 : if( rc != SQLITE_OK )
1628 : {
1629 : CPLError( CE_Failure, CPLE_AppDefined,
1630 0 : "Unable to create QUERY stmt for NODES" );
1631 0 : VSIFCloseL( fp );
1632 0 : return FALSE;
1633 : }
1634 :
1635 2 : VSIFPrintfL ( fp, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" );
1636 : VSIFPrintfL ( fp, "<ResolvedTopoFeatureCollection "
1637 2 : "xmlns:gml=\"http://www.opengis.net/gml\">\n" );
1638 2 : VSIFPrintfL ( fp, " <ResolvedTopoFeatureMembers>\n" );
1639 : /* exporting Nodes */
1640 2 : GFSTemplateList *pCC = new GFSTemplateList();
1641 66 : while ( TRUE )
1642 : {
1643 68 : rc = sqlite3_step( hStmtNodes );
1644 68 : if( rc == SQLITE_DONE )
1645 : break;
1646 66 : if ( rc == SQLITE_ROW )
1647 : {
1648 : const char *pszGmlId;
1649 : char* pszEscaped;
1650 : double x;
1651 : double y;
1652 66 : double z = 0.0;
1653 66 : int bHasZ = FALSE;
1654 66 : pszGmlId = (const char *)sqlite3_column_text ( hStmtNodes, 0 );
1655 66 : x = sqlite3_column_double ( hStmtNodes, 1 );
1656 66 : y = sqlite3_column_double ( hStmtNodes, 2 );
1657 66 : if ( sqlite3_column_type( hStmtNodes, 3 ) == SQLITE_FLOAT )
1658 : {
1659 0 : z = sqlite3_column_double ( hStmtNodes, 3 );
1660 0 : bHasZ = TRUE;
1661 : }
1662 :
1663 : /* inserting a node into the resolved GML file */
1664 66 : pCC->Update( "ResolvedNodes", TRUE );
1665 66 : VSIFPrintfL ( fp, " <ResolvedNodes>\n" );
1666 66 : pszEscaped = CPLEscapeString( pszGmlId, -1, CPLES_XML );
1667 66 : VSIFPrintfL ( fp, " <NodeGmlId>%s</NodeGmlId>\n", pszEscaped );
1668 66 : CPLFree(pszEscaped);
1669 66 : VSIFPrintfL ( fp, " <ResolvedGeometry> \n" );
1670 66 : if ( helper->nodeSrs == NULL )
1671 : VSIFPrintfL ( fp, " <gml:Point srsDimension=\"%d\">",
1672 66 : ( bHasZ == TRUE ) ? 3 : 2 );
1673 : else
1674 : {
1675 0 : pszEscaped = CPLEscapeString( helper->nodeSrs->c_str(), -1, CPLES_XML );
1676 : VSIFPrintfL ( fp, " <gml:Point srsDimension=\"%d\""
1677 : " srsName=\"%s\">",
1678 : ( bHasZ == TRUE ) ? 3 : 2,
1679 0 : pszEscaped );
1680 0 : CPLFree(pszEscaped);
1681 : }
1682 66 : if ( bHasZ == TRUE )
1683 : VSIFPrintfL ( fp, "<gml:pos>%1.8f %1.8f %1.8f</gml:pos>"
1684 : "</gml:Point>\n",
1685 0 : x, y, z );
1686 : else
1687 : VSIFPrintfL ( fp, "<gml:pos>%1.8f %1.8f</gml:pos>"
1688 : "</gml:Point>\n",
1689 66 : x, y );
1690 66 : VSIFPrintfL ( fp, " </ResolvedGeometry> \n" );
1691 66 : VSIFPrintfL ( fp, " </ResolvedNodes>\n" );
1692 66 : iOutCount++;
1693 : }
1694 : else
1695 : {
1696 : CPLError( CE_Failure, CPLE_AppDefined,
1697 : "ResolvedNodes QUERY: sqlite3_step(%s)",
1698 0 : sqlite3_errmsg(hDB) );
1699 0 : sqlite3_finalize ( hStmtNodes );
1700 0 : return FALSE;
1701 : }
1702 : }
1703 2 : sqlite3_finalize ( hStmtNodes );
1704 :
1705 : /* processing GML features */
1706 76 : while( (poFeature = pReader->NextFeature()) != NULL )
1707 : {
1708 72 : GMLFeatureClass *poClass = poFeature->GetClass();
1709 72 : const CPLXMLNode* const * papsGeomList = poFeature->GetGeometryList();
1710 72 : int iPropCount = poClass->GetPropertyCount();
1711 :
1712 72 : int b_has_geom = FALSE;
1713 72 : VSIFPrintfL ( fp, " <%s>\n", poClass->GetElementName() );
1714 :
1715 252 : for( int iProp = 0; iProp < iPropCount; iProp++ )
1716 : {
1717 180 : GMLPropertyDefn *poPropDefn = poClass->GetProperty( iProp );
1718 180 : const char *pszPropName = poPropDefn->GetName();
1719 180 : const GMLProperty *poProp = poFeature->GetProperty( iProp );
1720 :
1721 180 : if( poProp != NULL )
1722 : {
1723 360 : for( int iSub = 0; iSub < poProp->nSubProperties; iSub++ )
1724 : {
1725 180 : char *gmlText = CPLEscapeString( poProp->papszSubProperties[iSub],
1726 : -1,
1727 360 : CPLES_XML );
1728 : VSIFPrintfL ( fp, " <%s>%s</%s>\n",
1729 180 : pszPropName, gmlText, pszPropName );
1730 180 : CPLFree( gmlText );
1731 : }
1732 : }
1733 : }
1734 :
1735 72 : if( papsGeomList != NULL )
1736 : {
1737 72 : int i = 0;
1738 72 : const CPLXMLNode *psNode = papsGeomList[i];
1739 216 : while( psNode != NULL )
1740 : {
1741 72 : char *pszResolved = NULL;
1742 : int bNotToBeResolved;
1743 72 : if( psNode->eType != CXT_Element )
1744 0 : bNotToBeResolved = TRUE;
1745 : else
1746 : {
1747 144 : if( EQUAL(psNode->pszValue, "TopoCurve") == TRUE ||
1748 : EQUAL(psNode->pszValue, "TopoSurface") == TRUE )
1749 72 : bNotToBeResolved = FALSE;
1750 : else
1751 0 : bNotToBeResolved = TRUE;
1752 : }
1753 72 : if( bNotToBeResolved == TRUE )
1754 : {
1755 0 : VSIFPrintfL ( fp, " <ResolvedGeometry> \n" );
1756 0 : pszResolved = CPLSerializeXMLTree((CPLXMLNode *)psNode);
1757 0 : VSIFPrintfL ( fp, " %s\n", pszResolved );
1758 0 : CPLFree( pszResolved );
1759 0 : VSIFPrintfL ( fp, " </ResolvedGeometry>\n" );
1760 0 : b_has_geom = TRUE;
1761 : }
1762 : else
1763 : {
1764 72 : gmlHugeFileCheckPendingHrefs( helper, psNode, psNode );
1765 72 : if( helper->pFirstHref == NULL )
1766 : {
1767 58 : VSIFPrintfL ( fp, " <ResolvedGeometry> \n" );
1768 58 : pszResolved = CPLSerializeXMLTree((CPLXMLNode *)psNode);
1769 58 : VSIFPrintfL ( fp, " %s\n", pszResolved );
1770 58 : CPLFree( pszResolved );
1771 58 : VSIFPrintfL ( fp, " </ResolvedGeometry>\n" );
1772 58 : b_has_geom = TRUE;
1773 : }
1774 : else
1775 : {
1776 14 : if( gmlHugeResolveEdges( helper, (CPLXMLNode *)psNode,
1777 : hDB ) == FALSE)
1778 0 : bError = TRUE;
1779 14 : if( gmlHugeFileHrefCheck( helper ) == FALSE )
1780 0 : bError = TRUE;
1781 14 : VSIFPrintfL ( fp, " <ResolvedGeometry> \n" );
1782 14 : pszResolved = CPLSerializeXMLTree((CPLXMLNode *)psNode);
1783 14 : VSIFPrintfL ( fp, " %s\n", pszResolved );
1784 14 : CPLFree( pszResolved );
1785 14 : VSIFPrintfL ( fp, " </ResolvedGeometry>\n" );
1786 14 : b_has_geom = TRUE;
1787 14 : gmlHugeFileHrefReset( helper );
1788 : }
1789 : }
1790 72 : i++;
1791 72 : psNode = papsGeomList[i];
1792 : }
1793 : }
1794 72 : pCC->Update( poClass->GetElementName(), b_has_geom );
1795 :
1796 72 : VSIFPrintfL ( fp, " </%s>\n", poClass->GetElementName() );
1797 :
1798 72 : delete poFeature;
1799 72 : iOutCount++;
1800 : }
1801 :
1802 2 : VSIFPrintfL ( fp, " </ResolvedTopoFeatureMembers>\n" );
1803 2 : VSIFPrintfL ( fp, "</ResolvedTopoFeatureCollection>\n" );
1804 :
1805 2 : VSIFCloseL( fp );
1806 :
1807 2 : gmlUpdateFeatureClasses( pCC, pReader, m_bSequentialLayers );
1808 2 : if ( *m_bSequentialLayers == TRUE )
1809 2 : pReader->ReArrangeTemplateClasses( pCC );
1810 2 : delete pCC;
1811 2 : if( bError == TRUE || iOutCount == 0 )
1812 0 : return FALSE;
1813 2 : return TRUE;
1814 : }
1815 :
1816 : /**************************************************************/
1817 : /* */
1818 : /* private member(s): */
1819 : /* any other funtion is implemented as "internal" static, */
1820 : /* so to make all the SQLite own stuff nicely "invisible" */
1821 : /* */
1822 : /**************************************************************/
1823 :
1824 2 : int GMLReader::ParseXMLHugeFile( const char *pszOutputFilename,
1825 : const int bSqliteIsTempFile,
1826 : const int iSqliteCacheMB )
1827 :
1828 : {
1829 : GMLFeature *poFeature;
1830 2 : int iFeatureUID = 0;
1831 : int rc;
1832 2 : sqlite3 *hDB = NULL;
1833 2 : CPLString osSQLiteFilename;
1834 2 : const char *pszSQLiteFilename = NULL;
1835 : struct huge_helper helper;
1836 2 : char *pszErrMsg = NULL;
1837 :
1838 : /* initializing the helper struct */
1839 2 : helper.hDB = NULL;
1840 2 : helper.hNodes = NULL;
1841 2 : helper.hEdges = NULL;
1842 2 : helper.nodeSrs = NULL;
1843 2 : helper.pFirst = NULL;
1844 2 : helper.pLast = NULL;
1845 2 : helper.pFirstHref = NULL;
1846 2 : helper.pLastHref = NULL;
1847 2 : helper.pFirstParent = NULL;
1848 2 : helper.pLastParent = NULL;
1849 :
1850 : /* -------------------------------------------------------------------- */
1851 : /* Creating/Opening the SQLite DB file */
1852 : /* -------------------------------------------------------------------- */
1853 2 : osSQLiteFilename = CPLResetExtension( m_pszFilename, "sqlite" );
1854 2 : pszSQLiteFilename = osSQLiteFilename.c_str();
1855 :
1856 : VSIStatBufL statBufL;
1857 2 : if ( VSIStatExL ( pszSQLiteFilename, &statBufL, VSI_STAT_EXISTS_FLAG) == 0)
1858 : {
1859 : CPLError( CE_Failure, CPLE_OpenFailed,
1860 : "sqlite3_open(%s) failed:\n\tDB-file already exists",
1861 0 : pszSQLiteFilename );
1862 0 : return FALSE;
1863 : }
1864 :
1865 2 : rc = sqlite3_open( pszSQLiteFilename, &hDB );
1866 2 : if( rc != SQLITE_OK )
1867 : {
1868 : CPLError( CE_Failure, CPLE_OpenFailed,
1869 : "sqlite3_open(%s) failed: %s",
1870 0 : pszSQLiteFilename, sqlite3_errmsg( hDB ) );
1871 0 : return FALSE;
1872 : }
1873 2 : helper.hDB = hDB;
1874 :
1875 : /*
1876 : * setting SQLite for max speed; this is intrinsically unsafe,
1877 : * and the DB file could be potentially damaged (power failure ...]
1878 : *
1879 : * but after all this one simply is a TEMPORARY FILE !!
1880 : * so there is no real risk condition
1881 : */
1882 : rc = sqlite3_exec( hDB, "PRAGMA synchronous = OFF", NULL, NULL,
1883 2 : &pszErrMsg );
1884 2 : if( rc != SQLITE_OK )
1885 : {
1886 : CPLError( CE_Failure, CPLE_AppDefined,
1887 : "Unable to set PRAGMA synchronous = OFF: %s",
1888 0 : pszErrMsg );
1889 0 : sqlite3_free( pszErrMsg );
1890 : }
1891 : rc = sqlite3_exec( hDB, "PRAGMA journal_mode = OFF", NULL, NULL,
1892 2 : &pszErrMsg );
1893 2 : if( rc != SQLITE_OK )
1894 : {
1895 : CPLError( CE_Failure, CPLE_AppDefined,
1896 : "Unable to set PRAGMA journal_mode = OFF: %s",
1897 0 : pszErrMsg );
1898 0 : sqlite3_free( pszErrMsg );
1899 : }
1900 : rc = sqlite3_exec( hDB, "PRAGMA locking_mode = EXCLUSIVE", NULL, NULL,
1901 2 : &pszErrMsg );
1902 2 : if( rc != SQLITE_OK )
1903 : {
1904 : CPLError( CE_Failure, CPLE_AppDefined,
1905 : "Unable to set PRAGMA locking_mode = EXCLUSIVE: %s",
1906 0 : pszErrMsg );
1907 0 : sqlite3_free( pszErrMsg );
1908 : }
1909 :
1910 : /* setting the SQLite cache */
1911 2 : if( iSqliteCacheMB > 0 )
1912 : {
1913 0 : int cache_size = iSqliteCacheMB * 1024;
1914 :
1915 : /* refusing to allocate more than 1GB */
1916 0 : if( cache_size > 1024 * 1024 )
1917 0 : cache_size = 1024 * 1024;
1918 : char sqlPragma[1024];
1919 0 : sprintf( sqlPragma, "PRAGMA cache_size = %d", cache_size );
1920 0 : rc = sqlite3_exec( hDB, sqlPragma, NULL, NULL, &pszErrMsg );
1921 0 : if( rc != SQLITE_OK )
1922 : {
1923 : CPLError( CE_Failure, CPLE_AppDefined,
1924 0 : "Unable to set %s: %s", sqlPragma, pszErrMsg );
1925 0 : sqlite3_free( pszErrMsg );
1926 : }
1927 : }
1928 :
1929 2 : if( !SetupParser() )
1930 : {
1931 0 : gmlHugeFileCleanUp ( &helper );
1932 0 : return FALSE;
1933 : }
1934 :
1935 : /* creating SQLite tables and Insert cursors */
1936 2 : if( gmlHugeFileSQLiteInit( &helper ) == FALSE )
1937 : {
1938 0 : gmlHugeFileCleanUp ( &helper );
1939 0 : return FALSE;
1940 : }
1941 :
1942 : /* processing GML features */
1943 76 : while( (poFeature = NextFeature()) != NULL )
1944 : {
1945 72 : const CPLXMLNode* const * papsGeomList = poFeature->GetGeometryList();
1946 72 : if (papsGeomList != NULL)
1947 : {
1948 72 : int i = 0;
1949 72 : const CPLXMLNode *psNode = papsGeomList[i];
1950 216 : while(psNode)
1951 : {
1952 72 : gmlHugeFileCheckXrefs( &helper, psNode );
1953 : /* inserting into the SQLite DB any appropriate row */
1954 72 : gmlHugeFileSQLiteInsert ( &helper );
1955 : /* resetting an empty helper struct */
1956 72 : gmlHugeFileReset ( &helper );
1957 72 : i ++;
1958 72 : psNode = papsGeomList[i];
1959 : }
1960 : }
1961 72 : iFeatureUID++;
1962 72 : delete poFeature;
1963 : }
1964 :
1965 : /* finalizing any SQLite Insert cursor */
1966 2 : if( helper.hNodes != NULL )
1967 2 : sqlite3_finalize ( helper.hNodes );
1968 2 : helper.hNodes = NULL;
1969 2 : if( helper.hEdges != NULL )
1970 2 : sqlite3_finalize ( helper.hEdges );
1971 2 : helper.hEdges = NULL;
1972 :
1973 : /* confirming the still pending TRANSACTION */
1974 2 : rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL, &pszErrMsg );
1975 2 : if( rc != SQLITE_OK )
1976 : {
1977 : CPLError( CE_Failure, CPLE_AppDefined,
1978 : "Unable to perform COMMIT TRANSACTION: %s",
1979 0 : pszErrMsg );
1980 0 : sqlite3_free( pszErrMsg );
1981 0 : return FALSE;
1982 : }
1983 :
1984 : /* attempting to resolve GML strings */
1985 2 : if( gmlHugeFileResolveEdges( &helper ) == FALSE )
1986 : {
1987 0 : gmlHugeFileCleanUp ( &helper );
1988 0 : return FALSE;
1989 : }
1990 :
1991 : /* restarting the GML parser */
1992 2 : if( !SetupParser() )
1993 : {
1994 0 : gmlHugeFileCleanUp ( &helper );
1995 0 : return FALSE;
1996 : }
1997 :
1998 : /* output: writing the revolved GML file */
1999 2 : if ( gmlHugeFileWriteResolved( &helper, pszOutputFilename, this,
2000 : &m_bSequentialLayers ) == FALSE)
2001 : {
2002 0 : gmlHugeFileCleanUp ( &helper );
2003 0 : return FALSE;
2004 : }
2005 :
2006 2 : gmlHugeFileCleanUp ( &helper );
2007 2 : if ( bSqliteIsTempFile == TRUE )
2008 2 : VSIUnlink( pszSQLiteFilename );
2009 2 : return TRUE;
2010 : }
2011 :
2012 : /**************************************************************/
2013 : /* */
2014 : /* an alternative <xlink:href> resolver based on SQLite */
2015 : /* */
2016 : /**************************************************************/
2017 2 : int GMLReader::HugeFileResolver( const char *pszFile,
2018 : int bSqliteIsTempFile,
2019 : int iSqliteCacheMB )
2020 :
2021 : {
2022 : // Check if the original source file is set.
2023 2 : if( m_pszFilename == NULL )
2024 : {
2025 : CPLError( CE_Failure, CPLE_NotSupported,
2026 : "GML source file needs to be set first with "
2027 0 : "GMLReader::SetSourceFile()." );
2028 0 : return FALSE;
2029 : }
2030 2 : if ( ParseXMLHugeFile( pszFile, bSqliteIsTempFile, iSqliteCacheMB ) == FALSE )
2031 0 : return FALSE;
2032 :
2033 : //set the source file to the resolved file
2034 2 : CleanupParser();
2035 2 : if (fpGML)
2036 2 : VSIFCloseL(fpGML);
2037 2 : fpGML = NULL;
2038 2 : CPLFree( m_pszFilename );
2039 2 : m_pszFilename = CPLStrdup( pszFile );
2040 2 : return TRUE;
2041 : }
2042 :
2043 : #else // HAVE_SQLITE
2044 :
2045 : /**************************************************/
2046 : /* if SQLite support isn't available we'll */
2047 : /* simply output an error message */
2048 : /**************************************************/
2049 :
2050 : int GMLReader::HugeFileResolver( const char *pszFile,
2051 : int bSqliteIsTempFile,
2052 : int iSqliteCacheMB )
2053 :
2054 : {
2055 : CPLError( CE_Failure, CPLE_NotSupported,
2056 : "OGR was built without SQLite3 support\n"
2057 : "... sorry, the HUGE GML resolver is unsupported\n" );
2058 : return FALSE;
2059 : }
2060 :
2061 : int GMLReader::ParseXMLHugeFile( const char *pszOutputFilename,
2062 : const int bSqliteIsTempFile,
2063 : const int iSqliteCacheMB )
2064 : {
2065 : CPLError( CE_Failure, CPLE_NotSupported,
2066 : "OGR was built without SQLite3 support\n"
2067 : "... sorry, the HUGE GML resolver is unsupported\n" );
2068 : return FALSE;
2069 : }
2070 :
2071 : #endif // HAVE_SQLITE
|