<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html><head><meta name="robots" content="noindex"> <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"> <title>cpl_minixml.cpp Source File</title> <link href="doxygen.css" rel="stylesheet" type="text/css"> </head><body bgcolor="#ffffff"> <!-- Generated by Doxygen 1.2.3-20001105 on Sat Dec 21 14:01:57 2002 --> <center> <a class="qindex" href="index.html">Main Page</a> <a class="qindex" href="hierarchy.html">Class Hierarchy</a> <a class="qindex" href="annotated.html">Compound List</a> <a class="qindex" href="files.html">File List</a> <a class="qindex" href="functions.html">Compound Members</a> <a class="qindex" href="globals.html">File Members</a> <a class="qindex" href="pages.html">Related Pages</a> </center> <hr><h1>cpl_minixml.cpp</h1><div class="fragment"><pre>00001 <font class="comment">/**********************************************************************</font> 00002 <font class="comment"> * $Id: cpl_minixml_cpp-source.html,v 1.5 2002/12/21 19:13:12 warmerda Exp $</font> 00003 <font class="comment"> *</font> 00004 <font class="comment"> * Project: CPL - Common Portability Library</font> 00005 <font class="comment"> * Purpose: Implementation of MiniXML Parser and handling.</font> 00006 <font class="comment"> * Author: Frank Warmerdam, warmerdam@pobox.com</font> 00007 <font class="comment"> *</font> 00008 <font class="comment"> **********************************************************************</font> 00009 <font class="comment"> * Copyright (c) 2001, Frank Warmerdam</font> 00010 <font class="comment"> *</font> 00011 <font class="comment"> * Permission is hereby granted, free of charge, to any person obtaining a</font> 00012 <font class="comment"> * copy of this software and associated documentation files (the "Software"),</font> 00013 <font class="comment"> * to deal in the Software without restriction, including without limitation</font> 00014 <font class="comment"> * the rights to use, copy, modify, merge, publish, distribute, sublicense,</font> 00015 <font class="comment"> * and/or sell copies of the Software, and to permit persons to whom the</font> 00016 <font class="comment"> * Software is furnished to do so, subject to the following conditions:</font> 00017 <font class="comment"> * </font> 00018 <font class="comment"> * The above copyright notice and this permission notice shall be included</font> 00019 <font class="comment"> * in all copies or substantial portions of the Software.</font> 00020 <font class="comment"> * </font> 00021 <font class="comment"> * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR</font> 00022 <font class="comment"> * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,</font> 00023 <font class="comment"> * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL</font> 00024 <font class="comment"> * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER</font> 00025 <font class="comment"> * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING</font> 00026 <font class="comment"> * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER </font> 00027 <font class="comment"> * DEALINGS IN THE SOFTWARE.</font> 00028 <font class="comment"> **********************************************************************</font> 00029 <font class="comment"> *</font> 00030 <font class="comment"> * $Log: cpl_minixml_cpp-source.html,v $ 00030 <font class="comment"> * Revision 1.5 2002/12/21 19:13:12 warmerda 00030 <font class="comment"> * updated 00030 <font class="comment"> *</font> 00031 <font class="comment"> * Revision 1.16 2002/11/16 20:42:40 warmerda</font> 00032 <font class="comment"> * improved inline comments</font> 00033 <font class="comment"> *</font> 00034 <font class="comment"> * Revision 1.15 2002/11/16 20:38:34 warmerda</font> 00035 <font class="comment"> * added support for literals like DOCTYPE</font> 00036 <font class="comment"> *</font> 00037 <font class="comment"> * Revision 1.14 2002/07/16 15:06:26 warmerda</font> 00038 <font class="comment"> * ensure that attributes are serialized properly regardless of their order</font> 00039 <font class="comment"> *</font> 00040 <font class="comment"> * Revision 1.13 2002/07/09 20:25:25 warmerda</font> 00041 <font class="comment"> * expand tabs</font> 00042 <font class="comment"> *</font> 00043 <font class="comment"> * Revision 1.12 2002/05/28 18:54:05 warmerda</font> 00044 <font class="comment"> * added escaping/unescaping support</font> 00045 <font class="comment"> *</font> 00046 <font class="comment"> * Revision 1.11 2002/05/24 04:09:10 warmerda</font> 00047 <font class="comment"> * added clone and SetXMLValue functions</font> 00048 <font class="comment"> *</font> 00049 <font class="comment"> * Revision 1.10 2002/04/01 16:08:21 warmerda</font> 00050 <font class="comment"> * allow periods in tokens</font> 00051 <font class="comment"> *</font> 00052 <font class="comment"> * Revision 1.9 2002/03/07 22:19:20 warmerda</font> 00053 <font class="comment"> * don't do operations within CPLAssert(), in UnreadChar()</font> 00054 <font class="comment"> *</font> 00055 <font class="comment"> * Revision 1.8 2002/03/05 14:26:57 warmerda</font> 00056 <font class="comment"> * expanded tabs</font> 00057 <font class="comment"> *</font> 00058 <font class="comment"> * Revision 1.7 2002/01/23 20:45:05 warmerda</font> 00059 <font class="comment"> * handle <?...?> and comment elements</font> 00060 <font class="comment"> *</font> 00061 <font class="comment"> * Revision 1.6 2002/01/22 18:54:48 warmerda</font> 00062 <font class="comment"> * ensure text is property initialized when serializing</font> 00063 <font class="comment"> *</font> 00064 <font class="comment"> * Revision 1.5 2002/01/16 03:58:51 warmerda</font> 00065 <font class="comment"> * support single quotes as well as double quotes</font> 00066 <font class="comment"> *</font> 00067 <font class="comment"> * Revision 1.4 2001/12/06 18:13:49 warmerda</font> 00068 <font class="comment"> * added CPLAddXMLChild and CPLCreateElmentAndValue</font> 00069 <font class="comment"> *</font> 00070 <font class="comment"> * Revision 1.3 2001/11/16 21:20:16 warmerda</font> 00071 <font class="comment"> * fixed typo</font> 00072 <font class="comment"> *</font> 00073 <font class="comment"> * Revision 1.2 2001/11/16 20:29:58 warmerda</font> 00074 <font class="comment"> * fixed lost char in normal CString tokens</font> 00075 <font class="comment"> *</font> 00076 <font class="comment"> * Revision 1.1 2001/11/16 15:39:48 warmerda</font> 00077 <font class="comment"> * New</font> 00078 <font class="comment"> */</font> 00079 00080 <font class="preprocessor">#include <ctype.h></font> 00081 <font class="preprocessor">#include "cpl_minixml.h"</font> 00082 <font class="preprocessor">#include "<a class="code" href="cpl_error_h.html">cpl_error.h</a>"</font> 00083 <font class="preprocessor">#include "<a class="code" href="cpl_conv_h.html">cpl_conv.h</a>"</font> 00084 <font class="preprocessor">#include "cpl_string.h"</font> 00085 00086 CPL_CVSID(<font class="stringliteral">"$Id: cpl_minixml_cpp-source.html,v 1.5 2002/12/21 19:13:12 warmerda Exp $"</font>); 00087 00088 <font class="keyword">typedef</font> <font class="keyword">enum</font> { 00089 TNone, 00090 TString, 00091 TOpen, 00092 TClose, 00093 TEqual, 00094 TToken, 00095 TSlashClose, 00096 TQuestionClose, 00097 TComment, 00098 TLiteral 00099 } TokenType; 00100 00101 <font class="keyword">typedef</font> <font class="keyword">struct </font>{ 00102 <font class="keyword">const</font> <font class="keywordtype">char</font> *pszInput; 00103 <font class="keywordtype">int</font> nInputOffset; 00104 <font class="keywordtype">int</font> nInputLine; 00105 00106 <font class="keywordtype">int</font> bInElement; 00107 TokenType eTokenType; 00108 <font class="keywordtype">char</font> *pszToken; 00109 <font class="keywordtype">int</font> nTokenMaxSize; 00110 <font class="keywordtype">int</font> nTokenSize; 00111 00112 <font class="keywordtype">int</font> nStackMaxSize; 00113 <font class="keywordtype">int</font> nStackSize; 00114 CPLXMLNode **papsStack; 00115 00116 CPLXMLNode *psFirstNode; 00117 } ParseContext; 00118 00119 <font class="comment">/************************************************************************/</font> 00120 <font class="comment">/* ReadChar() */</font> 00121 <font class="comment">/************************************************************************/</font> 00122 00123 <font class="keyword">static</font> <font class="keywordtype">char</font> ReadChar( ParseContext *psContext )<font class="keyword"></font> 00124 <font class="keyword"></font> 00125 <font class="keyword"></font>{ 00126 <font class="keywordtype">char</font> chReturn; 00127 00128 chReturn = psContext->pszInput[psContext->nInputOffset++]; 00129 00130 <font class="keywordflow">if</font>( chReturn == <font class="charliteral">'\0'</font> ) 00131 psContext->nInputOffset--; 00132 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( chReturn == 10 ) 00133 psContext->nInputLine++; 00134 00135 <font class="keywordflow">return</font> chReturn; 00136 } 00137 00138 <font class="comment">/************************************************************************/</font> 00139 <font class="comment">/* UnreadChar() */</font> 00140 <font class="comment">/************************************************************************/</font> 00141 00142 <font class="keyword">static</font> <font class="keywordtype">void</font> UnreadChar( ParseContext *psContext, <font class="keywordtype">char</font> chToUnread )<font class="keyword"></font> 00143 <font class="keyword"></font> 00144 <font class="keyword"></font>{ 00145 <font class="keywordflow">if</font>( chToUnread == <font class="charliteral">'\0'</font> ) 00146 { 00147 <font class="comment">/* do nothing */</font> 00148 } 00149 <font class="keywordflow">else</font> 00150 { 00151 CPLAssert( chToUnread 00152 == psContext->pszInput[psContext->nInputOffset-1] ); 00153 00154 psContext->nInputOffset--; 00155 00156 <font class="keywordflow">if</font>( chToUnread == 10 ) 00157 psContext->nInputLine--; 00158 } 00159 } 00160 00161 <font class="comment">/************************************************************************/</font> 00162 <font class="comment">/* AddToToken() */</font> 00163 <font class="comment">/************************************************************************/</font> 00164 00165 <font class="keyword">static</font> <font class="keywordtype">void</font> AddToToken( ParseContext *psContext, <font class="keywordtype">char</font> chNewChar )<font class="keyword"></font> 00166 <font class="keyword"></font> 00167 <font class="keyword"></font>{ 00168 <font class="keywordflow">if</font>( psContext->pszToken == NULL ) 00169 { 00170 psContext->nTokenMaxSize = 10; 00171 psContext->pszToken = (<font class="keywordtype">char</font> *) <a class="code" href="cpl_conv_h.html#a3">CPLMalloc</a>(psContext->nTokenMaxSize); 00172 } 00173 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psContext->nTokenSize >= psContext->nTokenMaxSize - 2 ) 00174 { 00175 psContext->nTokenMaxSize *= 2; 00176 psContext->pszToken = (<font class="keywordtype">char</font> *) 00177 <a class="code" href="cpl_conv_h.html#a5">CPLRealloc</a>(psContext->pszToken,psContext->nTokenMaxSize); 00178 } 00179 00180 psContext->pszToken[psContext->nTokenSize++] = chNewChar; 00181 psContext->pszToken[psContext->nTokenSize] = <font class="charliteral">'\0'</font>; 00182 } 00183 00184 <font class="comment">/************************************************************************/</font> 00185 <font class="comment">/* ReadToken() */</font> 00186 <font class="comment">/************************************************************************/</font> 00187 00188 <font class="keyword">static</font> TokenType ReadToken( ParseContext *psContext )<font class="keyword"></font> 00189 <font class="keyword"></font> 00190 <font class="keyword"></font>{ 00191 <font class="keywordtype">char</font> chNext; 00192 00193 psContext->nTokenSize = 0; 00194 psContext->pszToken[0] = <font class="charliteral">'\0'</font>; 00195 00196 chNext = ReadChar( psContext ); 00197 <font class="keywordflow">while</font>( isspace(chNext) ) 00198 chNext = ReadChar( psContext ); 00199 00200 <font class="comment">/* -------------------------------------------------------------------- */</font> 00201 <font class="comment">/* Handle comments. */</font> 00202 <font class="comment">/* -------------------------------------------------------------------- */</font> 00203 <font class="keywordflow">if</font>( chNext == <font class="charliteral">'<'</font> 00204 && EQUALN(psContext->pszInput+psContext->nInputOffset,"!--",3) ) 00205 { 00206 psContext->eTokenType = TComment; 00207 00208 <font class="comment">// Skip "!--" characters</font> 00209 ReadChar(psContext); 00210 ReadChar(psContext); 00211 ReadChar(psContext); 00212 00213 <font class="keywordflow">while</font>( !EQUALN(psContext->pszInput+psContext->nInputOffset,"-->",3) 00214 && (chNext = ReadChar(psContext)) != <font class="charliteral">'\0'</font> ) 00215 AddToToken( psContext, chNext ); 00216 00217 <font class="comment">// Skip "-->" characters</font> 00218 ReadChar(psContext); 00219 ReadChar(psContext); 00220 ReadChar(psContext); 00221 } 00222 <font class="comment">/* -------------------------------------------------------------------- */</font> 00223 <font class="comment">/* Handle DOCTYPE or other literals. */</font> 00224 <font class="comment">/* -------------------------------------------------------------------- */</font> 00225 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( chNext == <font class="charliteral">'<'</font> 00226 && EQUALN(psContext->pszInput+psContext->nInputOffset,"!DOCTYPE",8) ) 00227 { 00228 <font class="keywordtype">int</font> bInQuotes = FALSE; 00229 psContext->eTokenType = TLiteral; 00230 00231 AddToToken( psContext, <font class="charliteral">'<'</font> ); 00232 <font class="keywordflow">do</font> { 00233 chNext = ReadChar(psContext); 00234 <font class="keywordflow">if</font>( chNext == <font class="charliteral">'\0'</font> ) 00235 { 00236 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00237 <font class="stringliteral">"Parse error in DOCTYPE on or before line %d, reached end of file without '>'."</font>, 00238 psContext->nInputLine ); 00239 00240 <font class="keywordflow">break</font>; 00241 } 00242 00243 <font class="keywordflow">if</font>( chNext == <font class="charliteral">'\"'</font> ) 00244 bInQuotes = !bInQuotes; 00245 00246 <font class="keywordflow">if</font>( chNext == <font class="charliteral">'>'</font> && !bInQuotes ) 00247 { 00248 AddToToken( psContext, <font class="charliteral">'>'</font> ); 00249 <font class="keywordflow">break</font>; 00250 } 00251 00252 AddToToken( psContext, chNext ); 00253 } <font class="keywordflow">while</font>( TRUE ); 00254 } 00255 <font class="comment">/* -------------------------------------------------------------------- */</font> 00256 <font class="comment">/* Simple single tokens of interest. */</font> 00257 <font class="comment">/* -------------------------------------------------------------------- */</font> 00258 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( chNext == <font class="charliteral">'<'</font> && !psContext->bInElement ) 00259 { 00260 psContext->eTokenType = TOpen; 00261 psContext->bInElement = TRUE; 00262 } 00263 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( chNext == <font class="charliteral">'>'</font> && psContext->bInElement ) 00264 { 00265 psContext->eTokenType = TClose; 00266 psContext->bInElement = FALSE; 00267 } 00268 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( chNext == <font class="charliteral">'='</font> && psContext->bInElement ) 00269 { 00270 psContext->eTokenType = TEqual; 00271 } 00272 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( chNext == <font class="charliteral">'\0'</font> ) 00273 { 00274 psContext->eTokenType = TNone; 00275 } 00276 <font class="comment">/* -------------------------------------------------------------------- */</font> 00277 <font class="comment">/* Handle the /> token terminator. */</font> 00278 <font class="comment">/* -------------------------------------------------------------------- */</font> 00279 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( chNext == <font class="charliteral">'/'</font> && psContext->bInElement 00280 && psContext->pszInput[psContext->nInputOffset] == <font class="charliteral">'>'</font> ) 00281 { 00282 chNext = ReadChar( psContext ); 00283 <font class="keywordflow">if</font>( chNext != <font class="charliteral">'>'</font> ) 00284 { 00285 psContext->eTokenType = TNone; 00286 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00287 <font class="stringliteral">"Parse error at '/' on line %d, expected '>'."</font>, 00288 psContext->nInputLine ); 00289 } 00290 <font class="keywordflow">else</font> 00291 { 00292 psContext->eTokenType = TSlashClose; 00293 psContext->bInElement = FALSE; 00294 } 00295 } 00296 <font class="comment">/* -------------------------------------------------------------------- */</font> 00297 <font class="comment">/* Handle the ?> token terminator. */</font> 00298 <font class="comment">/* -------------------------------------------------------------------- */</font> 00299 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( chNext == <font class="charliteral">'?'</font> && psContext->bInElement 00300 && psContext->pszInput[psContext->nInputOffset] == <font class="charliteral">'>'</font> ) 00301 { 00302 chNext = ReadChar( psContext ); 00303 <font class="keywordflow">if</font>( chNext != <font class="charliteral">'>'</font> ) 00304 { 00305 psContext->eTokenType = TNone; 00306 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00307 <font class="stringliteral">"Parse error at '?' on line %d, expected '>'."</font>, 00308 psContext->nInputLine ); 00309 } 00310 <font class="keywordflow">else</font> 00311 { 00312 psContext->eTokenType = TQuestionClose; 00313 psContext->bInElement = FALSE; 00314 } 00315 } 00316 00317 <font class="comment">/* -------------------------------------------------------------------- */</font> 00318 <font class="comment">/* Collect a quoted string. */</font> 00319 <font class="comment">/* -------------------------------------------------------------------- */</font> 00320 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psContext->bInElement && chNext == <font class="charliteral">'"'</font> ) 00321 { 00322 psContext->eTokenType = TString; 00323 00324 <font class="keywordflow">while</font>( (chNext = ReadChar(psContext)) != <font class="charliteral">'"'</font> 00325 && chNext != <font class="charliteral">'\0'</font> ) 00326 AddToToken( psContext, chNext ); 00327 00328 <font class="keywordflow">if</font>( chNext != <font class="charliteral">'"'</font> ) 00329 { 00330 psContext->eTokenType = TNone; 00331 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00332 <font class="stringliteral">"Parse error on line %d, reached EOF before closing quote."</font>, 00333 psContext->nInputLine ); 00334 } 00335 00336 <font class="comment">/* Do we need to unescape it? */</font> 00337 <font class="keywordflow">if</font>( strchr(psContext->pszToken,<font class="charliteral">'&'</font>) != NULL ) 00338 { 00339 <font class="keywordtype">int</font> nLength; 00340 <font class="keywordtype">char</font> *pszUnescaped = CPLUnescapeString( psContext->pszToken, 00341 &nLength, CPLES_XML ); 00342 strcpy( psContext->pszToken, pszUnescaped ); 00343 CPLFree( pszUnescaped ); 00344 psContext->nTokenSize = strlen(psContext->pszToken ); 00345 } 00346 } 00347 00348 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psContext->bInElement && chNext == <font class="charliteral">'\''</font> ) 00349 { 00350 psContext->eTokenType = TString; 00351 00352 <font class="keywordflow">while</font>( (chNext = ReadChar(psContext)) != <font class="charliteral">'\''</font> 00353 && chNext != <font class="charliteral">'\0'</font> ) 00354 AddToToken( psContext, chNext ); 00355 00356 <font class="keywordflow">if</font>( chNext != <font class="charliteral">'\''</font> ) 00357 { 00358 psContext->eTokenType = TNone; 00359 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00360 <font class="stringliteral">"Parse error on line %d, reached EOF before closing quote."</font>, 00361 psContext->nInputLine ); 00362 } 00363 } 00364 00365 <font class="comment">/* -------------------------------------------------------------------- */</font> 00366 <font class="comment">/* Collect an unquoted string, terminated by a open angle */</font> 00367 <font class="comment">/* bracket. */</font> 00368 <font class="comment">/* -------------------------------------------------------------------- */</font> 00369 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( !psContext->bInElement ) 00370 { 00371 psContext->eTokenType = TString; 00372 00373 AddToToken( psContext, chNext ); 00374 <font class="keywordflow">while</font>( (chNext = ReadChar(psContext)) != <font class="charliteral">'<'</font> 00375 && chNext != <font class="charliteral">'\0'</font> ) 00376 AddToToken( psContext, chNext ); 00377 UnreadChar( psContext, chNext ); 00378 00379 <font class="comment">/* Do we need to unescape it? */</font> 00380 <font class="keywordflow">if</font>( strchr(psContext->pszToken,<font class="charliteral">'&'</font>) != NULL ) 00381 { 00382 <font class="keywordtype">int</font> nLength; 00383 <font class="keywordtype">char</font> *pszUnescaped = CPLUnescapeString( psContext->pszToken, 00384 &nLength, CPLES_XML ); 00385 strcpy( psContext->pszToken, pszUnescaped ); 00386 CPLFree( pszUnescaped ); 00387 psContext->nTokenSize = strlen(psContext->pszToken ); 00388 } 00389 } 00390 00391 <font class="comment">/* -------------------------------------------------------------------- */</font> 00392 <font class="comment">/* Collect a regular token terminated by white space, or */</font> 00393 <font class="comment">/* special character(s) like an equal sign. */</font> 00394 <font class="comment">/* -------------------------------------------------------------------- */</font> 00395 <font class="keywordflow">else</font> 00396 { 00397 psContext->eTokenType = TToken; 00398 00399 <font class="comment">/* add the first character to the token regardless of what it is */</font> 00400 AddToToken( psContext, chNext ); 00401 00402 <font class="keywordflow">for</font>( chNext = ReadChar(psContext); 00403 (chNext >= <font class="charliteral">'A'</font> && chNext <= <font class="charliteral">'Z'</font>) 00404 || (chNext >= <font class="charliteral">'a'</font> && chNext <= <font class="charliteral">'z'</font>) 00405 || chNext == <font class="charliteral">'_'</font> 00406 || chNext == <font class="charliteral">'.'</font> 00407 || chNext == <font class="charliteral">':'</font> 00408 || (chNext >= <font class="charliteral">'0'</font> && chNext <= <font class="charliteral">'9'</font>); 00409 chNext = ReadChar(psContext) ) 00410 { 00411 AddToToken( psContext, chNext ); 00412 } 00413 00414 UnreadChar(psContext, chNext); 00415 } 00416 00417 <font class="keywordflow">return</font> psContext->eTokenType; 00418 } 00419 00420 <font class="comment">/************************************************************************/</font> 00421 <font class="comment">/* PushNode() */</font> 00422 <font class="comment">/************************************************************************/</font> 00423 00424 <font class="keyword">static</font> <font class="keywordtype">void</font> PushNode( ParseContext *psContext, CPLXMLNode *psNode )<font class="keyword"></font> 00425 <font class="keyword"></font> 00426 <font class="keyword"></font>{ 00427 <font class="keywordflow">if</font>( psContext->nStackMaxSize <= psContext->nStackSize ) 00428 { 00429 psContext->nStackMaxSize += 10; 00430 psContext->papsStack = (CPLXMLNode **) 00431 <a class="code" href="cpl_conv_h.html#a5">CPLRealloc</a>(psContext->papsStack, 00432 <font class="keyword">sizeof</font>(CPLXMLNode*) * psContext->nStackMaxSize); 00433 } 00434 00435 psContext->papsStack[psContext->nStackSize++] = psNode; 00436 } 00437 00438 <font class="comment">/************************************************************************/</font> 00439 <font class="comment">/* AttachNode() */</font> 00440 <font class="comment">/* */</font> 00441 <font class="comment">/* Attach the passed node as a child of the current node. */</font> 00442 <font class="comment">/* Special handling exists for adding siblings to psFirst if */</font> 00443 <font class="comment">/* there is nothing on the stack. */</font> 00444 <font class="comment">/************************************************************************/</font> 00445 00446 <font class="keyword">static</font> <font class="keywordtype">void</font> AttachNode( ParseContext *psContext, CPLXMLNode *psNode )<font class="keyword"></font> 00447 <font class="keyword"></font> 00448 <font class="keyword"></font>{ 00449 <font class="keywordflow">if</font>( psContext->psFirstNode == NULL ) 00450 psContext->psFirstNode = psNode; 00451 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psContext->nStackSize == 0 ) 00452 { 00453 CPLXMLNode *psSibling; 00454 00455 psSibling = psContext->psFirstNode; 00456 <font class="keywordflow">while</font>( psSibling->psNext != NULL ) 00457 psSibling = psSibling->psNext; 00458 psSibling->psNext = psNode; 00459 } 00460 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psContext->papsStack[psContext->nStackSize-1]->psChild == NULL ) 00461 { 00462 psContext->papsStack[psContext->nStackSize-1]->psChild = psNode; 00463 } 00464 <font class="keywordflow">else</font> 00465 { 00466 CPLXMLNode *psSibling; 00467 00468 psSibling = psContext->papsStack[psContext->nStackSize-1]->psChild; 00469 <font class="keywordflow">while</font>( psSibling->psNext != NULL ) 00470 psSibling = psSibling->psNext; 00471 psSibling->psNext = psNode; 00472 } 00473 } 00474 00475 <font class="comment">/************************************************************************/</font> 00476 <font class="comment">/* CPLParseXMLString() */</font> 00477 <font class="comment">/************************************************************************/</font> 00478 00479 CPLXMLNode *CPLParseXMLString( <font class="keyword">const</font> <font class="keywordtype">char</font> *pszString )<font class="keyword"></font> 00480 <font class="keyword"></font> 00481 <font class="keyword"></font>{ 00482 ParseContext sContext; 00483 00484 <a class="code" href="cpl_error_h.html#a19">CPLErrorReset</a>(); 00485 00486 <font class="comment">/* -------------------------------------------------------------------- */</font> 00487 <font class="comment">/* Initialize parse context. */</font> 00488 <font class="comment">/* -------------------------------------------------------------------- */</font> 00489 sContext.pszInput = pszString; 00490 sContext.nInputOffset = 0; 00491 sContext.nInputLine = 0; 00492 sContext.bInElement = FALSE; 00493 sContext.pszToken = NULL; 00494 sContext.nTokenMaxSize = 0; 00495 sContext.nTokenSize = 0; 00496 sContext.eTokenType = TNone; 00497 sContext.nStackMaxSize = 0; 00498 sContext.nStackSize = 0; 00499 sContext.papsStack = NULL; 00500 sContext.psFirstNode = NULL; 00501 00502 <font class="comment">/* ensure token is initialized */</font> 00503 AddToToken( &sContext, <font class="charliteral">' '</font> ); 00504 00505 <font class="comment">/* ==================================================================== */</font> 00506 <font class="comment">/* Loop reading tokens. */</font> 00507 <font class="comment">/* ==================================================================== */</font> 00508 <font class="keywordflow">while</font>( ReadToken( &sContext ) != TNone ) 00509 { 00510 <font class="comment">/* -------------------------------------------------------------------- */</font> 00511 <font class="comment">/* Create a new element. */</font> 00512 <font class="comment">/* -------------------------------------------------------------------- */</font> 00513 <font class="keywordflow">if</font>( sContext.eTokenType == TOpen ) 00514 { 00515 CPLXMLNode *psElement; 00516 00517 <font class="keywordflow">if</font>( ReadToken(&sContext) != TToken ) 00518 { 00519 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00520 <font class="stringliteral">"Line %d: Didn't find element token after open angle bracket."</font>, 00521 sContext.nInputLine ); 00522 <font class="keywordflow">break</font>; 00523 } 00524 00525 <font class="keywordflow">if</font>( sContext.pszToken[0] != <font class="charliteral">'/'</font> ) 00526 { 00527 psElement = CPLCreateXMLNode( NULL, CXT_Element, 00528 sContext.pszToken ); 00529 AttachNode( &sContext, psElement ); 00530 PushNode( &sContext, psElement ); 00531 } 00532 <font class="keywordflow">else</font> 00533 { 00534 <font class="keywordflow">if</font>( sContext.nStackSize == 0 00535 || !EQUAL(sContext.pszToken+1, 00536 sContext.papsStack[sContext.nStackSize-1]->pszValue) ) 00537 { 00538 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00539 <font class="stringliteral">"Line %d: <%s> doesn't have matching <%s>."</font>, 00540 sContext.nInputLine, 00541 sContext.pszToken, sContext.pszToken+1 ); 00542 <font class="keywordflow">break</font>; 00543 } 00544 <font class="keywordflow">else</font> 00545 { 00546 <font class="keywordflow">if</font>( ReadToken(&sContext) != TClose ) 00547 { 00548 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00549 <font class="stringliteral">"Line %d: Missing close angle bracket after <%s."</font>, 00550 sContext.nInputLine, 00551 sContext.pszToken ); 00552 <font class="keywordflow">break</font>; 00553 } 00554 00555 <font class="comment">/* pop element off stack */</font> 00556 sContext.nStackSize--; 00557 } 00558 } 00559 } 00560 00561 <font class="comment">/* -------------------------------------------------------------------- */</font> 00562 <font class="comment">/* Add an attribute to a token. */</font> 00563 <font class="comment">/* -------------------------------------------------------------------- */</font> 00564 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( sContext.eTokenType == TToken ) 00565 { 00566 CPLXMLNode *psAttr; 00567 00568 psAttr = CPLCreateXMLNode(NULL, CXT_Attribute, sContext.pszToken); 00569 AttachNode( &sContext, psAttr ); 00570 00571 <font class="keywordflow">if</font>( ReadToken(&sContext) != TEqual ) 00572 { 00573 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00574 <font class="stringliteral">"Line %d: Didn't find expected '=' for value of attribute '%s'."</font>, 00575 sContext.nInputLine, psAttr->pszValue ); 00576 <font class="keywordflow">break</font>; 00577 } 00578 00579 <font class="keywordflow">if</font>( ReadToken(&sContext) != TString 00580 && sContext.eTokenType != TToken ) 00581 { 00582 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00583 <font class="stringliteral">"Line %d: Didn't find expected attribute value."</font>, 00584 sContext.nInputLine ); 00585 <font class="keywordflow">break</font>; 00586 } 00587 00588 CPLCreateXMLNode( psAttr, CXT_Text, sContext.pszToken ); 00589 } 00590 00591 <font class="comment">/* -------------------------------------------------------------------- */</font> 00592 <font class="comment">/* Close the start section of an element. */</font> 00593 <font class="comment">/* -------------------------------------------------------------------- */</font> 00594 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( sContext.eTokenType == TClose ) 00595 { 00596 <font class="keywordflow">if</font>( sContext.nStackSize == 0 ) 00597 { 00598 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00599 <font class="stringliteral">"Line %d: Found unbalanced '>'."</font>, 00600 sContext.nInputLine ); 00601 <font class="keywordflow">break</font>; 00602 } 00603 } 00604 00605 <font class="comment">/* -------------------------------------------------------------------- */</font> 00606 <font class="comment">/* Close the start section of an element, and pop it */</font> 00607 <font class="comment">/* immediately. */</font> 00608 <font class="comment">/* -------------------------------------------------------------------- */</font> 00609 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( sContext.eTokenType == TSlashClose ) 00610 { 00611 <font class="keywordflow">if</font>( sContext.nStackSize == 0 ) 00612 { 00613 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00614 <font class="stringliteral">"Line %d: Found unbalanced '/>'."</font>, 00615 sContext.nInputLine ); 00616 <font class="keywordflow">break</font>; 00617 } 00618 00619 sContext.nStackSize--; 00620 } 00621 00622 <font class="comment">/* -------------------------------------------------------------------- */</font> 00623 <font class="comment">/* Close the start section of a <?...?> element, and pop it */</font> 00624 <font class="comment">/* immediately. */</font> 00625 <font class="comment">/* -------------------------------------------------------------------- */</font> 00626 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( sContext.eTokenType == TQuestionClose ) 00627 { 00628 <font class="keywordflow">if</font>( sContext.nStackSize == 0 ) 00629 { 00630 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00631 <font class="stringliteral">"Line %d: Found unbalanced '?>'."</font>, 00632 sContext.nInputLine ); 00633 <font class="keywordflow">break</font>; 00634 } 00635 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( sContext.papsStack[sContext.nStackSize-1]->pszValue[0] != <font class="charliteral">'?'</font> ) 00636 { 00637 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00638 <font class="stringliteral">"Line %d: Found '?>' without matching '<?'."</font>, 00639 sContext.nInputLine ); 00640 <font class="keywordflow">break</font>; 00641 } 00642 00643 sContext.nStackSize--; 00644 } 00645 00646 <font class="comment">/* -------------------------------------------------------------------- */</font> 00647 <font class="comment">/* Handle comments. They are returned as a whole token with the */</font> 00648 <font class="comment">/* prefix and postfix omitted. No processing of white space */</font> 00649 <font class="comment">/* will be done. */</font> 00650 <font class="comment">/* -------------------------------------------------------------------- */</font> 00651 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( sContext.eTokenType == TComment ) 00652 { 00653 CPLXMLNode *psValue; 00654 00655 psValue = CPLCreateXMLNode(NULL, CXT_Comment, sContext.pszToken); 00656 AttachNode( &sContext, psValue ); 00657 } 00658 00659 <font class="comment">/* -------------------------------------------------------------------- */</font> 00660 <font class="comment">/* Handle literals. They are returned without processing. */</font> 00661 <font class="comment">/* -------------------------------------------------------------------- */</font> 00662 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( sContext.eTokenType == TLiteral ) 00663 { 00664 CPLXMLNode *psValue; 00665 00666 psValue = CPLCreateXMLNode(NULL, CXT_Literal, sContext.pszToken); 00667 AttachNode( &sContext, psValue ); 00668 } 00669 00670 <font class="comment">/* -------------------------------------------------------------------- */</font> 00671 <font class="comment">/* Add a text value node as a child of the current element. */</font> 00672 <font class="comment">/* -------------------------------------------------------------------- */</font> 00673 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( sContext.eTokenType == TString && !sContext.bInElement ) 00674 { 00675 CPLXMLNode *psValue; 00676 00677 psValue = CPLCreateXMLNode(NULL, CXT_Text, sContext.pszToken); 00678 AttachNode( &sContext, psValue ); 00679 } 00680 <font class="comment">/* -------------------------------------------------------------------- */</font> 00681 <font class="comment">/* Anything else is an error. */</font> 00682 <font class="comment">/* -------------------------------------------------------------------- */</font> 00683 <font class="keywordflow">else</font> 00684 { 00685 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00686 <font class="stringliteral">"Parse error at line %d, unexpected token:%s\n"</font>, 00687 sContext.nInputLine, sContext.pszToken ); 00688 <font class="keywordflow">break</font>; 00689 } 00690 } 00691 00692 <font class="comment">/* -------------------------------------------------------------------- */</font> 00693 <font class="comment">/* Did we pop all the way out of our stack? */</font> 00694 <font class="comment">/* -------------------------------------------------------------------- */</font> 00695 <font class="keywordflow">if</font>( <a class="code" href="cpl_error_h.html#a21">CPLGetLastErrorType</a>() == CE_None && sContext.nStackSize != 0 ) 00696 { 00697 <a class="code" href="cpl_error_h.html#a17">CPLError</a>( CE_Failure, CPLE_AppDefined, 00698 <font class="stringliteral">"Parse error at EOF, not all elements have been closed,\n"</font> 00699 <font class="stringliteral">"starting with %s\n"</font>, 00700 sContext.papsStack[sContext.nStackSize-1]->pszValue ); 00701 } 00702 00703 <font class="comment">/* -------------------------------------------------------------------- */</font> 00704 <font class="comment">/* Cleanup */</font> 00705 <font class="comment">/* -------------------------------------------------------------------- */</font> 00706 CPLFree( sContext.pszToken ); 00707 <font class="keywordflow">if</font>( sContext.papsStack != NULL ) 00708 CPLFree( sContext.papsStack ); 00709 00710 <font class="keywordflow">if</font>( <a class="code" href="cpl_error_h.html#a21">CPLGetLastErrorType</a>() != CE_None ) 00711 { 00712 CPLDestroyXMLNode( sContext.psFirstNode ); 00713 sContext.psFirstNode = NULL; 00714 } 00715 00716 <font class="keywordflow">return</font> sContext.psFirstNode; 00717 } 00718 00719 <font class="comment">/************************************************************************/</font> 00720 <font class="comment">/* _GrowBuffer() */</font> 00721 <font class="comment">/************************************************************************/</font> 00722 00723 <font class="keyword">static</font> <font class="keywordtype">void</font> _GrowBuffer( <font class="keywordtype">unsigned</font> <font class="keywordtype">int</font> nNeeded, 00724 <font class="keywordtype">char</font> **ppszText, <font class="keywordtype">unsigned</font> <font class="keywordtype">int</font> *pnMaxLength )<font class="keyword"></font> 00725 <font class="keyword"></font> 00726 <font class="keyword"></font>{ 00727 <font class="keywordflow">if</font>( nNeeded+1 >= *pnMaxLength ) 00728 { 00729 *pnMaxLength = MAX(*pnMaxLength * 2,nNeeded+1); 00730 *ppszText = (<font class="keywordtype">char</font> *) <a class="code" href="cpl_conv_h.html#a5">CPLRealloc</a>(*ppszText, *pnMaxLength); 00731 } 00732 } 00733 00734 <font class="comment">/************************************************************************/</font> 00735 <font class="comment">/* CPLSerializeXMLNode() */</font> 00736 <font class="comment">/************************************************************************/</font> 00737 00738 <font class="keyword">static</font> <font class="keywordtype">void</font> 00739 CPLSerializeXMLNode( CPLXMLNode *psNode, <font class="keywordtype">int</font> nIndent, 00740 <font class="keywordtype">char</font> **ppszText, <font class="keywordtype">unsigned</font> <font class="keywordtype">int</font> *pnLength, 00741 <font class="keywordtype">unsigned</font> <font class="keywordtype">int</font> *pnMaxLength )<font class="keyword"></font> 00742 <font class="keyword"></font> 00743 <font class="keyword"></font>{ 00744 <font class="keywordflow">if</font>( psNode == NULL ) 00745 <font class="keywordflow">return</font>; 00746 00747 <font class="comment">/* -------------------------------------------------------------------- */</font> 00748 <font class="comment">/* Ensure the buffer is plenty large to hold this additional */</font> 00749 <font class="comment">/* string. */</font> 00750 <font class="comment">/* -------------------------------------------------------------------- */</font> 00751 *pnLength += strlen(*ppszText + *pnLength); 00752 <font class="keywordflow">if</font>(strlen(psNode->pszValue) + *pnLength + 40 + nIndent > *pnMaxLength) 00753 _GrowBuffer( strlen(psNode->pszValue) + *pnLength + 40 + nIndent, 00754 ppszText, pnMaxLength ); 00755 00756 <font class="comment">/* -------------------------------------------------------------------- */</font> 00757 <font class="comment">/* Text is just directly emitted. */</font> 00758 <font class="comment">/* -------------------------------------------------------------------- */</font> 00759 <font class="keywordflow">if</font>( psNode->eType == CXT_Text ) 00760 { 00761 <font class="keywordtype">char</font> *pszEscaped = CPLEscapeString( psNode->pszValue, -1, CPLES_XML ); 00762 00763 CPLAssert( psNode->psChild == NULL ); 00764 00765 strcat( *ppszText + *pnLength, pszEscaped ); 00766 00767 CPLFree( pszEscaped ); 00768 } 00769 00770 <font class="comment">/* -------------------------------------------------------------------- */</font> 00771 <font class="comment">/* Attributes require a little formatting. */</font> 00772 <font class="comment">/* -------------------------------------------------------------------- */</font> 00773 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psNode->eType == CXT_Attribute ) 00774 { 00775 CPLAssert( psNode->psChild != NULL 00776 && psNode->psChild->eType == CXT_Text ); 00777 00778 sprintf( *ppszText + *pnLength, <font class="stringliteral">" %s=\""</font>, psNode->pszValue ); 00779 CPLSerializeXMLNode( psNode->psChild, 0, ppszText, 00780 pnLength, pnMaxLength ); 00781 strcat( *ppszText + *pnLength, <font class="stringliteral">"\""</font> ); 00782 } 00783 00784 <font class="comment">/* -------------------------------------------------------------------- */</font> 00785 <font class="comment">/* Handle comment output. */</font> 00786 <font class="comment">/* -------------------------------------------------------------------- */</font> 00787 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psNode->eType == CXT_Comment ) 00788 { 00789 <font class="keywordtype">int</font> i; 00790 00791 CPLAssert( psNode->psChild == NULL ); 00792 00793 <font class="keywordflow">for</font>( i = 0; i < nIndent; i++ ) 00794 (*ppszText)[(*pnLength)++] = <font class="charliteral">' '</font>; 00795 00796 sprintf( *ppszText + *pnLength, <font class="stringliteral">"<!--%s-->\n"</font>, 00797 psNode->pszValue ); 00798 } 00799 00800 <font class="comment">/* -------------------------------------------------------------------- */</font> 00801 <font class="comment">/* Handle literal output (like <!DOCTYPE...>) */</font> 00802 <font class="comment">/* -------------------------------------------------------------------- */</font> 00803 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psNode->eType == CXT_Literal ) 00804 { 00805 <font class="keywordtype">int</font> i; 00806 00807 CPLAssert( psNode->psChild == NULL ); 00808 00809 <font class="keywordflow">for</font>( i = 0; i < nIndent; i++ ) 00810 (*ppszText)[(*pnLength)++] = <font class="charliteral">' '</font>; 00811 00812 strcpy( *ppszText + *pnLength, psNode->pszValue ); 00813 strcat( *ppszText + *pnLength, <font class="stringliteral">"\n"</font> ); 00814 } 00815 00816 <font class="comment">/* -------------------------------------------------------------------- */</font> 00817 <font class="comment">/* Elements actually have to deal with general children, and */</font> 00818 <font class="comment">/* various formatting issues. */</font> 00819 <font class="comment">/* -------------------------------------------------------------------- */</font> 00820 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psNode->eType == CXT_Element ) 00821 { 00822 <font class="keywordtype">int</font> bHasNonAttributeChildren = FALSE; 00823 CPLXMLNode *psChild; 00824 <font class="keywordtype">char</font> *pszIndent; 00825 00826 pszIndent = (<font class="keywordtype">char</font> *) <a class="code" href="cpl_conv_h.html#a4">CPLCalloc</a>(nIndent + 1,1); 00827 memset(pszIndent, <font class="charliteral">' '</font>, nIndent ); 00828 00829 strcat( *ppszText + *pnLength, pszIndent ); 00830 *pnLength += nIndent; 00831 sprintf( *ppszText + *pnLength, <font class="stringliteral">"<%s"</font>, psNode->pszValue ); 00832 00833 <font class="comment">/* Serialize *all* the attribute children, regardless of order */</font> 00834 <font class="keywordflow">for</font>( psChild = psNode->psChild; 00835 psChild != NULL; 00836 psChild = psChild->psNext ) 00837 { 00838 <font class="keywordflow">if</font>( psChild->eType == CXT_Attribute ) 00839 CPLSerializeXMLNode( psChild, 0, ppszText, pnLength, 00840 pnMaxLength ); 00841 <font class="keywordflow">else</font> 00842 bHasNonAttributeChildren = TRUE; 00843 } 00844 00845 <font class="keywordflow">if</font>( !bHasNonAttributeChildren ) 00846 { 00847 <font class="keywordflow">if</font>( psNode->pszValue[0] == <font class="charliteral">'?'</font> ) 00848 strcat( *ppszText + *pnLength, <font class="stringliteral">"?>\n"</font> ); 00849 <font class="keywordflow">else</font> 00850 strcat( *ppszText + *pnLength, <font class="stringliteral">"/>\n"</font> ); 00851 } 00852 <font class="keywordflow">else</font> 00853 { 00854 <font class="keywordtype">int</font> bJustText = TRUE; 00855 00856 strcat( *ppszText + *pnLength, <font class="stringliteral">">"</font> ); 00857 00858 <font class="keywordflow">for</font>( psChild = psNode->psChild; 00859 psChild != NULL; 00860 psChild = psChild->psNext ) 00861 { 00862 <font class="keywordflow">if</font>( psChild->eType == CXT_Attribute ) 00863 <font class="keywordflow">continue</font>; 00864 00865 <font class="keywordflow">if</font>( psChild->eType != CXT_Text && bJustText ) 00866 { 00867 bJustText = FALSE; 00868 strcat( *ppszText + *pnLength, <font class="stringliteral">"\n"</font> ); 00869 } 00870 00871 CPLSerializeXMLNode( psChild, nIndent + 2, ppszText, pnLength, 00872 pnMaxLength ); 00873 } 00874 00875 <font class="keywordflow">if</font>( strlen(psNode->pszValue)+*pnLength+40+nIndent > *pnMaxLength) 00876 _GrowBuffer( strlen(psNode->pszValue)+*pnLength+40+nIndent, 00877 ppszText, pnMaxLength ); 00878 00879 <font class="keywordflow">if</font>( !bJustText ) 00880 strcat( *ppszText + *pnLength, pszIndent ); 00881 00882 *pnLength += strlen(*ppszText + *pnLength); 00883 sprintf( *ppszText + *pnLength, <font class="stringliteral">"</%s>\n"</font>, psNode->pszValue ); 00884 } 00885 00886 CPLFree( pszIndent ); 00887 } 00888 } 00889 00890 <font class="comment">/************************************************************************/</font> 00891 <font class="comment">/* CPLSerializeXMLTree() */</font> 00892 <font class="comment">/************************************************************************/</font> 00893 00894 <font class="keywordtype">char</font> *CPLSerializeXMLTree( CPLXMLNode *psNode )<font class="keyword"></font> 00895 <font class="keyword"></font> 00896 <font class="keyword"></font>{ 00897 <font class="keywordtype">unsigned</font> <font class="keywordtype">int</font> nMaxLength = 10000, nLength = 0; 00898 <font class="keywordtype">char</font> *pszText = NULL; 00899 CPLXMLNode *psThis; 00900 00901 pszText = (<font class="keywordtype">char</font> *) <a class="code" href="cpl_conv_h.html#a3">CPLMalloc</a>(nMaxLength); 00902 pszText[0] = <font class="charliteral">'\0'</font>; 00903 00904 <font class="keywordflow">for</font>( psThis = psNode; psThis != NULL; psThis = psThis->psNext ) 00905 CPLSerializeXMLNode( psThis, 0, &pszText, &nLength, &nMaxLength ); 00906 00907 <font class="keywordflow">return</font> pszText; 00908 } 00909 00910 <font class="comment">/************************************************************************/</font> 00911 <font class="comment">/* CPLCreateXMLNode() */</font> 00912 <font class="comment">/************************************************************************/</font> 00913 00914 CPLXMLNode *CPLCreateXMLNode( CPLXMLNode *poParent, CPLXMLNodeType eType, 00915 <font class="keyword">const</font> <font class="keywordtype">char</font> *pszText )<font class="keyword"></font> 00916 <font class="keyword"></font> 00917 <font class="keyword"></font>{ 00918 CPLXMLNode *psNode; 00919 00920 <font class="comment">/* -------------------------------------------------------------------- */</font> 00921 <font class="comment">/* Create new node. */</font> 00922 <font class="comment">/* -------------------------------------------------------------------- */</font> 00923 psNode = (CPLXMLNode *) <a class="code" href="cpl_conv_h.html#a4">CPLCalloc</a>(<font class="keyword">sizeof</font>(CPLXMLNode),1); 00924 00925 psNode->eType = eType; 00926 psNode->pszValue = <a class="code" href="cpl_conv_h.html#a6">CPLStrdup</a>( pszText ); 00927 00928 <font class="comment">/* -------------------------------------------------------------------- */</font> 00929 <font class="comment">/* Attach to parent, if provided. */</font> 00930 <font class="comment">/* -------------------------------------------------------------------- */</font> 00931 <font class="keywordflow">if</font>( poParent != NULL ) 00932 { 00933 <font class="keywordflow">if</font>( poParent->psChild == NULL ) 00934 poParent->psChild = psNode; 00935 <font class="keywordflow">else</font> 00936 { 00937 CPLXMLNode *psLink = poParent->psChild; 00938 00939 <font class="keywordflow">while</font>( psLink->psNext != NULL ) 00940 psLink = psLink->psNext; 00941 00942 psLink->psNext = psNode; 00943 } 00944 } 00945 00946 <font class="keywordflow">return</font> psNode; 00947 } 00948 00949 <font class="comment">/************************************************************************/</font> 00950 <font class="comment">/* CPLDestroyXMLNode() */</font> 00951 <font class="comment">/************************************************************************/</font> 00952 00953 <font class="keywordtype">void</font> CPLDestroyXMLNode( CPLXMLNode *psNode )<font class="keyword"></font> 00954 <font class="keyword"></font> 00955 <font class="keyword"></font>{ 00956 <font class="keywordflow">if</font>( psNode->psChild != NULL ) 00957 CPLDestroyXMLNode( psNode->psChild ); 00958 00959 <font class="keywordflow">if</font>( psNode->psNext != NULL ) 00960 CPLDestroyXMLNode( psNode->psNext ); 00961 00962 CPLFree( psNode->pszValue ); 00963 CPLFree( psNode ); 00964 } 00965 00966 <font class="comment">/************************************************************************/</font> 00967 <font class="comment">/* CPLGetXMLNode() */</font> 00968 <font class="comment">/************************************************************************/</font> 00969 00970 CPLXMLNode *CPLGetXMLNode( CPLXMLNode *poRoot, <font class="keyword">const</font> <font class="keywordtype">char</font> *pszPath )<font class="keyword"></font> 00971 <font class="keyword"></font> 00972 <font class="keyword"></font>{ 00973 <font class="keywordtype">char</font> **papszTokens; 00974 <font class="keywordtype">int</font> iToken = 0; 00975 00976 papszTokens = CSLTokenizeStringComplex( pszPath, <font class="stringliteral">"."</font>, FALSE, FALSE ); 00977 00978 <font class="keywordflow">while</font>( papszTokens[iToken] != NULL && poRoot != NULL ) 00979 { 00980 CPLXMLNode *psChild; 00981 00982 <font class="keywordflow">for</font>( psChild = poRoot->psChild; psChild != NULL; 00983 psChild = psChild->psNext ) 00984 { 00985 <font class="keywordflow">if</font>( psChild->eType != CXT_Text 00986 && EQUAL(papszTokens[iToken],psChild->pszValue) ) 00987 <font class="keywordflow">break</font>; 00988 } 00989 00990 <font class="keywordflow">if</font>( psChild == NULL ) 00991 { 00992 poRoot = NULL; 00993 <font class="keywordflow">break</font>; 00994 } 00995 00996 poRoot = psChild; 00997 iToken++; 00998 } 00999 01000 CSLDestroy( papszTokens ); 01001 <font class="keywordflow">return</font> poRoot; 01002 } 01003 01004 <font class="comment">/************************************************************************/</font> 01005 <font class="comment">/* CPLGetXMLValue() */</font> 01006 <font class="comment">/************************************************************************/</font> 01007 01008 <font class="keyword">const</font> <font class="keywordtype">char</font> *CPLGetXMLValue( CPLXMLNode *poRoot, <font class="keyword">const</font> <font class="keywordtype">char</font> *pszPath, 01009 <font class="keyword">const</font> <font class="keywordtype">char</font> *pszDefault )<font class="keyword"></font> 01010 <font class="keyword"></font> 01011 <font class="keyword"></font>{ 01012 CPLXMLNode *psTarget; 01013 01014 psTarget = CPLGetXMLNode( poRoot, pszPath ); 01015 <font class="keywordflow">if</font>( psTarget == NULL ) 01016 <font class="keywordflow">return</font> pszDefault; 01017 01018 <font class="keywordflow">if</font>( psTarget->eType == CXT_Attribute ) 01019 { 01020 CPLAssert( psTarget->psChild != NULL 01021 && psTarget->psChild->eType == CXT_Text ); 01022 01023 <font class="keywordflow">return</font> psTarget->psChild->pszValue; 01024 } 01025 01026 <font class="keywordflow">if</font>( psTarget->eType == CXT_Element 01027 && psTarget->psChild != NULL 01028 && psTarget->psChild->eType == CXT_Text 01029 && psTarget->psChild->psNext == NULL ) 01030 { 01031 <font class="keywordflow">return</font> psTarget->psChild->pszValue; 01032 } 01033 01034 <font class="keywordflow">return</font> pszDefault; 01035 } 01036 01037 <font class="comment">/************************************************************************/</font> 01038 <font class="comment">/* CPLAddXMLChild() */</font> 01039 <font class="comment">/* */</font> 01040 <font class="comment">/* Add a node as a child of another. */</font> 01041 <font class="comment">/************************************************************************/</font> 01042 01043 <font class="keywordtype">void</font> CPLAddXMLChild( CPLXMLNode *psParent, CPLXMLNode *psChild )<font class="keyword"></font> 01044 <font class="keyword"></font> 01045 <font class="keyword"></font>{ 01046 CPLXMLNode *psSib; 01047 01048 CPLAssert( psChild->psNext == NULL ); 01049 psChild->psNext = NULL; 01050 01051 <font class="keywordflow">if</font>( psParent->psChild == NULL ) 01052 { 01053 psParent->psChild = psChild; 01054 <font class="keywordflow">return</font>; 01055 } 01056 01057 <font class="keywordflow">for</font>( psSib = psParent->psChild; 01058 psSib->psNext != NULL; 01059 psSib = psSib->psNext ) {} 01060 01061 psSib->psNext = psChild; 01062 } 01063 01064 <font class="comment">/************************************************************************/</font> 01065 <font class="comment">/* CPLCreateXMLElementAndValue() */</font> 01066 <font class="comment">/************************************************************************/</font> 01067 01068 CPLXMLNode *CPLCreateXMLElementAndValue( CPLXMLNode *psParent, 01069 <font class="keyword">const</font> <font class="keywordtype">char</font> *pszName, 01070 <font class="keyword">const</font> <font class="keywordtype">char</font> *pszValue )<font class="keyword"></font> 01071 <font class="keyword"></font> 01072 <font class="keyword"></font>{ 01073 <font class="keywordflow">return</font> CPLCreateXMLNode( 01074 CPLCreateXMLNode( psParent, CXT_Element, pszName ), 01075 CXT_Text, pszValue ); 01076 } 01077 01078 <font class="comment">/************************************************************************/</font> 01079 <font class="comment">/* CPLCloneXMLTree() */</font> 01080 <font class="comment">/* */</font> 01081 <font class="comment">/* Clone an XML Tree. We use recursion to handle children, but */</font> 01082 <font class="comment">/* we do siblings by looping. This means we can handle very */</font> 01083 <font class="comment">/* long lists of elements, but great depth may cause stack */</font> 01084 <font class="comment">/* overflow problems on some systems. */</font> 01085 <font class="comment">/************************************************************************/</font> 01086 01087 CPLXMLNode *CPLCloneXMLTree( CPLXMLNode *psTree )<font class="keyword"></font> 01088 <font class="keyword"></font> 01089 <font class="keyword"></font>{ 01090 CPLXMLNode *psPrevious = NULL; 01091 CPLXMLNode *psReturn = NULL; 01092 01093 <font class="keywordflow">while</font>( psTree != NULL ) 01094 { 01095 CPLXMLNode *psCopy; 01096 01097 psCopy = CPLCreateXMLNode( NULL, psTree->eType, psTree->pszValue ); 01098 <font class="keywordflow">if</font>( psReturn == NULL ) 01099 psReturn = psCopy; 01100 <font class="keywordflow">if</font>( psPrevious != NULL ) 01101 psPrevious->psNext = psCopy; 01102 01103 <font class="keywordflow">if</font>( psTree->psChild != NULL ) 01104 psCopy->psChild = CPLCloneXMLTree( psTree->psChild ); 01105 01106 psPrevious = psCopy; 01107 psTree = psTree->psNext; 01108 } 01109 01110 <font class="keywordflow">return</font> psReturn; 01111 } 01112 01113 <font class="comment">/************************************************************************/</font> 01114 <font class="comment">/* CPLSetXMLValue() */</font> 01115 <font class="comment">/* */</font> 01116 <font class="comment">/* Set the text value of an XML element to the suggested */</font> 01117 <font class="comment">/* value. Intermediate element nodes are created if */</font> 01118 <font class="comment">/* an existing component is missing. */</font> 01119 <font class="comment">/************************************************************************/</font> 01120 01121 <font class="keywordtype">int</font> CPLSetXMLValue( CPLXMLNode *psRoot, <font class="keyword">const</font> <font class="keywordtype">char</font> *pszPath, 01122 <font class="keyword">const</font> <font class="keywordtype">char</font> *pszValue )<font class="keyword"></font> 01123 <font class="keyword"></font> 01124 <font class="keyword"></font>{ 01125 <font class="keywordtype">char</font> **papszTokens; 01126 <font class="keywordtype">int</font> iToken = 0; 01127 01128 papszTokens = CSLTokenizeStringComplex( pszPath, <font class="stringliteral">"."</font>, FALSE, FALSE ); 01129 01130 <font class="keywordflow">while</font>( papszTokens[iToken] != NULL && psRoot != NULL ) 01131 { 01132 CPLXMLNode *psChild; 01133 <font class="keywordtype">int</font> bIsAttribute = FALSE; 01134 <font class="keyword">const</font> <font class="keywordtype">char</font> *pszName = papszTokens[iToken]; 01135 01136 <font class="keywordflow">if</font>( pszName[0] == <font class="charliteral">'#'</font> ) 01137 { 01138 bIsAttribute = TRUE; 01139 pszName++; 01140 } 01141 01142 <font class="keywordflow">if</font>( psRoot->eType != CXT_Element ) 01143 <font class="keywordflow">return</font> FALSE; 01144 01145 <font class="keywordflow">for</font>( psChild = psRoot->psChild; psChild != NULL; 01146 psChild = psChild->psNext ) 01147 { 01148 <font class="keywordflow">if</font>( psChild->eType != CXT_Text 01149 && EQUAL(pszName,psChild->pszValue) ) 01150 <font class="keywordflow">break</font>; 01151 } 01152 01153 <font class="keywordflow">if</font>( psChild == NULL ) 01154 { 01155 <font class="keywordflow">if</font>( bIsAttribute ) 01156 psChild = CPLCreateXMLNode( psRoot, CXT_Attribute, pszName ); 01157 <font class="keywordflow">else</font> 01158 psChild = CPLCreateXMLNode( psRoot, CXT_Element, pszName ); 01159 } 01160 01161 psRoot = psChild; 01162 iToken++; 01163 } 01164 01165 CSLDestroy( papszTokens ); 01166 01167 <font class="comment">/* -------------------------------------------------------------------- */</font> 01168 <font class="comment">/* Now set a value node under this node. */</font> 01169 <font class="comment">/* -------------------------------------------------------------------- */</font> 01170 <font class="keywordflow">if</font>( psRoot->psChild == NULL ) 01171 CPLCreateXMLNode( psRoot, CXT_Text, pszValue ); 01172 <font class="keywordflow">else</font> <font class="keywordflow">if</font>( psRoot->psChild->eType != CXT_Text ) 01173 <font class="keywordflow">return</font> FALSE; 01174 <font class="keywordflow">else</font> 01175 { 01176 CPLFree( psRoot->psChild->pszValue ); 01177 psRoot->psChild->pszValue = <a class="code" href="cpl_conv_h.html#a6">CPLStrdup</a>( pszValue ); 01178 } 01179 01180 <font class="keywordflow">return</font> TRUE; 01181 } 01182 </div></pre><hr><address><small>Generated at Sat Dec 21 14:01:57 2002 for GDAL by <a href="http://www.stack.nl/~dimitri/doxygen/index.html"> <img src="doxygen.gif" alt="doxygen" align="middle" border=0 width=110 height=53></a>1.2.3-20001105 written by <a href="mailto:dimitri@stack.nl">Dimitri van Heesch</a>, © 1997-2000</small></address> </body> </html>