/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id$ */ // --------------------------------------------------------------------------- // Includes // --------------------------------------------------------------------------- #if HAVE_CONFIG_H # include #endif #if !HAVE_STRICMP # include #endif #if !HAVE_STRNICMP # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include XERCES_CPP_NAMESPACE_BEGIN // --------------------------------------------------------------------------- // Local static data // // gConverter // This is initialized when the user calls the platform init method, // which calls our init method. This is the converter used for default // conversion to/from the local code page. // --------------------------------------------------------------------------- static XMLLCPTranscoder* gTranscoder = 0; static XMLCh gNullStr[] = { chOpenCurly, chLatin_n, chLatin_u, chLatin_l, chLatin_l, chCloseCurly, chNull }; MemoryManager* XMLString::fgMemoryManager = 0; // --------------------------------------------------------------------------- // XMLString: Public static methods // --------------------------------------------------------------------------- void XMLString::sizeToText( const XMLSize_t toFormat , char* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { static const char digitList[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' , 'A', 'B', 'C', 'D', 'E', 'F' }; if (!maxChars) ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_ZeroSizedTargetBuf, manager); // Handle special case if (!toFormat) { toFill[0] = '0'; toFill[1] = 0; return; } // This is used to fill the temp buffer XMLSize_t tmpIndex = 0; // A copy of the conversion value that we can modify XMLSize_t tmpVal = toFormat; // // Convert into a temp buffer that we know is large enough. This avoids // having to check for overflow in the inner loops, and we have to flip // the resulting XMLString anyway. // char tmpBuf[128]; // // For each radix, do the optimal thing. For bin and hex, we can special // case them and do shift and mask oriented stuff. For oct and decimal // there isn't much to do but bull through it with divides. // if (radix == 2) { while (tmpVal) { if (tmpVal & 0x1UL) tmpBuf[tmpIndex++] = '1'; else tmpBuf[tmpIndex++] = '0'; tmpVal >>= 1; } } else if (radix == 16) { while (tmpVal) { const XMLSize_t charInd = (tmpVal & 0xFUL); tmpBuf[tmpIndex++] = digitList[charInd]; tmpVal >>= 4; } } else if ((radix == 8) || (radix == 10)) { while (tmpVal) { const XMLSize_t charInd = (tmpVal % radix); tmpBuf[tmpIndex++] = digitList[charInd]; tmpVal /= radix; } } else { ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Str_UnknownRadix, manager); } // See if have enough room in the caller's buffer if (tmpIndex > maxChars) { ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_TargetBufTooSmall, manager); } // Reverse the tmp buffer into the caller's buffer XMLSize_t outIndex = 0; for (; tmpIndex > 0; tmpIndex--) toFill[outIndex++] = tmpBuf[tmpIndex-1]; // And cap off the caller's buffer toFill[outIndex] = char(0); } void XMLString::binToText( const unsigned long toFormat , char* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { static const char digitList[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' , 'A', 'B', 'C', 'D', 'E', 'F' }; if (!maxChars) ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_ZeroSizedTargetBuf, manager); // Handle special case if (!toFormat) { toFill[0] = '0'; toFill[1] = 0; return; } // This is used to fill the temp buffer XMLSize_t tmpIndex = 0; // A copy of the conversion value that we can modify unsigned long tmpVal = toFormat; // // Convert into a temp buffer that we know is large enough. This avoids // having to check for overflow in the inner loops, and we have to flip // the resulting XMLString anyway. // char tmpBuf[128]; // // For each radix, do the optimal thing. For bin and hex, we can special // case them and do shift and mask oriented stuff. For oct and decimal // there isn't much to do but bull through it with divides. // if (radix == 2) { while (tmpVal) { if (tmpVal & 0x1UL) tmpBuf[tmpIndex++] = '1'; else tmpBuf[tmpIndex++] = '0'; tmpVal >>= 1; } } else if (radix == 16) { while (tmpVal) { const unsigned long charInd = (tmpVal & 0xFUL); tmpBuf[tmpIndex++] = digitList[charInd]; tmpVal >>= 4; } } else if ((radix == 8) || (radix == 10)) { while (tmpVal) { const unsigned long charInd = (tmpVal % radix); tmpBuf[tmpIndex++] = digitList[charInd]; tmpVal /= radix; } } else { ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Str_UnknownRadix, manager); } // See if have enough room in the caller's buffer if (tmpIndex > maxChars) { ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_TargetBufTooSmall, manager); } // Reverse the tmp buffer into the caller's buffer XMLSize_t outIndex = 0; for (; tmpIndex > 0; tmpIndex--) toFill[outIndex++] = tmpBuf[tmpIndex-1]; // And cap off the caller's buffer toFill[outIndex] = char(0); } void XMLString::binToText( const unsigned int toFormat , char* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { // Just call the unsigned long version binToText((unsigned long)toFormat, toFill, maxChars, radix, manager); } void XMLString::binToText( const long toFormat , char* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { // // If its negative, then put a negative sign into the output and flip // the sign of the local temp value. // XMLSize_t startInd = 0; unsigned long actualVal; if (toFormat < 0) { toFill[0] = '-'; startInd++; // Signed integers can represent one extra negative value // compared to the positive values. If we simply do (v * -1) // we will overflow on that extra value. // long v = toFormat; v++; actualVal = (unsigned long)(v * -1); actualVal++; } else { actualVal = (unsigned long)(toFormat); } // And now call the unsigned long version binToText(actualVal, &toFill[startInd], maxChars, radix, manager); } void XMLString::binToText( const int toFormat , char* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { // Just call the long version binToText((long)toFormat, toFill, maxChars, radix, manager); } void XMLString::catString(char* const target, const char* const src) { strcat(target, src); } int XMLString::compareIString(const char* const str1, const char* const str2) { return stricmp(str1, str2); } int XMLString::compareNString( const char* const str1 , const char* const str2 , const XMLSize_t count) { // Watch for pathological secenario if (!count) return 0; return strncmp(str1, str2, count); } int XMLString::compareNIString( const char* const str1 , const char* const str2 , const XMLSize_t count) { if (!count) return 0; return strnicmp(str1, str2, count); } int XMLString::compareString( const char* const str1 , const char* const str2) { return strcmp(str1, str2); } void XMLString::copyString( char* const target , const char* const src) { strcpy(target, src); } void XMLString::cut( XMLCh* const toCutFrom , const XMLSize_t count) { #if defined(XML_DEBUG) if (count > stringLen(toCutFrom)) { // This is bad of course } #endif // If count is zero, then nothing to do if (!count) return; XMLCh* targetPtr = toCutFrom; XMLCh* srcPtr = toCutFrom + count; while (*srcPtr) *targetPtr++ = *srcPtr++; // Cap it off at the new end *targetPtr = 0; } XMLSize_t XMLString::hash( const char* const tohash , const XMLSize_t hashModulus) { XMLSize_t hashVal = 0; if (tohash) { const char* curCh = tohash; while (*curCh) { XMLSize_t top = hashVal >> 24; hashVal += (hashVal * 37) + top + (XMLSize_t)(*curCh); curCh++; } } // Divide by modulus return hashVal % hashModulus; } int XMLString::indexOf(const char* const toSearch, const char ch) { const XMLSize_t len = strlen(toSearch); for (XMLSize_t i = 0; i < len; i++) { if (toSearch[i] == ch) return (int)i; } return -1; } int XMLString::indexOf( const char* const toSearch , const char ch , const XMLSize_t fromIndex , MemoryManager* const manager) { const XMLSize_t len = strlen(toSearch); // Make sure the start index is within the XMLString bounds if ((int)fromIndex > ((int)len)-1) ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager); for (XMLSize_t i = fromIndex; i < len; i++) { if (toSearch[i] == ch) return (int)i; } return -1; } int XMLString::lastIndexOf(const char* const toSearch, const char ch) { const int len = (int)strlen(toSearch); for (int i = len-1; i >= 0; i--) { if (toSearch[i] == ch) return i; } return -1; } int XMLString::lastIndexOf( const char* const toSearch , const char ch , const XMLSize_t fromIndex , MemoryManager* const manager) { const XMLSize_t len = strlen(toSearch); // Make sure the start index is within the XMLString bounds if ((int)fromIndex > ((int)len)-1) ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager); for (int i = (int)fromIndex; i >= 0; i--) { if (toSearch[i] == ch) return i; } return -1; } XMLSize_t XMLString::replaceTokens( XMLCh* const errText , const XMLSize_t maxChars , const XMLCh* const text1 , const XMLCh* const text2 , const XMLCh* const text3 , const XMLCh* const text4 , MemoryManager* const manager) { // // We have to build the string back into the source string, so allocate // a temp string and copy the orignal text to it. We'll then treat the // incoming buffer as a target buffer. Put a janitor on it to make sure // it gets cleaned up. // XMLCh* orgText = replicate(errText, manager); ArrayJanitor janText(orgText, manager); XMLCh* pszSrc = orgText; XMLSize_t curOutInd = 0; while (*pszSrc && (curOutInd < maxChars)) { // // Loop until we see a { character. Until we do, just copy chars // from src to target, being sure not to overrun the output buffer. // while ((*pszSrc != chOpenCurly) && (curOutInd < maxChars)) { if (!*pszSrc) break; errText[curOutInd++] = *pszSrc++; } // If we did not find a curly, then we are done if (*pszSrc != chOpenCurly) break; // // Probe this one to see if it matches our pattern of {x}. If not // then copy over those chars and go back to the first loop. // if ((*(pszSrc+1) >= chDigit_0) && (*(pszSrc+1) <= chDigit_3) && (*(pszSrc+2) == chCloseCurly)) { // // Its one of our guys, so move the source pointer up past the // token we are replacing. First though get out the token number // character. // XMLCh tokCh = *(pszSrc+1); pszSrc += 3; // Now copy over the replacement text const XMLCh* repText = 0; if (tokCh == chDigit_0) repText = text1; else if (tokCh == chDigit_1) repText = text2; else if (tokCh == chDigit_2) repText = text3; else if (tokCh == chDigit_3) repText = text4; // If this one is null, copy over a null string if (!repText) repText = gNullStr; while (*repText && (curOutInd < maxChars)) errText[curOutInd++] = *repText++; } else { // Escape the curly brace character and continue errText[curOutInd++] = *pszSrc++; } } // Copy over a null terminator errText[curOutInd] = 0; // And return the count of chars we output return curOutInd; } char* XMLString::replicate( const char* const toRep , MemoryManager* const manager) { // If a null string, return a null string if (!toRep) return 0; // // Get the len of the source and allocate a new buffer. Make sure to // account for the nul terminator. // const XMLSize_t srcLen = strlen(toRep); char* ret = (char*) manager->allocate((srcLen+1) * sizeof(char)); //new char[srcLen+1]; // Copy over the text, adjusting for the size of a char memcpy(ret, toRep, (srcLen+1) * sizeof(char)); return ret; } bool XMLString::startsWith(const char* const toTest, const char* const prefix) { return (strncmp(toTest, prefix, strlen(prefix)) == 0); } bool XMLString::startsWithI(const char* const toTest , const char* const prefix) { return (strnicmp(toTest, prefix, strlen(prefix)) == 0); } XMLSize_t XMLString::stringLen(const char* const src) { return strlen(src); } char* XMLString::transcode(const XMLCh* const toTranscode, MemoryManager* const manager) { return gTranscoder->transcode(toTranscode, manager); } bool XMLString::transcode( const XMLCh* const toTranscode , char* const toFill , const XMLSize_t maxChars , MemoryManager* const manager) { return gTranscoder->transcode(toTranscode, toFill, maxChars, manager); } XMLCh* XMLString::transcode(const char* const toTranscode, MemoryManager* const manager) { return gTranscoder->transcode(toTranscode, manager); } bool XMLString::transcode( const char* const toTranscode , XMLCh* const toFill , const XMLSize_t maxChars , MemoryManager* const manager) { return gTranscoder->transcode(toTranscode, toFill, maxChars, manager); } void XMLString::trim(char* const toTrim) { const XMLSize_t len = strlen(toTrim); XMLSize_t skip, scrape; for (skip = 0; skip < len; skip++) { if (! isspace(toTrim[skip])) break; } for (scrape = len; scrape > skip; scrape--) { if (! isspace(toTrim[scrape - 1] )) break; } // Cap off at the scrap point if (scrape != len) toTrim[scrape] = 0; if (skip) { // Copy the chars down XMLSize_t index = 0; while (toTrim[skip]) toTrim[index++] = toTrim[skip++]; toTrim[index] = 0; } } void XMLString::subString(char* const targetStr, const char* const srcStr , const XMLSize_t startIndex, const XMLSize_t endIndex , MemoryManager* const manager) { if (targetStr == 0) ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_ZeroSizedTargetBuf, manager); const XMLSize_t srcLen = strlen(srcStr); // Make sure the start index is within the XMLString bounds if (startIndex > endIndex || endIndex > srcLen) ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager); const XMLSize_t copySize = endIndex - startIndex; for (XMLSize_t i= startIndex; i < endIndex; i++) { targetStr[i-startIndex] = srcStr[i]; } targetStr[copySize] = 0; } bool XMLString::isValidNOTATION(const XMLCh* const name , MemoryManager* const manager ) { // // NOTATATION: : // where URI is optional // ':' and localPart must be present // XMLSize_t nameLen = XMLString::stringLen(name); int colPos = XMLString::lastIndexOf(name, chColon); if ((colPos == 0) || // no ':' (colPos == ((int)nameLen) - 1) ) // ':' return false; // Examine localpart if (!XMLChar1_0::isValidNCName(&name[colPos+1], nameLen - colPos -1)) { return false; } else if (colPos == -1) { return true; } else { // Examine URI XMLCh* const temp = (XMLCh*) manager->allocate((colPos + 1) * sizeof(XMLCh)); const ArrayJanitor jan(temp, manager); copyNString(temp, name, colPos); temp[colPos] = 0; try { XMLUri newURI(temp, manager); // no relative uri support here } catch (const MalformedURLException&) { return false; } return true; } } /** * isValidEncName * * [80] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* * */ bool XMLString::isValidEncName(const XMLCh* const name) { if (name == 0 || *name == 0) return false; const XMLCh* tempName = name; XMLCh firstChar = *tempName++; if (!isAlpha(firstChar)) return false; while(*tempName) { if (( !isAlpha(*tempName)) && ( !isDigit(*tempName)) && ( *tempName != chPeriod) && ( *tempName != chUnderscore) && ( *tempName != chDash) ) return false; tempName++; } return true; } bool XMLString::isAlpha(XMLCh const theChar) { if ((( theChar >= chLatin_a ) && ( theChar <= chLatin_z )) || (( theChar >= chLatin_A ) && ( theChar <= chLatin_Z )) ) return true; return false; } bool XMLString::isDigit(XMLCh const theChar) { if (( theChar >= chDigit_0 ) && ( theChar <= chDigit_9 )) return true; return false; } bool XMLString::isAlphaNum(XMLCh const theChar) { return (isAlpha(theChar) || isDigit(theChar)); } bool XMLString::isHex(XMLCh const theChar) { return (isDigit(theChar) || (theChar >= chLatin_a && theChar <= chLatin_f) || (theChar >= chLatin_A && theChar <= chLatin_F)); } // --------------------------------------------------------------------------- // Wide char versions of most of the string methods // --------------------------------------------------------------------------- void XMLString::sizeToText( const XMLSize_t toFormat , XMLCh* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { static const XMLCh digitList[16] = { chDigit_0, chDigit_1, chDigit_2, chDigit_3, chDigit_4, chDigit_5 , chDigit_6, chDigit_7, chDigit_8, chDigit_9, chLatin_A, chLatin_B , chLatin_C, chLatin_D, chLatin_e, chLatin_F }; if (!maxChars) ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_ZeroSizedTargetBuf, manager); // Handle special case if (!toFormat) { toFill[0] = chDigit_0; toFill[1] = chNull; return; } // This is used to fill the temp buffer XMLSize_t tmpIndex = 0; // A copy of the conversion value that we can modify XMLSize_t tmpVal = toFormat; // // Convert into a temp buffer that we know is large enough. This avoids // having to check for overflow in the inner loops, and we have to flip // the resulting sring anyway. // XMLCh tmpBuf[128]; // // For each radix, do the optimal thing. For bin and hex, we can special // case them and do shift and mask oriented stuff. For oct and decimal // there isn't much to do but bull through it with divides. // if (radix == 2) { while (tmpVal) { if (tmpVal & 0x1UL) tmpBuf[tmpIndex++] = chDigit_1; else tmpBuf[tmpIndex++] = chDigit_0; tmpVal >>= 1; } } else if (radix == 16) { while (tmpVal) { const XMLSize_t charInd = (tmpVal & 0xFUL); tmpBuf[tmpIndex++] = digitList[charInd]; tmpVal >>= 4; } } else if ((radix == 8) || (radix == 10)) { while (tmpVal) { const XMLSize_t charInd = (tmpVal % radix); tmpBuf[tmpIndex++] = digitList[charInd]; tmpVal /= radix; } } else { ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Str_UnknownRadix, manager); } // See if have enough room in the caller's buffer if (tmpIndex > maxChars) { ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_TargetBufTooSmall, manager); } // Reverse the tmp buffer into the caller's buffer XMLSize_t outIndex = 0; for (; tmpIndex > 0; tmpIndex--) toFill[outIndex++] = tmpBuf[tmpIndex-1]; // And cap off the caller's buffer toFill[outIndex] = chNull; } void XMLString::binToText( const unsigned long toFormat , XMLCh* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { static const XMLCh digitList[16] = { chDigit_0, chDigit_1, chDigit_2, chDigit_3, chDigit_4, chDigit_5 , chDigit_6, chDigit_7, chDigit_8, chDigit_9, chLatin_A, chLatin_B , chLatin_C, chLatin_D, chLatin_e, chLatin_F }; if (!maxChars) ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_ZeroSizedTargetBuf, manager); // Handle special case if (!toFormat) { toFill[0] = chDigit_0; toFill[1] = chNull; return; } // This is used to fill the temp buffer XMLSize_t tmpIndex = 0; // A copy of the conversion value that we can modify unsigned long tmpVal = toFormat; // // Convert into a temp buffer that we know is large enough. This avoids // having to check for overflow in the inner loops, and we have to flip // the resulting sring anyway. // XMLCh tmpBuf[128]; // // For each radix, do the optimal thing. For bin and hex, we can special // case them and do shift and mask oriented stuff. For oct and decimal // there isn't much to do but bull through it with divides. // if (radix == 2) { while (tmpVal) { if (tmpVal & 0x1UL) tmpBuf[tmpIndex++] = chDigit_1; else tmpBuf[tmpIndex++] = chDigit_0; tmpVal >>= 1; } } else if (radix == 16) { while (tmpVal) { const unsigned long charInd = (tmpVal & 0xFUL); tmpBuf[tmpIndex++] = digitList[charInd]; tmpVal >>= 4; } } else if ((radix == 8) || (radix == 10)) { while (tmpVal) { const unsigned long charInd = (tmpVal % radix); tmpBuf[tmpIndex++] = digitList[charInd]; tmpVal /= radix; } } else { ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Str_UnknownRadix, manager); } // See if have enough room in the caller's buffer if (tmpIndex > maxChars) { ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_TargetBufTooSmall, manager); } // Reverse the tmp buffer into the caller's buffer XMLSize_t outIndex = 0; for (; tmpIndex > 0; tmpIndex--) toFill[outIndex++] = tmpBuf[tmpIndex-1]; // And cap off the caller's buffer toFill[outIndex] = chNull; } void XMLString::binToText( const unsigned int toFormat , XMLCh* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { // Just call the unsigned long version binToText((unsigned long)toFormat, toFill, maxChars, radix, manager); } void XMLString::binToText( const long toFormat , XMLCh* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { // // If its negative, then put a negative sign into the output and flip // the sign of the local temp value. // XMLSize_t startInd = 0; unsigned long actualVal; if (toFormat < 0) { toFill[0] = chDash; startInd++; // Signed integers can represent one extra negative value // compared to the positive values. If we simply do (v * -1) // we will overflow on that extra value. // long v = toFormat; v++; actualVal = (unsigned long)(v * -1); actualVal++; } else { actualVal = (unsigned long)(toFormat); } // And now call the unsigned long version binToText(actualVal, &toFill[startInd], maxChars, radix, manager); } void XMLString::binToText( const int toFormat , XMLCh* const toFill , const XMLSize_t maxChars , const unsigned int radix , MemoryManager* const manager) { // Just call the long version binToText((long)toFormat, toFill, maxChars, radix, manager); } void XMLString::catString(XMLCh* const target, const XMLCh* const src) { // Get the starting point for the cat on the target XMLString XMLSize_t index = stringLen(target); // While the source is not zero, add them to target and bump const XMLCh* pszTmp = src; while (*pszTmp) target[index++] = *pszTmp++; // Cap off the target where we ended target[index] = chNull; } int XMLString::compareIString( const XMLCh* const str1 , const XMLCh* const str2) { // Refer this one to the transcoding service return XMLPlatformUtils::fgTransService->compareIString(str1, str2); } int XMLString::compareIStringASCII( const XMLCh* const str1 , const XMLCh* const str2) { const XMLCh* psz1 = str1; const XMLCh* psz2 = str2; if (psz1 == 0 || psz2 == 0) { if (psz1 == 0) { return 0 - (int)XMLString::stringLen(psz2); } else if (psz2 == 0) { return (int)XMLString::stringLen(psz1); } } XMLCh ch1; XMLCh ch2; for (;;) { if (*psz1 >= chLatin_A && *psz1 <= chLatin_Z) ch1 = *psz1 - chLatin_A + chLatin_a; else ch1 = *psz1; if (*psz2 >= chLatin_A && *psz2 <= chLatin_Z) ch2 = *psz2 - chLatin_A + chLatin_a; else ch2 = *psz2; // If an inequality, then return difference if (ch1 != ch2) return int(ch1) - int(ch2); // If either ended, then both ended, so equal if (!ch1) break; // Move upwards to next chars psz1++; psz2++; } return 0; } int XMLString::compareNString( const XMLCh* const str1 , const XMLCh* const str2 , const XMLSize_t maxChars) { const XMLCh* psz1 = str1; const XMLCh* psz2 = str2; XMLSize_t curCount = 0; while (curCount < maxChars) { // If an inequality, then return difference if (*psz1 != *psz2) return int(*psz1) - int(*psz2); // If either ended, then both ended, so equal if (!*psz1) break; // Move upwards to next chars psz1++; psz2++; // // Bump the count of chars done. // curCount++; } // If we inspected all the maxChars, then we are equal. return 0; } int XMLString::compareNIString( const XMLCh* const str1 , const XMLCh* const str2 , const XMLSize_t maxChars) { // Refer this oneto the transcoding service return XMLPlatformUtils::fgTransService->compareNIString(str1, str2, maxChars); } int XMLString::compareString( const XMLCh* const str1 , const XMLCh* const str2) { const XMLCh* psz1 = str1; const XMLCh* psz2 = str2; if (psz1 == 0 || psz2 == 0) { if (psz1 == 0) { return 0 - (int)XMLString::stringLen(psz2); } else if (psz2 == 0) { return (int)XMLString::stringLen(psz1); } } for (;;) { // If an inequality, then return the difference if (*psz1 != *psz2) return int(*psz1) - int(*psz2); // If either has ended, then they both ended, so equal if (!*psz1) break; // Move upwards for the next round psz1++; psz2++; } return 0; } bool XMLString::regionMatches(const XMLCh* const str1 , const int offset1 , const XMLCh* const str2 , const int offset2 , const XMLSize_t charCount) { if (!validateRegion(str1, offset1,str2, offset2, charCount)) return false; if (compareNString(str1+offset1, str2+offset2, charCount) != 0) return false; return true; } bool XMLString::regionIMatches(const XMLCh* const str1 , const int offset1 , const XMLCh* const str2 , const int offset2 , const XMLSize_t charCount) { if (!validateRegion(str1, offset1,str2, offset2, charCount)) return false; if (compareNIString(str1+offset1, str2+offset2, charCount) != 0) return false; return true; } void XMLString::copyString(XMLCh* const target, const XMLCh* const src) { if (!src) { *target = 0; return; } XMLCh* pszOut = target; const XMLCh* pszIn = src; while (*pszIn) *pszOut++ = *pszIn++; // Cap off the target where we ended *pszOut = 0; } bool XMLString::copyNString( XMLCh* const target , const XMLCh* const src , const XMLSize_t maxChars) { // Return whether we copied it all or hit the max XMLSize_t len = stringLen(src); if(len > maxChars) { XMLString::moveChars(target, src, maxChars); target[maxChars] = 0; return false; } XMLString::moveChars(target, src, len+1); return true; } const XMLCh* XMLString::findAny(const XMLCh* const toSearch , const XMLCh* const searchList) { const XMLCh* srcPtr = toSearch; while (*srcPtr) { const XMLCh* listPtr = searchList; const XMLCh curCh = *srcPtr; while (*listPtr) { if (curCh == *listPtr++) return srcPtr; } srcPtr++; } return 0; } XMLCh* XMLString::findAny( XMLCh* const toSearch , const XMLCh* const searchList) { XMLCh* srcPtr = toSearch; while (*srcPtr) { const XMLCh* listPtr = searchList; const XMLCh curCh = *srcPtr; while (*listPtr) { if (curCh == *listPtr++) return srcPtr; } srcPtr++; } return 0; } int XMLString::patternMatch( const XMLCh* const toSearch , const XMLCh* const pattern) { if (!toSearch || !*toSearch ) return -1; const XMLSize_t patnLen = XMLString::stringLen(pattern); if ( !patnLen ) return -1; const XMLCh* srcPtr = toSearch; const XMLCh* patnStart = toSearch; XMLSize_t patnIndex = 0; while (*srcPtr) { if ( !(*srcPtr++ == pattern[patnIndex])) { patnIndex = 0; srcPtr = ++patnStart; } else { if (++patnIndex == patnLen) // full pattern match found return (int)(srcPtr - patnLen - toSearch); } } return -1; } int XMLString::indexOf(const XMLCh* const toSearch, const XMLCh ch) { if (!toSearch || !*toSearch) return -1; const XMLCh* srcPtr = toSearch; while (*srcPtr) if (ch == *srcPtr++) return (int)(srcPtr - toSearch - 1); return -1; } int XMLString::indexOf( const XMLCh* const toSearch , const XMLCh ch , const XMLSize_t fromIndex , MemoryManager* const manager) { const XMLSize_t len = stringLen(toSearch); // Make sure the start index is within the XMLString bounds if (fromIndex >= len) ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager); const XMLCh* srcPtr = toSearch+fromIndex; while (*srcPtr) if (ch == *srcPtr++) return (int)(srcPtr - toSearch - 1); return -1; } int XMLString::lastIndexOf(const XMLCh ch, const XMLCh* const toSearch, const XMLSize_t toSearchLen) { const XMLCh* srcPtr = toSearch+toSearchLen; while (srcPtr >= toSearch) if (ch == *srcPtr--) return (int)(srcPtr + 1 - toSearch); return -1; } int XMLString::lastIndexOf( const XMLCh* const toSearch , const XMLCh ch , const XMLSize_t fromIndex , MemoryManager* const manager) { const XMLSize_t len = stringLen(toSearch); if (fromIndex >= len) ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager); const XMLCh* srcPtr = toSearch+fromIndex; while (srcPtr >= toSearch) if (ch == *srcPtr--) return (int)(srcPtr + 1 - toSearch); return -1; } XMLCh* XMLString::makeUName(const XMLCh* const pszURI, const XMLCh* const pszName) { // // If there is a URI, then format out the full name in the {uri}name // form. Otherwise, just set it to the same thing as the base name. // XMLCh* pszRet = 0; const XMLSize_t uriLen = stringLen(pszURI); if (uriLen) { pszRet = new XMLCh[uriLen + stringLen(pszName) + 3]; XMLCh szTmp[2]; szTmp[1] = 0; szTmp[0] = chOpenCurly; copyString(pszRet, szTmp); catString(pszRet, pszURI); szTmp[0] = chCloseCurly; catString(pszRet, szTmp); catString(pszRet, pszName); } else { pszRet = replicate(pszName); } return pszRet; } bool XMLString::textToBin(const XMLCh* const toConvert, unsigned int& toFill , MemoryManager* const manager) { toFill = 0; // If no string, then its a failure if ((!toConvert) || (!*toConvert)) return false; XMLCh* trimmedStr = XMLString::replicate(toConvert, manager); ArrayJanitor jan1(trimmedStr, manager); XMLString::trim(trimmedStr); XMLSize_t trimmedStrLen = XMLString::stringLen(trimmedStr); if ( !trimmedStrLen ) return false; // we don't allow '-' sign if (XMLString::indexOf(trimmedStr, chDash, 0, manager) != -1) return false; //the errno set by previous run is NOT automatically cleared errno = 0; char *nptr = XMLString::transcode(trimmedStr, manager); ArrayJanitor jan2(nptr, manager); char *endptr; // // REVISIT: conversion of (unsigned long) to (unsigned int) // may truncate value on IA64 toFill = (unsigned int) strtoul(nptr, &endptr, 10); // check if all chars are valid char // check if overflow/underflow occurs if ( ( (endptr - nptr) != (int) trimmedStrLen) || (errno == ERANGE) ) return false; return true; } int XMLString::parseInt(const XMLCh* const toConvert , MemoryManager* const manager) { // If no string, or empty string, then it is a failure if ((!toConvert) || (!*toConvert)) ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_null_ptr, manager); XMLCh* trimmedStr = XMLString::replicate(toConvert, manager); ArrayJanitor jan1(trimmedStr, manager); XMLString::trim(trimmedStr); XMLSize_t trimmedStrLen = XMLString::stringLen(trimmedStr); if ( !trimmedStrLen ) ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_null_ptr, manager); //the errno set by previous run is NOT automatically cleared errno = 0; char *nptr = XMLString::transcode(trimmedStr, manager); ArrayJanitor jan2(nptr, manager); char *endptr; long retVal = strtol(nptr, &endptr, 10); // check if all chars are valid char if ( (endptr - nptr) != (int) trimmedStrLen) ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, manager); // check if overflow/underflow occurs if (errno == ERANGE) ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::Str_ConvertOverflow, manager); // // REVISIT: conversion of (long) to (int) // may truncate value on IA64 return (int) retVal; } void XMLString::trim(XMLCh* const toTrim) { const XMLSize_t len = stringLen(toTrim); XMLSize_t skip, scrape; for (skip = 0; skip < len; skip++) { if (!XMLChar1_0::isWhitespace(toTrim[skip])) break; } for (scrape = len; scrape > skip; scrape--) { if (!XMLChar1_0::isWhitespace(toTrim[scrape - 1])) break; } // Cap off at the scrap point if (scrape != len) toTrim[scrape] = 0; if (skip) { // Copy the chars down XMLSize_t index = 0; while (toTrim[skip]) toTrim[index++] = toTrim[skip++]; toTrim[index] = 0; } } void XMLString::upperCase(XMLCh* const toUpperCase) { // Refer this one to the transcoding service XMLPlatformUtils::fgTransService->upperCase(toUpperCase); } void XMLString::upperCaseASCII(XMLCh* const toUpperCase) { XMLCh* psz1 = toUpperCase; if (!psz1) return; while (*psz1) { if (*psz1 >= chLatin_a && *psz1 <= chLatin_z) *psz1 = *psz1 - chLatin_a + chLatin_A; psz1++; } } void XMLString::lowerCase(XMLCh* const toLowerCase) { // Refer this one to the transcoding service XMLPlatformUtils::fgTransService->lowerCase(toLowerCase); } void XMLString::lowerCaseASCII(XMLCh* const toLowerCase) { XMLCh* psz1 = toLowerCase; if (!psz1) return; while (*psz1) { if (*psz1 >= chLatin_A && *psz1 <= chLatin_Z) *psz1 = *psz1 - chLatin_A + chLatin_a; psz1++; } } void XMLString::subString(XMLCh* const targetStr, const XMLCh* const srcStr , const XMLSize_t startIndex, const XMLSize_t endIndex , MemoryManager* const manager) { subString(targetStr, srcStr, startIndex, endIndex, stringLen(srcStr), manager); } void XMLString::subString(XMLCh* const targetStr, const XMLCh* const srcStr , const XMLSize_t startIndex, const XMLSize_t endIndex , const XMLSize_t srcStrLength , MemoryManager* const manager) { //if (startIndex < 0 || endIndex < 0) // ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_NegativeIndex); if (targetStr == 0) ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_ZeroSizedTargetBuf, manager); // Make sure the start index is within the XMLString bounds if (startIndex > endIndex || endIndex > srcStrLength) ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager); const XMLSize_t copySize = endIndex - startIndex; for (XMLSize_t i= startIndex; i < endIndex; i++) { targetStr[i-startIndex] = srcStr[i]; } targetStr[copySize] = 0; } BaseRefVectorOf* XMLString::tokenizeString(const XMLCh* const tokenizeSrc , MemoryManager* const manager) { XMLCh* orgText = replicate(tokenizeSrc, manager); ArrayJanitor janText(orgText, manager); XMLCh* tokenizeStr = orgText; RefArrayVectorOf* tokenStack = new (manager) RefArrayVectorOf(16, true, manager); XMLSize_t len = stringLen(tokenizeStr); XMLSize_t skip; XMLSize_t index = 0; while (index != len) { // find the first non-space character for (skip = index; skip < len; skip++) { if (!XMLChar1_0::isWhitespace(tokenizeStr[skip])) break; } index = skip; // find the delimiter (space character) for (; skip < len; skip++) { if (XMLChar1_0::isWhitespace(tokenizeStr[skip])) break; } // we reached the end of the string if (skip == index) break; // these tokens are adopted in the RefVector and will be deleted // when the vector is deleted by the caller XMLCh* token = (XMLCh*) manager->allocate ( (skip+1-index) * sizeof(XMLCh) );//new XMLCh[skip+1-index]; XMLString::subString(token, tokenizeStr, index, skip, len, manager); tokenStack->addElement(token); index = skip; } return tokenStack; } // // This method is called when we get a notation or enumeration type attribute // to validate. We have to confirm that the passed value to find is one of // the values in the passed list. The list is a space separated string of // values to match against. // bool XMLString::isInList(const XMLCh* const toFind, const XMLCh* const enumList) { // // We loop through the values in the list via this outer loop. We end // when we hit the end of the enum list or get a match. // const XMLCh* listPtr = enumList; const XMLSize_t findLen = XMLString::stringLen(toFind); while (*listPtr) { XMLSize_t testInd; for (testInd = 0; testInd < findLen; testInd++) { // // If they don't match, then reset and try again. Note that // hitting the end of the current item will cause a mismatch // because there can be no spaces in the toFind string. // if (listPtr[testInd] != toFind[testInd]) break; } // // If we went the distance, see if we matched. If we did, the current // list character has to be null or space. // if (testInd == findLen) { if ((listPtr[testInd] == chSpace) || !listPtr[testInd]) return true; } // Run the list pointer up to the next substring while ((*listPtr != chSpace) && *listPtr) listPtr++; // If we hit the end, then we failed if (!*listPtr) return false; // Else move past the space and try again listPtr++; } // We never found it return false; } // // a string is whitespace:replaced, is having no // #xD Carriage Return // #xA Line Feed // #x9 TAB // bool XMLString::isWSReplaced(const XMLCh* const toCheck) { // If no string, then its a OK if (( !toCheck ) || ( !*toCheck )) return true; const XMLCh* startPtr = toCheck; while ( *startPtr ) { if ( ( *startPtr == chCR) || ( *startPtr == chLF) || ( *startPtr == chHTab)) return false; startPtr++; } return true; } // // to replace characters listed below to #x20 // #xD Carriage Return // #xA Line Feed // #x9 TAB // void XMLString::replaceWS(XMLCh* toConvert, MemoryManager* const) { // If no string, then its a OK if (( !toConvert ) || ( !*toConvert )) return; XMLCh* cursorPtr = toConvert; while ( *cursorPtr ) { if ( ( *cursorPtr == chCR) || ( *cursorPtr == chLF) || ( *cursorPtr == chHTab)) *cursorPtr = chSpace; cursorPtr++; } } // // a string is whitespace:collapsed, is whitespace::replaced // and no // leading space (#x20) // trailing space // no contiguous sequences of spaces // bool XMLString::isWSCollapsed(const XMLCh* const toCheck) { if (( !toCheck ) || ( !*toCheck )) return true; // shall be whitespace::replaced first if ( !isWSReplaced(toCheck) ) return false; // no leading or trailing space if ((*toCheck == chSpace) || (toCheck[XMLString::stringLen(toCheck)-1] == chSpace)) return false; const XMLCh* startPtr = toCheck; XMLCh theChar; bool inSpace = false; while ( (theChar = *startPtr) != 0 ) { if ( theChar == chSpace) { if (inSpace) return false; else inSpace = true; } else inSpace = false; startPtr++; } return true; } // // no leading and/or trailing spaces // no continuous sequences of spaces // void XMLString::collapseWS(XMLCh* toConvert , MemoryManager* const manager) { // If no string, then its a failure if (( !toConvert ) || ( !*toConvert )) return; // replace whitespace first if(!isWSReplaced(toConvert)) replaceWS(toConvert, manager); // remove leading spaces XMLCh* startPtr = toConvert; while ( *startPtr == chSpace ) startPtr++; if (!*startPtr) { *toConvert = chNull; return; } // remove trailing spaces XMLCh* endPtr = toConvert + stringLen(toConvert); while (*(endPtr - 1) == chSpace) endPtr--; *endPtr = chNull; // move data to beginning only if there were spaces in front if(startPtr != toConvert) XMLString::moveChars(toConvert, startPtr, endPtr - startPtr + 1); if(!isWSCollapsed(toConvert)) { // // Work through what remains and chop continuous spaces // XMLCh* retPtr = toConvert; startPtr = toConvert; bool inSpace = false; while (*startPtr) { if ( *startPtr == chSpace) { // copy a single space, then ignore subsequent if (!inSpace) { inSpace = true; *retPtr++ = chSpace; } } else { inSpace = false; *retPtr++ = *startPtr; } startPtr++; } *retPtr = chNull; } } // // remove whitespace // void XMLString::removeWS(XMLCh* toConvert, MemoryManager* const) { // If no string, then its a failure if (( !toConvert ) || ( !*toConvert )) return; XMLCh* retPtr = toConvert; XMLCh* startPtr = toConvert; while (*startPtr) { if ( ( *startPtr != chCR) && ( *startPtr != chLF) && ( *startPtr != chHTab) && ( *startPtr != chSpace) ) { *retPtr++ = *startPtr; } startPtr++; } *retPtr = chNull; } void XMLString::removeChar(const XMLCh* const srcString , const XMLCh& toRemove , XMLBuffer& dstBuffer) { if(!srcString) return; const XMLCh* pszSrc = srcString; XMLCh c; dstBuffer.reset(); while ((c=*pszSrc++)!=0) { if (c != toRemove) dstBuffer.append(c); } } /** * Fixes a platform dependent absolute path filename to standard URI form. * 1. Windows: fix 'x:' to 'file:///x:' and convert any backslash to forward slash * 2. UNIX: fix '/blah/blahblah' to 'file:///blah/blahblah' */ void XMLString::fixURI(const XMLCh* const str, XMLCh* const target) { if (!str || !*str) return; int colonIdx = XMLString::indexOf(str, chColon); // If starts with a '/' we assume // this is an absolute (UNIX) file path and prefix it with file:// if (colonIdx == -1 && XMLString::indexOf(str, chForwardSlash) == 0) { unsigned index = 0; target[index++] = chLatin_f; target[index++] = chLatin_i; target[index++] = chLatin_l; target[index++] = chLatin_e; target[index++] = chColon; target[index++] = chForwardSlash; target[index++] = chForwardSlash; // copy the string const XMLCh* inPtr = str; while (*inPtr) target[index++] = *inPtr++; target[index] = chNull; } else if (colonIdx == 1 && XMLString::isAlpha(*str)) { // If starts with a driver letter 'x:' we assume // this is an absolute (Windows) file path and prefix it with file:/// unsigned index = 0; target[index++] = chLatin_f; target[index++] = chLatin_i; target[index++] = chLatin_l; target[index++] = chLatin_e; target[index++] = chColon; target[index++] = chForwardSlash; target[index++] = chForwardSlash; target[index++] = chForwardSlash; // copy the string and fix any backward slash const XMLCh* inPtr = str; while (*inPtr) { if (*inPtr == chYenSign || *inPtr == chWonSign || *inPtr == chBackSlash) target[index++] = chForwardSlash; else target[index++] = *inPtr; inPtr++; } // cap it with null target[index] = chNull; } else { // not specific case, so just copy the string over copyString(target, str); } } void XMLString::release(char** buf, MemoryManager* const manager) { manager->deallocate(*buf); *buf = 0; } void XMLString::release(XMLCh** buf, MemoryManager* const manager) { manager->deallocate(*buf); *buf = 0; } // --------------------------------------------------------------------------- // XMLString: Private static methods // --------------------------------------------------------------------------- void XMLString::initString(XMLLCPTranscoder* const defToUse, MemoryManager* const manager) { // Store away the default transcoder that we are to use gTranscoder = defToUse; // Store memory manager fgMemoryManager = manager; } void XMLString::termString() { // Just clean up our local code page transcoder delete gTranscoder; gTranscoder = 0; // reset memory manager fgMemoryManager = 0; } XERCES_CPP_NAMESPACE_END