blob: 29fcbac98038b533cef84a97f589b83dced68d21 [file] [log] [blame]
/*
* 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: XMLString.cpp 568078 2007-08-21 11:43:25Z amassari $
*/
// ---------------------------------------------------------------------------
// Includes
// ---------------------------------------------------------------------------
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/ArrayIndexOutOfBoundsException.hpp>
#include <xercesc/util/IllegalArgumentException.hpp>
#include <xercesc/util/NumberFormatException.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/util/RuntimeException.hpp>
#include <xercesc/util/TranscodingException.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/RefArrayVectorOf.hpp>
#include <xercesc/util/TransService.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/XMLUri.hpp>
#include <xercesc/util/XMLURL.hpp>
#include <xercesc/internal/XMLReader.hpp>
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::binToText( const unsigned long toFormat
, char* const toFill
, const unsigned int 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
unsigned int tmpIndex = 0;
// A copy of the conversion value that we can modify
unsigned int 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 int charInd = (tmpVal & 0xFUL);
tmpBuf[tmpIndex++] = digitList[charInd];
tmpVal >>= 4;
}
}
else if ((radix == 8) || (radix == 10))
{
while (tmpVal)
{
const unsigned int 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
unsigned int 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 unsigned int 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 unsigned int 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.
//
unsigned int startInd = 0;
unsigned long actualVal;
if (toFormat < 0)
{
toFill[0] = '-';
startInd++;
actualVal = (unsigned long)(toFormat * -1);
}
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 unsigned int 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.
//
unsigned int startInd = 0;
unsigned long actualVal;
if (toFormat < 0)
{
toFill[0] = '-';
startInd++;
actualVal = (unsigned long)(toFormat * -1);
}
else
{
actualVal = (unsigned long)(toFormat);
}
// And now call the unsigned long version
binToText(actualVal, &toFill[startInd], 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 unsigned int 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 unsigned int 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 unsigned int count)
{
#if defined(XML_DEBUG)
if (count > stringLen(toCutFrom))
{
// <TBD> 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;
}
unsigned int XMLString::hash( const char* const tohash
, const unsigned int hashModulus
, MemoryManager* const)
{
assert(hashModulus);
unsigned int hashVal = 0;
if (tohash) {
const char* curCh = tohash;
while (*curCh)
{
unsigned int top = hashVal >> 24;
hashVal += (hashVal * 37) + top + (unsigned int)(*curCh);
curCh++;
}
}
// Divide by modulus
return hashVal % hashModulus;
}
int XMLString::indexOf(const char* const toSearch, const char ch)
{
const unsigned int len = strlen(toSearch);
for (unsigned int i = 0; i < len; i++)
{
if (toSearch[i] == ch)
return i;
}
return -1;
}
int XMLString::indexOf( const char* const toSearch
, const char ch
, const unsigned int fromIndex
, MemoryManager* const manager)
{
const unsigned int 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 (unsigned int i = fromIndex; i < len; i++)
{
if (toSearch[i] == ch)
return i;
}
return -1;
}
int XMLString::lastIndexOf(const char* const toSearch, const char ch)
{
const int len = 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 unsigned int fromIndex
, MemoryManager* const manager)
{
const int len = strlen(toSearch);
// Make sure the start index is within the XMLString bounds
if ((int)fromIndex > len-1)
ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager);
for (int i = (int)fromIndex; i >= 0; i--)
{
if (toSearch[i] == ch)
return i;
}
return -1;
}
unsigned int XMLString::replaceTokens( XMLCh* const errText
, const unsigned int 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<XMLCh> janText(orgText, manager);
XMLCh* pszSrc = orgText;
unsigned int 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;
}
XMLCh* XMLString::replicate(const XMLCh* const toRep)
{
// If a null string, return a null string!
XMLCh* ret = 0;
if (toRep)
{
const unsigned int len = stringLen(toRep);
ret = new XMLCh[len + 1];
memcpy(ret, toRep, (len + 1) * sizeof(XMLCh));
}
return ret;
}
char* XMLString::replicate(const char* const toRep)
{
// 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 unsigned int srcLen = strlen(toRep);
char* ret = new char[srcLen+1];
// Copy over the text, adjusting for the size of a char
memcpy(ret, toRep, (srcLen+1) * sizeof(char));
return ret;
}
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 unsigned int 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);
}
unsigned int XMLString::stringLen(const char* const src)
{
return strlen(src);
}
char* XMLString::transcode(const XMLCh* const toTranscode)
{
return gTranscoder->transcode(toTranscode);
}
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 unsigned int maxChars
, MemoryManager* const manager)
{
if (!gTranscoder->transcode(toTranscode, toFill, maxChars, manager))
return false;
return true;
}
XMLCh* XMLString::transcode(const char* const toTranscode)
{
return gTranscoder->transcode(toTranscode);
}
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 unsigned int maxChars
, MemoryManager* const manager)
{
if (!gTranscoder->transcode(toTranscode, toFill, maxChars, manager))
return false;
return true;
}
void XMLString::trim(char* const toTrim)
{
const unsigned int len = strlen(toTrim);
unsigned int 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
unsigned int index = 0;
while (toTrim[skip])
toTrim[index++] = toTrim[skip++];
toTrim[index] = 0;
}
}
void XMLString::subString(char* const targetStr, const char* const srcStr
, const int startIndex, const int endIndex
, MemoryManager* const manager)
{
if (targetStr == 0)
ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_ZeroSizedTargetBuf, manager);
const int srcLen = strlen(srcStr);
const int copySize = endIndex - startIndex;
// Make sure the start index is within the XMLString bounds
if ( startIndex < 0 || startIndex > endIndex || endIndex > srcLen)
ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager);
for (int i= startIndex; i < endIndex; i++) {
targetStr[i-startIndex] = srcStr[i];
}
targetStr[copySize] = 0;
}
bool XMLString::isValidNOTATION(const XMLCh* const name
, MemoryManager* const manager )
{
//
// NOTATATION: <URI>:<localPart>
// where URI is optional
// ':' and localPart must be present
//
int nameLen = XMLString::stringLen(name);
int colPos = XMLString::lastIndexOf(name, chColon);
if ((colPos == -1) || // no ':'
(colPos == nameLen - 1) ) // <URI>':'
return false;
// Examine localpart
if (!XMLString::isValidNCName(&name[colPos+1]))
{
return false;
}
else if (colPos == 0)
{
return true;
}
else
{
// Examine URI
XMLCh* const temp =
(XMLCh*) manager->allocate((colPos + 1) * sizeof(XMLCh));
const ArrayJanitor<XMLCh> 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;
}
}
/**
* Deprecated: isValidNCName
* Check first char, and then the rest of the name char.
* But colon should be excluded
*/
bool XMLString::isValidNCName(const XMLCh* const name) {
return XMLChar1_0::isValidNCName(name, XMLString::stringLen(name));
}
/**
* Deprecated: isValidName
* Check first char, and then the rest of the name char
*
*/
bool XMLString::isValidName(const XMLCh* const name) {
return XMLChar1_0::isValidName(name, XMLString::stringLen(name));
}
/**
* isValidEncName
*
* [80] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
*
*/
bool XMLString::isValidEncName(const XMLCh* const name)
{
if ( XMLString::stringLen(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;
}
/**
* Deprecated: isValidQName
*
*/
bool XMLString::isValidQName(const XMLCh* const name)
{
return XMLChar1_0::isValidQName(name, XMLString::stringLen(name));
}
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));
}
// Deprecated
bool XMLString::isAllWhiteSpace(const XMLCh* const toCheck)
{
return XMLChar1_0::isAllSpaces(toCheck, XMLString::stringLen(toCheck));
}
// ---------------------------------------------------------------------------
// Wide char versions of most of the string methods
// ---------------------------------------------------------------------------
void XMLString::binToText( const unsigned long toFormat
, XMLCh* const toFill
, const unsigned int 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
unsigned int tmpIndex = 0;
// A copy of the conversion value that we can modify
unsigned int 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 int charInd = (tmpVal & 0xFUL);
tmpBuf[tmpIndex++] = digitList[charInd];
tmpVal >>= 4;
}
}
else if ((radix == 8) || (radix == 10))
{
while (tmpVal)
{
const unsigned int 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
unsigned int 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 unsigned int 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 unsigned int 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.
//
unsigned int startInd = 0;
unsigned long actualVal;
if (toFormat < 0)
{
toFill[0] = chDash;
startInd++;
actualVal = (unsigned long)(toFormat * -1);
}
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 unsigned int 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.
//
unsigned int startInd = 0;
unsigned long actualVal;
if (toFormat < 0)
{
toFill[0] = chDash;
startInd++;
actualVal = (unsigned long)(toFormat * -1);
}
else
{
actualVal = (unsigned long)(toFormat);
}
// And now call the unsigned long version
binToText(actualVal, &toFill[startInd], maxChars, radix, manager);
}
void XMLString::catString(XMLCh* const target, const XMLCh* const src)
{
// Get the starting point for the cat on the target XMLString
unsigned int 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 - XMLString::stringLen(psz2);
}
else if (psz2 == 0) {
return XMLString::stringLen(psz1);
}
}
XMLCh ch1;
XMLCh ch2;
while (true) {
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 unsigned int maxChars)
{
const XMLCh* psz1 = str1;
const XMLCh* psz2 = str2;
unsigned int 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 unsigned int 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 - XMLString::stringLen(psz2);
}
else if (psz2 == 0) {
return XMLString::stringLen(psz1);
}
}
while (true)
{
// 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 unsigned int 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 unsigned int 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++;
// Capp off the target where we ended
*pszOut = 0;
}
bool XMLString::copyNString( XMLCh* const target
, const XMLCh* const src
, const unsigned int maxChars)
{
XMLCh* outPtr = target;
const XMLCh* srcPtr = src;
const XMLCh* endPtr = target + maxChars - 1;
while (*srcPtr && (outPtr <= endPtr))
*outPtr++ = *srcPtr++;
// Cap it off here
*outPtr = 0;
// Return whether we copied it all or hit the max
return (*srcPtr == 0);
}
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 int patnLen = XMLString::stringLen(pattern);
if ( !patnLen )
return -1;
const XMLCh* srcPtr = toSearch;
const XMLCh* patnStart = toSearch;
int patnIndex = 0;
while (*srcPtr)
{
if ( !(*srcPtr++ == pattern[patnIndex]))
{
patnIndex = 0;
srcPtr = ++patnStart;
}
else
{
if (++patnIndex == patnLen)
// full pattern match found
return (srcPtr - patnLen - toSearch);
}
}
return -1;
}
unsigned int XMLString::hashN( const XMLCh* const tohash
, const unsigned int n
, const unsigned int hashModulus
, MemoryManager* const)
{
assert(hashModulus);
unsigned int hashVal = 0;
if (tohash) {
const XMLCh* curCh = tohash;
int i = n;
while (i--)
{
unsigned int top = hashVal >> 24;
hashVal += (hashVal * 37) + top + (unsigned int)(*curCh);
curCh++;
}
}
// Divide by modulus
return hashVal % hashModulus;
}
int XMLString::indexOf(const XMLCh* const toSearch, const XMLCh ch)
{
if (toSearch)
{
const XMLCh* srcPtr = toSearch;
while (*srcPtr)
{
if (ch == *srcPtr)
return (int)(srcPtr - toSearch);
srcPtr++;
}
}
return -1;
}
int XMLString::indexOf( const XMLCh* const toSearch
, const XMLCh ch
, const unsigned int fromIndex
, MemoryManager* const manager)
{
const int len = stringLen(toSearch);
// Make sure the start index is within the XMLString bounds
if ((int)fromIndex > len-1)
ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager);
for (int i = (int)fromIndex; i < len; i++)
{
if (toSearch[i] == ch)
return i;
}
return -1;
}
int XMLString::lastIndexOf(const XMLCh ch,
const XMLCh* const toSearch,
const unsigned int toSearchLen)
{
for (int i = (int)toSearchLen-1; i >= 0; i--)
{
if (toSearch[i] == ch)
return i;
}
return -1;
}
int XMLString::lastIndexOf( const XMLCh* const toSearch
, const XMLCh ch
, const unsigned int fromIndex
, MemoryManager* const manager)
{
const int len = stringLen(toSearch);
if ((int)fromIndex > len-1)
ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager);
for (int i = (int)fromIndex; i >= 0; i--)
{
if (toSearch[i] == ch)
return i;
}
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 unsigned int 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<XMLCh> jan1(trimmedStr, manager);
XMLString::trim(trimmedStr);
unsigned int 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<char> 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<XMLCh> jan1(trimmedStr, manager);
XMLString::trim(trimmedStr);
unsigned int 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<char> 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 unsigned int len = stringLen(toTrim);
unsigned int 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
unsigned int 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 int startIndex, const int endIndex
, MemoryManager* const manager)
{
subString(targetStr, srcStr, startIndex, endIndex, stringLen(srcStr), manager);
}
void XMLString::subString(XMLCh* const targetStr, const XMLCh* const srcStr
, const int startIndex, const int endIndex
, const int srcStrLength
, MemoryManager* const manager)
{
//if (startIndex < 0 || endIndex < 0)
// ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_NegativeIndex);
if (targetStr == 0)
ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Str_ZeroSizedTargetBuf, manager);
const int copySize = endIndex - startIndex;
// Make sure the start index is within the XMLString bounds
if ( startIndex < 0 || startIndex > endIndex || endIndex > srcStrLength)
ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Str_StartIndexPastEnd, manager);
for (int i= startIndex; i < endIndex; i++) {
targetStr[i-startIndex] = srcStr[i];
}
targetStr[copySize] = 0;
}
BaseRefVectorOf<XMLCh>* XMLString::tokenizeString(const XMLCh* const tokenizeSrc
, MemoryManager* const manager)
{
XMLCh* orgText = replicate(tokenizeSrc, manager);
ArrayJanitor<XMLCh> janText(orgText, manager);
XMLCh* tokenizeStr = orgText;
RefArrayVectorOf<XMLCh>* tokenStack = new (manager) RefArrayVectorOf<XMLCh>(16, true, manager);
unsigned int len = stringLen(tokenizeStr);
unsigned int skip;
unsigned int 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 unsigned int findLen = XMLString::stringLen(toFind);
while (*listPtr)
{
unsigned int 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* const toConvert
, MemoryManager* const manager)
{
int strLen = XMLString::stringLen(toConvert);
if (strLen == 0)
return;
XMLCh* retBuf = (XMLCh*) manager->allocate
(
(strLen+1) * sizeof(XMLCh)
);//new XMLCh[strLen+1];
XMLCh* retPtr = &retBuf[0];
XMLCh* startPtr = toConvert;
while ( *startPtr )
{
if ( ( *startPtr == chCR) ||
( *startPtr == chLF) ||
( *startPtr == chHTab))
*retPtr = chSpace;
else
*retPtr = *startPtr;
retPtr++;
startPtr++;
}
retBuf[strLen] = chNull;
XMLString::moveChars(toConvert, retBuf, strLen);
manager->deallocate(retBuf);//delete[] retBuf;
return;
}
//
// 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* const toConvert
, MemoryManager* const manager)
{
// If no string, then its a failure
if (( !toConvert ) || ( !*toConvert ))
return;
// replace whitespace first
replaceWS(toConvert, manager);
// remove leading spaces
const XMLCh* startPtr = toConvert;
while ( *startPtr == chSpace )
startPtr++;
if (!*startPtr)
return;
// remove trailing spaces
const XMLCh* endPtr = toConvert + stringLen(toConvert);
while (*(endPtr - 1) == chSpace)
endPtr--;
//
// Work through what remains and chop continuous spaces
//
XMLCh* retBuf = (XMLCh*) manager->allocate
(
(endPtr - startPtr + 1) * sizeof(XMLCh)
);//new XMLCh[endPtr - startPtr + 1];
XMLCh* retPtr = &retBuf[0];
bool inSpace = false;
while (startPtr < endPtr)
{
if ( *startPtr == chSpace)
{
if (inSpace)
{
//discard it;
}
else
{
inSpace = true;
*retPtr = chSpace; //copy the first chSpace
retPtr++;
}
}
else
{
inSpace = false;
*retPtr = *startPtr;
retPtr++;
}
startPtr++;
}
*retPtr = chNull;
XMLString::moveChars(toConvert, retBuf, stringLen(retBuf)+1); //copy the last chNull as well
manager->deallocate(retBuf);//delete[] retBuf;
return;
}
//
// remove whitespace
//
void XMLString::removeWS(XMLCh* const toConvert
, MemoryManager* const manager)
{
// If no string, then its a failure
if (( !toConvert ) || ( !*toConvert ))
return;
XMLCh* retBuf = (XMLCh*) manager->allocate
(
(XMLString::stringLen(toConvert) + 1) * sizeof(XMLCh)
);//new XMLCh[ XMLString::stringLen(toConvert) + 1];
XMLCh* retPtr = &retBuf[0];
XMLCh* startPtr = toConvert;
while (*startPtr)
{
if ( ( *startPtr != chCR) &&
( *startPtr != chLF) &&
( *startPtr != chHTab) &&
( *startPtr != chSpace) )
{
*retPtr++ = *startPtr;
}
startPtr++;
}
*retPtr = chNull;
XMLString::moveChars(toConvert, retBuf, stringLen(retBuf)+1); //copy the last chNull as well
manager->deallocate(retBuf);//delete[] retBuf;
return;
}
void XMLString::removeChar(const XMLCh* const srcString
, const XMLCh& toRemove
, XMLBuffer& dstBuffer)
{
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)
{
delete [] *buf;
*buf = 0;
}
void XMLString::release(XMLCh** buf)
{
delete [] *buf;
*buf = 0;
}
void XMLString::release(XMLByte** buf)
{
delete [] *buf;
*buf = 0;
}
void XMLString::release(void** 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