blob: ab4997fd08410292f05c144afb482012dfbbd793 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2000-2002 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/>.
*/
#include "ICUBridge.hpp"
#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanDecimalFormatSymbols.hpp>
#include <PlatformSupport/DoubleSupport.hpp>
#include <unicode/coll.h>
#include <unicode/dcfmtsym.h>
#include <unicode/decimfmt.h>
#include <Include/XalanAutoPtr.hpp>
#if defined(XALAN_NO_NAMESPACES)
typedef vector<UChar> UCharVectorType;
#else
typedef std::vector<UChar> UCharVectorType;
#endif
#if defined(XALAN_XALANDOMCHAR_USHORT_MISMATCH)
inline void
doCopyData(
const XalanDOMChar* theString,
unsigned int theStringLength,
XalanDOMChar* theBuffer)
{
// Copy the data, truncating each character...
for (unsigned int i = 0; i < theStringLength; ++i)
{
// There should be no truncation, since XalanDOMChars
// hold UTF-16 code points, but assert, just in case...
assert(theString[i] == UChar(theString[i]));
theBuffer[i] = theString[i];
}
}
#endif
// Use a stack-based buffer up to this size.
const unsigned int theStackBufferSize = 200u;
const UnicodeString
ICUBridge::XalanDOMCharStringToUnicodeString(const XalanDOMChar* theString)
{
if (theString == 0)
{
return UnicodeString();
}
else
{
#if defined(XALAN_XALANDOMCHAR_USHORT_MISMATCH)
const unsigned int theLength = length(theString);
if (theStackBufferSize > theLength)
{
XalanDOMChar theBuffer[theStackBufferSize];
doCopyData(theString, theLength, theBuffer);
#if U_SIZEOF_WCHAR_T==2
return UnicodeString((wchar_t*)&theBuffer[0], theLength);
#else
return UnicodeString(&theBuffer[0], theLength);
#endif
}
else
{
// Create a buffer to copy out the UnicodeString data...
UCharVectorType theBuffer;
// Resize the buffer appropriately...
theBuffer.resize(theLength);
#if U_SIZEOF_WCHAR_T==2
doCopyData(theString, theLength, (XalanDOMChar*)&theBuffer[0]);
#else
doCopyData(theString, theLength, &theBuffer[0]);
#endif
assert(theLength == theBuffer.size());
return UnicodeString(&theBuffer[0], theLength);
}
#else
return UnicodeString(theString, length(theString));
#endif
}
}
const UnicodeString
ICUBridge::XalanDOMStringToUnicodeString(const XalanDOMString& theString)
{
// Just call up to the XalanDOMChar* version...
return XalanDOMCharStringToUnicodeString(c_wstr(theString));
}
const XalanDOMString
ICUBridge::UnicodeStringToXalanDOMString(const UnicodeString& theString)
{
const int32_t theLength = theString.length();
#if defined(XALAN_XALANDOMCHAR_USHORT_MISMATCH)
// If XalanDOMChar is larger than the ICU's UChar, we have to more work...
// Create a buffer...
XalanDOMCharVectorType theBuffer;
// Reserve the appropriate amount of space...
theBuffer.reserve(theLength);
// Copy the data...
for (int32_t i = 0; i < theLength; ++i)
{
theBuffer.push_back(theString[i]);
}
return XalanDOMString(&theBuffer[0], theBuffer.size());
#else
if (theStackBufferSize > theLength)
{
UChar theBuffer[theStackBufferSize];
// Extract the data...
theString.extract(0, theLength, theBuffer);
return XalanDOMString(theBuffer, theLength);
}
else
{
// Create a buffer to copy out the UnicodeString data...
UCharVectorType theBuffer;
// Resize the buffer appropriately...
theBuffer.resize(theLength);
// Extract the data...
theString.extract(0, theLength, &theBuffer[0]);
assert(theLength == int32_t(theBuffer.size()));
return XalanDOMString(&theBuffer[0], theLength);
}
#endif
}
void
ICUBridge::UnicodeStringToXalanDOMString(
const UnicodeString& theString,
XalanDOMString& theResult)
{
#if defined(XALAN_XALANDOMCHAR_USHORT_MISMATCH)
// If XalanDOMChar is larger than the ICU's UChar, we have to more work.
// Don't bother to provide the optimized version, just call to the
// previous function.
theResult = UnicodeStringToXalanDOMString(theString);
#else
const int32_t theLength = theString.length();
if (theStackBufferSize > theLength)
{
UChar theBuffer[theStackBufferSize];
// Extract the data...
theString.extract(0, theLength, theBuffer);
theResult = XalanDOMString(theBuffer, theLength);
}
else
{
#if defined(XALAN_NO_NAMESPACES)
typedef vector<UChar> UCharVectorType;
#else
typedef std::vector<UChar> UCharVectorType;
#endif
// Create a buffer to copy out the UnicodeString data...
UCharVectorType theBuffer;
// Resize the buffer appropriately...
theBuffer.resize(theLength);
// Extract the data...
theString.extract(0, theLength, &theBuffer[0]);
theResult = XalanDOMString(&theBuffer[0], theBuffer.size());
}
#endif
}
static void
doFormatNumber(
const XalanDOMString& thePattern,
double theNumber,
const XalanDecimalFormatSymbols& theXalanDFS,
UErrorCode& theStatus,
XalanDOMString& theResult)
{
if (theStatus == U_ZERO_ERROR ||
theStatus == U_USING_DEFAULT_ERROR)
{
// Use a XalanAutoPtr, to keep this safe until we construct the DecimalFormat instance.
XalanAutoPtr<DecimalFormatSymbols> theDFS(new DecimalFormatSymbols(theStatus));
// We got a XalanDecimalFormatSymbols, so set the
// corresponding data in the ICU DecimalFormatSymbols.
theDFS->setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, UChar(theXalanDFS.getZeroDigit()));
theDFS->setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, UChar(theXalanDFS.getGroupingSeparator()));
theDFS->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, UChar(theXalanDFS.getDecimalSeparator()));
theDFS->setSymbol(DecimalFormatSymbols::kPerMillSymbol, UChar(theXalanDFS.getPerMill()));
theDFS->setSymbol(DecimalFormatSymbols::kPercentSymbol, UChar(theXalanDFS.getPercent()));
theDFS->setSymbol(DecimalFormatSymbols::kDigitSymbol, UChar(theXalanDFS.getDigit()));
theDFS->setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, UChar(theXalanDFS.getPatternSeparator()));
theDFS->setSymbol(DecimalFormatSymbols::kInfinitySymbol, ICUBridge::XalanDOMStringToUnicodeString(theXalanDFS.getInfinity()));
theDFS->setSymbol(DecimalFormatSymbols::kNaNSymbol, ICUBridge::XalanDOMStringToUnicodeString(theXalanDFS.getNaN()));
theDFS->setSymbol(DecimalFormatSymbols::kMinusSignSymbol, UChar(theXalanDFS.getMinusSign()));
theDFS->setSymbol(DecimalFormatSymbols::kCurrencySymbol, ICUBridge::XalanDOMStringToUnicodeString(theXalanDFS.getCurrencySymbol()));
theDFS->setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, ICUBridge::XalanDOMStringToUnicodeString(theXalanDFS.getInternationalCurrencySymbol()));
theDFS->setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, UChar(theXalanDFS.getMonetaryDecimalSeparator()));
UnicodeString theUnicodeResult;
// Construct a DecimalFormat. Note that we release the XalanAutoPtr, since the
// DecimalFormat will adopt the DecimalFormatSymbols instance.
DecimalFormat theFormatter(ICUBridge::XalanDOMStringToUnicodeString(thePattern), theDFS.release(), theStatus);
if (theStatus == U_ZERO_ERROR ||
(theStatus >= U_ERROR_INFO_START && theStatus < U_ERROR_INFO_LIMIT))
{
// Do the format...
theFormatter.format(theNumber, theUnicodeResult);
ICUBridge::UnicodeStringToXalanDOMString(theUnicodeResult, theResult);
theStatus = U_ZERO_ERROR;
}
}
}
unsigned long
ICUBridge::FormatNumber(
const XalanDOMString& thePattern,
double theNumber,
const XalanDecimalFormatSymbols* theXalanDFS,
XalanDOMString& theResult)
{
UErrorCode theStatus = U_ZERO_ERROR;
if (theXalanDFS == 0)
{
XalanDecimalFormatSymbols theDefaultSymbols;
doFormatNumber(
thePattern,
theNumber,
theDefaultSymbols,
theStatus,
theResult);
}
else
{
doFormatNumber(
thePattern,
theNumber,
*theXalanDFS,
theStatus,
theResult);
}
return theStatus;
}
int
ICUBridge::collationCompare(
const XalanDOMString& theLHS,
const XalanDOMString& theRHS)
{
// Just call to the XalanDOMChar* version...
return collationCompare(c_wstr(theLHS), c_wstr(theRHS));
}
int
ICUBridge::collationCompare(
const XalanDOMChar* theLHS,
const XalanDOMChar* theRHS)
{
UErrorCode theStatus = U_ZERO_ERROR;
// Create a collator, and keep it in an XalanAutoPtr...
const XalanAutoPtr<Collator> theCollator(Collator::createInstance(theStatus));
if (theStatus == U_ZERO_ERROR || theStatus == U_USING_DEFAULT_ERROR)
{
// OK, do the compare...
return theCollator->compare(
#if defined(XALAN_XALANDOMCHAR_USHORT_MISMATCH)
ICUBridge::XalanDOMCharStringToUnicodeString(theLHS),
ICUBridge::XalanDOMCharStringToUnicodeString(theRHS));
#else
theLHS,
length(theLHS),
theRHS,
length(theRHS));
#endif
}
else
{
// If creating the ICU Collator failed, fall back to the default...
return collationCompare(theLHS, theRHS);
}
}