blob: 8d8c9624f4767bf4fad998cab9828423fd3c97bb [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.ibm.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
// Class header file.
#include "DOMStringHelper.hpp"
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#if defined(XALAN_OLD_STREAM_HEADERS)
#include <strstream.h>
#else
#include <strstream>
#endif
#if !defined(XALAN_NO_NAMESPACES)
using std::back_inserter;
using std::copy;
using std::hex;
using std::ios;
using std::istrstream;
using std::ostream;
using std::ostrstream;
using std::transform;
using std::vector;
#endif
// Xerces header files
#include <util/XMLString.hpp>
#if !defined(XML_LSTRSUPPORT)
#include <util/PlatformUtils.hpp>
#endif
#include <Include/XalanAutoPtr.hpp>
#include <Include/STLHelper.hpp>
#include "DoubleSupport.hpp"
#include "XalanOutputStream.hpp"
#include "XalanUnicode.hpp"
// The maximum number of digits that sprintf can put in a buffer.
// 100 for now. We're using this because we want to avoid transcoding
// number strings when we don't have to,
const size_t MAX_PRINTF_DIGITS = 100;
// The maximum number of characters for a floating point number.
const size_t MAX_FLOAT_CHARACTERS = 100;
static XalanDOMString theNaNString;
static XalanDOMString theNegativeInfinityString;
static XalanDOMString thePositiveInfinityString;
static XalanDOMString theNegativeZeroString;
static XalanDOMString thePositiveZeroString;
/**
* Initialize static data. Must be called before any
* other functions are called. See PlatformSupportInit.
*/
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
DOMStringHelperInitialize()
{
theNaNString = XALAN_STATIC_UCODE_STRING("NaN");
theNegativeInfinityString = XALAN_STATIC_UCODE_STRING("-Infinity");
thePositiveInfinityString = XALAN_STATIC_UCODE_STRING("Infinity");
theNegativeZeroString = XALAN_STATIC_UCODE_STRING("-0");
thePositiveZeroString = XALAN_STATIC_UCODE_STRING("0");
}
/**
* Destroy static data. After thus function is called,
* no other functions can be called. See PlatformSupportInit.
*/
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
DOMStringHelperTerminate()
{
releaseMemory(theNaNString);
releaseMemory(theNegativeInfinityString);
releaseMemory(thePositiveInfinityString);
releaseMemory(theNegativeZeroString);
releaseMemory(thePositiveZeroString);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString::size_type)
indexOf(
const XalanDOMChar* theString,
const XalanDOMChar* theSubstring)
{
assert(theString != 0);
assert(theSubstring != 0);
const XalanDOMString::size_type theStringLength = length(theString);
const XalanDOMString::size_type theSubstringLength = length(theSubstring);
// If the substring is longer than the string, then
// it's not a substring.
if (theStringLength < theSubstringLength)
{
return theStringLength;
}
else
{
bool fMatch = false;
XalanDOMString::size_type theStringIndex = 0;
// While we haven't matched, and we haven't finished with the
// first string, and the number of characters left in the first
// string is greater than the length of the second string, try
// to match the strings.
while(fMatch == false &&
theStringIndex < theStringLength &&
theStringLength - theStringIndex >= theSubstringLength)
{
// We always start over from the beginning of the second string.
XalanDOMString::size_type theSubstringIndex = 0;
// This variable will be incremented to index into the first
// string. That way, we preserve the first string index for
// when we have to restart the following loop with the next
// position in the first string.
XalanDOMString::size_type theOffset = 0;
// Compare the characters in the two strings, at the
// current indices, until the characters don't match.
while(theStringIndex < theStringLength &&
theSubstringIndex < theSubstringLength &&
theString[theStringIndex + theOffset] ==
theSubstring[theSubstringIndex])
{
theOffset++;
theSubstringIndex++;
}
// If we've reached the end of the second string,
// then we've found a match.
if (theSubstringIndex == theSubstringLength)
{
fMatch = true;
}
else
{
theStringIndex++;
}
}
return fMatch == false ? theStringLength : theStringIndex;
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString::size_type)
indexOf(
const XalanDOMString& theString,
const XalanDOMString& theSubstring)
{
if (isEmpty(theString) == true)
{
return 0;
}
else if (isEmpty(theSubstring) == true)
{
return theString.length();
}
else
{
return indexOf(c_wstr(theString), c_wstr(theSubstring));
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString::size_type)
lastIndexOf(
const XalanDOMChar* theString,
XalanDOMChar theChar)
{
const XalanDOMString::size_type theLength = length(theString);
if (theLength == 0)
{
return theLength;
}
else
{
XalanDOMString::size_type theIndex = theLength;
while(theIndex > 0 && theString[theIndex - 1] != theChar)
{
theIndex--;
}
return theIndex == 0 ? theLength : theIndex - 1;
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
startsWith(
const XalanDOMChar* theString,
const XalanDOMChar* theSubstring)
{
bool fResult = false;
const XalanDOMString::size_type theStringLength = length(theString);
const XalanDOMString::size_type theSubstringLength = length(theSubstring);
if (theSubstringLength == 0)
{
// Make this work like Java...
return true;
}
else if (theStringLength >= theSubstringLength)
{
XalanDOMString::size_type i = 0;
// Compare each character...
for (;
i < theSubstringLength &&
theString[i] == theSubstring[i];
i++)
{
;
}
// If we've gotten to the end of the substring, then
// return true.
if (i == theSubstringLength)
{
fResult = true;
}
}
return fResult;
}
static const XalanDOMChar theDummyEmptyString = 0;
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
startsWith(
const XalanDOMChar* theString,
const XalanDOMString& theSubstring)
{
const XalanDOMChar* const theBuffer =
c_wstr(theSubstring);
return startsWith(theString, theBuffer == 0 ? &theDummyEmptyString : theBuffer);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
startsWith(
const XalanDOMString& theString,
const XalanDOMChar* theSubstring)
{
const XalanDOMChar* const theBuffer =
c_wstr(theString);
return startsWith(theBuffer == 0 ? &theDummyEmptyString : theBuffer, theSubstring);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
startsWith(
const XalanDOMString& theString,
const XalanDOMString& theSubstring)
{
const XalanDOMChar* const theStringBuffer =
c_wstr(theString);
const XalanDOMChar* const theSubstringBuffer =
c_wstr(theSubstring);
return startsWith(
theStringBuffer == 0 ? &theDummyEmptyString : theStringBuffer,
theSubstringBuffer == 0 ? &theDummyEmptyString : theSubstringBuffer);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
endsWith(
const XalanDOMChar* theString,
const XalanDOMChar* theSubstring)
{
assert(theString != 0);
assert(theSubstring != 0);
bool fResult = false;
const XalanDOMString::size_type theStringLength = length(theString);
const XalanDOMString::size_type theSubstringLength = length(theSubstring);
// If the substring is longer, there's no point in continuing.
if (theSubstringLength > 0 && theStringLength >= theSubstringLength)
{
XalanDOMString::size_type i = theStringLength;
XalanDOMString::size_type j = theSubstringLength;
// Compare each character...
for (;
j > 0 &&
theString[i - 1] == theSubstring[j - 1];
--j, --i)
{
;
}
// If we've gotten to the beginning of the substring, then
// return true.
if (j == 0)
{
fResult = true;
}
}
return fResult;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
OutputString(XalanOutputStream& theStream,
const CharVectorType& theString)
{
if (theString.size() > 0)
{
theStream.write(c_str(theString));
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
OutputString(
#if defined(XALAN_NO_NAMESPACES)
ostream& theStream,
#else
std::ostream& theStream,
#endif
const CharVectorType& theString)
{
if (theString.size() > 0)
{
theStream << c_str(theString);
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
OutputString(XalanOutputStream& theStream,
const XalanDOMChar* theString)
{
if (theString != 0)
{
theStream.write(theString);
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
OutputString(
#if defined(XALAN_NO_NAMESPACES)
ostream& theStream,
#else
std::ostream& theStream,
#endif
const XalanDOMChar* theString)
{
OutputString(theStream, TranscodeToLocalCodePage(theString));
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)
substring(
const XalanDOMChar* theString,
XalanDOMString::size_type theStartIndex,
XalanDOMString::size_type theEndIndex)
{
assert(theString != 0);
const XalanDOMString::size_type theStringLength = length(theString);
// $$$ ToDo: In Java-land, any failing of this
// assertion would result in an exception being thrown.
assert(theStartIndex <= theStringLength);
if (theStartIndex == theStringLength)
{
// This is allowed, and should return an empty string.
return XalanDOMString();
}
else
{
const XalanDOMString::size_type theLength = theEndIndex == XalanDOMString::npos ? theStringLength - theStartIndex :
theEndIndex - theStartIndex;
assert(theStartIndex + theLength <= theStringLength);
return XalanDOMString(theString + theStartIndex, theLength);
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)&
substring(
const XalanDOMChar* theString,
XalanDOMString& theSubstring,
XalanDOMString::size_type theStartIndex,
XalanDOMString::size_type theEndIndex)
{
assert(theString != 0);
const XalanDOMString::size_type theStringLength = length(theString);
// $$$ ToDo: In Java-land, any failing of this
// assertion would result in an exception being thrown.
assert(theStartIndex <= theStringLength);
if (theStartIndex == theStringLength)
{
// This is allowed, and should return an empty string.
clear(theSubstring);
}
else
{
const XalanDOMString::size_type theLength = theEndIndex == XalanDOMString::npos ? theStringLength - theStartIndex :
theEndIndex - theStartIndex;
assert(theStartIndex + theLength <= theStringLength);
theSubstring.assign(theString + theStartIndex, theLength);
}
return theSubstring;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
substring(
const XalanDOMString& theString,
XalanDOMString& theSubstring,
XalanDOMString::size_type theStartIndex,
XalanDOMString::size_type theEndIndex)
{
const XalanDOMString::size_type theStringLength = length(theString);
// $$$ ToDo: In Java-land, any failing of this
// assertion would result in an exception being thrown.
assert(theStartIndex <= theStringLength);
if (theStartIndex == theStringLength)
{
// This is allowed, and should return an empty string.
clear(theSubstring);
}
else
{
const XalanDOMString::size_type theLength = theEndIndex == XalanDOMString::npos ? theStringLength - theStartIndex :
theEndIndex - theStartIndex;
if (theLength == 0)
{
clear(theSubstring);
}
else
{
assert(theStartIndex + theLength <= theStringLength);
theString.substr(theSubstring, theStartIndex, theLength);
}
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)
substring(
const XalanDOMString& theString,
XalanDOMString::size_type theStartIndex,
XalanDOMString::size_type theEndIndex)
{
const XalanDOMString::size_type theStringLength = length(theString);
// $$$ ToDo: In Java-land, any failing of this
// assertion would result in an exception being thrown.
assert(theStartIndex <= theStringLength);
if (theStartIndex == theStringLength)
{
// This is allowed, and should return an empty string.
return XalanDOMString();
}
else
{
const XalanDOMString::size_type theLength = theEndIndex == XalanDOMString::npos ? theStringLength - theStartIndex :
theEndIndex - theStartIndex;
if (theLength == 0)
{
return XalanDOMString();
}
else
{
assert(theStartIndex + theLength <= theStringLength);
return theString.substr(theStartIndex, theLength);
}
}
}
#if defined(XALAN_NO_ALGORITHMS_WITH_BUILTINS)
template<class InputIteratorType, class OutputIteratorType>
inline OutputIteratorType
XalanCopy(
InputIteratorType begin,
InputIteratorType end,
OutputIteratorType iterator)
{
for(; begin != end; ++iterator, ++begin)
{
*iterator = *begin;
}
return iterator;
}
template<class InputIteratorType, class OutputIteratorType, class UnaryFunction>
inline OutputIteratorType
XalanTransform(
InputIteratorType begin,
InputIteratorType end,
OutputIteratorType iterator,
UnaryFunction function)
{
for(; begin != end; ++iterator, ++begin)
{
*iterator = function(*begin);
}
return iterator;
}
#endif
template <class InputIteratorType, class OutputIteratorType, class FunctionType>
OutputIteratorType
TransformString(
InputIteratorType theInputBegin,
InputIteratorType theInputEnd,
OutputIteratorType theOutputIterator,
FunctionType theFunction)
{
#if defined(XALAN_NO_ALGORITHMS_WITH_BUILTINS)
return XalanTransform(
theInputBegin,
theInputEnd,
theOutputIterator,
theFunction);
#else
return transform(
theInputBegin,
theInputEnd,
theOutputIterator,
theFunction);
#endif
}
template <class SizeType, class FunctionType>
XalanDOMString
TransformString(
const XalanDOMChar* theInputString,
SizeType theInputStringLength,
FunctionType theFunction)
{
assert(theInputString != 0);
XalanDOMString theConvertedString;
TransformString(
theInputString,
theInputString + theInputStringLength,
back_inserter(theConvertedString),
theFunction);
return theConvertedString;
}
template <class FunctionType>
XalanDOMString
TransformXalanDOMString(
const XalanDOMString& theInputString,
FunctionType theFunction)
{
const XalanDOMString::size_type theStringLength = length(theInputString);
if (theStringLength == 0)
{
return theInputString;
}
else
{
const XalanDOMChar* const theBuffer = c_wstr(theInputString);
assert(theBuffer != 0);
return TransformString(theBuffer, unsigned(theStringLength), theFunction);
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)
toLowerCaseASCII(const XalanDOMChar* theString)
{
return TransformString(theString, length(theString), toLowerASCII);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)
toLowerCaseASCII(const XalanDOMString& theString)
{
return TransformXalanDOMString(theString, toLowerASCII);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)
toUpperCaseASCII(const XalanDOMChar* theString)
{
return TransformString(theString, length(theString), toUpperASCII);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)
toUpperCaseASCII(const XalanDOMString& theString)
{
return TransformXalanDOMString(theString, toUpperASCII);
}
template <class InputCharType, class OutputCharType>
class IdentityTransform
{
public:
OutputCharType
operator()(InputCharType theChar) const
{
return OutputCharType(theChar);
}
};
template<class InputCharType, class OutputCharType>
IdentityTransform<InputCharType, OutputCharType>
makeIdentityTransform(
const InputCharType*,
const OutputCharType*)
{
return IdentityTransform<InputCharType, OutputCharType>();
}
IdentityTransform<char, char>
makeCharIdentityTransform()
{
char theDummy;
return makeIdentityTransform(&theDummy, &theDummy);
}
IdentityTransform<XalanDOMChar, XalanDOMChar>
makeXalanDOMCharIdentityTransform()
{
XalanDOMChar theDummy;
return makeIdentityTransform(&theDummy, &theDummy);
}
template <class Type, class SizeType, class FunctionType>
int
doCompare(
const Type* theLHS,
SizeType theLHSLength,
const Type* theRHS,
SizeType theRHSLength,
FunctionType theTransformFunction)
{
// We don't really have to order, so save some time...
if (theLHSLength < theRHSLength)
{
return -1;
}
else if (theRHSLength < theLHSLength)
{
return 1;
}
else
{
Type theLHSChar = Type(0);
Type theRHSChar = Type(0);
for(SizeType i = 0; i < theLHSLength; i++)
{
theLHSChar = theTransformFunction(theLHS[i]);
theRHSChar = theTransformFunction(theRHS[i]);
if (theLHSChar != theRHSChar)
{
break;
}
}
return int(theLHSChar - theRHSChar);
}
}
template <class Type, class SizeType, class FunctionType>
int
doCollationCompare(
const Type* theLHS,
SizeType theLHSLength,
const Type* theRHS,
SizeType theRHSLength,
FunctionType theTransformFunction)
{
int theResult = 0;
if (theLHSLength != 0 || theRHSLength != 0)
{
Type theLHSChar = Type(0);
Type theRHSChar = Type(0);
SizeType i = 0;
for(; i < theLHSLength && i < theRHSLength; i++)
{
theLHSChar = theTransformFunction(theLHS[i]);
theRHSChar = theTransformFunction(theRHS[i]);
if (theLHSChar != theRHSChar)
{
break;
}
}
if (i == theLHSLength)
{
// We reached the end of theLHS...
if (i != theRHSLength)
{
// but not the end of theRHS.
theResult = -1;
}
}
else if (i == theRHSLength)
{
// We reached the end of theRHS string...
if (i != theLHSLength)
{
// but not the end of theLHS string.
theResult = 1;
}
}
else
{
// We didn't reach the end of _either_ string, so
// return the difference between the two characters
// that caused the problem.
theResult = theLHSChar - theRHSChar;
}
}
return theResult;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
compare(
const CharVectorType& theLHS,
const CharVectorType& theRHS)
{
return doCompare(
toCharArray(theLHS),
theLHS.size(),
toCharArray(theRHS),
theRHS.size(),
makeCharIdentityTransform());
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
compare(
const XalanDOMChar* theLHS,
XalanDOMString::size_type theLHSLength,
const XalanDOMChar* theRHS,
XalanDOMString::size_type theRHSLength)
{
return doCompare(
theLHS,
theLHSLength,
theRHS,
theRHSLength,
makeXalanDOMCharIdentityTransform());
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
compareIgnoreCaseASCII(
const XalanDOMChar* theLHS,
XalanDOMString::size_type theLHSLength,
const XalanDOMChar* theRHS,
XalanDOMString::size_type theRHSLength)
{
return doCompare(
theLHS,
theLHSLength,
theRHS,
theRHSLength,
toUpperASCII);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
collationCompare(
const XalanDOMChar* theLHS,
XalanDOMString::size_type theLHSLength,
const XalanDOMChar* theRHS,
XalanDOMString::size_type theRHSLength)
{
return doCollationCompare(
theLHS,
theLHSLength,
theRHS,
theRHSLength,
makeXalanDOMCharIdentityTransform());
}
template <class Type, class SizeType, class FunctionType>
bool
doEquals(
const Type* theLHS,
const Type* theRHS,
SizeType theLength,
FunctionType theTransformFunction)
{
assert(theLHS != 0 && theRHS != 0);
#if 1
if (theLength == 0)
{
return true;
}
else
{
const Type* const theEnd = theLHS + theLength;
while(theTransformFunction(*theLHS) == theTransformFunction(*theRHS))
{
++theLHS;
if (theLHS == theEnd)
{
return true;
}
else
{
++theRHS;
}
}
return false;
}
#else
for(SizeType i = 0; i < theLength; ++i)
{
const Type theLHSChar = theTransformFunction(theLHS[i]);
const Type theRHSChar = theTransformFunction(theRHS[i]);
if (theLHSChar != theRHSChar)
{
return false;
}
}
return true;
#endif
}
template <class Type, class SizeType, class FunctionType>
bool
doEqualsIgnoreCase(
const Type* theLHS,
const Type* theRHS,
SizeType theLength,
FunctionType theToUpperFunction)
{
// Check each character, converting to uppercase
// for the test.
for(SizeType i = 0; i < theLength; i++)
{
const Type charLHS = theLHS[i];
const Type charRHS = theRHS[i];
if (charLHS != charRHS &&
Type(theToUpperFunction(charLHS)) != charRHS &&
charLHS != Type(theToUpperFunction(charRHS)))
{
return false;
}
}
return true;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
equals(
const XalanDOMChar* theLHS,
const XalanDOMChar* theRHS,
XalanDOMString::size_type theLength)
{
return doEquals(
theLHS,
theRHS,
theLength,
makeXalanDOMCharIdentityTransform());
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
equalsIgnoreCaseASCII(
const XalanDOMChar* theLHS,
const XalanDOMChar* theRHS,
XalanDOMString::size_type theLength)
{
return doEqualsIgnoreCase(
theLHS,
theRHS,
theLength,
toUpperASCII);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMCharVectorType)
MakeXalanDOMCharVector(
const char* data,
bool fTranscode)
{
assert(data != 0);
XalanDOMCharVectorType theResult;
if (fTranscode == true)
{
// Create a vector which includes the terminating 0.
TranscodeFromLocalCodePage(data, theResult, true);
}
else
{
// Include the terminating null byte...
const size_t theLength = strlen(data) + 1;
theResult.reserve(theLength);
#if defined(XALAN_NO_ALGORITHMS_WITH_BUILTINS)
XalanCopy(
data,
data + theLength,
back_inserter(theResult));
#else
copy(
data,
data + theLength,
back_inserter(theResult));
#endif
}
return theResult;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMCharVectorType)
MakeXalanDOMCharVector(const XalanDOMChar* data)
{
assert(data != 0);
const XalanDOMString::size_type theLength = length(data);
// Create a vector which includes the terminating 0.
return XalanDOMCharVectorType(data, data + theLength + 1);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
CopyWideStringToVector(
const XalanDOMChar* theString,
CharVectorType& theVector)
{
const XalanDOMString::size_type theLength = length(theString);
if (theLength != 0)
{
theVector.reserve(theVector.size() + theLength + 1);
for(XalanDOMString::size_type i = 0; i < theLength; i++)
{
// Assert that the truncation will not affect the resulting character.
assert(theString[i] == char(theString[i]));
theVector.push_back(char(theString[i]));
}
// Put a terminating 0 byte.
theVector.push_back(0);
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
CopyStringToVector(
const char* theString,
CharVectorType& theVector)
{
theVector.insert(
theVector.end(),
theString,
theString + strlen(theString) + 1);
}
template <class Type>
Type
WideStringToIntegral(
const XalanDOMChar* theString,
Type /* theDummy */)
{
if (theString == 0 || DoubleSupport::isValid(theString) == false)
{
return Type(0);
}
else
{
// OK, now we know we have a valid string, so start converting...
Type theResult = 0;
// Consume any leading whitespace (which we allow)
while(isXMLWhitespace(*theString) == true)
{
++theString;
}
const bool isNegative = *theString == XalanUnicode::charHyphenMinus ? true : false;
if (isNegative == true)
{
++theString;
}
while(*theString != 0)
{
if (*theString >= XalanUnicode::charDigit_0 && *theString <= XalanUnicode::charDigit_9)
{
theResult *= 10;
theResult += *theString - XalanUnicode::charDigit_0;
++theString;
}
else if (isXMLWhitespace(*theString) == true)
{
// This must be trailing whitespace...
break;
}
else
{
// An non-numeric character was encountered, so stop...
return 0;
}
}
return isNegative == true ? -theResult : theResult;
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
WideStringToInt(const XalanDOMChar* theString)
{
return WideStringToIntegral(theString, int(0));
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(long)
WideStringToLong(const XalanDOMChar* theString)
{
return WideStringToIntegral(theString, long(0));
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(unsigned long)
WideStringToUnsignedLong(const XalanDOMChar* theString)
{
return WideStringToIntegral(theString, (unsigned long)0);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(double)
WideStringToDouble(const XalanDOMChar* theString)
{
return DoubleSupport::toDouble(theString);
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)
trim(const XalanDOMString& theString)
{
if (isEmpty(theString))
return theString;
const XalanDOMString::size_type strLen = length(theString);
assert(strLen > 0);
// index of first non-whitespace character
XalanDOMString::size_type leadingSpace = 0;
for (; leadingSpace < strLen; ++leadingSpace)
if (!isXMLWhitespace(charAt(theString, leadingSpace)))
break;
// index of last non-whitespace character
XalanDOMString::size_type trailingSpace = strLen -1;
for (; trailingSpace > 0; --trailingSpace)
if (!isXMLWhitespace(charAt(theString, trailingSpace)))
break;
return substring(theString, leadingSpace, trailingSpace +1);
}
// A very cheap decimal number transcoder...
template <class InputCharType, class OutputCharType>
class DecimalNumberTranscodeTransform
{
public:
OutputCharType
operator()(InputCharType theChar) const
{
switch(theChar)
{
case '-':
return OutputCharType(XalanUnicode::charHyphenMinus);
break;
case '.':
return OutputCharType(XalanUnicode::charFullStop);
break;
case '0':
return OutputCharType(XalanUnicode::charDigit_0);
break;
case '1':
return OutputCharType(XalanUnicode::charDigit_1);
break;
case '2':
return OutputCharType(XalanUnicode::charDigit_2);
break;
case '3':
return OutputCharType(XalanUnicode::charDigit_3);
break;
case '4':
return OutputCharType(XalanUnicode::charDigit_4);
break;
case '5':
return OutputCharType(XalanUnicode::charDigit_5);
break;
case '6':
return OutputCharType(XalanUnicode::charDigit_6);
break;
case '7':
return OutputCharType(XalanUnicode::charDigit_7);
break;
case '8':
return OutputCharType(XalanUnicode::charDigit_8);
break;
case '9':
return OutputCharType(XalanUnicode::charDigit_9);
break;
default:
return OutputCharType(0);
break;
}
}
};
template<class InputCharType, class OutputCharType>
DecimalNumberTranscodeTransform<InputCharType, OutputCharType>
makeDecimalNumberTranscodeTransform(
const InputCharType*,
const OutputCharType*)
{
return DecimalNumberTranscodeTransform<InputCharType, OutputCharType>();
}
// A very cheap hex number transcoder...
template <class InputCharType, class OutputCharType>
class HexadecimalNumberTranscodeTransform : public DecimalNumberTranscodeTransform<InputCharType, OutputCharType>
{
public:
typedef DecimalNumberTranscodeTransform<InputCharType, OutputCharType> BaseClassType;
OutputCharType
operator()(InputCharType theChar) const
{
switch(theChar)
{
case 'A':
return OutputCharType(XalanUnicode::charLetter_A);
break;
case 'a':
return OutputCharType(XalanUnicode::charLetter_a);
break;
case 'B':
return OutputCharType(XalanUnicode::charLetter_B);
break;
case 'b':
return OutputCharType(XalanUnicode::charLetter_b);
break;
case 'C':
return OutputCharType(XalanUnicode::charLetter_C);
break;
case 'c':
return OutputCharType(XalanUnicode::charLetter_c);
break;
case 'D':
return OutputCharType(XalanUnicode::charLetter_D);
break;
case 'd':
return OutputCharType(XalanUnicode::charLetter_d);
break;
case 'E':
return OutputCharType(XalanUnicode::charLetter_E);
break;
case 'e':
return OutputCharType(XalanUnicode::charLetter_e);
break;
case 'F':
return OutputCharType(XalanUnicode::charLetter_F);
break;
case 'f':
return OutputCharType(XalanUnicode::charLetter_f);
break;
default:
return BaseClassType::operator()(theChar);
break;
}
}
};
template <class InputIteratorType, class OutputIteratorType>
OutputIteratorType
TranscodeNumber(
InputIteratorType theInputBegin,
InputIteratorType theInputEnd,
OutputIteratorType theOutputIterator)
{
return TransformString(
theInputBegin,
theInputEnd,
theOutputIterator,
#if defined(XALAN_NON_ASCII_PLATFORM)
DecimalNumberTranscodeTransform<char, XalanDOMChar>());
#else
IdentityTransform<char, XalanDOMChar>());
#endif
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)&
PointerToDOMString(
const void* theValue,
XalanDOMString& theResult)
{
char theBuffer[MAX_PRINTF_DIGITS + 1];
unsigned int theCharsWritten = sprintf(theBuffer, "%p", theValue);
assert(theCharsWritten != 0);
reserve(theResult, length(theResult) + theCharsWritten);
TranscodeNumber(
theBuffer,
theBuffer + theCharsWritten,
back_inserter(theResult));
return theResult;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)&
DoubleToDOMString(
double theDouble,
XalanDOMString& theResult)
{
if (DoubleSupport::isNaN(theDouble) == true)
{
append(theResult, theNaNString);
}
else if (DoubleSupport::isPositiveInfinity(theDouble) == true)
{
append(theResult, thePositiveInfinityString);
}
else if (DoubleSupport::isNegativeInfinity(theDouble) == true)
{
append(theResult, theNegativeInfinityString);
}
else if (DoubleSupport::isPositiveZero(theDouble) == true)
{
append(theResult, thePositiveZeroString);
}
else if (DoubleSupport::isNegativeZero(theDouble) == true)
{
append(theResult, theNegativeZeroString);
}
else if (long(theDouble) == theDouble)
{
LongToDOMString(long(theDouble), theResult);
}
else
{
char theBuffer[MAX_PRINTF_DIGITS + 1];
unsigned int theCharsWritten = sprintf(theBuffer, "%f", theDouble);
assert(theCharsWritten != 0);
// First, cleanup the output to conform to the XPath standard,
// which says no trailing '0's for the decimal portion.
// So start with the last digit, and search until we find
// the last correct character for the output.
// Also, according to the XPath standard, any values without
// a fractional part are printed as integers. There's always
// a decimal point, so we have to strip stuff away...
// Now, move back while there are zeros...
while(theBuffer[--theCharsWritten] == '0')
{
}
// If a decimal point stopped the loop, then
// we don't want to preserve it. Otherwise,
// another digit stopped the loop, so we must
// preserve it.
if(theBuffer[theCharsWritten] != '.')
{
++theCharsWritten;
}
reserve(theResult, length(theResult) + theCharsWritten);
TranscodeNumber(
theBuffer,
theBuffer + theCharsWritten,
back_inserter(theResult));
}
return theResult;
}
template <class ScalarType>
XalanDOMChar*
ScalarToDecimalString(
ScalarType theValue,
XalanDOMChar* theOutput)
{
// Null terminate it...
*theOutput = 0;
if (theValue < 0)
{
do
{
*--theOutput = XalanDOMChar(-(theValue % 10) + XalanUnicode::charDigit_0);
// OK, we're done with it...
theValue /= 10;
}
while(theValue != 0);
*--theOutput = XalanUnicode::charHyphenMinus;
}
else
{
do
{
*--theOutput = XalanDOMChar(theValue % 10 + XalanUnicode::charDigit_0);
// OK, we're done with it...
theValue /= 10;
}
while(theValue != 0);
}
return theOutput;
}
template <class ScalarType>
void
ScalarToDecimalString(
ScalarType theValue,
XalanDOMString& theResult)
{
// We don't need to transcode, so just make it a
// wide character string...
XalanDOMChar theBuffer[MAX_PRINTF_DIGITS + 1];
XalanDOMChar* const theEnd = &theBuffer[MAX_PRINTF_DIGITS];
XalanDOMChar* const theBegin = ScalarToDecimalString(theValue, theEnd);
append(theResult, theBegin, theEnd - theBegin);
}
template <class ScalarType>
XalanDOMChar*
UnsignedScalarToHexadecimalString(
ScalarType theValue,
XalanDOMChar* theOutput)
{
if (theValue >= 0)
{
// Null terminate it...
*theOutput = 0;
do
{
// Next spot...
--theOutput;
const ScalarType theTemp = theValue % 16;
// Isolate the left most character.
if (theTemp >= 0 && theTemp <= 9)
{
*theOutput = XalanDOMChar(theTemp + XalanUnicode::charDigit_0);
}
else
{
assert(theTemp >= 10 && theTemp <= 15);
*theOutput = XalanDOMChar(theTemp - 10 + XalanUnicode::charLetter_A);
}
// OK, we're done with it...
theValue /= 16;
}
while(theValue != 0);
}
return theOutput;
}
template <class ScalarType>
void
UnsignedScalarToHexadecimalString(
ScalarType theValue,
XalanDOMString& theResult)
{
if (theValue >= 0)
{
// We don't need to transcode, so just make it a
// wide character string...
XalanDOMChar theBuffer[MAX_PRINTF_DIGITS + 1];
XalanDOMChar* const theEnd = &theBuffer[MAX_PRINTF_DIGITS];
XalanDOMChar* const theBegin = UnsignedScalarToHexadecimalString(theValue, theEnd);
append(theResult, theBegin, theEnd - theBegin);
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)&
LongToHexDOMString(
long theValue,
XalanDOMString& theResult)
{
UnsignedScalarToHexadecimalString(theValue, theResult);
return theResult;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)&
UnsignedLongToHexDOMString(
unsigned long theValue,
XalanDOMString& theResult)
{
UnsignedScalarToHexadecimalString(theValue, theResult);
return theResult;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)&
LongToDOMString(
long theValue,
XalanDOMString& theResult)
{
ScalarToDecimalString(theValue, theResult);
return theResult;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString)&
UnsignedLongToDOMString(
unsigned long theValue,
XalanDOMString& theResult)
{
ScalarToDecimalString(theValue, theResult);
return theResult;
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
isXMLWhitespace(const XalanDOMString& string)
{
const XalanDOMString::size_type theLength = length(string);
if (theLength == 0)
{
return true;
}
else
{
const XalanDOMChar* const theBuffer =
c_wstr(string);
assert(theBuffer != 0);
return isXMLWhitespace(theBuffer, 0, theLength);
}
}
XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
isXMLWhitespace(
const XalanDOMChar ch[],
XalanDOMString::size_type start,
XalanDOMString::size_type length)
{
const XalanDOMString::size_type end = start + length;
for(XalanDOMString::size_type s = start; s < end; s++)
{
if (!isXMLWhitespace(ch[s]))
return false;
}
return true;
}