📄 markupstl.cpp
字号:
// MarkupSTL.cpp: implementation of the CMarkupSTL class.//// Markup Release 6.3// Copyright (C) 1999-2002 First Objective Software, Inc. All rights reserved// Go to www.firstobject.com for the latest CMarkup and EDOM documentation// Use in commercial applications requires written permission// This software is provided "as is", with no warranty.#include "MarkupSTL.h"#include <stdio.h>using namespace std;#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endifvoid CMarkupSTL::operator=( const CMarkupSTL& markup ){ m_iPosParent = markup.m_iPosParent; m_iPos = markup.m_iPos; m_iPosChild = markup.m_iPosChild; m_iPosFree = markup.m_iPosFree; m_nNodeType = markup.m_nNodeType; m_aPos = markup.m_aPos; m_strDoc = markup.m_strDoc; MARKUP_SETDEBUGSTATE;}bool CMarkupSTL::SetDoc( const char* szDoc ){ // Reset indexes m_iPosFree = 1; ResetPos(); m_mapSavedPos.clear(); // Set document text if ( szDoc ) m_strDoc = szDoc; else m_strDoc.erase(); // Starting size of position array: 1 element per 64 bytes of document // Tight fit when parsing small doc, only 0 to 2 reallocs when parsing large doc // Start at 8 when creating new document int nStartSize = m_strDoc.size() / 64 + 8; if ( m_aPos.size() < nStartSize ) m_aPos.resize( nStartSize ); // Parse document bool bWellFormed = false; if ( m_strDoc.size() ) { m_aPos[0].Clear(); int iPos = x_ParseElem( 0 ); if ( iPos > 0 ) { m_aPos[0].iElemChild = iPos; bWellFormed = true; } } // Clear indexes if parse failed or empty document if ( ! bWellFormed ) { m_aPos[0].Clear(); m_iPosFree = 1; } ResetPos(); return bWellFormed;};bool CMarkupSTL::IsWellFormed(){ if ( m_aPos.size() && m_aPos[0].iElemChild ) return true; return false;}bool CMarkupSTL::Load( const char* szFileName ){ // Load document from file bool bResult = false; FILE* fp = fopen( szFileName, "rb" ); if ( fp ) { // Determine file length fseek( fp, 0L, SEEK_END ); int nFileLen = ftell(fp); fseek( fp, 0L, SEEK_SET ); // Load string allocator<char> mem; allocator<char>::pointer pBuffer = mem.allocate(nFileLen+1, NULL); if ( fread( pBuffer, nFileLen, 1, fp ) == 1 ) { pBuffer[nFileLen] = '\0'; bResult = SetDoc( pBuffer ); } fclose(fp); mem.deallocate(pBuffer,1); } if ( ! bResult ) SetDoc(NULL); MARKUP_SETDEBUGSTATE; return bResult;}bool CMarkupSTL::Save( const char* szFileName ){ // Save document to file bool bResult = false; FILE* fp = fopen( szFileName, "wb" ); if ( fp ) { // Save string int nFileLen = m_strDoc.size(); if ( ! nFileLen ) bResult = true; else if ( fwrite( m_strDoc.c_str(), nFileLen, 1, fp ) == 1 ) bResult = true; fclose(fp); } return bResult;}bool CMarkupSTL::FindElem( const char* szName ){ // Change current position only if found // if ( m_aPos.size() ) { int iPos = x_FindElem( m_iPosParent, m_iPos, szName ); if ( iPos ) { // Assign new position x_SetPos( m_aPos[iPos].iElemParent, iPos, 0 ); return true; } } return false;}bool CMarkupSTL::FindChildElem( const char* szName ){ // Change current child position only if found // // Shorthand: call this with no current main position // means find child under root element if ( ! m_iPos ) FindElem(); int iPosChild = x_FindElem( m_iPos, m_iPosChild, szName ); if ( iPosChild ) { // Assign new position int iPos = m_aPos[iPosChild].iElemParent; x_SetPos( m_aPos[iPos].iElemParent, iPos, iPosChild ); return true; } return false;}string CMarkupSTL::GetTagName() const{ // Return the tag name at the current main position string strTagName; if ( m_iPos ) strTagName = x_GetTagName( m_iPos ); return strTagName;}bool CMarkupSTL::IntoElem(){ // If there is no child position and IntoElem is called it will succeed in release 6.3 // (A subsequent call to FindElem will find the first element) // The following short-hand behavior was never part of EDOM and was misleading // It would find a child element if there was no current child element position and go into it // It is removed in release 6.3, this change is NOT backwards compatible! // if ( ! m_iPosChild ) // FindChildElem(); if ( m_iPos && m_nNodeType == MNT_ELEMENT ) { x_SetPos( m_iPos, m_iPosChild, 0 ); return true; } return false;}bool CMarkupSTL::OutOfElem(){ // Go to parent element if ( m_iPosParent ) { x_SetPos( m_aPos[m_iPosParent].iElemParent, m_iPosParent, m_iPos ); return true; } return false;}string CMarkupSTL::GetAttribName( int n ) const{ // Return nth attribute name of main position if ( ! m_iPos || m_nNodeType != MNT_ELEMENT ) return ""; TokenPos token( m_strDoc.c_str() ); token.nNext = m_aPos[m_iPos].nStartL + 1; for ( int nAttrib=0; nAttrib<=n; ++nAttrib ) if ( ! x_FindAttrib(token) ) return ""; // Return substring of document return x_GetToken( token );}bool CMarkupSTL::SavePos( const char* szPosName ){ // Save current element position in saved position map if ( szPosName ) { SavedPos savedpos; savedpos.iPosParent = m_iPosParent; savedpos.iPos = m_iPos; savedpos.iPosChild = m_iPosChild; string strPosName = szPosName; m_mapSavedPos[strPosName] = savedpos; return true; } return false;}bool CMarkupSTL::RestorePos( const char* szPosName ){ // Restore element position if found in saved position map if ( szPosName ) { string strPosName = szPosName; mapSavedPosT::const_iterator iterSavePos = m_mapSavedPos.find( strPosName ); if ( iterSavePos != m_mapSavedPos.end() ) { SavedPos savedpos = (*iterSavePos).second; x_SetPos( savedpos.iPosParent, savedpos.iPos, savedpos.iPosChild ); return true; } } return false;}bool CMarkupSTL::GetOffsets( int& nStart, int& nEnd ) const{ // Return document offsets of current main position element // This is not part of EDOM but is used by the Markup project if ( m_iPos ) { nStart = m_aPos[m_iPos].nStartL; nEnd = m_aPos[m_iPos].nEndR; return true; } return false;}string CMarkupSTL::GetChildSubDoc() const{ if ( m_iPosChild ) { int nL = m_aPos[m_iPosChild].nStartL; int nR = m_aPos[m_iPosChild].nEndR + 1; TokenPos token( m_strDoc.c_str() ); token.nNext = nR; if ( ! x_FindToken(token) || m_strDoc[token.nL] == '<' ) nR = token.nL; return m_strDoc.substr( nL, nR - nL ); } return "";}bool CMarkupSTL::RemoveElem(){ // Remove current main position element if ( m_iPos && m_nNodeType == MNT_ELEMENT ) { int iPos = x_RemoveElem( m_iPos ); x_SetPos( m_iPosParent, iPos, 0 ); return true; } return false;}bool CMarkupSTL::RemoveChildElem(){ // Remove current child position element if ( m_iPosChild ) { int iPosChild = x_RemoveElem( m_iPosChild ); x_SetPos( m_iPosParent, m_iPos, iPosChild ); return true; } return false;}//////////////////////////////////////////////////////////////////////// Private Methods//////////////////////////////////////////////////////////////////////int CMarkupSTL::x_GetFreePos(){ // // This returns the index of the next unused ElemPos in the array // if ( m_iPosFree == m_aPos.size() ) m_aPos.resize( m_iPosFree + m_iPosFree / 2 ); ++m_iPosFree; return m_iPosFree - 1;}int CMarkupSTL::x_ReleasePos(){ // // This decrements the index of the next unused ElemPos in the array // allowing the element index returned by GetFreePos() to be reused // --m_iPosFree; return 0;}int CMarkupSTL::x_ParseError( const char* szError, const char* szName ){ if ( szName ) { char szFormat[300]; sprintf( szFormat, szError, szName ); m_strError = szFormat; } else m_strError = szError; x_ReleasePos(); return -1;}int CMarkupSTL::x_ParseElem( int iPosParent ){ // This is either called by SetDoc, x_AddSubDoc, or itself recursively // m_aPos[iPosParent].nEndL is where to start parsing for the child element // This returns the new position if a tag is found, otherwise zero // In all cases we need to get a new ElemPos, but release it if unused // int iPos = x_GetFreePos(); m_aPos[iPos].nStartL = m_aPos[iPosParent].nEndL; m_aPos[iPos].iElemParent = iPosParent; m_aPos[iPos].iElemChild = 0; m_aPos[iPos].iElemNext = 0; // Start Tag // A loop is used to ignore all remarks tags and special tags // i.e. <?xml version="1.0"?>, and <!-- comment here --> // So any tag beginning with ? or ! is ignored // Loop past ignored tags TokenPos token( m_strDoc.c_str() ); token.nNext = m_aPos[iPosParent].nEndL; string strName; while ( strName.empty() ) { // Look for left angle bracket of start tag m_aPos[iPos].nStartL = token.nNext; if ( ! x_FindChar( token.szDoc, m_aPos[iPos].nStartL, '<' ) ) return x_ParseError( "Element tag not found" ); // Set parent's End tag to start looking from here (or later) m_aPos[iPosParent].nEndL = m_aPos[iPos].nStartL; // Determine whether this is an element, or bypass other type of node token.nNext = m_aPos[iPos].nStartL + 1; if ( x_FindToken( token ) ) { if ( token.bIsString ) return x_ParseError( "Tag starts with quote" ); char cFirstChar = m_strDoc[token.nL]; if ( cFirstChar == '?' || cFirstChar == '!' ) { token.nNext = m_aPos[iPos].nStartL; if ( ! x_ParseNode(token) ) return x_ParseError( "Invalid node" ); } else if ( cFirstChar != '/' ) { strName = x_GetToken( token ); // Look for end of tag if ( ! x_FindChar(token.szDoc, token.nNext, '>') ) return x_ParseError( "End of tag not found" ); } else return x_ReleasePos(); // probably end tag of parent } else return x_ParseError( "Abrupt end within tag" ); } m_aPos[iPos].nStartR = token.nNext; // Is ending mark within start tag, i.e. empty element? if ( m_strDoc[m_aPos[iPos].nStartR-1] == '/' ) { // Empty element // Close tag left is set to ending mark, and right to open tag right m_aPos[iPos].nEndL = m_aPos[iPos].nStartR-1; m_aPos[iPos].nEndR = m_aPos[iPos].nStartR; } else // look for end tag { // Element probably has contents // Determine where to start looking for left angle bracket of end tag // This is done by recursively parsing the contents of this element int iInner, iInnerPrev = 0; m_aPos[iPos].nEndL = m_aPos[iPos].nStartR + 1; while ( (iInner = x_ParseElem( iPos )) > 0 ) { // Set links to iInner if ( iInnerPrev ) m_aPos[iInnerPrev].iElemNext = iInner; else m_aPos[iPos].iElemChild = iInner; iInnerPrev = iInner; // Set offset to reflect child m_aPos[iPos].nEndL = m_aPos[iInner].nEndR + 1; } if ( iInner == -1 ) return -1; // Look for left angle bracket of end tag if ( ! x_FindChar( token.szDoc, m_aPos[iPos].nEndL, '<' ) ) return x_ParseError( "End tag of %s element not found", strName.c_str() ); // Look through tokens of end tag token.nNext = m_aPos[iPos].nEndL + 1; int nTokenCount = 0; while ( x_FindToken( token ) ) { ++nTokenCount; if ( ! token.bIsString ) { // Is first token not an end slash mark? if ( nTokenCount == 1 && m_strDoc[token.nL] != '/' ) return x_ParseError( "Expecting end tag of element %s", strName.c_str() ); else if ( nTokenCount == 2 && ! token.Match(strName.c_str()) ) return x_ParseError( "End tag does not correspond to %s", strName.c_str() ); // Else is it a right angle bracket? else if ( m_strDoc[token.nL] == '>' ) break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -