1 #define _CRT_SECURE_NO_WARNINGS
23 static char THIS_FILE[] = __FILE__;
55 std::string::size_type nStartSize =
m_csDoc.length() / 64 + 8;
56 if (
m_aPos.size() < nStartSize)
m_aPos.resize(nStartSize);
59 bool bWellFormed =
false;
64 m_aPos[0].iElemChild = iPos;
83 if (!(
m_aPos.empty()) &&
m_aPos[0].iElemChild)
return true;
111 int iPos =
m_aPos[iPosChild].iElemParent;
121 std::string csTagName;
192 m_aPos[iPos].iElemParent = iPosParent;
193 m_aPos[iPos].iElemChild = 0;
194 m_aPos[iPos].iElemNext = 0;
204 while (csName.empty()) {
218 if (cFirstChar ==
'?' || cFirstChar ==
'!') {
221 }
else if (cFirstChar !=
'/') {
244 int iInner, iInnerPrev = 0;
249 m_aPos[iInnerPrev].iElemNext = iInner;
251 m_aPos[iPos].iElemChild = iInner;
257 if (iInner == -1)
return -1;
261 return x_ParseError(
"End tag of %s element not found", csName.c_str());
270 if (nTokenCount == 1 &&
m_csDoc[token.
nL] !=
'/')
274 else if (nTokenCount == 2 && !token.
Match(csName.c_str()))
275 return x_ParseError(
"End tag does not correspond to %s",
285 if (!token.
szDoc[token.
nL] || nTokenCount < 2)
286 return x_ParseError(
"End tag not completed for element %s",
297 const char* pChar = &szDoc[nChar];
298 while (*pChar && *pChar !=
c) pChar += 1;
299 nChar = (int)(pChar - szDoc);
300 if (!*pChar)
return false;
314 while (szDoc[nChar] && strchr(
" \t\n\r", szDoc[nChar])) ++nChar;
315 return szDoc[nChar] !=
'\0';
322 const char* szDoc = token.
szDoc;
323 int nChar = token.
nNext;
336 char cFirstChar = szDoc[nChar];
337 if (cFirstChar ==
'\"' || cFirstChar ==
'\'') {
348 token.
nR = nChar - 1;
351 if (szDoc[nChar]) ++nChar;
355 while (szDoc[nChar] && !strchr(
" \t\n\r<>=\\/?!", szDoc[nChar]))
359 if (nChar == token.
nL) ++nChar;
360 token.
nR = nChar - 1;
371 if (token.
nL > token.
nR)
return "";
374 token.
nR - token.
nL + ((token.
nR < (
int)(
m_csDoc.length())) ? 1 : 0));
382 iPos =
m_aPos[iPos].iElemNext;
384 iPos =
m_aPos[iPosParent].iElemChild;
387 if (szPath == NULL || !szPath[0])
return iPos;
395 if (token.
Match(szPath))
return iPos;
396 iPos =
m_aPos[iPos].iElemNext;
406 const char* szDoc = token.
szDoc;
408 if (szDoc[token.
nL] ==
'<') {
416 if (!szDoc[token.
nL + 1] || !szDoc[token.
nL + 2])
return 0;
417 char cFirstChar = szDoc[token.
nL + 1];
418 const char* szEndOfNode = NULL;
419 if (cFirstChar ==
'?') {
422 }
else if (cFirstChar ==
'!') {
423 char cSecondChar = szDoc[token.
nL + 2];
424 if (cSecondChar ==
'[') {
427 }
else if (cSecondChar ==
'-') {
436 char cChar = szDoc[token.
nL];
439 else if (cChar ==
']')
441 else if (nBrackets == 0 && cChar ==
'>') {
447 if (!nTypeFound)
return 0;
449 }
else if (cFirstChar ==
'/') {
458 const char* pEnd = strstr(&szDoc[token.
nNext], szEndOfNode);
460 token.
nNext = (int)(pEnd - szDoc) + (int)strlen(szEndOfNode);
462 }
else if (szDoc[token.
nL]) {
467 if (szDoc[token.
nNext] !=
'<') {
487 const char* szAttrib)
const {
491 for (
int nCount = 0;
x_FindToken(token); ++nCount) {
495 if (cChar ==
'>' || cChar ==
'/' || cChar ==
'?')
499 if (cChar ==
'=')
continue;
502 if (!nAttrib && nCount) {
504 if (!szAttrib || !szAttrib[0])
508 if (token.
Match(szAttrib)) nAttrib = nCount;
510 }
else if (nAttrib && nCount == nAttrib + 2) {
529 token.
nL, token.
nR - ((token.
nR < (
int)(
m_csDoc.length())) ? 0 : 1));
539 nInsertAt =
m_aPos[iPos].nStartR - (
m_aPos[iPos].IsEmptyElement() ? 1 : 0);
545 std::string csInsert;
550 nInsertAt = token.
nL;
551 nReplace = token.
nR - token.
nL + 1;
554 std::string csFormat;
556 csFormat += szAttrib;
564 int nAdjust = (int)csInsert.length() - nReplace;
565 m_aPos[iPos].nStartR += nAdjust;
566 m_aPos[iPos].AdjustEnd(nAdjust);
575 if (!
m_aPos[iPos].iElemChild && !
m_aPos[iPos].IsEmptyElement()) {
577 const char* szDoc = (
const char*)(
m_csDoc.c_str());
578 int nChar =
m_aPos[iPos].nStartR + 1;
579 if (
x_FindAny(szDoc, nChar) && szDoc[nChar] ==
'<' &&
580 nChar + 11 <
m_aPos[iPos].nEndL &&
581 strncmp(&szDoc[nChar],
"<![CDATA[", 9) == 0) {
583 int nEndCDATA = (int)
m_csDoc.find(
"]]>", nChar);
584 if (nEndCDATA != -1 && nEndCDATA <
m_aPos[iPos].nEndL) {
585 return Mid(
m_csDoc, nChar, nEndCDATA - nChar);
607 static const char* szaReplace[] = {
"<",
"&",
">",
"'",
609 const char* pFind = bAttrib ?
"<&>\'\"" :
"<&>";
611 const char* pSource = szText;
612 int nDestSize = (int)strlen(pSource);
613 nDestSize += nDestSize / 10 + 7;
614 char* pDest = GetBuffer(csText, nDestSize);
616 char cSource = *pSource;
619 if (nLen > nDestSize - 6) {
620 ReleaseBuffer(csText, nLen);
622 pDest = GetBuffer(csText, nDestSize);
624 if ((pFound = strchr(pFind, cSource)) != NULL) {
625 pFound = szaReplace[pFound - pFind];
627 strcpy_s(&pDest[nLen], nDestSize, pFound);
629 strncpy(&pDest[nLen], pFound, nDestSize);
631 nLen += (int)strlen(pFound);
633 pDest[nLen] = *pSource;
639 ReleaseBuffer(csText, nLen);
649 static const char* szaCode[] = {
"lt;",
"amp;",
"gt;",
"apos;",
"quot;"};
650 static int anCodeLen[] = {3, 4, 3, 5, 5};
651 static const char* szSymbol =
"<&>\'\"";
653 const char* pSource =
m_csDoc.c_str();
654 int nDestSize = nRight - nLeft + 1;
655 char* pDest = GetBuffer(csText, nDestSize);
659 while (nChar <= nRight) {
660 if (pSource[nChar] ==
'&') {
662 bool bCodeConverted =
false;
663 for (
int nMatch = 0; nMatch < 5; ++nMatch) {
664 if (nChar <= nRight - anCodeLen[nMatch] &&
665 strncmp(szaCode[nMatch], &pSource[nChar + 1], anCodeLen[nMatch]) ==
668 pDest[nLen++] = szSymbol[nMatch];
669 nChar += anCodeLen[nMatch] + 1;
670 bCodeConverted =
true;
676 if (!bCodeConverted) {
683 pDest[nLen] = pSource[nChar];
688 ReleaseBuffer(csText, nLen);
693 const std::string& csInsert) {
697 int nDocLength = (int)
m_csDoc.length();
698 int nInsLength = (int)csInsert.length();
701 nLeft = std::max(0, std::min(nLeft, nDocLength));
702 nReplace = std::max(0, std::min(nReplace, nDocLength - nLeft));
705 int nNewLength = nInsLength + nDocLength - nReplace;
706 int nBufferLen = nNewLength;
707 char* pDoc = GetBuffer(
m_csDoc, nBufferLen);
710 if (nLeft + nReplace < nDocLength)
711 memmove(&pDoc[nLeft + nInsLength], &pDoc[nLeft + nReplace],
712 (nDocLength - nLeft - nReplace) *
sizeof(
char));
715 memcpy(&pDoc[nLeft], csInsert.c_str(), nInsLength *
sizeof(
char));
718 ReleaseBuffer(
m_csDoc, nNewLength);
729 int iPosTop =
m_aPos[iPos].iElemParent;
730 bool bPosFirst = bAfterPos;
733 bool bPosTop =
false;
734 if (iPos == iPosTop) {
736 iPosTop =
m_aPos[iPos].iElemParent;
741 if (!bPosTop && !bPosFirst &&
m_aPos[iPos].iElemChild) {
743 iPos =
m_aPos[iPos].iElemChild;
744 }
else if (
m_aPos[iPos].iElemNext) {
745 iPos =
m_aPos[iPos].iElemNext;
749 while ((iPos =
m_aPos[iPos].iElemParent) != 0 && iPos != iPosTop)
750 if (
m_aPos[iPos].iElemNext) {
751 iPos =
m_aPos[iPos].iElemNext;
758 if (iPos != iPosTop)
m_aPos[iPos].AdjustStart(nShift);
759 m_aPos[iPos].AdjustEnd(nShift);
764 int nLength,
int nFlags) {
767 bool bInsert = (nFlags & 1) ?
true :
false;
768 bool bHonorWhitespace = (nFlags & 2) ?
true :
false;
770 std::string::size_type nStartL;
776 nStartL = nOffset + nLength;
777 }
else if (iPosRel) {
780 nStartL =
m_aPos[iPosRel].nStartL;
782 nStartL =
m_aPos[iPosRel].nEndR + 1;
783 }
else if (!iPosParent) {
789 }
else if (
m_aPos[iPosParent].IsEmptyElement()) {
791 nStartL =
m_aPos[iPosParent].nStartR;
794 nStartL =
m_aPos[iPosParent].nStartR + 1;
796 nStartL =
m_aPos[iPosParent].nEndL;
800 if (!bHonorWhitespace && !
m_aPos[iPosParent].IsEmptyElement()) {
801 const char* szDoc = (
const char*)
m_csDoc.c_str();
802 int nChar = (int)nStartL;
803 if (!
x_FindAny(szDoc, nChar) || szDoc[nChar] ==
'<') nStartL = nChar;
811 int iPosPrev =
m_aPos[iPosParent].iElemChild;
812 if (iPosPrev != iPosRel) {
814 while (
m_aPos[iPosPrev].iElemNext != iPosRel)
815 iPosPrev =
m_aPos[iPosPrev].iElemNext;
816 iPosBefore = iPosPrev;
819 iPosBefore = iPosRel;
821 }
else if (
m_aPos[iPosParent].iElemChild) {
824 int iPosLast =
m_aPos[iPosParent].iElemChild;
825 int iPosNext = iPosLast;
828 iPosNext =
m_aPos[iPosNext].iElemNext;
830 iPosBefore = iPosLast;
834 nOffset = (int)nStartL;
835 iPosRel = iPosBefore;
842 if (!
m_iPos)
return false;
852 int iPosParent, iPosBefore, nOffset = 0, nLength = 0;
860 int nFlags = bInsert ? 1 : 0;
861 x_LocateNew(iPosParent, iPosBefore, nOffset, nLength, nFlags);
867 int nTopParent = iPosParent;
870 nTopParent =
m_aPos[nTopParent].iElemParent;
873 int nIndentChars = nLevel *
mnIndent;
876 bool bEmptyParent =
m_aPos[iPosParent].IsEmptyElement();
878 m_aPos[iPosParent].nStartR + 1 ==
m_aPos[iPosParent].nEndL) {
881 if ((nOffset < (
int)(
m_csDoc.length())) && (0 < nOffset) &&
882 (
' ' ==
m_csDoc[nOffset - 1])) {
883 while ((0 < nOffset) && (
' ' ==
m_csDoc[nOffset - 1])) --nOffset;
891 m_aPos[iPos].nStartL = nOffset + nIndentChars;
894 m_aPos[iPos].iElemParent = iPosParent;
895 m_aPos[iPos].iElemChild = 0;
896 m_aPos[iPos].iElemNext = 0;
900 m_aPos[iPosBefore].iElemNext = iPos;
904 m_aPos[iPosParent].iElemChild = iPos;
908 std::string csInsert;
909 int nLenName = (int)strlen(szName);
910 int nLenValue = szValue ? (int)strlen(szValue) : 0;
916 csInsert +=
"/>\r\n";
917 m_aPos[iPos].nStartR =
m_aPos[iPos].nStartL + nLenName + 2;
923 nLenValue = (int)csValue.length();
932 m_aPos[iPos].nStartR =
m_aPos[iPos].nStartL + nLenName + 1;
933 m_aPos[iPos].nEndL =
m_aPos[iPos].nStartR + nLenValue + 1;
939 int nReplace = 0, nLeft =
m_aPos[iPos].nStartL;
942 std::string csFormat;
944 csFormat += csInsert;
949 csFormat += csParentTagName;
951 nLeft =
m_aPos[iPosParent].nStartR - 1;
957 m_aPos[iPosParent].nStartR -= 1;
962 m_aPos[iPosParent].nEndL -= (int)(csParentTagName.length() + 1);
963 }
else if (
m_aPos[iPosParent].nStartR + 1 ==
m_aPos[iPosParent].nEndL) {
965 csInsert =
"\r\n" + csInsert;
969 nLeft =
m_aPos[iPosParent].nStartR + 1;
971 nLeft -= nIndentChars;
975 x_Adjust(iPos, (
int)csInsert.length() - nReplace);
994 va_start(marker, fmt);
998 size_t len = _vscprintf(fmt, marker) + 1;
1001 va_copy(argcopy, marker);
1002 auto len = vsnprintf(NULL, 0, fmt, marker) + 1;
1007 vector<char> buffer(len,
'\0');
1009 int nWritten = _vsnprintf_s(&buffer[0], buffer.size(), len, fmt, marker);
1011 int nWritten = vsnprintf(&buffer[0], len, fmt, marker);
1014 retStr = &buffer[0];
1024 std::string CMarkup::Mid(
const std::string& tStr,
int nFirst)
const {
1025 return Mid(tStr, nFirst, (
int)tStr.length() - nFirst);
1028 std::string CMarkup::Mid(
const std::string& tStr,
int nFirst,
1037 int nSize =
static_cast<int>(tStr.size());
1039 if (nFirst + nCount > nSize) {
1040 nCount = nSize - nFirst;
1043 if (nFirst > nSize) {
1044 std::string tStrEmpty;
1048 assert(nFirst >= 0);
1049 assert(nFirst + nCount <= nSize);
1051 return tStr.substr(nFirst, nCount);
1054 char* CMarkup::GetBuffer(std::string& tStr,
int nMinLen)
const {
1055 if (
static_cast<int>(tStr.size()) < nMinLen) {
1056 tStr.resize(nMinLen);
1059 return const_cast<char*
>(
1064 void CMarkup::ReleaseBuffer(std::string& tStr,
int nNewLen)
const {
1065 tStr.resize(nNewLen > -1 ? nNewLen : strlen(tStr.c_str()));
1069 int nLen =
nR -
nL + 1;
1070 return ((strncmp(&
szDoc[
nL], szName, nLen) == 0) &&
1071 (szName[nLen] ==
'\0' || strchr(
" =/[", szName[nLen])));