?? markupstl.cpp
字號:
{
// Starting at token.nNext, bypass whitespace and find the next token
nChar = token.nNext;
nPreSpaceStart = nChar;
if ( ! x_FindAny(szDoc,nChar) )
break;
nPreSpaceLength = nChar - nPreSpaceStart;
// Is it an opening quote?
cFirstChar = szDoc[nChar];
if ( cFirstChar == '\"' || cFirstChar == '\'' )
{
token.nTokenFlags |= MNF_QUOTED;
// Move past opening quote
++nChar;
token.nL = nChar;
// Look for closing quote
while ( szDoc[nChar] && szDoc[nChar] != cFirstChar )
++nChar;
// Set right to before closing quote
token.nR = nChar - 1;
// Set nChar past closing quote unless at end of document
if ( szDoc[nChar] )
++nChar;
}
else
{
token.nTokenFlags &= ~MNF_QUOTED;
// Go until special char or whitespace
token.nL = nChar;
if ( bAfterEqual )
{
while ( szDoc[nChar] && ! strchr(" \t\n\r>",szDoc[nChar]) )
++nChar;
}
else
{
while ( szDoc[nChar] && ! strchr("= \t\n\r>/?",szDoc[nChar]) )
++nChar;
}
// Adjust end position if it is one special char
if ( nChar == token.nL )
++nChar; // it is a special char
token.nR = nChar - 1;
}
// nNext points to one past last char of token
token.nNext = nChar;
if ( ! bAfterEqual && ! (token.nTokenFlags&MNF_QUOTED) )
{
// Is it an equal sign?
char cChar = szDoc[token.nL];
if ( cChar == '=' )
{
bAfterEqual = true;
continue;
}
// Is it the right angle bracket?
if ( cChar == '>' || cChar == '/' || cChar == '?' )
{
token.nNext = nPreSpaceStart;
break; // attrib not found
}
if ( nFoundAttribNameR )
break;
// Attribute name
if ( nAttrib != -1 )
{
if ( ! szAttrib )
{
if ( nAttrib == n )
return true; // found by number
}
else if ( token.Match(szAttrib) )
{
// Matched attrib name, go forward to value
nFoundAttribNameR = token.nR;
token.nPreSpaceStart = nPreSpaceStart;
token.nPreSpaceLength = nPreSpaceLength;
}
}
++nAttrib;
}
else if ( nFoundAttribNameR )
break;
bAfterEqual = false;
}
if ( nFoundAttribNameR )
{
if ( ! bAfterEqual )
{
// when attribute has no value the value is the attribute name
token.nL = token.nPreSpaceStart + token.nPreSpaceLength;
token.nR = nFoundAttribNameR;
token.nNext = nFoundAttribNameR + 1;
}
return true; // found by name
}
return false; // not found
}
string CMarkupSTL::x_GetAttrib( int iPos, const char* szAttrib ) const
{
// Return the value of the attrib
TokenPos token( m_strDoc, m_nFlags );
if ( iPos && m_nNodeType == MNT_ELEMENT )
token.nNext = m_aPos[iPos].nStart + 1;
else if ( iPos == m_iPos && m_nNodeLength && m_nNodeType == MNT_PROCESSING_INSTRUCTION )
token.nNext = m_nNodeOffset + 2;
else
return "";
if ( szAttrib && x_FindAttrib( token, szAttrib ) )
return UnescapeText( &token.szDoc[token.nL], token.Length() );
return "";
}
bool CMarkupSTL::x_SetAttrib( int iPos, const char* szAttrib, int nValue )
{
// Convert integer to string and call SetChildAttrib
char szVal[25];
sprintf( szVal, "%d", nValue );
return x_SetAttrib( iPos, szAttrib, szVal );
}
bool CMarkupSTL::x_SetAttrib( int iPos, const char* szAttrib, const char* szValue )
{
// Set attribute in iPos element
TokenPos token( m_strDoc, m_nFlags );
if ( iPos && m_nNodeType == MNT_ELEMENT )
token.nNext = m_aPos[iPos].nStart + 1;
else if ( iPos == m_iPos && m_nNodeLength && m_nNodeType == MNT_PROCESSING_INSTRUCTION )
token.nNext = m_nNodeOffset + 2;
else
return false;
// Create insertion text depending on whether attribute already exists
// Decision: for empty value leaving attrib="" instead of removing attrib
int nReplace = 0;
int nInsertAt;
string strInsert;
strInsert += x_ATTRIBQUOTE;
strInsert += EscapeText( szValue, MNF_ESCAPEQUOTES );
strInsert += x_ATTRIBQUOTE;
if ( x_FindAttrib( token, szAttrib ) )
{
// Replace value
nInsertAt = token.nL - ((token.nTokenFlags&MNF_QUOTED)?1:0);
nReplace = token.Length() + ((token.nTokenFlags&MNF_QUOTED)?2:0);
}
else
{
// Insert string name value pair
string strFormat;
strFormat = " ";
strFormat += szAttrib;
strFormat += "=";
strFormat += strInsert;
strInsert = strFormat;
nInsertAt = token.nNext;
}
x_DocChange( nInsertAt, nReplace, strInsert );
int nAdjust = (int)strInsert.size() - nReplace;
if ( m_nNodeType == MNT_PROCESSING_INSTRUCTION )
{
x_AdjustForNode( m_iPosParent, m_iPos, nAdjust );
m_nNodeLength += nAdjust;
MARKUP_SETDEBUGSTATE;
return true;
}
m_aPos[iPos].AdjustStartTagLen( nAdjust );
m_aPos[iPos].nLength += nAdjust;
x_Adjust( iPos, nAdjust );
MARKUP_SETDEBUGSTATE;
return true;
}
bool CMarkupSTL::x_CreateNode( string& strNode, int nNodeType, const char* szText )
{
// Set strNode based on nNodeType and szData
// Return false if szData would jeopardize well-formed document
//
switch ( nNodeType )
{
case MNT_PROCESSING_INSTRUCTION:
strNode = "<?";
strNode += szText;
strNode += "?>";
break;
case MNT_COMMENT:
strNode = "<!--";
strNode += szText;
strNode += "-->";
break;
case MNT_ELEMENT:
strNode = "<";
strNode += szText;
strNode += "/>";
break;
case MNT_TEXT:
case MNT_WHITESPACE:
strNode = EscapeText( szText );
break;
case MNT_DOCUMENT_TYPE:
strNode = szText;
break;
case MNT_LONE_END_TAG:
return false;
case MNT_CDATA_SECTION:
if ( strstr(szText,"]]>") != NULL )
return false;
strNode = "<![CDATA[";
strNode += szText;
strNode += "]]>";
break;
}
return true;
}
string CMarkupSTL::x_EncodeCDATASection( const char* szData )
{
// Split CDATA Sections if there are any end delimiters
string strData = "<![CDATA[";
const char* pszNextStart = szData;
const char* pszEnd = strstr( szData, "]]>" );
while ( pszEnd )
{
strData += string( pszNextStart, (int)(pszEnd - pszNextStart) );
strData += "]]]]><![CDATA[>";
pszNextStart = pszEnd + 3;
pszEnd = strstr( pszNextStart, "]]>" );
}
strData += pszNextStart;
strData += "]]>";
return strData;
}
bool CMarkupSTL::x_SetData( int iPos, int nValue )
{
// Convert integer to string
char szVal[25];
sprintf( szVal, "%d", nValue );
return x_SetData( iPos, szVal, 0 );
}
bool CMarkupSTL::x_SetData( int iPos, const char* szData, int nFlags )
{
// Set data at specified position
// if nFlags==1, set content of element to a CDATA Section
string strInsert;
if ( iPos == m_iPos && m_nNodeLength )
{
// Not an element
if ( ! x_CreateNode(strInsert, m_nNodeType, szData) )
return false;
x_DocChange( m_nNodeOffset, m_nNodeLength, strInsert );
x_AdjustForNode( m_iPosParent, iPos, (int)strInsert.size() - m_nNodeLength );
m_nNodeLength = (int)strInsert.size();
MARKUP_SETDEBUGSTATE;
return true;
}
// Set data in iPos element
if ( ! iPos || m_aPos[iPos].iElemChild )
return false;
// Build strInsert from szData based on nFlags
if ( nFlags & MNF_WITHCDATA )
strInsert = x_EncodeCDATASection( szData );
else
strInsert = EscapeText( szData, nFlags );
// Insert
NodePos node( MNF_WITHNOLINES|MNF_REPLACE );
node.strMeta = strInsert;
int iPosBefore = 0;
int nReplace = x_InsertNew( iPos, iPosBefore, node );
int nAdjust = (int)node.strMeta.size() - nReplace;
x_Adjust( iPos, nAdjust );
m_aPos[iPos].nLength += nAdjust;
if ( m_aPos[iPos].nFlags & MNF_ILLDATA )
m_aPos[iPos].nFlags &= ~MNF_ILLDATA;
MARKUP_SETDEBUGSTATE;
return true;
}
string CMarkupSTL::x_GetData( int iPos ) const
{
if ( iPos == m_iPos && m_nNodeLength )
{
if ( m_nNodeType == MNT_COMMENT )
return m_strDoc.substr( m_nNodeOffset+4, m_nNodeLength-7 );
else if ( m_nNodeType == MNT_PROCESSING_INSTRUCTION )
return m_strDoc.substr( m_nNodeOffset+2, m_nNodeLength-4 );
else if ( m_nNodeType == MNT_CDATA_SECTION )
return m_strDoc.substr( m_nNodeOffset+9, m_nNodeLength-12 );
else if ( m_nNodeType == MNT_TEXT )
return UnescapeText( &(m_strDoc.c_str())[m_nNodeOffset], m_nNodeLength );
else if ( m_nNodeType == MNT_LONE_END_TAG )
return m_strDoc.substr( m_nNodeOffset+2, m_nNodeLength-3 );
else
return m_strDoc.substr( m_nNodeOffset, m_nNodeLength );
}
// Return a string representing data between start and end tag
// Return empty string if there are any children elements
string strData;
if ( ! m_aPos[iPos].iElemChild && ! m_aPos[iPos].IsEmptyElement() )
{
// Quick scan for any tags inside content
int nContentLen = m_aPos[iPos].ContentLen();
int nStartContent = m_aPos[iPos].StartContent();
const char* pszContent = &(m_strDoc.c_str())[nStartContent];
const char* pszTag = strchr( pszContent, '<' );
if ( pszTag && ((int)(pszTag-pszContent) < nContentLen) )
{
// Concatenate all CDATA Sections and text nodes, ignore other nodes
TokenPos token( m_strDoc, m_nFlags );
token.nNext = nStartContent;
NodePos node;
while ( token.nNext < nStartContent + nContentLen )
{
x_ParseNode( token, node );
if ( node.nNodeType == MNT_TEXT )
strData += UnescapeText( &token.szDoc[node.nStart], node.nLength );
else if ( node.nNodeType == MNT_CDATA_SECTION )
strData += m_strDoc.substr( node.nStart+9, node.nLength-12 );
}
}
else // no tags
strData = UnescapeText( &(m_strDoc.c_str())[nStartContent], nContentLen );
}
return strData;
}
string CMarkupSTL::x_GetElemContent( int iPos ) const
{
if ( iPos && m_aPos[iPos].ContentLen() )
return m_strDoc.substr( m_aPos[iPos].StartContent(), m_aPos[iPos].ContentLen() );
return "";
}
bool CMarkupSTL::x_SetElemContent( const char* szContent )
{
// Set data in iPos element only
if ( ! m_iPos )
return false;
if ( m_nNodeLength )
return false; // not an element
// Unlink all children
int iPos = m_iPos;
int iPosChild = m_aPos[iPos].iElemChild;
bool bHadChild = (iPosChild != 0);
while ( iPosChild )
iPosChild = x_ReleaseSubDoc( iPosChild );
if ( bHadChild )
x_CheckSavedPos();
// Parse content
bool bWellFormed = true;
TokenPos token( szContent, m_nFlags );
int iPosVirtual = x_GetFreePos();
m_aPos[iPosVirtual].ClearVirtualParent();
m_aPos[iPosVirtual].SetLevel( m_aPos[iPos].Level() + 1 );
iPosChild = x_ParseElem( iPosVirtual, token );
if ( m_aPos[iPosVirtual].nFlags & MNF_ILLFORMED )
bWellFormed = false;
m_aPos[iPos].nFlags = (m_aPos[iPos].nFlags & ~MNF_ILLDATA) | (m_aPos[iPosVirtual].nFlags & MNF_ILLDATA);
// Prepare insert and adjust offsets
NodePos node( MNF_WITHNOLINES|MNF_REPLACE );
node.strMeta = szContent;
int iPosBefore = 0;
int nReplace = x_InsertNew( iPos, iPosBefore, node );
// Adjust and link in the inserted elements
x_Adjust( iPosChild, node.nStart );
m_aPos[iPosChild].nStart += node.nStart;
m_aPos[iPos].iElemChild = iPosChild;
while ( iPosChild )
{
m_aPos[iPosChild].iElemParent = iPos;
iPosChild = m_aPos[iPosChild].iElemNext;
}
x_ReleasePos( iPosVirtual );
int nAdjust = (int)node.strMeta.size() - nReplace;
x_Adjust( iPos, nAdjust, true );
m_aPos[iPos].nLength += nAdjust;
x_SetPos( m_iPosParent, m_iPos, 0 );
return bWellFormed;
}
void CMarkupSTL::x_DocChange( int nLeft, int nReplace, const string& strInsert )
{
// Insert strInsert int m_strDoc at nLeft replacing nReplace chars
// Do this with only one buffer reallocation if it grows
//
int nDocLength = (int)m_strDoc.size();
int nInsLength = (int)strInsert.size();
int nNewLength = nInsLength + nDocLength - nReplace;
// When creating a document, reduce reallocs by reserving string space
// Allow for 1.5 times the current allocation
int nBufferLen = nNewLength;
int nAllocLen = (int)m_strDoc.capacity();
if ( nNewLength > nAllocLen )
{
nBufferLen += nBufferLen/2 + 128;
if ( nBufferLen < nNewLength )
nBufferLen = nNewLength;
m_strDoc.reserve( nBufferLen );
}
m_strDoc.replace( nLeft, nReplace, strInsert );
}
void CMarkupSTL::x_Adjust( int iPos, int nShift, bool bAfterPos /*=false*/ )
{
// Loop through affected elements and adjust indexes
// Algorithm:
// 1. update children unless bAfterPos
// (if no children or bAfterPos is true, length of iPos not affected)
// 2. update starts of next siblings and their children
// 3. go up until there is a next sibling of a parent and update starts
// 4. step 2
int iPosTop = m_aPos[iPos].iElemParent;
bool bPosFirst = bAfterPos; // mark as first to skip its children
// Stop when we've reached the virtual parent (which has no tags)
while ( m_aPos[iPos].StartTagLen() )
{
// Were we at containing parent of affected position?
bool bPosTop = false;
if ( iPos == iPosTop )
{
// Move iPosTop up one towards root
iPosTop = m_aPos[iPos].iElemParent;
bPosTop = true;
}
// Traverse to the next update position
if ( ! bPosTop && ! bPosFirst && m_aPos[iPos].iElemChild )
{
// Depth first
iPos = m_aPos[iPos].iElemChild;
}
else if ( m_aPos[iPos].iElemNext )
{
iPos = m_aPos[iPos].iElemNext;
}
else
{
// Look for next sibling of a parent of iPos
// When going back up, parents have already been done except iPosTop
while ( 1 )
{
iPos = m_aPos[iPos].iElemParent;
if ( iPos == iPosTop )
break;
if ( m_aPos[iPos].iElemNext )
{
iPos = m_aPos[iPos].iElemNext;
break;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -