📄 cpl_minixml.cpp
字号:
/********************************************************************** * $Id: cpl_minixml.cpp,v 1.45 2006/11/07 03:45:22 fwarmerdam Exp $ * * Project: CPL - Common Portability Library * Purpose: Implementation of MiniXML Parser and handling. * Author: Frank Warmerdam, warmerdam@pobox.com * ********************************************************************** * Copyright (c) 2001, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * Independent Security Audit 2003/04/05 Andrey Kiselev: * Completed audit of this module. Any documents may be parsed without * buffer overflows and stack corruptions. * * Security Audit 2003/03/28 warmerda: * Completed security audit. I believe that this module may be safely used * to parse, and serialize arbitrary documents provided by a potentially * hostile source. * * $Log: cpl_minixml.cpp,v $ * Revision 1.45 2006/11/07 03:45:22 fwarmerdam * Added support for CDATA. * * Revision 1.44 2006/06/30 18:18:17 dron * Avoid warnings. * * Revision 1.43 2006/06/30 14:25:24 dron * Avoid warnings on win/64. * * Revision 1.42 2006/04/19 02:00:20 fwarmerdam * moved ctype.h after cpl include files for VS2005 * * Revision 1.41 2006/02/20 00:42:35 fwarmerdam * Trim. * * Revision 1.40 2006/02/19 21:54:34 mloskot * [WINCE] Changes related to Windows CE port of CPL. Most changes are #ifdef wrappers. * * Revision 1.39 2005/10/07 00:03:29 fwarmerdam * improve documentation * * Revision 1.38 2005/09/11 19:30:12 fwarmerdam * Try to write in text mode through large file API. * * Revision 1.37 2005/09/11 19:14:54 fwarmerdam * Use largefile API for virtualization support. Note that XML files are * no longer produced in machine-local text format. * * Revision 1.36 2005/05/22 08:17:07 fwarmerdam * allow CPLAddXMLChild() to support siblings * * Revision 1.35 2005/05/13 18:17:48 fwarmerdam * added CPLRemoveXMLChild * * Revision 1.34 2005/03/09 17:07:25 fwarmerdam * added CPLSearchXMLNode * * Revision 1.33 2005/01/17 17:01:56 fwarmerdam * ensure that namespace stripping apply to attributes * * Revision 1.32 2004/10/21 18:59:00 fwarmerdam * Ensure that an empty path in CPLGetXMLValue() means the current node. * * Revision 1.31 2004/08/11 18:42:00 warmerda * fix quirks with CPLSetXMLValue() * * Revision 1.30 2004/03/31 17:11:41 warmerda * fixed return value of CPLCreateXMLElementAndValue() * * Revision 1.29 2004/01/29 17:01:51 warmerda * Added reference to spec. * * Revision 1.28 2004/01/29 15:29:28 warmerda * Added CPLCleanXMLElementName */#include "cpl_minixml.h"#include "cpl_error.h"#include "cpl_conv.h"#include "cpl_string.h"#include <ctype.h>CPL_CVSID("$Id: cpl_minixml.cpp,v 1.45 2006/11/07 03:45:22 fwarmerdam Exp $");typedef enum { TNone, TString, TOpen, TClose, TEqual, TToken, TSlashClose, TQuestionClose, TComment, TLiteral} XMLTokenType;typedef struct { const char *pszInput; int nInputOffset; int nInputLine; int bInElement; XMLTokenType eTokenType; char *pszToken; size_t nTokenMaxSize; size_t nTokenSize; int nStackMaxSize; int nStackSize; CPLXMLNode **papsStack; CPLXMLNode *psFirstNode;} ParseContext;/************************************************************************//* ReadChar() *//************************************************************************/static char ReadChar( ParseContext *psContext ){ char chReturn; chReturn = psContext->pszInput[psContext->nInputOffset++]; if( chReturn == '\0' ) psContext->nInputOffset--; else if( chReturn == 10 ) psContext->nInputLine++; return chReturn;}/************************************************************************//* UnreadChar() *//************************************************************************/static void UnreadChar( ParseContext *psContext, char chToUnread ){ if( chToUnread == '\0' ) { /* do nothing */ } else { CPLAssert( chToUnread == psContext->pszInput[psContext->nInputOffset-1] ); psContext->nInputOffset--; if( chToUnread == 10 ) psContext->nInputLine--; }}/************************************************************************//* AddToToken() *//************************************************************************/static void AddToToken( ParseContext *psContext, char chNewChar ){ if( psContext->pszToken == NULL ) { psContext->nTokenMaxSize = 10; psContext->pszToken = (char *) CPLMalloc(psContext->nTokenMaxSize); } else if( psContext->nTokenSize >= psContext->nTokenMaxSize - 2 ) { psContext->nTokenMaxSize *= 2; psContext->pszToken = (char *) CPLRealloc(psContext->pszToken,psContext->nTokenMaxSize); } psContext->pszToken[psContext->nTokenSize++] = chNewChar; psContext->pszToken[psContext->nTokenSize] = '\0';}/************************************************************************//* ReadToken() *//************************************************************************/static XMLTokenType ReadToken( ParseContext *psContext ){ char chNext; psContext->nTokenSize = 0; psContext->pszToken[0] = '\0'; chNext = ReadChar( psContext ); while( isspace(chNext) ) chNext = ReadChar( psContext );/* -------------------------------------------------------------------- *//* Handle comments. *//* -------------------------------------------------------------------- */ if( chNext == '<' && EQUALN(psContext->pszInput+psContext->nInputOffset,"!--",3) ) { psContext->eTokenType = TComment; // Skip "!--" characters ReadChar(psContext); ReadChar(psContext); ReadChar(psContext); while( !EQUALN(psContext->pszInput+psContext->nInputOffset,"-->",3) && (chNext = ReadChar(psContext)) != '\0' ) AddToToken( psContext, chNext ); // Skip "-->" characters ReadChar(psContext); ReadChar(psContext); ReadChar(psContext); }/* -------------------------------------------------------------------- *//* Handle DOCTYPE. *//* -------------------------------------------------------------------- */ else if( chNext == '<' && EQUALN(psContext->pszInput+psContext->nInputOffset,"!DOCTYPE",8) ) { int bInQuotes = FALSE; psContext->eTokenType = TLiteral; AddToToken( psContext, '<' ); do { chNext = ReadChar(psContext); if( chNext == '\0' ) { CPLError( CE_Failure, CPLE_AppDefined, "Parse error in DOCTYPE on or before line %d, " "reached end of file without '>'.", psContext->nInputLine ); break; } if( chNext == '\"' ) bInQuotes = !bInQuotes; if( chNext == '>' && !bInQuotes ) { AddToToken( psContext, '>' ); break; } AddToToken( psContext, chNext ); } while( TRUE ); }/* -------------------------------------------------------------------- *//* Handle CDATA. *//* -------------------------------------------------------------------- */ else if( chNext == '<' && EQUALN(psContext->pszInput+psContext->nInputOffset,"![CDATA[",8) ) { psContext->eTokenType = TString; // Skip !CDATA[ ReadChar( psContext ); ReadChar( psContext ); ReadChar( psContext ); ReadChar( psContext ); ReadChar( psContext ); ReadChar( psContext ); ReadChar( psContext ); ReadChar( psContext ); while( !EQUALN(psContext->pszInput+psContext->nInputOffset,"]]>",3) && (chNext = ReadChar(psContext)) != '\0' ) AddToToken( psContext, chNext ); // Skip "]]>" characters ReadChar(psContext); ReadChar(psContext); ReadChar(psContext); }/* -------------------------------------------------------------------- *//* Simple single tokens of interest. *//* -------------------------------------------------------------------- */ else if( chNext == '<' && !psContext->bInElement ) { psContext->eTokenType = TOpen; psContext->bInElement = TRUE; } else if( chNext == '>' && psContext->bInElement ) { psContext->eTokenType = TClose; psContext->bInElement = FALSE; } else if( chNext == '=' && psContext->bInElement ) { psContext->eTokenType = TEqual; } else if( chNext == '\0' ) { psContext->eTokenType = TNone; }/* -------------------------------------------------------------------- *//* Handle the /> token terminator. *//* -------------------------------------------------------------------- */ else if( chNext == '/' && psContext->bInElement && psContext->pszInput[psContext->nInputOffset] == '>' ) { chNext = ReadChar( psContext ); CPLAssert( chNext == '>' ); psContext->eTokenType = TSlashClose; psContext->bInElement = FALSE; }/* -------------------------------------------------------------------- *//* Handle the ?> token terminator. *//* -------------------------------------------------------------------- */ else if( chNext == '?' && psContext->bInElement && psContext->pszInput[psContext->nInputOffset] == '>' ) { chNext = ReadChar( psContext ); CPLAssert( chNext == '>' ); psContext->eTokenType = TQuestionClose; psContext->bInElement = FALSE; }/* -------------------------------------------------------------------- *//* Collect a quoted string. *//* -------------------------------------------------------------------- */ else if( psContext->bInElement && chNext == '"' ) { psContext->eTokenType = TString; while( (chNext = ReadChar(psContext)) != '"' && chNext != '\0' ) AddToToken( psContext, chNext ); if( chNext != '"' ) { psContext->eTokenType = TNone; CPLError( CE_Failure, CPLE_AppDefined, "Parse error on line %d, reached EOF before closing quote.", psContext->nInputLine ); } /* Do we need to unescape it? */ if( strchr(psContext->pszToken,'&') != NULL ) { int nLength; char *pszUnescaped = CPLUnescapeString( psContext->pszToken, &nLength, CPLES_XML ); strcpy( psContext->pszToken, pszUnescaped ); CPLFree( pszUnescaped ); psContext->nTokenSize = strlen(psContext->pszToken ); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -