1 #define _CRT_SECURE_NO_WARNINGS 22 static char THIS_FILE[]=__FILE__;
59 std::string::size_type nStartSize =
m_csDoc.length() / 64 + 8;
60 if (
m_aPos.size() < nStartSize)
64 bool bWellFormed =
false;
71 m_aPos[0].iElemChild = iPos;
127 int iPos =
m_aPos[iPosChild].iElemParent;
139 std::string csTagName;
220 m_aPos[iPos].iElemParent = iPosParent;
221 m_aPos[iPos].iElemChild = 0;
222 m_aPos[iPos].iElemNext = 0;
232 while (csName.empty())
235 m_aPos[iPos].nStartL = token.nNext;
243 token.nNext =
m_aPos[iPos].nStartL + 1;
248 char cFirstChar =
m_csDoc[token.nL];
249 if (cFirstChar ==
'?' || cFirstChar ==
'!')
251 token.nNext =
m_aPos[iPos].nStartL;
255 else if (cFirstChar !=
'/')
259 if (!
x_FindChar(token.szDoc, token.nNext,
'>'))
268 m_aPos[iPos].nStartR = token.nNext;
283 int iInner, iInnerPrev = 0;
289 m_aPos[iInnerPrev].iElemNext = iInner;
291 m_aPos[iPos].iElemChild = iInner;
302 return x_ParseError(
"End tag of %s element not found", csName.c_str());
305 token.nNext =
m_aPos[iPos].nEndL + 1;
310 if (! token.bIsString)
313 if (nTokenCount == 1 &&
m_csDoc[token.nL] !=
'/')
314 return x_ParseError(
"Expecting end tag of element %s", csName.c_str());
316 else if (nTokenCount == 2 && ! token.Match(csName.c_str()))
317 return x_ParseError(
"End tag does not correspond to %s", csName.c_str());
320 else if (
m_csDoc[token.nL] ==
'>')
326 if (! token.szDoc[token.nL] || nTokenCount < 2)
327 return x_ParseError(
"End tag not completed for element %s", csName.c_str());
328 m_aPos[iPos].nEndR = token.nL;
338 const char* pChar = &szDoc[nChar];
339 while (*pChar && *pChar != c)
341 nChar = (int)(pChar - szDoc);
358 while (szDoc[nChar] && strchr(
" \t\n\r", szDoc[nChar]))
360 return szDoc[nChar] !=
'\0';
368 const char* szDoc = token.
szDoc;
369 int nChar = token.
nNext;
383 char cFirstChar = szDoc[nChar];
384 if (cFirstChar ==
'\"' || cFirstChar ==
'\'')
396 token.
nR = nChar - 1;
406 while (szDoc[nChar] && ! strchr(
" \t\n\r<>=\\/?!", szDoc[nChar]))
410 if (nChar == token.
nL)
412 token.
nR = nChar - 1;
424 if (token.
nL > token.
nR)
427 token.
nR - token.
nL + ((token.
nR < (
int)(
m_csDoc.length())) ? 1 : 0));
436 iPos =
m_aPos[iPos].iElemNext;
438 iPos =
m_aPos[iPosParent].iElemChild;
441 if (szPath == NULL || !szPath[0])
451 if (token.Match(szPath))
453 iPos =
m_aPos[iPos].iElemNext;
464 const char* szDoc = token.
szDoc;
466 if (szDoc[token.
nL] ==
'<')
475 if (! szDoc[token.
nL+1] || ! szDoc[token.
nL+2])
477 char cFirstChar = szDoc[token.
nL+1];
478 const char* szEndOfNode = NULL;
479 if (cFirstChar ==
'?')
484 else if (cFirstChar ==
'!')
486 char cSecondChar = szDoc[token.
nL+2];
487 if (cSecondChar ==
'[')
492 else if (cSecondChar ==
'-')
506 char cChar = szDoc[token.
nL];
509 else if (cChar ==
']')
511 else if (nBrackets == 0 && cChar ==
'>')
522 else if (cFirstChar ==
'/')
535 const char* pEnd = strstr(&szDoc[token.
nNext], szEndOfNode);
538 token.
nNext = (int)(pEnd - szDoc) + (int)strlen(szEndOfNode);
541 else if (szDoc[token.
nL])
548 if (szDoc[token.
nNext] !=
'<')
581 if (cChar ==
'>' || cChar ==
'/' || cChar ==
'?')
589 if (! nAttrib && nCount)
592 if (! szAttrib || ! szAttrib[0])
596 if (token.
Match(szAttrib))
600 else if (nAttrib && nCount == nAttrib + 2)
632 nInsertAt =
m_aPos[iPos].nStartR - (
m_aPos[iPos].IsEmptyElement()?1:0);
639 std::string csInsert;
645 nInsertAt = token.nL;
646 nReplace = token.nR-token.nL+1;
651 std::string csFormat;
653 csFormat += szAttrib;
661 int nAdjust = (int)csInsert.length() - nReplace;
662 m_aPos[iPos].nStartR += nAdjust;
663 m_aPos[iPos].AdjustEnd(nAdjust);
674 if (!
m_aPos[iPos].iElemChild && !
m_aPos[iPos].IsEmptyElement())
677 const char* szDoc = (
const char*)(
m_csDoc.c_str());
678 int nChar =
m_aPos[iPos].nStartR + 1;
679 if (
x_FindAny(szDoc, nChar) && szDoc[nChar] ==
'<' 680 && nChar + 11 <
m_aPos[iPos].nEndL
681 && strncmp(&szDoc[nChar],
"<![CDATA[", 9) == 0)
684 int nEndCDATA = (int)
m_csDoc.find(
"]]>", nChar);
685 if (nEndCDATA != -1 && nEndCDATA <
m_aPos[iPos].nEndL)
687 return Mid(
m_csDoc, nChar, nEndCDATA - nChar);
710 static const char* szaReplace[] = {
"<",
"&",
">",
"'",
""" };
711 const char* pFind = bAttrib ?
"<&>\'\"" :
"<&>";
713 const char* pSource = szText;
714 int nDestSize = (int)strlen(pSource);
715 nDestSize += nDestSize / 10 + 7;
716 char* pDest = GetBuffer(csText, nDestSize);
718 char cSource = *pSource;
722 if (nLen > nDestSize - 6)
724 ReleaseBuffer(csText, nLen);
726 pDest = GetBuffer(csText, nDestSize);
728 if ((pFound = strchr(pFind,cSource)) != NULL)
730 pFound = szaReplace[pFound-pFind];
732 strcpy_s(&pDest[nLen], nDestSize, pFound);
734 strncpy(&pDest[nLen], pFound, nDestSize);
736 nLen += (int)strlen(pFound);
740 pDest[nLen] = *pSource;
746 ReleaseBuffer(csText, nLen);
756 static const char* szaCode[] = {
"lt;",
"amp;",
"gt;",
"apos;",
"quot;" };
757 static int anCodeLen[] = { 3,4,3,5,5 };
758 static const char* szSymbol =
"<&>\'\"";
760 const char* pSource =
m_csDoc.c_str();
761 int nDestSize = nRight - nLeft + 1;
762 char* pDest = GetBuffer(csText, nDestSize);
766 while (nChar <= nRight)
768 if (pSource[nChar] ==
'&')
771 bool bCodeConverted =
false;
772 for (
int nMatch = 0; nMatch < 5; ++nMatch)
774 if (nChar <= nRight - anCodeLen[nMatch]
775 && strncmp(szaCode[nMatch],&pSource[nChar+1],anCodeLen[nMatch]) == 0)
778 pDest[nLen++] = szSymbol[nMatch];
779 nChar += anCodeLen[nMatch] + 1;
780 bCodeConverted =
true;
786 if (! bCodeConverted)
795 pDest[nLen] = pSource[nChar];
800 ReleaseBuffer(csText, nLen);
809 int nDocLength = (int)
m_csDoc.length();
810 int nInsLength = (int)csInsert.length();
813 nLeft = std::max(0, std::min(nLeft, nDocLength));
814 nReplace = std::max(0, std::min(nReplace, nDocLength-nLeft));
817 int nNewLength = nInsLength + nDocLength - nReplace;
818 int nBufferLen = nNewLength;
819 char* pDoc = GetBuffer(
m_csDoc, nBufferLen);
822 if (nLeft+nReplace < nDocLength)
823 memmove(&pDoc[nLeft+nInsLength], &pDoc[nLeft+nReplace], (nDocLength-nLeft-nReplace)*
sizeof(
char));
826 memcpy(&pDoc[nLeft], csInsert.c_str(), nInsLength*
sizeof(char));
829 ReleaseBuffer(
m_csDoc, nNewLength);
841 int iPosTop =
m_aPos[iPos].iElemParent;
842 bool bPosFirst = bAfterPos;
846 bool bPosTop =
false;
850 iPosTop =
m_aPos[iPos].iElemParent;
855 if (! bPosTop && ! bPosFirst &&
m_aPos[iPos].iElemChild)
858 iPos =
m_aPos[iPos].iElemChild;
860 else if (
m_aPos[iPos].iElemNext)
862 iPos =
m_aPos[iPos].iElemNext;
868 while ((iPos=
m_aPos[iPos].iElemParent) != 0 && iPos != iPosTop)
869 if (
m_aPos[iPos].iElemNext)
871 iPos =
m_aPos[iPos].iElemNext;
879 m_aPos[iPos].AdjustStart(nShift);
880 m_aPos[iPos].AdjustEnd(nShift);
888 bool bInsert = (nFlags&1)?
true:
false;
889 bool bHonorWhitespace = (nFlags&2)?
true:
false;
891 std::string::size_type nStartL;
898 nStartL = nOffset + nLength;
904 nStartL =
m_aPos[iPosRel].nStartL;
906 nStartL =
m_aPos[iPosRel].nEndR + 1;
908 else if (! iPosParent)
916 else if (
m_aPos[iPosParent].IsEmptyElement())
919 nStartL =
m_aPos[iPosParent].nStartR;
924 nStartL =
m_aPos[iPosParent].nStartR + 1;
926 nStartL =
m_aPos[iPosParent].nEndL;
930 if (! bHonorWhitespace && !
m_aPos[iPosParent].IsEmptyElement())
932 const char* szDoc = (
const char*)
m_csDoc.c_str();
933 int nChar = (int)nStartL;
934 if (!
x_FindAny(szDoc,nChar) || szDoc[nChar] ==
'<')
945 int iPosPrev =
m_aPos[iPosParent].iElemChild;
946 if (iPosPrev != iPosRel)
949 while (
m_aPos[iPosPrev].iElemNext != iPosRel)
950 iPosPrev =
m_aPos[iPosPrev].iElemNext;
951 iPosBefore = iPosPrev;
956 iPosBefore = iPosRel;
959 else if (
m_aPos[iPosParent].iElemChild)
964 int iPosLast =
m_aPos[iPosParent].iElemChild;
965 int iPosNext = iPosLast;
969 iPosNext =
m_aPos[iPosNext].iElemNext;
971 iPosBefore = iPosLast;
975 nOffset = (int)nStartL;
976 iPosRel = iPosBefore;
999 int iPosParent, iPosBefore, nOffset = 0, nLength = 0;
1010 int nFlags = bInsert?1:0;
1011 x_LocateNew(iPosParent, iPosBefore, nOffset, nLength, nFlags);
1017 int nTopParent = iPosParent;
1021 nTopParent =
m_aPos[nTopParent].iElemParent;
1024 int nIndentChars = nLevel *
mnIndent;
1028 bool bEmptyParent =
m_aPos[iPosParent].IsEmptyElement();
1029 if (bEmptyParent ||
m_aPos[iPosParent].nStartR + 1 ==
m_aPos[iPosParent].nEndL)
1035 if ((nOffset < (
int)(
m_csDoc.length())) && (0 < nOffset) &&
1038 while ((0 < nOffset) && (
' ' ==
m_csDoc[nOffset-1]))
1047 m_aPos[iPos].nStartL = nOffset + nIndentChars;
1050 m_aPos[iPos].iElemParent = iPosParent;
1051 m_aPos[iPos].iElemChild = 0;
1052 m_aPos[iPos].iElemNext = 0;
1057 m_aPos[iPosBefore].iElemNext = iPos;
1062 m_aPos[iPos].iElemNext =
m_aPos[iPosParent].iElemChild;
1063 m_aPos[iPosParent].iElemChild = iPos;
1067 std::string csInsert;
1068 int nLenName = (int)strlen(szName);
1069 int nLenValue = szValue ? (int)strlen(szValue) : 0;
1076 csInsert +=
"/>\r\n";
1077 m_aPos[iPos].nStartR =
m_aPos[iPos].nStartL + nLenName + 2;
1085 nLenValue = (int)csValue.length();
1090 csInsert += csValue;
1093 csInsert +=
">\r\n";
1094 m_aPos[iPos].nStartR =
m_aPos[iPos].nStartL + nLenName + 1;
1095 m_aPos[iPos].nEndL =
m_aPos[iPos].nStartR + nLenValue + 1;
1096 m_aPos[iPos].nEndR =
m_aPos[iPos].nEndL + nLenName + 2;
1104 int nReplace = 0, nLeft =
m_aPos[iPos].nStartL;
1107 std::string csParentTagName =
x_GetTagName(iPosParent);
1108 std::string csFormat;
1110 csFormat += csInsert;
1115 csFormat += csParentTagName;
1116 csInsert = csFormat;
1117 nLeft =
m_aPos[iPosParent].nStartR - 1;
1123 m_aPos[iPosParent].nStartR -= 1;
1128 m_aPos[iPosParent].nEndL -= (int)(csParentTagName.length() + 1);
1130 else if (
m_aPos[iPosParent].nStartR + 1 ==
m_aPos[iPosParent].nEndL)
1133 csInsert =
"\r\n" + csInsert;
1137 nLeft =
m_aPos[iPosParent].nStartR + 1;
1141 nLeft -= nIndentChars;
1145 x_Adjust(iPos, (
int)csInsert.length() - nReplace);
1166 va_start(marker, fmt);
1170 size_t len = _vscprintf(fmt, marker) + 1;
1173 va_copy(argcopy, marker);
1174 auto len = vsnprintf(NULL, 0, fmt, marker) + 1;
1179 vector<char> buffer(len,
'\0');
1181 int nWritten = _vsnprintf_s(&buffer[0], buffer.size(), len, fmt, marker);
1183 int nWritten = vsnprintf(&buffer[0], len, fmt, marker);
1187 retStr = &buffer[0];
1197 std::string CMarkup::Mid(
const std::string &tStr,
int nFirst)
const 1199 return Mid(tStr, nFirst, (
int)tStr.length() - nFirst);
1202 std::string CMarkup::Mid(
const std::string &tStr,
int nFirst,
int nCount)
const 1213 int nSize =
static_cast<int>(tStr.size());
1215 if (nFirst + nCount > nSize)
1217 nCount = nSize - nFirst;
1222 std::string tStrEmpty;
1226 assert(nFirst >= 0);
1227 assert(nFirst + nCount <= nSize);
1229 return tStr.substr(nFirst, nCount);
1232 char* CMarkup::GetBuffer(std::string &tStr,
int nMinLen)
const 1234 if (static_cast<int>(tStr.size()) < nMinLen)
1236 tStr.resize(nMinLen);
1239 return const_cast<char*
>(tStr.c_str());
1242 void CMarkup::ReleaseBuffer(std::string &tStr,
int nNewLen)
const 1244 tStr.resize(nNewLen > -1 ? nNewLen : strlen(tStr.c_str()));
1249 int nLen = nR - nL + 1;
1250 return ((strncmp(&szDoc[nL], szName, nLen) == 0)
1251 && (szName[nLen] ==
'\0' || strchr(
" =/[", szName[nLen])));
void SetIndent(int nIndent=4)
void x_Adjust(int iPos, int nShift, bool bAfterPos=false)
static bool x_FindAny(const char *szDoc, int &nChar)
void operator=(const CMarkup &markup)
static bool x_FindToken(TokenPos &token)
void x_DocChange(int nLeft, int nReplace, const std::string &csInsert)
#define MARKUP_SETDEBUGSTATE
void x_SetPos(int iPosParent, int iPos, int iPosChild)
static bool x_FindChar(const char *szDoc, int &nChar, char c)
bool x_AddElem(const char *szName, const char *szValue, bool bInsert, bool bAddChild)
bool SetDoc(const char *szDoc)
int x_FindElem(int iPosParent, int iPos, const char *szPath)
std::string x_GetAttrib(int iPos, const char *szAttrib) const
int x_ParseElem(int iPos)
std::string x_GetToken(const TokenPos &token) const
std::string x_TextToDoc(const char *szText, bool bAttrib=false) const
bool x_SetAttrib(int iPos, const char *szAttrib, const char *szValue)
static std::string Format(const char *fmt,...)
int x_ParseNode(TokenPos &token)
std::vector< ElemPos > m_aPos
std::string x_GetTagName(int iPos) const
bool FindChildElem(const char *szName=NULL)
std::string GetTagName() const
std::string x_GetData(int iPos) const
bool x_FindAttrib(TokenPos &token, const char *szAttrib=NULL) const
bool Match(const char *szName) const
int x_ParseError(const char *szError, const char *szName=NULL)
bool FindElem(const char *szName=NULL)
void x_LocateNew(int iPosParent, int &iPosRel, int &nOffset, int nLength, int nFlags)
std::string x_TextFromDoc(int nLeft, int nRight) const