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