Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: The OGR_SRSNode class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Les Technologies SoftMap Inc.
9 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "ogr_spatialref.h"
32 :
33 : #include <cctype>
34 : #include <cstddef>
35 : #include <cstring>
36 :
37 : #include "ogr_core.h"
38 : #include "ogr_p.h"
39 : #include "cpl_conv.h"
40 : #include "cpl_error.h"
41 : #include "cpl_string.h"
42 :
43 : /************************************************************************/
44 : /* OGR_SRSNode() */
45 : /************************************************************************/
46 :
47 : /**
48 : * Constructor.
49 : *
50 : * @param pszValueIn this optional parameter can be used to initialize
51 : * the value of the node upon creation. If omitted the node will be created
52 : * with a value of "". Newly created OGR_SRSNodes have no children.
53 : */
54 :
55 855616 : OGR_SRSNode::OGR_SRSNode(const char *pszValueIn)
56 855616 : : pszValue(CPLStrdup(pszValueIn)), papoChildNodes(nullptr),
57 855616 : poParent(nullptr), nChildren(0)
58 : {
59 855616 : }
60 :
61 : /************************************************************************/
62 : /* ~OGR_SRSNode() */
63 : /************************************************************************/
64 :
65 829957 : OGR_SRSNode::~OGR_SRSNode()
66 :
67 : {
68 829957 : CPLFree(pszValue);
69 :
70 829957 : ClearChildren();
71 829957 : }
72 :
73 : /************************************************************************/
74 : /* ~Listener() */
75 : /************************************************************************/
76 :
77 : OGR_SRSNode::Listener::~Listener() = default;
78 :
79 : /************************************************************************/
80 : /* RegisterListener() */
81 : /************************************************************************/
82 :
83 21001 : void OGR_SRSNode::RegisterListener(const std::shared_ptr<Listener> &listener)
84 : {
85 21001 : m_listener = listener;
86 21001 : }
87 :
88 : /************************************************************************/
89 : /* notifyChange() */
90 : /************************************************************************/
91 :
92 1668000 : void OGR_SRSNode::notifyChange()
93 : {
94 3336000 : auto locked = m_listener.lock();
95 1668000 : if (locked)
96 : {
97 1643620 : locked->notifyChange(this);
98 : }
99 1668000 : }
100 :
101 : /************************************************************************/
102 : /* ClearChildren() */
103 : /************************************************************************/
104 :
105 : /** Clear children nodes
106 : */
107 1662920 : void OGR_SRSNode::ClearChildren()
108 :
109 : {
110 2471760 : for (int i = 0; i < nChildren; i++)
111 : {
112 808847 : delete papoChildNodes[i];
113 : }
114 :
115 1662920 : CPLFree(papoChildNodes);
116 :
117 1662920 : papoChildNodes = nullptr;
118 1662920 : nChildren = 0;
119 1662920 : }
120 :
121 : /************************************************************************/
122 : /* GetChildCount() */
123 : /************************************************************************/
124 :
125 : /**
126 : * \fn int OGR_SRSNode::GetChildCount() const;
127 : *
128 : * Get number of children nodes.
129 : *
130 : * @return 0 for leaf nodes, or the number of children nodes.
131 : */
132 :
133 : /************************************************************************/
134 : /* GetChild() */
135 : /************************************************************************/
136 :
137 : /**
138 : * Fetch requested child.
139 : *
140 : * @param iChild the index of the child to fetch, from 0 to
141 : * GetChildCount() - 1.
142 : *
143 : * @return a pointer to the child OGR_SRSNode, or NULL if there is no such
144 : * child.
145 : */
146 :
147 34198 : OGR_SRSNode *OGR_SRSNode::GetChild(int iChild)
148 :
149 : {
150 34198 : if (iChild < 0 || iChild >= nChildren)
151 0 : return nullptr;
152 :
153 34198 : return papoChildNodes[iChild];
154 : }
155 :
156 : /**
157 : * Fetch requested child.
158 : *
159 : * @param iChild the index of the child to fetch, from 0 to
160 : * GetChildCount() - 1.
161 : *
162 : * @return a pointer to the child OGR_SRSNode, or NULL if there is no such
163 : * child.
164 : */
165 :
166 147217 : const OGR_SRSNode *OGR_SRSNode::GetChild(int iChild) const
167 :
168 : {
169 147217 : if (iChild < 0 || iChild >= nChildren)
170 0 : return nullptr;
171 :
172 147217 : return papoChildNodes[iChild];
173 : }
174 :
175 : /************************************************************************/
176 : /* GetNode() */
177 : /************************************************************************/
178 :
179 : /**
180 : * Find named node in tree.
181 : *
182 : * This method does a pre-order traversal of the node tree searching for
183 : * a node with this exact value (case insensitive), and returns it. Leaf
184 : * nodes are not considered, under the assumption that they are just
185 : * attribute value nodes.
186 : *
187 : * If a node appears more than once in the tree (such as UNIT for instance),
188 : * the first encountered will be returned. Use GetNode() on a subtree to be
189 : * more specific.
190 : *
191 : * @param pszName the name of the node to search for.
192 : *
193 : * @return a pointer to the node found, or NULL if none.
194 : */
195 :
196 553549 : OGR_SRSNode *OGR_SRSNode::GetNode(const char *pszName)
197 :
198 : {
199 553549 : if (nChildren > 0 && EQUAL(pszName, pszValue))
200 30535 : return this;
201 :
202 : /* -------------------------------------------------------------------- */
203 : /* First we check the immediate children so we will get an */
204 : /* immediate child in preference to a subchild. */
205 : /* -------------------------------------------------------------------- */
206 1100010 : for (int i = 0; i < nChildren; i++)
207 : {
208 619117 : if (EQUAL(papoChildNodes[i]->pszValue, pszName) &&
209 42117 : papoChildNodes[i]->nChildren > 0)
210 42117 : return papoChildNodes[i];
211 : }
212 :
213 : /* -------------------------------------------------------------------- */
214 : /* Then get each child to check their children. */
215 : /* -------------------------------------------------------------------- */
216 937494 : for (int i = 0; i < nChildren; i++)
217 : {
218 466638 : OGR_SRSNode *poNode = papoChildNodes[i]->GetNode(pszName);
219 466638 : if (poNode != nullptr)
220 10041 : return poNode;
221 : }
222 :
223 470856 : return nullptr;
224 : }
225 :
226 : /**
227 : * Find named node in tree.
228 : *
229 : * This method does a pre-order traversal of the node tree searching for
230 : * a node with this exact value (case insensitive), and returns it. Leaf
231 : * nodes are not considered, under the assumption that they are just
232 : * attribute value nodes.
233 : *
234 : * If a node appears more than once in the tree (such as UNIT for instance),
235 : * the first encountered will be returned. Use GetNode() on a subtree to be
236 : * more specific.
237 : *
238 : * @param pszName the name of the node to search for.
239 : *
240 : * @return a pointer to the node found, or NULL if none.
241 : */
242 :
243 93 : const OGR_SRSNode *OGR_SRSNode::GetNode(const char *pszName) const
244 :
245 : {
246 93 : return const_cast<OGR_SRSNode *>(this)->GetNode(pszName);
247 : }
248 :
249 : /************************************************************************/
250 : /* AddChild() */
251 : /************************************************************************/
252 :
253 : /**
254 : * Add passed node as a child of target node.
255 : *
256 : * Note that ownership of the passed node is assumed by the node on which
257 : * the method is invoked ... use the Clone() method if the original is to
258 : * be preserved. New children are always added at the end of the list.
259 : *
260 : * @param poNew the node to add as a child.
261 : */
262 :
263 834287 : void OGR_SRSNode::AddChild(OGR_SRSNode *poNew)
264 :
265 : {
266 834287 : InsertChild(poNew, nChildren);
267 834287 : }
268 :
269 : /************************************************************************/
270 : /* InsertChild() */
271 : /************************************************************************/
272 :
273 : /**
274 : * Insert the passed node as a child of target node, at the indicated
275 : * position.
276 : *
277 : * Note that ownership of the passed node is assumed by the node on which
278 : * the method is invoked ... use the Clone() method if the original is to
279 : * be preserved. All existing children at location iChild and beyond are
280 : * push down one space to make space for the new child.
281 : *
282 : * @param poNew the node to add as a child.
283 : * @param iChild position to insert, use 0 to insert at the beginning.
284 : */
285 :
286 834293 : void OGR_SRSNode::InsertChild(OGR_SRSNode *poNew, int iChild)
287 :
288 : {
289 834293 : if (iChild > nChildren)
290 0 : iChild = nChildren;
291 :
292 834293 : nChildren++;
293 834293 : papoChildNodes = static_cast<OGR_SRSNode **>(
294 834293 : CPLRealloc(papoChildNodes, sizeof(void *) * nChildren));
295 :
296 834293 : memmove(papoChildNodes + iChild + 1, papoChildNodes + iChild,
297 834293 : sizeof(void *) * (nChildren - iChild - 1));
298 :
299 834293 : papoChildNodes[iChild] = poNew;
300 834293 : poNew->poParent = this;
301 :
302 834293 : poNew->m_listener = m_listener;
303 834293 : notifyChange();
304 834293 : }
305 :
306 : /************************************************************************/
307 : /* DestroyChild() */
308 : /************************************************************************/
309 :
310 : /**
311 : * Remove a child node, and it's subtree.
312 : *
313 : * Note that removing a child node will result in children after it
314 : * being renumbered down one.
315 : *
316 : * @param iChild the index of the child.
317 : */
318 :
319 353 : void OGR_SRSNode::DestroyChild(int iChild)
320 :
321 : {
322 353 : if (iChild < 0 || iChild >= nChildren)
323 0 : return;
324 :
325 353 : delete papoChildNodes[iChild];
326 722 : while (iChild < nChildren - 1)
327 : {
328 369 : papoChildNodes[iChild] = papoChildNodes[iChild + 1];
329 369 : iChild++;
330 : }
331 :
332 353 : nChildren--;
333 353 : notifyChange();
334 : }
335 :
336 : /************************************************************************/
337 : /* FindChild() */
338 : /************************************************************************/
339 :
340 : /**
341 : * Find the index of the child matching the given string.
342 : *
343 : * Note that the node value must match pszValue with the exception of
344 : * case. The comparison is case insensitive.
345 : *
346 : * @param pszValueIn the node value being searched for.
347 : *
348 : * @return the child index, or -1 on failure.
349 : */
350 :
351 42591 : int OGR_SRSNode::FindChild(const char *pszValueIn) const
352 :
353 : {
354 152240 : for (int i = 0; i < nChildren; i++)
355 : {
356 138887 : if (EQUAL(papoChildNodes[i]->pszValue, pszValueIn))
357 29238 : return i;
358 : }
359 :
360 13353 : return -1;
361 : }
362 :
363 : /************************************************************************/
364 : /* GetValue() */
365 : /************************************************************************/
366 :
367 : /**
368 : * \fn const char *OGR_SRSNode::GetValue() const;
369 : *
370 : * Fetch value string for this node.
371 : *
372 : * @return A non-NULL string is always returned. The returned pointer is to
373 : * the internal value of this node, and should not be modified, or freed.
374 : */
375 :
376 : /************************************************************************/
377 : /* SetValue() */
378 : /************************************************************************/
379 :
380 : /**
381 : * Set the node value.
382 : *
383 : * @param pszNewValue the new value to assign to this node. The passed
384 : * string is duplicated and remains the responsibility of the caller.
385 : */
386 :
387 833353 : void OGR_SRSNode::SetValue(const char *pszNewValue)
388 :
389 : {
390 833353 : CPLFree(pszValue);
391 833353 : pszValue = CPLStrdup(pszNewValue);
392 833353 : notifyChange();
393 833353 : }
394 :
395 : /************************************************************************/
396 : /* Clone() */
397 : /************************************************************************/
398 :
399 : /**
400 : * Make a duplicate of this node, and it's children.
401 : *
402 : * @return a new node tree, which becomes the responsibility of the caller.
403 : */
404 :
405 2561 : OGR_SRSNode *OGR_SRSNode::Clone() const
406 :
407 : {
408 2561 : OGR_SRSNode *poNew = new OGR_SRSNode(pszValue);
409 :
410 5060 : for (int i = 0; i < nChildren; i++)
411 : {
412 2499 : poNew->AddChild(papoChildNodes[i]->Clone());
413 : }
414 2561 : poNew->m_listener = m_listener;
415 :
416 2561 : return poNew;
417 : }
418 :
419 : /************************************************************************/
420 : /* NeedsQuoting() */
421 : /* */
422 : /* Does this node need to be quoted when it is exported to Wkt? */
423 : /************************************************************************/
424 :
425 257166 : int OGR_SRSNode::NeedsQuoting() const
426 :
427 : {
428 : // Non-terminals are never quoted.
429 257166 : if (GetChildCount() != 0)
430 92428 : return FALSE;
431 :
432 : // As per bugzilla bug 201, the OGC spec says the authority code
433 : // needs to be quoted even though it appears well behaved.
434 164738 : if (poParent != nullptr && EQUAL(poParent->GetValue(), "AUTHORITY"))
435 45944 : return TRUE;
436 :
437 : // As per bugzilla bug 294, the OGC spec says the direction
438 : // values for the AXIS keywords should *not* be quoted.
439 145466 : if (poParent != nullptr && EQUAL(poParent->GetValue(), "AXIS") &&
440 26672 : this != poParent->GetChild(0))
441 13336 : return FALSE;
442 :
443 105458 : if (poParent != nullptr && EQUAL(poParent->GetValue(), "CS") &&
444 0 : this == poParent->GetChild(0))
445 0 : return FALSE;
446 :
447 : // Strings starting with e or E are not valid numeric values, so they
448 : // need quoting, like in AXIS["E",EAST]
449 105458 : if ((pszValue[0] == 'e' || pszValue[0] == 'E'))
450 6842 : return TRUE;
451 :
452 : // Non-numeric tokens are generally quoted while clean numeric values
453 : // are generally not.
454 409413 : for (int i = 0; pszValue[i] != '\0'; i++)
455 : {
456 373422 : if ((pszValue[i] < '0' || pszValue[i] > '9') && pszValue[i] != '.' &&
457 62805 : pszValue[i] != '-' && pszValue[i] != '+' && pszValue[i] != 'e' &&
458 62625 : pszValue[i] != 'E')
459 62625 : return TRUE;
460 : }
461 :
462 35991 : return FALSE;
463 : }
464 :
465 : /************************************************************************/
466 : /* exportToWkt() */
467 : /************************************************************************/
468 :
469 : /**
470 : * Convert this tree of nodes into WKT format.
471 : *
472 : * Note that the returned WKT string should be freed with
473 : * CPLFree() when no longer needed. It is the responsibility of the caller.
474 : *
475 : * @param ppszResult the resulting string is returned in this pointer.
476 : *
477 : * @return currently OGRERR_NONE is always returned, but the future it
478 : * is possible error conditions will develop.
479 : */
480 :
481 257094 : OGRErr OGR_SRSNode::exportToWkt(char **ppszResult) const
482 :
483 : {
484 : /* -------------------------------------------------------------------- */
485 : /* Build a list of the WKT format for the children. */
486 : /* -------------------------------------------------------------------- */
487 : char **papszChildrenWkt =
488 257094 : static_cast<char **>(CPLCalloc(sizeof(char *), nChildren + 1));
489 257094 : size_t nLength = strlen(pszValue) + 4;
490 :
491 507259 : for (int i = 0; i < nChildren; i++)
492 : {
493 250165 : papoChildNodes[i]->exportToWkt(papszChildrenWkt + i);
494 250165 : nLength += strlen(papszChildrenWkt[i]) + 1;
495 : }
496 :
497 : /* -------------------------------------------------------------------- */
498 : /* Allocate the result string. */
499 : /* -------------------------------------------------------------------- */
500 257094 : *ppszResult = static_cast<char *>(CPLMalloc(nLength));
501 257094 : *ppszResult[0] = '\0';
502 :
503 : /* -------------------------------------------------------------------- */
504 : /* Capture this nodes value. We put it in double quotes if */
505 : /* this is a leaf node, otherwise we assume it is a well formed */
506 : /* node name. */
507 : /* -------------------------------------------------------------------- */
508 257094 : if (NeedsQuoting())
509 : {
510 115385 : strcat(*ppszResult, "\"");
511 115385 : strcat(*ppszResult, pszValue); // Should we do quoting?
512 115385 : strcat(*ppszResult, "\"");
513 : }
514 : else
515 141709 : strcat(*ppszResult, pszValue);
516 :
517 : /* -------------------------------------------------------------------- */
518 : /* Add the children strings with appropriate brackets and commas. */
519 : /* -------------------------------------------------------------------- */
520 257094 : if (nChildren > 0)
521 92402 : strcat(*ppszResult, "[");
522 :
523 507259 : for (int i = 0; i < nChildren; i++)
524 : {
525 250165 : strcat(*ppszResult, papszChildrenWkt[i]);
526 250165 : if (i == nChildren - 1)
527 92402 : strcat(*ppszResult, "]");
528 : else
529 157763 : strcat(*ppszResult, ",");
530 : }
531 :
532 257094 : CSLDestroy(papszChildrenWkt);
533 :
534 257094 : return OGRERR_NONE;
535 : }
536 :
537 : /************************************************************************/
538 : /* exportToPrettyWkt() */
539 : /************************************************************************/
540 :
541 : /**
542 : * Convert this tree of nodes into pretty WKT format.
543 : *
544 : * Note that the returned WKT string should be freed with
545 : * CPLFree() when no longer needed. It is the responsibility of the caller.
546 : *
547 : * @param ppszResult the resulting string is returned in this pointer.
548 : *
549 : * @param nDepth depth of the node
550 : *
551 : * @return currently OGRERR_NONE is always returned, but the future it
552 : * is possible error conditions will develop.
553 : */
554 :
555 72 : OGRErr OGR_SRSNode::exportToPrettyWkt(char **ppszResult, int nDepth) const
556 :
557 : {
558 : /* -------------------------------------------------------------------- */
559 : /* Build a list of the WKT format for the children. */
560 : /* -------------------------------------------------------------------- */
561 : char **papszChildrenWkt =
562 72 : static_cast<char **>(CPLCalloc(sizeof(char *), nChildren + 1));
563 72 : size_t nLength = strlen(pszValue) + 4;
564 :
565 142 : for (int i = 0; i < nChildren; i++)
566 : {
567 70 : papoChildNodes[i]->exportToPrettyWkt(papszChildrenWkt + i, nDepth + 1);
568 70 : nLength += strlen(papszChildrenWkt[i]) + 2 + nDepth * 4;
569 : }
570 :
571 : /* -------------------------------------------------------------------- */
572 : /* Allocate the result string. */
573 : /* -------------------------------------------------------------------- */
574 72 : *ppszResult = static_cast<char *>(CPLMalloc(nLength));
575 72 : *ppszResult[0] = '\0';
576 :
577 : /* -------------------------------------------------------------------- */
578 : /* Capture this nodes value. We put it in double quotes if */
579 : /* this is a leaf node, otherwise we assume it is a well formed */
580 : /* node name. */
581 : /* -------------------------------------------------------------------- */
582 72 : if (NeedsQuoting())
583 : {
584 26 : strcat(*ppszResult, "\"");
585 26 : strcat(*ppszResult, pszValue); // Should we do quoting?
586 26 : strcat(*ppszResult, "\"");
587 : }
588 : else
589 : {
590 46 : strcat(*ppszResult, pszValue);
591 : }
592 :
593 : /* -------------------------------------------------------------------- */
594 : /* Add the children strings with appropriate brackets and commas. */
595 : /* -------------------------------------------------------------------- */
596 72 : if (nChildren > 0)
597 26 : strcat(*ppszResult, "[");
598 :
599 142 : for (int i = 0; i < nChildren; i++)
600 : {
601 70 : if (papoChildNodes[i]->GetChildCount() > 0)
602 : {
603 24 : strcat(*ppszResult, "\n");
604 160 : for (int j = 0; j < 4 * nDepth; j++)
605 136 : strcat(*ppszResult, " ");
606 : }
607 70 : strcat(*ppszResult, papszChildrenWkt[i]);
608 70 : if (i < nChildren - 1)
609 44 : strcat(*ppszResult, ",");
610 : }
611 :
612 72 : if (nChildren > 0)
613 : {
614 26 : if ((*ppszResult)[strlen(*ppszResult) - 1] == ',')
615 0 : (*ppszResult)[strlen(*ppszResult) - 1] = '\0';
616 :
617 26 : strcat(*ppszResult, "]");
618 : }
619 :
620 72 : CSLDestroy(papszChildrenWkt);
621 :
622 72 : return OGRERR_NONE;
623 : }
624 :
625 : /************************************************************************/
626 : /* importFromWkt() */
627 : /************************************************************************/
628 :
629 : /**
630 : * Import from WKT string.
631 : *
632 : * This method will wipe the existing children and value of this node, and
633 : * reassign them based on the contents of the passed WKT string. Only as
634 : * much of the input string as needed to construct this node, and its
635 : * children is consumed from the input string, and the input string pointer
636 : * is then updated to point to the remaining (unused) input.
637 : *
638 : * @param ppszInput Pointer to pointer to input. The pointer is updated to
639 : * point to remaining unused input text.
640 : *
641 : * @return OGRERR_NONE if import succeeds, or OGRERR_CORRUPT_DATA if it
642 : * fails for any reason.
643 : * @deprecated GDAL 2.3. Use importFromWkt(const char**) instead.
644 : */
645 :
646 0 : OGRErr OGR_SRSNode::importFromWkt(char **ppszInput)
647 :
648 : {
649 0 : int nNodes = 0;
650 0 : return importFromWkt(const_cast<const char **>(ppszInput), 0, &nNodes);
651 : }
652 :
653 : /**
654 : * Import from WKT string.
655 : *
656 : * This method will wipe the existing children and value of this node, and
657 : * reassign them based on the contents of the passed WKT string. Only as
658 : * much of the input string as needed to construct this node, and its
659 : * children is consumed from the input string, and the input string pointer
660 : * is then updated to point to the remaining (unused) input.
661 : *
662 : * @param ppszInput Pointer to pointer to input. The pointer is updated to
663 : * point to remaining unused input text.
664 : *
665 : * @return OGRERR_NONE if import succeeds, or OGRERR_CORRUPT_DATA if it
666 : * fails for any reason.
667 : *
668 : * @since GDAL 2.3
669 : */
670 :
671 21288 : OGRErr OGR_SRSNode::importFromWkt(const char **ppszInput)
672 :
673 : {
674 21288 : int nNodes = 0;
675 42576 : return importFromWkt(ppszInput, 0, &nNodes);
676 : }
677 :
678 832958 : OGRErr OGR_SRSNode::importFromWkt(const char **ppszInput, int nRecLevel,
679 : int *pnNodes)
680 :
681 : {
682 : // Sanity checks.
683 832958 : if (nRecLevel == 10)
684 : {
685 0 : return OGRERR_CORRUPT_DATA;
686 : }
687 832958 : if (*pnNodes == 1000)
688 : {
689 0 : return OGRERR_CORRUPT_DATA;
690 : }
691 :
692 832958 : const char *pszInput = *ppszInput;
693 832958 : bool bInQuotedString = false;
694 :
695 : /* -------------------------------------------------------------------- */
696 : /* Clear any existing children of this node. */
697 : /* -------------------------------------------------------------------- */
698 832958 : ClearChildren();
699 :
700 : /* -------------------------------------------------------------------- */
701 : /* Read the ``value'' for this node. */
702 : /* -------------------------------------------------------------------- */
703 : {
704 : char szToken[512]; // do not initialize whole buffer. significant
705 : // overhead
706 832958 : size_t nTokenLen = 0;
707 832958 : szToken[0] = '\0';
708 :
709 7660420 : while (*pszInput != '\0' && nTokenLen + 1 < sizeof(szToken))
710 : {
711 7660420 : if (*pszInput == '"')
712 : {
713 736324 : bInQuotedString = !bInQuotedString;
714 : }
715 6924100 : else if (!bInQuotedString &&
716 3992420 : (*pszInput == '[' || *pszInput == ']' ||
717 3507250 : *pszInput == ',' || *pszInput == '(' || *pszInput == ')'))
718 : {
719 : break;
720 : }
721 6091140 : else if (!bInQuotedString &&
722 3159470 : (*pszInput == ' ' || *pszInput == '\t' ||
723 3158970 : *pszInput == 10 || *pszInput == 13))
724 : {
725 : // Skip over whitespace.
726 : }
727 : else
728 : {
729 6090600 : szToken[nTokenLen++] = *pszInput;
730 : }
731 :
732 6827460 : pszInput++;
733 : }
734 :
735 832958 : if (*pszInput == '\0' || nTokenLen == sizeof(szToken) - 1)
736 0 : return OGRERR_CORRUPT_DATA;
737 :
738 832958 : szToken[nTokenLen++] = '\0';
739 832958 : SetValue(szToken);
740 : }
741 :
742 : /* -------------------------------------------------------------------- */
743 : /* Read children, if we have a sublist. */
744 : /* -------------------------------------------------------------------- */
745 832958 : if (*pszInput == '[' || *pszInput == '(')
746 : {
747 518351 : do
748 : {
749 811670 : pszInput++; // Skip bracket or comma.
750 :
751 811670 : OGR_SRSNode *poNewChild = new OGR_SRSNode();
752 811670 : poNewChild->m_listener = m_listener;
753 :
754 811670 : (*pnNodes)++;
755 : const OGRErr eErr =
756 811670 : poNewChild->importFromWkt(&pszInput, nRecLevel + 1, pnNodes);
757 811670 : if (eErr != OGRERR_NONE)
758 : {
759 0 : delete poNewChild;
760 0 : return eErr;
761 : }
762 :
763 811670 : AddChild(poNewChild);
764 :
765 : // Swallow whitespace.
766 811670 : while (isspace(static_cast<unsigned char>(*pszInput)))
767 0 : pszInput++;
768 811670 : } while (*pszInput == ',');
769 :
770 293319 : if (*pszInput != ')' && *pszInput != ']')
771 0 : return OGRERR_CORRUPT_DATA;
772 :
773 293319 : pszInput++;
774 : }
775 :
776 832958 : *ppszInput = pszInput;
777 :
778 832958 : return OGRERR_NONE;
779 : }
780 :
781 : /************************************************************************/
782 : /* MakeValueSafe() */
783 : /************************************************************************/
784 :
785 : /**
786 : * Massage value string, stripping special characters so it will be a
787 : * database safe string.
788 : *
789 : * The operation is also applies to all subnodes of the current node.
790 : */
791 :
792 0 : void OGR_SRSNode::MakeValueSafe()
793 :
794 : {
795 : /* -------------------------------------------------------------------- */
796 : /* First process subnodes. */
797 : /* -------------------------------------------------------------------- */
798 0 : for (int iChild = 0; iChild < GetChildCount(); iChild++)
799 : {
800 0 : GetChild(iChild)->MakeValueSafe();
801 : }
802 :
803 : /* -------------------------------------------------------------------- */
804 : /* Skip numeric nodes. */
805 : /* -------------------------------------------------------------------- */
806 0 : if ((pszValue[0] >= '0' && pszValue[0] <= '9') || pszValue[0] != '.')
807 0 : return;
808 :
809 : /* -------------------------------------------------------------------- */
810 : /* Translate non-alphanumeric values to underscores. */
811 : /* -------------------------------------------------------------------- */
812 0 : for (int i = 0; pszValue[i] != '\0'; i++)
813 : {
814 0 : if (!(pszValue[i] >= 'A' && pszValue[i] <= 'Z') &&
815 0 : !(pszValue[i] >= 'a' && pszValue[i] <= 'z') &&
816 0 : !(pszValue[i] >= '0' && pszValue[i] <= '9'))
817 : {
818 0 : pszValue[i] = '_';
819 : }
820 : }
821 :
822 : /* -------------------------------------------------------------------- */
823 : /* Remove repeated and trailing underscores. */
824 : /* -------------------------------------------------------------------- */
825 0 : int j = 0;
826 0 : for (int i = 1; pszValue[i] != '\0'; i++)
827 : {
828 0 : if (pszValue[j] == '_' && pszValue[i] == '_')
829 0 : continue;
830 :
831 0 : pszValue[++j] = pszValue[i];
832 : }
833 :
834 0 : if (pszValue[j] == '_')
835 0 : pszValue[j] = '\0';
836 : else
837 0 : pszValue[j + 1] = '\0';
838 : }
839 :
840 : /************************************************************************/
841 : /* StripNodes() */
842 : /************************************************************************/
843 :
844 : /**
845 : * Strip child nodes matching name.
846 : *
847 : * Removes any descendant nodes of this node that match the given name.
848 : * Of course children of removed nodes are also discarded.
849 : *
850 : * @param pszName the name for nodes that should be removed.
851 : */
852 :
853 5390 : void OGR_SRSNode::StripNodes(const char *pszName)
854 :
855 : {
856 : /* -------------------------------------------------------------------- */
857 : /* Strip any children matching this name. */
858 : /* -------------------------------------------------------------------- */
859 5390 : while (FindChild(pszName) >= 0)
860 70 : DestroyChild(FindChild(pszName));
861 :
862 : /* -------------------------------------------------------------------- */
863 : /* Recurse */
864 : /* -------------------------------------------------------------------- */
865 10337 : for (int i = 0; i < GetChildCount(); i++)
866 5017 : GetChild(i)->StripNodes(pszName);
867 5320 : }
|