1 /******************************************************************************
2  * $Id: ogr_srsnode.cpp 27975 2014-11-17 12:37:48Z rouault $
3  *
4  * Project:  OpenGIS Simple Features Reference Implementation
5  * Purpose:  The OGR_SRSNode class.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
10  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  ****************************************************************************/
30 
31 #include "ogr_spatialref.h"
32 #include "ogr_p.h"
33 
34 CPL_CVSID("$Id: ogr_srsnode.cpp 27975 2014-11-17 12:37:48Z rouault $");
35 
36 /************************************************************************/
37 /*                            OGR_SRSNode()                             */
38 /************************************************************************/
39 
40 /**
41  * Constructor.
42  *
43  * @param pszValueIn this optional parameter can be used to initialize
44  * the value of the node upon creation.  If omitted the node will be created
45  * with a value of "".  Newly created OGR_SRSNodes have no children.
46  */
47 
OGR_SRSNode(const char * pszValueIn)48 OGR_SRSNode::OGR_SRSNode( const char * pszValueIn )
49 
50 {
51     pszValue = CPLStrdup( pszValueIn );
52 
53     nChildren = 0;
54     papoChildNodes = NULL;
55 
56     poParent = NULL;
57 }
58 
59 /************************************************************************/
60 /*                            ~OGR_SRSNode()                            */
61 /************************************************************************/
62 
~OGR_SRSNode()63 OGR_SRSNode::~OGR_SRSNode()
64 
65 {
66     CPLFree( pszValue );
67 
68     ClearChildren();
69 }
70 
71 /************************************************************************/
72 /*                           ClearChildren()                            */
73 /************************************************************************/
74 
ClearChildren()75 void OGR_SRSNode::ClearChildren()
76 
77 {
78     for( int i = 0; i < nChildren; i++ )
79     {
80         delete papoChildNodes[i];
81     }
82 
83     CPLFree( papoChildNodes );
84 
85     papoChildNodes = NULL;
86     nChildren = 0;
87 }
88 
89 /************************************************************************/
90 /*                           GetChildCount()                            */
91 /************************************************************************/
92 
93 /**
94  * \fn int OGR_SRSNode::GetChildCount() const;
95  *
96  * Get number of children nodes.
97  *
98  * @return 0 for leaf nodes, or the number of children nodes.
99  */
100 
101 /************************************************************************/
102 /*                              GetChild()                              */
103 /************************************************************************/
104 
105 /**
106  * Fetch requested child.
107  *
108  * @param iChild the index of the child to fetch, from 0 to
109  * GetChildCount() - 1.
110  *
111  * @return a pointer to the child OGR_SRSNode, or NULL if there is no such
112  * child.
113  */
114 
GetChild(int iChild)115 OGR_SRSNode *OGR_SRSNode::GetChild( int iChild )
116 
117 {
118     if( iChild < 0 || iChild >= nChildren )
119         return NULL;
120     else
121         return papoChildNodes[iChild];
122 }
123 
GetChild(int iChild) const124 const OGR_SRSNode *OGR_SRSNode::GetChild( int iChild ) const
125 
126 {
127     if( iChild < 0 || iChild >= nChildren )
128         return NULL;
129     else
130         return papoChildNodes[iChild];
131 }
132 
133 /************************************************************************/
134 /*                              GetNode()                               */
135 /************************************************************************/
136 
137 /**
138  * Find named node in tree.
139  *
140  * This method does a pre-order traversal of the node tree searching for
141  * a node with this exact value (case insensitive), and returns it.  Leaf
142  * nodes are not considered, under the assumption that they are just
143  * attribute value nodes.
144  *
145  * If a node appears more than once in the tree (such as UNIT for instance),
146  * the first encountered will be returned.  Use GetNode() on a subtree to be
147  * more specific.
148  *
149  * @param pszName the name of the node to search for.
150  *
151  * @return a pointer to the node found, or NULL if none.
152  */
153 
GetNode(const char * pszName)154 OGR_SRSNode *OGR_SRSNode::GetNode( const char * pszName )
155 
156 {
157     int  i;
158 
159     if( this == NULL )
160         return NULL;
161 
162     if( nChildren > 0 && EQUAL(pszName,pszValue) )
163         return this;
164 
165 /* -------------------------------------------------------------------- */
166 /*      First we check the immediate children so we will get an         */
167 /*      immediate child in preference to a subchild.                    */
168 /* -------------------------------------------------------------------- */
169     for( i = 0; i < nChildren; i++ )
170     {
171         if( EQUAL(papoChildNodes[i]->pszValue,pszName)
172             && papoChildNodes[i]->nChildren > 0 )
173             return papoChildNodes[i];
174     }
175 
176 /* -------------------------------------------------------------------- */
177 /*      Then get each child to check their children.                    */
178 /* -------------------------------------------------------------------- */
179     for( i = 0; i < nChildren; i++ )
180     {
181         OGR_SRSNode *poNode;
182 
183         poNode = papoChildNodes[i]->GetNode( pszName );
184         if( poNode != NULL )
185             return poNode;
186     }
187 
188     return NULL;
189 }
190 
GetNode(const char * pszName) const191 const OGR_SRSNode *OGR_SRSNode::GetNode( const char * pszName ) const
192 
193 {
194     return ((OGR_SRSNode *) this)->GetNode( pszName );
195 }
196 
197 /************************************************************************/
198 /*                              AddChild()                              */
199 /************************************************************************/
200 
201 /**
202  * Add passed node as a child of target node.
203  *
204  * Note that ownership of the passed node is assumed by the node on which
205  * the method is invoked ... use the Clone() method if the original is to
206  * be preserved.  New children are always added at the end of the list.
207  *
208  * @param poNew the node to add as a child.
209  */
210 
AddChild(OGR_SRSNode * poNew)211 void OGR_SRSNode::AddChild( OGR_SRSNode * poNew )
212 
213 {
214     InsertChild( poNew, nChildren );
215 }
216 
217 /************************************************************************/
218 /*                            InsertChild()                             */
219 /************************************************************************/
220 
221 /**
222  * Insert the passed node as a child of target node, at the indicated
223  * position.
224  *
225  * Note that ownership of the passed node is assumed by the node on which
226  * the method is invoked ... use the Clone() method if the original is to
227  * be preserved.  All existing children at location iChild and beyond are
228  * push down one space to make space for the new child.
229  *
230  * @param poNew the node to add as a child.
231  * @param iChild position to insert, use 0 to insert at the beginning.
232  */
233 
InsertChild(OGR_SRSNode * poNew,int iChild)234 void OGR_SRSNode::InsertChild( OGR_SRSNode * poNew, int iChild )
235 
236 {
237     if( iChild > nChildren )
238         iChild = nChildren;
239 
240     nChildren++;
241     papoChildNodes = (OGR_SRSNode **)
242         CPLRealloc( papoChildNodes, sizeof(void*) * nChildren );
243 
244     memmove( papoChildNodes + iChild + 1, papoChildNodes + iChild,
245              sizeof(void*) * (nChildren - iChild - 1) );
246 
247     papoChildNodes[iChild] = poNew;
248     poNew->poParent = this;
249 }
250 
251 /************************************************************************/
252 /*                            DestroyChild()                            */
253 /************************************************************************/
254 
255 /**
256  * Remove a child node, and it's subtree.
257  *
258  * Note that removing a child node will result in children after it
259  * being renumbered down one.
260  *
261  * @param iChild the index of the child.
262  */
263 
DestroyChild(int iChild)264 void OGR_SRSNode::DestroyChild( int iChild )
265 
266 {
267     if( iChild < 0 || iChild >= nChildren )
268         return;
269 
270     delete papoChildNodes[iChild];
271     while( iChild < nChildren-1 )
272     {
273         papoChildNodes[iChild] = papoChildNodes[iChild+1];
274         iChild++;
275     }
276 
277     nChildren--;
278 }
279 
280 /************************************************************************/
281 /*                             FindChild()                              */
282 /************************************************************************/
283 
284 /**
285  * Find the index of the child matching the given string.
286  *
287  * Note that the node value must match pszValue with the exception of
288  * case.  The comparison is case insensitive.
289  *
290  * @param pszValue the node value being searched for.
291  *
292  * @return the child index, or -1 on failure.
293  */
294 
FindChild(const char * pszValue) const295 int OGR_SRSNode::FindChild( const char * pszValue ) const
296 
297 {
298     for( int i = 0; i < nChildren; i++ )
299     {
300         if( EQUAL(papoChildNodes[i]->pszValue,pszValue) )
301             return i;
302     }
303 
304     return -1;
305 }
306 
307 /************************************************************************/
308 /*                              GetValue()                              */
309 /************************************************************************/
310 
311 /**
312  * \fn const char *OGR_SRSNode::GetValue() const;
313  *
314  * Fetch value string for this node.
315  *
316  * @return A non-NULL string is always returned.  The returned pointer is to
317  * the internal value of this node, and should not be modified, or freed.
318  */
319 
320 /************************************************************************/
321 /*                              SetValue()                              */
322 /************************************************************************/
323 
324 /**
325  * Set the node value.
326  *
327  * @param pszNewValue the new value to assign to this node.  The passed
328  * string is duplicated and remains the responsibility of the caller.
329  */
330 
SetValue(const char * pszNewValue)331 void OGR_SRSNode::SetValue( const char * pszNewValue )
332 
333 {
334     CPLFree( pszValue );
335     pszValue = CPLStrdup( pszNewValue );
336 }
337 
338 /************************************************************************/
339 /*                               Clone()                                */
340 /************************************************************************/
341 
342 /**
343  * Make a duplicate of this node, and it's children.
344  *
345  * @return a new node tree, which becomes the responsiblity of the caller.
346  */
347 
Clone() const348 OGR_SRSNode *OGR_SRSNode::Clone() const
349 
350 {
351     OGR_SRSNode *poNew;
352 
353     poNew = new OGR_SRSNode( pszValue );
354 
355     for( int i = 0; i < nChildren; i++ )
356     {
357         poNew->AddChild( papoChildNodes[i]->Clone() );
358     }
359 
360     return poNew;
361 }
362 
363 /************************************************************************/
364 /*                            NeedsQuoting()                            */
365 /*                                                                      */
366 /*      Does this node need to be quoted when it is exported to Wkt?    */
367 /************************************************************************/
368 
NeedsQuoting() const369 int OGR_SRSNode::NeedsQuoting() const
370 
371 {
372     // non-terminals are never quoted.
373     if( GetChildCount() != 0 )
374         return FALSE;
375 
376     // As per bugzilla bug 201, the OGC spec says the authority code
377     // needs to be quoted even though it appears well behaved.
378     if( poParent != NULL && EQUAL(poParent->GetValue(),"AUTHORITY") )
379         return TRUE;
380 
381     // As per bugzilla bug 294, the OGC spec says the direction
382     // values for the AXIS keywords should *not* be quoted.
383     if( poParent != NULL && EQUAL(poParent->GetValue(),"AXIS")
384         && this != poParent->GetChild(0) )
385         return FALSE;
386 
387     // Strings starting with e or E are not valid numeric values, so they
388     // need quoting, like in AXIS["E",EAST]
389     if( (pszValue[0] == 'e' || pszValue[0] == 'E') )
390         return TRUE;
391 
392     // Non-numeric tokens are generally quoted while clean numeric values
393     // are generally not.
394     for( int i = 0; pszValue[i] != '\0'; i++ )
395     {
396         if( (pszValue[i] < '0' || pszValue[i] > '9')
397             && pszValue[i] != '.'
398             && pszValue[i] != '-' && pszValue[i] != '+'
399             && pszValue[i] != 'e' && pszValue[i] != 'E' )
400             return TRUE;
401     }
402 
403     return FALSE;
404 }
405 
406 /************************************************************************/
407 /*                            exportToWkt()                             */
408 /************************************************************************/
409 
410 /**
411  * Convert this tree of nodes into WKT format.
412  *
413  * Note that the returned WKT string should be freed with OGRFree() or
414  * CPLFree() when no longer needed.  It is the responsibility of the caller.
415  *
416  * @param ppszResult the resulting string is returned in this pointer.
417  *
418  * @return currently OGRERR_NONE is always returned, but the future it
419  * is possible error conditions will develop.
420  */
421 
422 
exportToWkt(char ** ppszResult) const423 OGRErr OGR_SRSNode::exportToWkt( char ** ppszResult ) const
424 
425 {
426     char        **papszChildrenWkt = NULL;
427     int         nLength = strlen(pszValue)+4;
428     int         i;
429 
430 /* -------------------------------------------------------------------- */
431 /*      Build a list of the WKT format for the children.                */
432 /* -------------------------------------------------------------------- */
433     papszChildrenWkt = (char **) CPLCalloc(sizeof(char*),(nChildren+1));
434 
435     for( i = 0; i < nChildren; i++ )
436     {
437         papoChildNodes[i]->exportToWkt( papszChildrenWkt + i );
438         nLength += strlen(papszChildrenWkt[i]) + 1;
439     }
440 
441 /* -------------------------------------------------------------------- */
442 /*      Allocate the result string.                                     */
443 /* -------------------------------------------------------------------- */
444     *ppszResult = (char *) CPLMalloc(nLength);
445     *ppszResult[0] = '\0';
446 
447 /* -------------------------------------------------------------------- */
448 /*      Capture this nodes value.  We put it in double quotes if        */
449 /*      this is a leaf node, otherwise we assume it is a well formed    */
450 /*      node name.                                                      */
451 /* -------------------------------------------------------------------- */
452     if( NeedsQuoting() )
453     {
454         strcat( *ppszResult, "\"" );
455         strcat( *ppszResult, pszValue ); /* should we do quoting? */
456         strcat( *ppszResult, "\"" );
457     }
458     else
459         strcat( *ppszResult, pszValue );
460 
461 /* -------------------------------------------------------------------- */
462 /*      Add the children strings with appropriate brackets and commas.  */
463 /* -------------------------------------------------------------------- */
464     if( nChildren > 0 )
465         strcat( *ppszResult, "[" );
466 
467     for( i = 0; i < nChildren; i++ )
468     {
469         strcat( *ppszResult, papszChildrenWkt[i] );
470         if( i == nChildren-1 )
471             strcat( *ppszResult, "]" );
472         else
473             strcat( *ppszResult, "," );
474     }
475 
476     CSLDestroy( papszChildrenWkt );
477 
478     return OGRERR_NONE;
479 }
480 
481 /************************************************************************/
482 /*                         exportToPrettyWkt()                          */
483 /************************************************************************/
484 
exportToPrettyWkt(char ** ppszResult,int nDepth) const485 OGRErr OGR_SRSNode::exportToPrettyWkt( char ** ppszResult, int nDepth ) const
486 
487 {
488     char        **papszChildrenWkt = NULL;
489     int         nLength = strlen(pszValue)+4;
490     int         i;
491 
492 /* -------------------------------------------------------------------- */
493 /*      Build a list of the WKT format for the children.                */
494 /* -------------------------------------------------------------------- */
495     papszChildrenWkt = (char **) CPLCalloc(sizeof(char*),(nChildren+1));
496 
497     for( i = 0; i < nChildren; i++ )
498     {
499         papoChildNodes[i]->exportToPrettyWkt( papszChildrenWkt + i,
500                                               nDepth + 1);
501         nLength += strlen(papszChildrenWkt[i]) + 2 + nDepth*4;
502     }
503 
504 /* -------------------------------------------------------------------- */
505 /*      Allocate the result string.                                     */
506 /* -------------------------------------------------------------------- */
507     *ppszResult = (char *) CPLMalloc(nLength);
508     *ppszResult[0] = '\0';
509 
510 /* -------------------------------------------------------------------- */
511 /*      Capture this nodes value.  We put it in double quotes if        */
512 /*      this is a leaf node, otherwise we assume it is a well formed    */
513 /*      node name.                                                      */
514 /* -------------------------------------------------------------------- */
515     if( NeedsQuoting() )
516     {
517         strcat( *ppszResult, "\"" );
518         strcat( *ppszResult, pszValue ); /* should we do quoting? */
519         strcat( *ppszResult, "\"" );
520     }
521     else
522         strcat( *ppszResult, pszValue );
523 
524 /* -------------------------------------------------------------------- */
525 /*      Add the children strings with appropriate brackets and commas.  */
526 /* -------------------------------------------------------------------- */
527     if( nChildren > 0 )
528         strcat( *ppszResult, "[" );
529 
530     for( i = 0; i < nChildren; i++ )
531     {
532         if( papoChildNodes[i]->GetChildCount() > 0 )
533         {
534             int  j;
535 
536             strcat( *ppszResult, "\n" );
537             for( j = 0; j < 4*nDepth; j++ )
538                 strcat( *ppszResult, " " );
539         }
540         strcat( *ppszResult, papszChildrenWkt[i] );
541         if( i < nChildren-1 )
542             strcat( *ppszResult, "," );
543     }
544 
545     if( nChildren > 0 )
546     {
547         if( (*ppszResult)[strlen(*ppszResult)-1] == ',' )
548             (*ppszResult)[strlen(*ppszResult)-1] = '\0';
549 
550         strcat( *ppszResult, "]" );
551     }
552 
553     CSLDestroy( papszChildrenWkt );
554 
555     return OGRERR_NONE;
556 }
557 
558 /************************************************************************/
559 /*                           importFromWkt()                            */
560 /************************************************************************/
561 
562 /**
563  * Import from WKT string.
564  *
565  * This method will wipe the existing children and value of this node, and
566  * reassign them based on the contents of the passed WKT string.  Only as
567  * much of the input string as needed to construct this node, and it's
568  * children is consumed from the input string, and the input string pointer
569  * is then updated to point to the remaining (unused) input.
570  *
571  * @param ppszInput Pointer to pointer to input.  The pointer is updated to
572  * point to remaining unused input text.
573  *
574  * @return OGRERR_NONE if import succeeds, or OGRERR_CORRUPT_DATA if it
575  * fails for any reason.
576  */
577 
importFromWkt(char ** ppszInput)578 OGRErr OGR_SRSNode::importFromWkt( char ** ppszInput )
579 
580 {
581     int nNodes = 0;
582     return importFromWkt( ppszInput, 0, &nNodes );
583 }
584 
importFromWkt(char ** ppszInput,int nRecLevel,int * pnNodes)585 OGRErr OGR_SRSNode::importFromWkt( char ** ppszInput, int nRecLevel, int* pnNodes )
586 
587 {
588     const char  *pszInput = *ppszInput;
589     int         bInQuotedString = FALSE;
590 
591     /* Sanity checks */
592     if( nRecLevel == 10 )
593     {
594         return OGRERR_CORRUPT_DATA;
595     }
596     if( *pnNodes == 1000 )
597     {
598         return OGRERR_CORRUPT_DATA;
599     }
600 
601 /* -------------------------------------------------------------------- */
602 /*      Clear any existing children of this node.                       */
603 /* -------------------------------------------------------------------- */
604     ClearChildren();
605 
606 /* -------------------------------------------------------------------- */
607 /*      Read the ``value'' for this node.                               */
608 /* -------------------------------------------------------------------- */
609     char        szToken[512];
610     int         nTokenLen = 0;
611 
612     while( *pszInput != '\0' && nTokenLen < (int) sizeof(szToken)-1 )
613     {
614         if( *pszInput == '"' )
615         {
616             bInQuotedString = !bInQuotedString;
617         }
618         else if( !bInQuotedString
619               && (*pszInput == '[' || *pszInput == ']' || *pszInput == ','
620                   || *pszInput == '(' || *pszInput == ')' ) )
621         {
622             break;
623         }
624         else if( !bInQuotedString
625                  && (*pszInput == ' ' || *pszInput == '\t'
626                      || *pszInput == 10 || *pszInput == 13) )
627         {
628             /* just skip over whitespace */
629         }
630         else
631         {
632             szToken[nTokenLen++] = *pszInput;
633         }
634 
635         pszInput++;
636     }
637 
638     if( *pszInput == '\0' || nTokenLen == sizeof(szToken) - 1 )
639         return OGRERR_CORRUPT_DATA;
640 
641     szToken[nTokenLen++] = '\0';
642     SetValue( szToken );
643 
644 /* -------------------------------------------------------------------- */
645 /*      Read children, if we have a sublist.                            */
646 /* -------------------------------------------------------------------- */
647     if( *pszInput == '[' || *pszInput == '(' )
648     {
649         do
650         {
651             OGR_SRSNode *poNewChild;
652             OGRErr      eErr;
653 
654             pszInput++; // Skip bracket or comma.
655 
656             poNewChild = new OGR_SRSNode();
657 
658             (*pnNodes) ++;
659             eErr = poNewChild->importFromWkt( (char **) &pszInput, nRecLevel + 1, pnNodes );
660             if( eErr != OGRERR_NONE )
661             {
662                 delete poNewChild;
663                 return eErr;
664             }
665 
666             AddChild( poNewChild );
667 
668             // swallow whitespace
669             while( isspace(*pszInput) )
670                 pszInput++;
671 
672         } while( *pszInput == ',' );
673 
674         if( *pszInput != ')' && *pszInput != ']' )
675             return OGRERR_CORRUPT_DATA;
676 
677         pszInput++;
678     }
679 
680     *ppszInput = (char *) pszInput;
681 
682     return OGRERR_NONE;
683 }
684 
685 /************************************************************************/
686 /*                           MakeValueSafe()                            */
687 /************************************************************************/
688 
689 /**
690  * Massage value string, stripping special characters so it will be a
691  * database safe string.
692  *
693  * The operation is also applies to all subnodes of the current node.
694  */
695 
696 
MakeValueSafe()697 void OGR_SRSNode::MakeValueSafe()
698 
699 {
700     int         i, j;
701 
702 /* -------------------------------------------------------------------- */
703 /*      First process subnodes.                                         */
704 /* -------------------------------------------------------------------- */
705     for( int iChild = 0; iChild < GetChildCount(); iChild++ )
706     {
707         GetChild(iChild)->MakeValueSafe();
708     }
709 
710 /* -------------------------------------------------------------------- */
711 /*      Skip numeric nodes.                                             */
712 /* -------------------------------------------------------------------- */
713     if( (pszValue[0] >= '0' && pszValue[0] <= '9') || pszValue[0] != '.' )
714         return;
715 
716 /* -------------------------------------------------------------------- */
717 /*      Translate non-alphanumeric values to underscores.               */
718 /* -------------------------------------------------------------------- */
719     for( i = 0; pszValue[i] != '\0'; i++ )
720     {
721         if( !(pszValue[i] >= 'A' && pszValue[i] <= 'Z')
722             && !(pszValue[i] >= 'a' && pszValue[i] <= 'z')
723             && !(pszValue[i] >= '0' && pszValue[i] <= '9') )
724         {
725             pszValue[i] = '_';
726         }
727     }
728 
729 /* -------------------------------------------------------------------- */
730 /*      Remove repeated and trailing underscores.                       */
731 /* -------------------------------------------------------------------- */
732     for( i = 1, j = 0; pszValue[i] != '\0'; i++ )
733     {
734         if( pszValue[j] == '_' && pszValue[i] == '_' )
735             continue;
736 
737         pszValue[++j] = pszValue[i];
738     }
739 
740     if( pszValue[j] == '_' )
741         pszValue[j] = '\0';
742     else
743         pszValue[j+1] = '\0';
744 }
745 
746 /************************************************************************/
747 /*                           applyRemapper()                            */
748 /************************************************************************/
749 
750 /**
751  * Remap node values matching list.
752  *
753  * Remap the value of this node or any of it's children if it matches
754  * one of the values in the source list to the corresponding value from
755  * the destination list.  If the pszNode value is set, only do so if the
756  * parent node matches that value.  Even if a replacement occurs, searching
757  * continues.
758  *
759  * @param pszNode Restrict remapping to children of this type of node
760  *                (eg. "PROJECTION")
761  * @param papszSrcValues a NULL terminated array of source string.  If the
762  * node value matches one of these (case insensitive) then replacement occurs.
763  * @param papszDstValues an array of destination strings.  On a match, the
764  * one corresponding to a source value will be used to replace a node.
765  * @param nStepSize increment when stepping through source and destination
766  * arrays, allowing source and destination arrays to be one interleaved array
767  * for instances.  Defaults to 1.
768  * @param bChildOfHit Only TRUE if we the current node is the child of a match,
769  * and so needs to be set.  Application code would normally pass FALSE for this
770  * argument.
771  *
772  * @return returns OGRERR_NONE unless something bad happens.  There is no
773  * indication returned about whether any replacement occured.
774  */
775 
applyRemapper(const char * pszNode,char ** papszSrcValues,char ** papszDstValues,int nStepSize,int bChildOfHit)776 OGRErr OGR_SRSNode::applyRemapper( const char *pszNode,
777                                    char **papszSrcValues,
778                                    char **papszDstValues,
779                                    int nStepSize, int bChildOfHit )
780 
781 {
782     int i;
783 
784 /* -------------------------------------------------------------------- */
785 /*      Scan for value, and replace if our parent was a "hit".          */
786 /* -------------------------------------------------------------------- */
787     if( bChildOfHit || pszNode == NULL )
788     {
789         for( i = 0; papszSrcValues[i] != NULL; i += nStepSize )
790         {
791             if( EQUAL(papszSrcValues[i],pszValue) &&
792                 ! EQUAL(papszDstValues[i],"") )
793             {
794                 SetValue( papszDstValues[i] );
795                 break;
796             }
797         }
798     }
799 
800 /* -------------------------------------------------------------------- */
801 /*      Are the the target node?                                        */
802 /* -------------------------------------------------------------------- */
803     if( pszNode != NULL )
804         bChildOfHit = EQUAL(pszValue,pszNode);
805 
806 /* -------------------------------------------------------------------- */
807 /*      Recurse                                                         */
808 /* -------------------------------------------------------------------- */
809     for( i = 0; i < GetChildCount(); i++ )
810     {
811         GetChild(i)->applyRemapper( pszNode, papszSrcValues,
812                                     papszDstValues, nStepSize, bChildOfHit );
813     }
814 
815     return OGRERR_NONE;
816 }
817 
818 /************************************************************************/
819 /*                             StripNodes()                             */
820 /************************************************************************/
821 
822 /**
823  * Strip child nodes matching name.
824  *
825  * Removes any decendent nodes of this node that match the given name.
826  * Of course children of removed nodes are also discarded.
827  *
828  * @param pszName the name for nodes that should be removed.
829  */
830 
StripNodes(const char * pszName)831 void OGR_SRSNode::StripNodes( const char * pszName )
832 
833 {
834 /* -------------------------------------------------------------------- */
835 /*      Strip any children matching this name.                          */
836 /* -------------------------------------------------------------------- */
837     while( FindChild( pszName ) >= 0 )
838         DestroyChild( FindChild( pszName ) );
839 
840 /* -------------------------------------------------------------------- */
841 /*      Recurse                                                         */
842 /* -------------------------------------------------------------------- */
843     for( int i = 0; i < GetChildCount(); i++ )
844         GetChild(i)->StripNodes( pszName );
845 }
846 
847 /************************************************************************/
848 /*                           FixupOrdering()                            */
849 /************************************************************************/
850 
851 /* EXTENSION ... being a OSR extension... is arbitrary placed before the AUTHORITY */
852 static const char * const apszPROJCSRule[] =
853 { "PROJCS", "GEOGCS", "PROJECTION", "PARAMETER", "UNIT", "AXIS", "EXTENSION", "AUTHORITY",
854   NULL };
855 
856 static const char * const apszDATUMRule[] =
857 { "DATUM", "SPHEROID", "TOWGS84", "EXTENSION", "AUTHORITY", NULL };
858 
859 static const char * const apszGEOGCSRule[] =
860 { "GEOGCS", "DATUM", "PRIMEM", "UNIT", "AXIS", "EXTENSION", "AUTHORITY", NULL };
861 
862 static const char * const apszGEOCCSRule[] =
863 { "GEOCCS", "DATUM", "PRIMEM", "UNIT", "AXIS", "AUTHORITY", NULL };
864 
865 static const char * const apszVERTCSRule[] =
866 { "VERT_CS", "VERT_DATUM", "UNIT", "AXIS", "EXTENSION", "AUTHORITY", NULL };
867 
868 static const char * const *apszOrderingRules[] = {
869     apszPROJCSRule, apszGEOGCSRule, apszDATUMRule, apszGEOCCSRule, apszVERTCSRule, NULL };
870 
871 /**
872  * Correct parameter ordering to match CT Specification.
873  *
874  * Some mechanisms to create WKT using OGRSpatialReference, and some
875  * imported WKT fail to maintain the order of parameters required according
876  * to the BNF definitions in the OpenGIS SF-SQL and CT Specifications.  This
877  * method attempts to massage things back into the required order.
878  *
879  * This method will reorder the children of the node it is invoked on and
880  * then recurse to all children to fix up their children.
881  *
882  * @return OGRERR_NONE on success or an error code if something goes
883  * wrong.
884  */
885 
FixupOrdering()886 OGRErr OGR_SRSNode::FixupOrdering()
887 
888 {
889     int    i;
890 
891 /* -------------------------------------------------------------------- */
892 /*      Recurse ordering children.                                      */
893 /* -------------------------------------------------------------------- */
894     for( i = 0; i < GetChildCount(); i++ )
895         GetChild(i)->FixupOrdering();
896 
897     if( GetChildCount() < 3 )
898         return OGRERR_NONE;
899 
900 /* -------------------------------------------------------------------- */
901 /*      Is this a node for which an ordering rule exists?               */
902 /* -------------------------------------------------------------------- */
903     const char * const * papszRule = NULL;
904 
905     for( i = 0; apszOrderingRules[i] != NULL; i++ )
906     {
907         if( EQUAL(apszOrderingRules[i][0],pszValue) )
908         {
909             papszRule = apszOrderingRules[i] + 1;
910             break;
911         }
912     }
913 
914     if( papszRule == NULL )
915         return OGRERR_NONE;
916 
917 /* -------------------------------------------------------------------- */
918 /*      If we have a rule, apply it.  We create an array                */
919 /*      (panChildPr) with the priority code for each child (derived     */
920 /*      from the rule) and we then bubble sort based on this.           */
921 /* -------------------------------------------------------------------- */
922     int  *panChildKey = (int *) CPLCalloc(sizeof(int),GetChildCount());
923 
924     for( i = 1; i < GetChildCount(); i++ )
925     {
926         panChildKey[i] = CSLFindString( (char**) papszRule,
927                                         GetChild(i)->GetValue() );
928         if( panChildKey[i] == -1 )
929         {
930             CPLDebug( "OGRSpatialReference",
931                       "Found unexpected key %s when trying to order SRS nodes.",
932                       GetChild(i)->GetValue() );
933         }
934     }
935 
936 /* -------------------------------------------------------------------- */
937 /*      Sort - Note we don't try to do anything with the first child    */
938 /*      which we assume is a name string.                               */
939 /* -------------------------------------------------------------------- */
940     int j, bChange = TRUE;
941 
942     for( i = 1; bChange && i < GetChildCount()-1; i++ )
943     {
944         bChange = FALSE;
945         for( j = 1; j < GetChildCount()-i; j++ )
946         {
947             if( panChildKey[j] == -1 || panChildKey[j+1] == -1 )
948                 continue;
949 
950             if( panChildKey[j] > panChildKey[j+1] )
951             {
952                 OGR_SRSNode *poTemp = papoChildNodes[j];
953                 int          nKeyTemp = panChildKey[j];
954 
955                 papoChildNodes[j] = papoChildNodes[j+1];
956                 papoChildNodes[j+1] = poTemp;
957 
958                 nKeyTemp = panChildKey[j];
959                 panChildKey[j] = panChildKey[j+1];
960                 panChildKey[j+1] = nKeyTemp;
961 
962                 bChange = TRUE;
963             }
964         }
965     }
966 
967     CPLFree( panChildKey );
968 
969     return OGRERR_NONE;
970 }
971 
972 
973