summaryrefslogtreecommitdiff
path: root/sax/source/tools
diff options
context:
space:
mode:
Diffstat (limited to 'sax/source/tools')
-rw-r--r--sax/source/tools/converter.cxx1901
-rw-r--r--sax/source/tools/fastattribs.cxx171
-rw-r--r--sax/source/tools/fastserializer.cxx531
-rw-r--r--sax/source/tools/fastserializer.hxx207
-rw-r--r--sax/source/tools/fshelper.cxx202
-rw-r--r--sax/source/tools/makefile.mk67
6 files changed, 3079 insertions, 0 deletions
diff --git a/sax/source/tools/converter.cxx b/sax/source/tools/converter.cxx
new file mode 100644
index 000000000000..efa9f1687d7f
--- /dev/null
+++ b/sax/source/tools/converter.cxx
@@ -0,0 +1,1901 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+#include <com/sun/star/i18n/UnicodeType.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Duration.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <rtl/ustrbuf.hxx>
+#include <rtl/math.hxx>
+#include "sax/tools/converter.hxx"
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::util;
+using namespace ::com::sun::star::i18n;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+namespace sax {
+
+static const sal_Char* gpsMM = "mm";
+static const sal_Char* gpsCM = "cm";
+static const sal_Char* gpsPT = "pt";
+static const sal_Char* gpsINCH = "in";
+static const sal_Char* gpsPC = "pc";
+
+const sal_Int8 XML_MAXDIGITSCOUNT_TIME = 11;
+const sal_Int8 XML_MAXDIGITSCOUNT_DATETIME = 6;
+#define XML_NULLDATE "NullDate"
+
+/** convert string to measure using optional min and max values*/
+bool Converter::convertMeasure( sal_Int32& rValue,
+ const OUString& rString,
+ sal_Int16 nTargetUnit /* = MeasureUnit::MM_100TH */,
+ sal_Int32 nMin /* = SAL_MIN_INT32 */,
+ sal_Int32 nMax /* = SAL_MAX_INT32 */ )
+{
+ bool bNeg = false;
+ double nVal = 0;
+
+ sal_Int32 nPos = 0;
+ sal_Int32 nLen = rString.getLength();
+
+ // skip white space
+ while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
+ nPos++;
+
+ if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
+ {
+ bNeg = true;
+ nPos++;
+ }
+
+ // get number
+ while( nPos < nLen &&
+ sal_Unicode('0') <= rString[nPos] &&
+ sal_Unicode('9') >= rString[nPos] )
+ {
+ // TODO: check overflow!
+ nVal *= 10;
+ nVal += (rString[nPos] - sal_Unicode('0'));
+ nPos++;
+ }
+ double nDiv = 1.;
+ if( nPos < nLen && sal_Unicode('.') == rString[nPos] )
+ {
+ nPos++;
+
+ while( nPos < nLen &&
+ sal_Unicode('0') <= rString[nPos] &&
+ sal_Unicode('9') >= rString[nPos] )
+ {
+ // TODO: check overflow!
+ nDiv *= 10;
+ nVal += ( ((double)(rString[nPos] - sal_Unicode('0'))) / nDiv );
+ nPos++;
+ }
+ }
+
+ // skip white space
+ while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
+ nPos++;
+
+ if( nPos < nLen )
+ {
+
+ if( MeasureUnit::PERCENT == nTargetUnit )
+ {
+ if( sal_Unicode('%') != rString[nPos] )
+ return false;
+ }
+ else if( MeasureUnit::PIXEL == nTargetUnit )
+ {
+ if( nPos + 1 >= nLen ||
+ (sal_Unicode('p') != rString[nPos] &&
+ sal_Unicode('P') != rString[nPos])||
+ (sal_Unicode('x') != rString[nPos+1] &&
+ sal_Unicode('X') != rString[nPos+1]) )
+ return false;
+ }
+ else
+ {
+ OSL_ENSURE( MeasureUnit::TWIP == nTargetUnit || MeasureUnit::POINT == nTargetUnit ||
+ MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit, "unit is not supported");
+ const sal_Char *aCmpsL[2] = { 0, 0 };
+ const sal_Char *aCmpsU[2] = { 0, 0 };
+ double aScales[2] = { 1., 1. };
+
+ if( MeasureUnit::TWIP == nTargetUnit )
+ {
+ switch( rString[nPos] )
+ {
+ case sal_Unicode('c'):
+ case sal_Unicode('C'):
+ aCmpsL[0] = "cm";
+ aCmpsU[0] = "CM";
+ aScales[0] = (72.*20.)/2.54; // twip
+ break;
+ case sal_Unicode('i'):
+ case sal_Unicode('I'):
+ aCmpsL[0] = "in";
+ aCmpsU[0] = "IN";
+ aScales[0] = 72.*20.; // twip
+ break;
+ case sal_Unicode('m'):
+ case sal_Unicode('M'):
+ aCmpsL[0] = "mm";
+ aCmpsU[0] = "MM";
+ aScales[0] = (72.*20.)/25.4; // twip
+ break;
+ case sal_Unicode('p'):
+ case sal_Unicode('P'):
+ aCmpsL[0] = "pt";
+ aCmpsU[0] = "PT";
+ aScales[0] = 20.; // twip
+
+ aCmpsL[1] = "pc";
+ aCmpsU[1] = "PC";
+ aScales[1] = 12.*20.; // twip
+ break;
+ }
+ }
+ else if( MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit )
+ {
+ double nScaleFactor = (MeasureUnit::MM_100TH == nTargetUnit) ? 100.0 : 10.0;
+ switch( rString[nPos] )
+ {
+ case sal_Unicode('c'):
+ case sal_Unicode('C'):
+ aCmpsL[0] = "cm";
+ aCmpsU[0] = "CM";
+ aScales[0] = 10.0 * nScaleFactor; // mm/100
+ break;
+ case sal_Unicode('i'):
+ case sal_Unicode('I'):
+ aCmpsL[0] = "in";
+ aCmpsU[0] = "IN";
+ aScales[0] = 1000.*2.54; // mm/100
+ break;
+ case sal_Unicode('m'):
+ case sal_Unicode('M'):
+ aCmpsL[0] = "mm";
+ aCmpsU[0] = "MM";
+ aScales[0] = 1.0 * nScaleFactor; // mm/100
+ break;
+ case sal_Unicode('p'):
+ case sal_Unicode('P'):
+ aCmpsL[0] = "pt";
+ aCmpsU[0] = "PT";
+ aScales[0] = (10.0 * nScaleFactor*2.54)/72.; // mm/100
+
+ aCmpsL[1] = "pc";
+ aCmpsU[1] = "PC";
+ aScales[1] = (10.0 * nScaleFactor*2.54)/12.; // mm/100
+ break;
+ }
+ }
+ else if( MeasureUnit::POINT == nTargetUnit )
+ {
+ if( rString[nPos] == 'p' || rString[nPos] == 'P' )
+ {
+ aCmpsL[0] = "pt";
+ aCmpsU[0] = "PT";
+ aScales[0] = 1;
+ }
+ }
+
+ if( aCmpsL[0] == NULL )
+ return false;
+
+ double nScale = 0.;
+ for( sal_uInt16 i= 0; i < 2; i++ )
+ {
+ const sal_Char *pL = aCmpsL[i];
+ if( pL )
+ {
+ const sal_Char *pU = aCmpsU[i];
+ while( nPos < nLen && *pL )
+ {
+ sal_Unicode c = rString[nPos];
+ if( c != *pL && c != *pU )
+ break;
+ pL++;
+ pU++;
+ nPos++;
+ }
+ if( !*pL && (nPos == nLen || ' ' == rString[nPos]) )
+ {
+ nScale = aScales[i];
+ break;
+ }
+ }
+ }
+
+ if( 0. == nScale )
+ return false;
+
+ // TODO: check overflow
+ if( nScale != 1. )
+ nVal *= nScale;
+ }
+ }
+
+ nVal += .5;
+ if( bNeg )
+ nVal = -nVal;
+
+ if( nVal <= (double)nMin )
+ rValue = nMin;
+ else if( nVal >= (double)nMax )
+ rValue = nMax;
+ else
+ rValue = (sal_Int32)nVal;
+
+ return true;
+}
+
+/** convert measure in given unit to string with given unit */
+void Converter::convertMeasure( OUStringBuffer& rBuffer,
+ sal_Int32 nMeasure,
+ sal_Int16 nSourceUnit /* = MeasureUnit::MM_100TH */,
+ sal_Int16 nTargetUnit /* = MeasureUnit::INCH */ )
+{
+ OSL_FAIL( "Converter::convertMeasure - not implemented, tools/BigInt needs replacement" );
+ (void)rBuffer;
+ (void)nMeasure;
+ (void)nSourceUnit;
+ (void)nTargetUnit;
+}
+
+static const OUString& getTrueString()
+{
+ static const OUString sTrue( RTL_CONSTASCII_USTRINGPARAM( "true" ) );
+ return sTrue;
+}
+
+static const OUString& getFalseString()
+{
+ static const OUString sFalse( RTL_CONSTASCII_USTRINGPARAM( "false" ) );
+ return sFalse;
+}
+
+/** convert string to boolean */
+bool Converter::convertBool( bool& rBool, const OUString& rString )
+{
+ rBool = rString == getTrueString();
+
+ return rBool || (rString == getFalseString());
+}
+
+/** convert boolean to string */
+void Converter::convertBool( OUStringBuffer& rBuffer, bool bValue )
+{
+ rBuffer.append( bValue ? getTrueString() : getFalseString() );
+}
+
+/** convert string to percent */
+bool Converter::convertPercent( sal_Int32& rPercent, const OUString& rString )
+{
+ return convertMeasure( rPercent, rString, MeasureUnit::PERCENT );
+}
+
+/** convert percent to string */
+void Converter::convertPercent( OUStringBuffer& rBuffer, sal_Int32 nValue )
+{
+ rBuffer.append( nValue );
+ rBuffer.append( sal_Unicode('%' ) );
+}
+
+/** convert string to pixel measure */
+bool Converter::convertMeasurePx( sal_Int32& rPixel, const OUString& rString )
+{
+ return convertMeasure( rPixel, rString, MeasureUnit::PIXEL );
+}
+
+/** convert pixel measure to string */
+void Converter::convertMeasurePx( OUStringBuffer& rBuffer, sal_Int32 nValue )
+{
+ rBuffer.append( nValue );
+ rBuffer.append( sal_Unicode('p' ) );
+ rBuffer.append( sal_Unicode('x' ) );
+}
+
+int lcl_gethex( int nChar )
+{
+ if( nChar >= '0' && nChar <= '9' )
+ return nChar - '0';
+ else if( nChar >= 'a' && nChar <= 'f' )
+ return nChar - 'a' + 10;
+ else if( nChar >= 'A' && nChar <= 'F' )
+ return nChar - 'A' + 10;
+ else
+ return 0;
+}
+
+/** convert string to color */
+bool Converter::convertColor( sal_Int32& rColor, const OUString& rValue )
+{
+ if( rValue.getLength() != 7 || rValue[0] != '#' )
+ return false;
+
+ rColor = lcl_gethex( rValue[1] ) * 16 + lcl_gethex( rValue[2] );
+ rColor <<= 8;
+
+ rColor |= ( lcl_gethex( rValue[3] ) * 16 + lcl_gethex( rValue[4] ) );
+ rColor <<= 8;
+
+ rColor |= ( lcl_gethex( rValue[5] ) * 16 + lcl_gethex( rValue[6] ) );
+
+ return true;
+}
+
+static sal_Char aHexTab[] = "0123456789abcdef";
+
+/** convert color to string */
+void Converter::convertColor( OUStringBuffer& rBuffer, sal_Int32 nColor )
+{
+ rBuffer.append( sal_Unicode( '#' ) );
+
+ sal_uInt8 nCol = (sal_uInt8)(nColor >> 16);
+ rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
+ rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
+
+ nCol = (sal_uInt8)(nColor >> 8);
+ rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
+ rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
+
+ nCol = (sal_uInt8)nColor;
+ rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
+ rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
+}
+
+/** convert number to string */
+void Converter::convertNumber( OUStringBuffer& rBuffer, sal_Int32 nNumber )
+{
+ rBuffer.append( nNumber );
+}
+
+/** convert string to number with optional min and max values */
+bool Converter::convertNumber( sal_Int32& rValue,
+ const OUString& rString,
+ sal_Int32 nMin, sal_Int32 nMax )
+{
+ bool bNeg = false;
+ rValue = 0;
+
+ sal_Int32 nPos = 0;
+ sal_Int32 nLen = rString.getLength();
+
+ // skip white space
+ while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
+ nPos++;
+
+ if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
+ {
+ bNeg = true;
+ nPos++;
+ }
+
+ // get number
+ while( nPos < nLen &&
+ sal_Unicode('0') <= rString[nPos] &&
+ sal_Unicode('9') >= rString[nPos] )
+ {
+ // TODO: check overflow!
+ rValue *= 10;
+ rValue += (rString[nPos] - sal_Unicode('0'));
+ nPos++;
+ }
+
+ if( bNeg )
+ rValue *= -1;
+
+ if( rValue < nMin )
+ rValue = nMin;
+ else if( rValue > nMax )
+ rValue = nMax;
+
+ return nPos == nLen;
+}
+
+/** convert double number to string (using ::rtl::math) */
+void Converter::convertDouble( OUStringBuffer& rBuffer,
+ double fNumber,
+ bool bWriteUnits,
+ sal_Int16 nSourceUnit,
+ sal_Int16 nTargetUnit)
+{
+ if(MeasureUnit::PERCENT == nSourceUnit)
+ {
+ OSL_ENSURE( nTargetUnit == MeasureUnit::PERCENT, "MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
+ ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
+ if(bWriteUnits)
+ rBuffer.append(sal_Unicode('%'));
+ }
+ else
+ {
+ OUStringBuffer sUnit;
+ double fFactor = GetConversionFactor(sUnit, nSourceUnit, nTargetUnit);
+ if(fFactor != 1.0)
+ fNumber *= fFactor;
+ ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
+ if(bWriteUnits)
+ rBuffer.append(sUnit);
+ }
+}
+
+/** convert double number to string (using ::rtl::math) */
+void Converter::convertDouble( ::rtl::OUStringBuffer& rBuffer, double fNumber)
+{
+ ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
+}
+
+/** convert string to double number (using ::rtl::math) */
+bool Converter::convertDouble(double& rValue,
+ const ::rtl::OUString& rString, sal_Int16 nTargetUnit)
+{
+ sal_Int16 nSourceUnit = GetUnitFromString(rString, nTargetUnit);
+
+ return convertDouble(rValue, rString, nSourceUnit, nTargetUnit );
+}
+
+/** convert string to double number (using ::rtl::math) */
+bool Converter::convertDouble(double& rValue,
+ const ::rtl::OUString& rString, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
+{
+ rtl_math_ConversionStatus eStatus;
+ rValue = ::rtl::math::stringToDouble( rString, (sal_Unicode)('.'), (sal_Unicode)(','), &eStatus, NULL );
+
+ if(eStatus == rtl_math_ConversionStatus_Ok)
+ {
+ OUStringBuffer sUnit;
+ double fFactor = GetConversionFactor(sUnit, nSourceUnit, nTargetUnit);
+ if(fFactor != 1.0 && fFactor != 0.0)
+ rValue /= fFactor;
+ }
+
+ return ( eStatus == rtl_math_ConversionStatus_Ok );
+}
+
+/** convert string to double number (using ::rtl::math) */
+bool Converter::convertDouble(double& rValue, const ::rtl::OUString& rString)
+{
+ rtl_math_ConversionStatus eStatus;
+ rValue = ::rtl::math::stringToDouble( rString, (sal_Unicode)('.'), (sal_Unicode)(','), &eStatus, NULL );
+ return ( eStatus == rtl_math_ConversionStatus_Ok );
+}
+
+/** convert double to ISO "duration" string; negative durations allowed */
+void Converter::convertDuration(::rtl::OUStringBuffer& rBuffer,
+ const double fTime)
+{
+ double fValue = fTime;
+
+ // take care of negative durations as specified in:
+ // XML Schema, W3C Working Draft 07 April 2000, section 3.2.6.1
+ if (fValue < 0.0)
+ {
+ rBuffer.append(sal_Unicode('-'));
+ fValue = - fValue;
+ }
+
+ rBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM( "PT" ));
+ fValue *= 24;
+ double fHoursValue = ::rtl::math::approxFloor (fValue);
+ fValue -= fHoursValue;
+ fValue *= 60;
+ double fMinsValue = ::rtl::math::approxFloor (fValue);
+ fValue -= fMinsValue;
+ fValue *= 60;
+ double fSecsValue = ::rtl::math::approxFloor (fValue);
+ fValue -= fSecsValue;
+ double f100SecsValue;
+ if (fValue > 0.00001)
+ f100SecsValue = ::rtl::math::round( fValue, XML_MAXDIGITSCOUNT_TIME - 5);
+ else
+ f100SecsValue = 0.0;
+
+ if (f100SecsValue == 1.0)
+ {
+ f100SecsValue = 0.0;
+ fSecsValue += 1.0;
+ }
+ if (fSecsValue >= 60.0)
+ {
+ fSecsValue -= 60.0;
+ fMinsValue += 1.0;
+ }
+ if (fMinsValue >= 60.0)
+ {
+ fMinsValue -= 60.0;
+ fHoursValue += 1.0;
+ }
+
+ if (fHoursValue < 10)
+ rBuffer.append( sal_Unicode('0'));
+ rBuffer.append( sal_Int32( fHoursValue));
+ rBuffer.append( sal_Unicode('H'));
+ if (fMinsValue < 10)
+ rBuffer.append( sal_Unicode('0'));
+ rBuffer.append( sal_Int32( fMinsValue));
+ rBuffer.append( sal_Unicode('M'));
+ if (fSecsValue < 10)
+ rBuffer.append( sal_Unicode('0'));
+ rBuffer.append( sal_Int32( fSecsValue));
+ if (f100SecsValue > 0.0)
+ {
+ ::rtl::OUString a100th( ::rtl::math::doubleToUString( fValue,
+ rtl_math_StringFormat_F, XML_MAXDIGITSCOUNT_TIME - 5, '.',
+ true));
+ if ( a100th.getLength() > 2 )
+ {
+ rBuffer.append( sal_Unicode('.'));
+ rBuffer.append( a100th.copy( 2 ) ); // strip 0.
+ }
+ }
+ rBuffer.append( sal_Unicode('S'));
+}
+
+/** convert ISO "duration" string to double; negative durations allowed */
+bool Converter::convertDuration(double& rfTime,
+ const ::rtl::OUString& rString)
+{
+ rtl::OUString aTrimmed = rString.trim().toAsciiUpperCase();
+ const sal_Unicode* pStr = aTrimmed.getStr();
+
+ // negative time duration?
+ bool bIsNegativeDuration = false;
+ if ( sal_Unicode('-') == (*pStr) )
+ {
+ bIsNegativeDuration = true;
+ pStr++;
+ }
+
+ if ( *(pStr++) != sal_Unicode('P') ) // duration must start with "P"
+ return false;
+
+ rtl::OUString sDoubleStr;
+ bool bSuccess = true;
+ bool bDone = false;
+ bool bTimePart = false;
+ bool bIsFraction = false;
+ sal_Int32 nDays = 0;
+ sal_Int32 nHours = 0;
+ sal_Int32 nMins = 0;
+ sal_Int32 nSecs = 0;
+ sal_Int32 nTemp = 0;
+
+ while ( bSuccess && !bDone )
+ {
+ sal_Unicode c = *(pStr++);
+ if ( !c ) // end
+ bDone = true;
+ else if ( sal_Unicode('0') <= c && sal_Unicode('9') >= c )
+ {
+ if ( nTemp >= SAL_MAX_INT32 / 10 )
+ bSuccess = false;
+ else
+ {
+ if ( !bIsFraction )
+ {
+ nTemp *= 10;
+ nTemp += (c - sal_Unicode('0'));
+ }
+ else
+ {
+ sDoubleStr += OUString::valueOf(c);
+ }
+ }
+ }
+ else if ( bTimePart )
+ {
+ if ( c == sal_Unicode('H') )
+ {
+ nHours = nTemp;
+ nTemp = 0;
+ }
+ else if ( c == sal_Unicode('M') )
+ {
+ nMins = nTemp;
+ nTemp = 0;
+ }
+ else if ( (c == sal_Unicode(',')) || (c == sal_Unicode('.')) )
+ {
+ nSecs = nTemp;
+ nTemp = 0;
+ bIsFraction = true;
+ sDoubleStr = OUString(RTL_CONSTASCII_USTRINGPARAM("0."));
+ }
+ else if ( c == sal_Unicode('S') )
+ {
+ if ( !bIsFraction )
+ {
+ nSecs = nTemp;
+ nTemp = 0;
+ sDoubleStr = OUString(RTL_CONSTASCII_USTRINGPARAM("0.0"));
+ }
+ }
+ else
+ bSuccess = false; // invalid character
+ }
+ else
+ {
+ if ( c == sal_Unicode('T') ) // "T" starts time part
+ bTimePart = true;
+ else if ( c == sal_Unicode('D') )
+ {
+ nDays = nTemp;
+ nTemp = 0;
+ }
+ else if ( c == sal_Unicode('Y') || c == sal_Unicode('M') )
+ {
+ //! how many days is a year or month?
+
+ OSL_FAIL( "years or months in duration: not implemented");
+ bSuccess = false;
+ }
+ else
+ bSuccess = false; // invalid character
+ }
+ }
+
+ if ( bSuccess )
+ {
+ if ( nDays )
+ nHours += nDays * 24; // add the days to the hours part
+ double fTempTime = 0.0;
+ double fHour = nHours;
+ double fMin = nMins;
+ double fSec = nSecs;
+ double fSec100 = 0.0;
+ double fFraction = sDoubleStr.toDouble();
+ fTempTime = fHour / 24;
+ fTempTime += fMin / (24 * 60);
+ fTempTime += fSec / (24 * 60 * 60);
+ fTempTime += fSec100 / (24 * 60 * 60 * 60);
+ fTempTime += fFraction / (24 * 60 * 60);
+
+ // negative duration?
+ if ( bIsNegativeDuration )
+ {
+ fTempTime = -fTempTime;
+ }
+
+ rfTime = fTempTime;
+ }
+ return bSuccess;
+}
+
+/** convert util::Duration to ISO "duration" string */
+void Converter::convertDuration(::rtl::OUStringBuffer& rBuffer,
+ const ::util::Duration& rDuration)
+{
+ if (rDuration.Negative)
+ {
+ rBuffer.append(sal_Unicode('-'));
+ }
+ rBuffer.append(sal_Unicode('P'));
+ const bool bHaveDate(static_cast<sal_Int32>(rDuration.Years)
+ +static_cast<sal_Int32>(rDuration.Months)
+ +static_cast<sal_Int32>(rDuration.Days));
+ if (rDuration.Years)
+ {
+ rBuffer.append(static_cast<sal_Int32>(rDuration.Years));
+ rBuffer.append(sal_Unicode('Y'));
+ }
+ if (rDuration.Months)
+ {
+ rBuffer.append(static_cast<sal_Int32>(rDuration.Months));
+ rBuffer.append(sal_Unicode('M'));
+ }
+ if (rDuration.Days)
+ {
+ rBuffer.append(static_cast<sal_Int32>(rDuration.Days));
+ rBuffer.append(sal_Unicode('D'));
+ }
+ const sal_Int32 nMSecs(static_cast<sal_Int32>(rDuration.Seconds)
+ + static_cast<sal_Int32>(rDuration.MilliSeconds));
+ if (static_cast<sal_Int32>(rDuration.Hours) +
+ static_cast<sal_Int32>(rDuration.Minutes) + nMSecs)
+ {
+ rBuffer.append(sal_Unicode('T')); // time separator
+ if (rDuration.Hours)
+ {
+ rBuffer.append(static_cast<sal_Int32>(rDuration.Hours));
+ rBuffer.append(sal_Unicode('H'));
+ }
+ if (rDuration.Minutes)
+ {
+ rBuffer.append(static_cast<sal_Int32>(rDuration.Minutes));
+ rBuffer.append(sal_Unicode('M'));
+ }
+ if (nMSecs)
+ {
+ // seconds must not be omitted (i.e. ".42S" is not valid)
+ rBuffer.append(static_cast<sal_Int32>(rDuration.Seconds));
+ if (rDuration.MilliSeconds)
+ {
+ rBuffer.append(sal_Unicode('.'));
+ const sal_Int32 nMilliSeconds(rDuration.MilliSeconds % 1000);
+ if (nMilliSeconds < 100)
+ {
+ rBuffer.append(sal_Unicode('0'));
+ }
+ if (nMilliSeconds < 10)
+ {
+ rBuffer.append(sal_Unicode('0'));
+ }
+ if (0 == (nMilliSeconds % 10))
+ {
+ if (0 == (nMilliSeconds % 100))
+ {
+ rBuffer.append(nMilliSeconds / 100);
+ }
+ else
+ {
+ rBuffer.append(nMilliSeconds / 10);
+ }
+ }
+ else
+ {
+ rBuffer.append(nMilliSeconds);
+ }
+ }
+ rBuffer.append(sal_Unicode('S'));
+ }
+ }
+ else if (!bHaveDate)
+ {
+ // zero duration: XMLSchema-2 says there must be at least one component
+ rBuffer.append(sal_Unicode('0'));
+ rBuffer.append(sal_Unicode('D'));
+ }
+}
+
+enum Result { R_NOTHING, R_OVERFLOW, R_SUCCESS };
+
+static Result
+readUnsignedNumber(const ::rtl::OUString & rString,
+ sal_Int32 & io_rnPos, sal_Int32 & o_rNumber)
+{
+ bool bOverflow(false);
+ sal_Int32 nTemp(0);
+ sal_Int32 nPos(io_rnPos);
+
+ while (nPos < rString.getLength())
+ {
+ const sal_Unicode c = rString[nPos];
+ if ((sal_Unicode('0') <= c) && (c <= sal_Unicode('9')))
+ {
+ nTemp *= 10;
+ nTemp += (c - sal_Unicode('0'));
+ if (nTemp >= SAL_MAX_INT16)
+ {
+ bOverflow = true;
+ }
+ }
+ else
+ {
+ break;
+ }
+ ++nPos;
+ }
+
+ if (io_rnPos == nPos) // read something?
+ {
+ o_rNumber = -1;
+ return R_NOTHING;
+ }
+
+ io_rnPos = nPos;
+ o_rNumber = nTemp;
+ return (bOverflow) ? R_OVERFLOW : R_SUCCESS;
+}
+
+static bool
+readDurationT(const ::rtl::OUString & rString, sal_Int32 & io_rnPos)
+{
+ if ((io_rnPos < rString.getLength()) &&
+ (rString[io_rnPos] == sal_Unicode('T')))
+ {
+ ++io_rnPos;
+ return true;
+ }
+ return false;
+}
+
+static bool
+readDurationComponent(const ::rtl::OUString & rString,
+ sal_Int32 & io_rnPos, sal_Int32 & io_rnTemp, bool & io_rbTimePart,
+ sal_Int32 & o_rnTarget, const sal_Unicode c)
+{
+ if ((io_rnPos < rString.getLength()))
+ {
+ if (c == rString[io_rnPos])
+ {
+ ++io_rnPos;
+ if (-1 != io_rnTemp)
+ {
+ o_rnTarget = io_rnTemp;
+ io_rnTemp = -1;
+ if (!io_rbTimePart)
+ {
+ io_rbTimePart = readDurationT(rString, io_rnPos);
+ }
+ return (R_OVERFLOW !=
+ readUnsignedNumber(rString, io_rnPos, io_rnTemp));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/** convert ISO "duration" string to util::Duration */
+bool Converter::convertDuration(util::Duration& rDuration,
+ const ::rtl::OUString& rString)
+{
+ const ::rtl::OUString string = rString.trim().toAsciiUpperCase();
+ sal_Int32 nPos(0);
+
+ bool bIsNegativeDuration(false);
+ if (string.getLength() && (sal_Unicode('-') == string[0]))
+ {
+ bIsNegativeDuration = true;
+ ++nPos;
+ }
+
+ if ((nPos < string.getLength())
+ && (string[nPos] != sal_Unicode('P'))) // duration must start with "P"
+ {
+ return false;
+ }
+
+ ++nPos;
+
+ /// last read number; -1 == no valid number! always reset after using!
+ sal_Int32 nTemp(-1);
+ bool bTimePart(false); // have we read 'T'?
+ bool bSuccess(false);
+ sal_Int32 nYears(0);
+ sal_Int32 nMonths(0);
+ sal_Int32 nDays(0);
+ sal_Int32 nHours(0);
+ sal_Int32 nMinutes(0);
+ sal_Int32 nSeconds(0);
+ sal_Int32 nMilliSeconds(0);
+
+ bTimePart = readDurationT(string, nPos);
+ bSuccess = (R_SUCCESS == readUnsignedNumber(string, nPos, nTemp));
+
+ if (!bTimePart && bSuccess)
+ {
+ bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
+ nYears, sal_Unicode('Y'));
+ }
+
+ if (!bTimePart && bSuccess)
+ {
+ bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
+ nMonths, sal_Unicode('M'));
+ }
+
+ if (!bTimePart && bSuccess)
+ {
+ bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
+ nDays, sal_Unicode('D'));
+ }
+
+ if (bTimePart)
+ {
+ if (-1 == nTemp) // a 'T' must be followed by a component
+ {
+ bSuccess = false;
+ }
+
+ if (bSuccess)
+ {
+ bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
+ nHours, sal_Unicode('H'));
+ }
+
+ if (bSuccess)
+ {
+ bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
+ nMinutes, sal_Unicode('M'));
+ }
+
+ // eeek! seconds are icky.
+ if ((nPos < string.getLength()) && bSuccess)
+ {
+ if (sal_Unicode('.') == string[nPos])
+ {
+ ++nPos;
+ if (-1 != nTemp)
+ {
+ nSeconds = nTemp;
+ nTemp = -1;
+ const sal_Int32 nStart(nPos);
+ bSuccess =
+ (R_NOTHING != readUnsignedNumber(string, nPos, nTemp));
+ if ((nPos < string.getLength()) && bSuccess)
+ {
+ if (-1 != nTemp)
+ {
+ nTemp = -1;
+ const sal_Int32 nDigits = nPos - nStart;
+ OSL_ENSURE(nDigits > 0, "bad code monkey");
+ const sal_Unicode cZero('0');
+ nMilliSeconds = 100 * (string[nStart] - cZero);
+ if (nDigits >= 2)
+ {
+ nMilliSeconds += 10 *
+ (string[nStart+1] - cZero);
+ if (nDigits >= 3)
+ {
+ nMilliSeconds += (string[nStart+2] - cZero);
+ }
+ }
+
+ if (sal_Unicode('S') == string[nPos])
+ {
+ ++nPos;
+ }
+ else
+ {
+ bSuccess = false;
+ }
+ }
+ else
+ {
+ bSuccess = false;
+ }
+ }
+ }
+ else
+ {
+ bSuccess = false;
+ }
+ }
+ else if (sal_Unicode('S') == string[nPos])
+ {
+ ++nPos;
+ if (-1 != nTemp)
+ {
+ nSeconds = nTemp;
+ nTemp = -1;
+ }
+ else
+ {
+ bSuccess = false;
+ }
+ }
+ }
+ }
+
+ if (nPos != string.getLength()) // string not processed completely?
+ {
+ bSuccess = false;
+ }
+
+ if (nTemp != -1) // unprocessed number?
+ {
+ bSuccess = false;
+ }
+
+ if (bSuccess)
+ {
+ rDuration.Negative = bIsNegativeDuration;
+ rDuration.Years = static_cast<sal_Int16>(nYears);
+ rDuration.Months = static_cast<sal_Int16>(nMonths);
+ rDuration.Days = static_cast<sal_Int16>(nDays);
+ rDuration.Hours = static_cast<sal_Int16>(nHours);
+ rDuration.Minutes = static_cast<sal_Int16>(nMinutes);
+ rDuration.Seconds = static_cast<sal_Int16>(nSeconds);
+ rDuration.MilliSeconds = static_cast<sal_Int16>(nMilliSeconds);
+ }
+
+ return bSuccess;
+}
+
+
+/** convert util::Date to ISO "date" string */
+void Converter::convertDate(
+ ::rtl::OUStringBuffer& i_rBuffer,
+ const util::Date& i_rDate)
+{
+ const util::DateTime dt(
+ 0, 0, 0, 0, i_rDate.Day, i_rDate.Month, i_rDate.Year);
+ convertDateTime(i_rBuffer, dt, false);
+}
+
+/** convert util::DateTime to ISO "date" or "dateTime" string */
+void Converter::convertDateTime(
+ ::rtl::OUStringBuffer& i_rBuffer,
+ const com::sun::star::util::DateTime& i_rDateTime,
+ bool i_bAddTimeIf0AM )
+{
+ const sal_Unicode dash('-');
+ const sal_Unicode col (':');
+ const sal_Unicode dot ('.');
+ const sal_Unicode zero('0');
+ const sal_Unicode tee ('T');
+
+ if (i_rDateTime.Year < 1000) {
+ i_rBuffer.append(zero);
+ }
+ if (i_rDateTime.Year < 100) {
+ i_rBuffer.append(zero);
+ }
+ if (i_rDateTime.Year < 10) {
+ i_rBuffer.append(zero);
+ }
+ i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Year) ).append(dash);
+ if( i_rDateTime.Month < 10 ) {
+ i_rBuffer.append(zero);
+ }
+ i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Month) ).append(dash);
+ if( i_rDateTime.Day < 10 ) {
+ i_rBuffer.append(zero);
+ }
+ i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Day) );
+
+ if( i_rDateTime.Seconds != 0 ||
+ i_rDateTime.Minutes != 0 ||
+ i_rDateTime.Hours != 0 ||
+ i_bAddTimeIf0AM )
+ {
+ i_rBuffer.append(tee);
+ if( i_rDateTime.Hours < 10 ) {
+ i_rBuffer.append(zero);
+ }
+ i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Hours) )
+ .append(col);
+ if( i_rDateTime.Minutes < 10 ) {
+ i_rBuffer.append(zero);
+ }
+ i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Minutes) )
+ .append(col);
+ if( i_rDateTime.Seconds < 10 ) {
+ i_rBuffer.append(zero);
+ }
+ i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Seconds) );
+ if( i_rDateTime.HundredthSeconds > 0 ) {
+ i_rBuffer.append(dot);
+ if( i_rDateTime.HundredthSeconds < 10 ) {
+ i_rBuffer.append(zero);
+ }
+ i_rBuffer.append(
+ static_cast<sal_Int32>(i_rDateTime.HundredthSeconds) );
+ }
+ }
+}
+
+/** convert ISO "date" or "dateTime" string to util::DateTime */
+bool Converter::convertDateTime( util::DateTime& rDateTime,
+ const ::rtl::OUString& rString )
+{
+ bool isDateTime;
+ util::Date date;
+ if (convertDateOrDateTime(date, rDateTime, isDateTime, rString))
+ {
+ if (!isDateTime)
+ {
+ rDateTime.Year = date.Year;
+ rDateTime.Month = date.Month;
+ rDateTime.Day = date.Day;
+ rDateTime.Hours = 0;
+ rDateTime.Minutes = 0;
+ rDateTime.Seconds = 0;
+ rDateTime.HundredthSeconds = 0;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+static bool
+readDateTimeComponent(const ::rtl::OUString & rString,
+ sal_Int32 & io_rnPos, sal_Int32 & o_rnTarget,
+ const sal_Int32 nMinLength, const bool bExactLength)
+{
+ const sal_Int32 nOldPos(io_rnPos);
+ sal_Int32 nTemp(0);
+ if (R_SUCCESS != readUnsignedNumber(rString, io_rnPos, nTemp))
+ {
+ return false;
+ }
+ const sal_Int32 nTokenLength(io_rnPos - nOldPos);
+ if ((nTokenLength < nMinLength) ||
+ (bExactLength && (nTokenLength > nMinLength)))
+ {
+ return false; // bad length
+ }
+ o_rnTarget = nTemp;
+ return true;
+}
+
+static bool lcl_isLeapYear(const sal_uInt32 nYear)
+{
+ return ((nYear % 4) == 0)
+ && !(((nYear % 100) == 0) || ((nYear % 400) == 0));
+}
+
+static sal_uInt16
+lcl_MaxDaysPerMonth(const sal_Int32 nMonth, const sal_Int32 nYear)
+{
+ static sal_uInt16 s_MaxDaysPerMonth[12] =
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ OSL_ASSERT(0 < nMonth && nMonth <= 12);
+ if ((2 == nMonth) && lcl_isLeapYear(nYear))
+ {
+ return 29;
+ }
+ return s_MaxDaysPerMonth[nMonth - 1];
+}
+
+/** convert ISO "date" or "dateTime" string to util::DateTime or util::Date */
+bool Converter::convertDateOrDateTime(
+ util::Date & rDate, util::DateTime & rDateTime,
+ bool & rbDateTime, const ::rtl::OUString & rString )
+{
+ bool bSuccess = true;
+
+ const ::rtl::OUString string = rString.trim().toAsciiUpperCase();
+ sal_Int32 nPos(0);
+ if ((string.getLength() > nPos) && (sal_Unicode('-') == string[nPos]))
+ {
+ //Negative Number
+ ++nPos;
+ }
+
+ sal_Int32 nYear(0);
+ {
+ bSuccess = readDateTimeComponent(string, nPos, nYear, 4, false);
+ bSuccess &= (0 < nYear);
+ bSuccess &= (nPos < string.getLength()); // not last token
+ }
+ if (bSuccess && (sal_Unicode('-') != string[nPos])) // separator
+ {
+ bSuccess = false;
+ }
+ if (bSuccess)
+ {
+ ++nPos;
+ }
+
+ sal_Int32 nMonth(0);
+ if (bSuccess)
+ {
+ bSuccess = readDateTimeComponent(string, nPos, nMonth, 2, true);
+ bSuccess &= (0 < nMonth) && (nMonth <= 12);
+ bSuccess &= (nPos < string.getLength()); // not last token
+ }
+ if (bSuccess && (sal_Unicode('-') != string[nPos])) // separator
+ {
+ bSuccess = false;
+ }
+ if (bSuccess)
+ {
+ ++nPos;
+ }
+
+ sal_Int32 nDay(0);
+ if (bSuccess)
+ {
+ bSuccess = readDateTimeComponent(string, nPos, nDay, 2, true);
+ bSuccess &= (0 < nDay) && (nDay <= lcl_MaxDaysPerMonth(nMonth, nYear));
+ }
+
+ bool bHaveTime(false);
+ if (bSuccess && (nPos < string.getLength()))
+ {
+ if (sal_Unicode('T') == string[nPos]) // time separator
+ {
+ bHaveTime = true;
+ ++nPos;
+ }
+ }
+
+ sal_Int32 nHours(0);
+ sal_Int32 nMinutes(0);
+ sal_Int32 nSeconds(0);
+ sal_Int32 nMilliSeconds(0);
+ if (bSuccess && bHaveTime)
+ {
+ {
+ bSuccess = readDateTimeComponent(string, nPos, nHours, 2, true);
+ bSuccess &= (0 <= nHours) && (nHours <= 24);
+ bSuccess &= (nPos < string.getLength()); // not last token
+ }
+ if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
+ {
+ bSuccess = false;
+ }
+ if (bSuccess)
+ {
+ ++nPos;
+ }
+
+ if (bSuccess)
+ {
+ bSuccess = readDateTimeComponent(string, nPos, nMinutes, 2, true);
+ bSuccess &= (0 <= nMinutes) && (nMinutes < 60);
+ bSuccess &= (nPos < string.getLength()); // not last token
+ }
+ if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
+ {
+ bSuccess = false;
+ }
+ if (bSuccess)
+ {
+ ++nPos;
+ }
+
+ if (bSuccess)
+ {
+ bSuccess = readDateTimeComponent(string, nPos, nSeconds, 2, true);
+ bSuccess &= (0 <= nSeconds) && (nSeconds < 60);
+ }
+ if (bSuccess && (nPos < string.getLength()) &&
+ (sal_Unicode('.') == string[nPos])) // fraction separator
+ {
+ ++nPos;
+ const sal_Int32 nStart(nPos);
+ sal_Int32 nTemp(0);
+ if (R_NOTHING == readUnsignedNumber(string, nPos, nTemp))
+ {
+ bSuccess = false;
+ }
+ if (bSuccess)
+ {
+ // cannot use nTemp because of possible leading zeros
+ // and possible overflow => read digits directly
+ const sal_Int32 nDigits(nPos - nStart);
+ OSL_ENSURE(nDigits > 0, "bad code monkey");
+ const sal_Unicode cZero('0');
+ nMilliSeconds = 100 * (string[nStart] - cZero);
+ if (nDigits >= 2)
+ {
+ nMilliSeconds += 10 * (string[nStart+1] - cZero);
+ if (nDigits >= 3)
+ {
+ nMilliSeconds += (string[nStart+2] - cZero);
+ }
+ }
+ }
+ }
+
+ if (bSuccess && (nHours == 24))
+ {
+ if (!((0 == nMinutes) && (0 == nSeconds) && (0 == nMilliSeconds)))
+ {
+ bSuccess = false; // only 24:00:00 is valid
+ }
+ }
+ }
+
+ bool bHaveTimezone(false);
+ bool bHaveTimezonePlus(false);
+ bool bHaveTimezoneMinus(false);
+ if (bSuccess && (nPos < string.getLength()))
+ {
+ const sal_Unicode c(string[nPos]);
+ if (sal_Unicode('+') == c)
+ {
+ bHaveTimezone = true;
+ bHaveTimezonePlus = true;
+ ++nPos;
+ }
+ else if (sal_Unicode('-') == c)
+ {
+ bHaveTimezone = true;
+ bHaveTimezoneMinus = true;
+ ++nPos;
+ }
+ else if (sal_Unicode('Z') == c)
+ {
+ bHaveTimezone = true;
+ ++nPos;
+ }
+ else
+ {
+ bSuccess = false;
+ }
+ }
+ sal_Int32 nTimezoneHours(0);
+ sal_Int32 nTimezoneMinutes(0);
+ if (bSuccess && (bHaveTimezonePlus || bHaveTimezoneMinus))
+ {
+ bSuccess = readDateTimeComponent(
+ string, nPos, nTimezoneHours, 2, true);
+ bSuccess &= (0 <= nTimezoneHours) && (nTimezoneHours <= 14);
+ bSuccess &= (nPos < string.getLength()); // not last token
+ if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
+ {
+ bSuccess = false;
+ }
+ if (bSuccess)
+ {
+ ++nPos;
+ }
+ if (bSuccess)
+ {
+ bSuccess = readDateTimeComponent(
+ string, nPos, nTimezoneMinutes, 2, true);
+ bSuccess &= (0 <= nTimezoneMinutes) && (nTimezoneMinutes < 60);
+ }
+ if (bSuccess && (nTimezoneHours == 14))
+ {
+ if (0 != nTimezoneMinutes)
+ {
+ bSuccess = false; // only +-14:00 is valid
+ }
+ }
+ }
+
+ bSuccess &= (nPos == string.getLength()); // trailing junk?
+
+ if (bSuccess && bHaveTimezone)
+ {
+ // util::DateTime does not support timezones!
+ }
+
+ if (bSuccess)
+ {
+ if (bHaveTime) // time is optional
+ {
+ // util::DateTime does not support negative years!
+ rDateTime.Year = static_cast<sal_uInt16>(nYear);
+ rDateTime.Month = static_cast<sal_uInt16>(nMonth);
+ rDateTime.Day = static_cast<sal_uInt16>(nDay);
+ rDateTime.Hours = static_cast<sal_uInt16>(nHours);
+ rDateTime.Minutes = static_cast<sal_uInt16>(nMinutes);
+ rDateTime.Seconds = static_cast<sal_uInt16>(nSeconds);
+ // util::DateTime does not support 3 decimal digits of precision!
+ rDateTime.HundredthSeconds =
+ static_cast<sal_uInt16>(nMilliSeconds / 10);
+ rbDateTime = true;
+ }
+ else
+ {
+ rDate.Year = static_cast<sal_uInt16>(nYear);
+ rDate.Month = static_cast<sal_uInt16>(nMonth);
+ rDate.Day = static_cast<sal_uInt16>(nDay);
+ rbDateTime = false;
+ }
+ }
+ return bSuccess;
+}
+
+
+/** gets the position of the first comma after npos in the string
+ rStr. Commas inside '"' pairs are not matched */
+sal_Int32 Converter::indexOfComma( const OUString& rStr,
+ sal_Int32 nPos )
+{
+ sal_Unicode cQuote = 0;
+ sal_Int32 nLen = rStr.getLength();
+ for( ; nPos < nLen; nPos++ )
+ {
+ sal_Unicode c = rStr[nPos];
+ switch( c )
+ {
+ case sal_Unicode('\''):
+ if( 0 == cQuote )
+ cQuote = c;
+ else if( '\'' == cQuote )
+ cQuote = 0;
+ break;
+
+ case sal_Unicode('"'):
+ if( 0 == cQuote )
+ cQuote = c;
+ else if( '\"' == cQuote )
+ cQuote = 0;
+ break;
+
+ case sal_Unicode(','):
+ if( 0 == cQuote )
+ return nPos;
+ break;
+ }
+ }
+
+ return -1;
+}
+
+const
+ sal_Char aBase64EncodeTable[] =
+ { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
+
+const
+ sal_uInt8 aBase64DecodeTable[] =
+ { 62,255,255,255, 63, // 43-47
+// + /
+
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255, // 48-63
+// 0 1 2 3 4 5 6 7 8 9 =
+
+ 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
+// A B C D E F G H I J K L M N O
+
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, // 80-95
+// P Q R S T U V W X Y Z
+
+ 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
+// a b c d e f g h i j k l m n o
+
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; // 112-123
+// p q r s t u v w x y z
+
+
+
+void ThreeByteToFourByte (const sal_Int8* pBuffer, const sal_Int32 nStart, const sal_Int32 nFullLen, rtl::OUStringBuffer& sBuffer)
+{
+ sal_Int32 nLen(nFullLen - nStart);
+ if (nLen > 3)
+ nLen = 3;
+ if (nLen == 0)
+ {
+ sBuffer.setLength(0);
+ return;
+ }
+
+ sal_Int32 nBinaer;
+ switch (nLen)
+ {
+ case 1:
+ {
+ nBinaer = ((sal_uInt8)pBuffer[nStart + 0]) << 16;
+ }
+ break;
+ case 2:
+ {
+ nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) +
+ (((sal_uInt8)pBuffer[nStart + 1]) << 8);
+ }
+ break;
+ default:
+ {
+ nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) +
+ (((sal_uInt8)pBuffer[nStart + 1]) << 8) +
+ ((sal_uInt8)pBuffer[nStart + 2]);
+ }
+ break;
+ }
+
+ sBuffer.appendAscii("====");
+
+ sal_uInt8 nIndex (static_cast<sal_uInt8>((nBinaer & 0xFC0000) >> 18));
+ sBuffer.setCharAt(0, aBase64EncodeTable [nIndex]);
+
+ nIndex = static_cast<sal_uInt8>((nBinaer & 0x3F000) >> 12);
+ sBuffer.setCharAt(1, aBase64EncodeTable [nIndex]);
+ if (nLen == 1)
+ return;
+
+ nIndex = static_cast<sal_uInt8>((nBinaer & 0xFC0) >> 6);
+ sBuffer.setCharAt(2, aBase64EncodeTable [nIndex]);
+ if (nLen == 2)
+ return;
+
+ nIndex = static_cast<sal_uInt8>((nBinaer & 0x3F));
+ sBuffer.setCharAt(3, aBase64EncodeTable [nIndex]);
+}
+
+void Converter::encodeBase64(rtl::OUStringBuffer& aStrBuffer, const uno::Sequence<sal_Int8>& aPass)
+{
+ sal_Int32 i(0);
+ sal_Int32 nBufferLength(aPass.getLength());
+ const sal_Int8* pBuffer = aPass.getConstArray();
+ while (i < nBufferLength)
+ {
+ rtl::OUStringBuffer sBuffer;
+ ThreeByteToFourByte (pBuffer, i, nBufferLength, sBuffer);
+ aStrBuffer.append(sBuffer);
+ i += 3;
+ }
+}
+
+void Converter::decodeBase64(uno::Sequence<sal_Int8>& aBuffer, const rtl::OUString& sBuffer)
+{
+#if OSL_DEBUG_LEVEL > 0
+ sal_Int32 nCharsDecoded =
+#endif
+ decodeBase64SomeChars( aBuffer, sBuffer );
+ OSL_ENSURE( nCharsDecoded == sBuffer.getLength(), "some bytes left in base64 decoding!" );
+}
+
+sal_Int32 Converter::decodeBase64SomeChars(
+ uno::Sequence<sal_Int8>& rOutBuffer,
+ const rtl::OUString& rInBuffer)
+{
+ sal_Int32 nInBufferLen = rInBuffer.getLength();
+ sal_Int32 nMinOutBufferLen = (nInBufferLen / 4) * 3;
+ if( rOutBuffer.getLength() < nMinOutBufferLen )
+ rOutBuffer.realloc( nMinOutBufferLen );
+
+ const sal_Unicode *pInBuffer = rInBuffer.getStr();
+ sal_Int8 *pOutBuffer = rOutBuffer.getArray();
+ sal_Int8 *pOutBufferStart = pOutBuffer;
+ sal_Int32 nCharsDecoded = 0;
+
+ sal_uInt8 aDecodeBuffer[4];
+ sal_Int32 nBytesToDecode = 0;
+ sal_Int32 nBytesGotFromDecoding = 3;
+ sal_Int32 nInBufferPos= 0;
+ while( nInBufferPos < nInBufferLen )
+ {
+ sal_Unicode cChar = *pInBuffer;
+ if( cChar >= '+' && cChar <= 'z' )
+ {
+ sal_uInt8 nByte = aBase64DecodeTable[cChar-'+'];
+ if( nByte != 255 )
+ {
+ // We have found a valid character!
+ aDecodeBuffer[nBytesToDecode++] = nByte;
+
+ // One '=' character at the end means 2 out bytes
+ // Two '=' characters at the end mean 1 out bytes
+ if( '=' == cChar && nBytesToDecode > 2 )
+ nBytesGotFromDecoding--;
+ if( 4 == nBytesToDecode )
+ {
+ // Four characters found, so we may convert now!
+ sal_uInt32 nOut = (aDecodeBuffer[0] << 18) +
+ (aDecodeBuffer[1] << 12) +
+ (aDecodeBuffer[2] << 6) +
+ aDecodeBuffer[3];
+
+ *pOutBuffer++ = (sal_Int8)((nOut & 0xff0000) >> 16);
+ if( nBytesGotFromDecoding > 1 )
+ *pOutBuffer++ = (sal_Int8)((nOut & 0xff00) >> 8);
+ if( nBytesGotFromDecoding > 2 )
+ *pOutBuffer++ = (sal_Int8)(nOut & 0xff);
+ nCharsDecoded = nInBufferPos + 1;
+ nBytesToDecode = 0;
+ nBytesGotFromDecoding = 3;
+ }
+ }
+ else
+ {
+ nCharsDecoded++;
+ }
+ }
+ else
+ {
+ nCharsDecoded++;
+ }
+
+ nInBufferPos++;
+ pInBuffer++;
+ }
+ if( (pOutBuffer - pOutBufferStart) != rOutBuffer.getLength() )
+ rOutBuffer.realloc( pOutBuffer - pOutBufferStart );
+
+ return nCharsDecoded;
+}
+
+void Converter::clearUndefinedChars(rtl::OUString& rTarget, const rtl::OUString& rSource)
+{
+ sal_uInt32 nLength(rSource.getLength());
+ rtl::OUStringBuffer sBuffer(nLength);
+ for (sal_uInt32 i = 0; i < nLength; i++)
+ {
+ sal_Unicode cChar = rSource[i];
+ if (!(cChar < 0x0020) ||
+ (cChar == 0x0009) || // TAB
+ (cChar == 0x000A) || // LF
+ (cChar == 0x000D)) // legal character
+ sBuffer.append(cChar);
+ }
+ rTarget = sBuffer.makeStringAndClear();
+}
+
+double Converter::GetConversionFactor(::rtl::OUStringBuffer& rUnit, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
+{
+ double fRetval(1.0);
+ rUnit.setLength(0L);
+
+ const sal_Char* psUnit = 0;
+
+ if(nSourceUnit != nTargetUnit)
+ {
+ switch(nSourceUnit)
+ {
+ case MeasureUnit::TWIP:
+ {
+ switch(nTargetUnit)
+ {
+ case MeasureUnit::MM_100TH:
+ case MeasureUnit::MM_10TH:
+ {
+ OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for twip values");
+ }
+ case MeasureUnit::MM:
+ {
+ // 0.01mm = 0.57twip (exactly)
+ fRetval = ((25400.0 / 1440.0) / 1000.0);
+ psUnit = gpsMM;
+ break;
+ }
+ case MeasureUnit::CM:
+ {
+ // 0.001cm = 0.57twip (exactly)
+ fRetval = ((25400.0 / 1440.0) / 10000.0);
+ psUnit = gpsCM;
+ break;
+ }
+ case MeasureUnit::POINT:
+ {
+ // 0.01pt = 0.2twip (exactly)
+ fRetval = ((1000.0 / 20.0) / 1000.0);
+ psUnit = gpsPT;
+ break;
+ }
+ case MeasureUnit::INCH:
+ default:
+ {
+ OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for twip values");
+ // 0.0001in = 0.144twip (exactly)
+ fRetval = ((100000.0 / 1440.0) / 100000.0);
+ psUnit = gpsINCH;
+ break;
+ }
+ }
+ break;
+ }
+ case MeasureUnit::POINT:
+ {
+ switch(nTargetUnit)
+ {
+ case MeasureUnit::MM:
+ // 1mm = 72 / 25.4 pt (exactly)
+ fRetval = ( 25.4 / 72.0 );
+ psUnit = gpsMM;
+ break;
+
+ case MeasureUnit::CM:
+ // 1cm = 72 / 2.54 pt (exactly)
+ fRetval = ( 2.54 / 72.0 );
+ psUnit = gpsCM;
+ break;
+
+ case MeasureUnit::TWIP:
+ // 1twip = 72 / 1440 pt (exactly)
+ fRetval = 20.0; // 1440.0 / 72.0
+ psUnit = gpsPC;
+ break;
+
+ case MeasureUnit::INCH:
+ default:
+ OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for pt values");
+ // 1in = 72 pt (exactly)
+ fRetval = ( 1.0 / 72.0 );
+ psUnit = gpsINCH;
+ break;
+ }
+ break;
+ }
+ case MeasureUnit::MM_10TH:
+ {
+ switch(nTargetUnit)
+ {
+ case MeasureUnit::MM_100TH:
+ case MeasureUnit::MM_10TH:
+ {
+ OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
+ }
+ case MeasureUnit::MM:
+ {
+ // 0.01mm = 1 mm/100 (exactly)
+ fRetval = ((10.0 / 1.0) / 100.0);
+ psUnit = gpsMM;
+ break;
+ }
+ case MeasureUnit::CM:
+ {
+ // 0.001mm = 1 mm/100 (exactly)
+ fRetval = ((10.0 / 1.0) / 1000.0);
+ psUnit = gpsCM;
+ break;
+ }
+ case MeasureUnit::POINT:
+ {
+ // 0.01pt = 0.35 mm/100 (exactly)
+ fRetval = ((72000.0 / 2540.0) / 100.0);
+ psUnit = gpsPT;
+ break;
+ }
+ case MeasureUnit::INCH:
+ default:
+ {
+ OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
+ // 0.0001in = 0.254 mm/100 (exactly)
+ fRetval = ((100000.0 / 2540.0) / 10000.0);
+ psUnit = gpsINCH;
+ break;
+ }
+ }
+ break;
+ }
+ case MeasureUnit::MM_100TH:
+ {
+ switch(nTargetUnit)
+ {
+ case MeasureUnit::MM_100TH:
+ case MeasureUnit::MM_10TH:
+ {
+ OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
+ }
+ case MeasureUnit::MM:
+ {
+ // 0.01mm = 1 mm/100 (exactly)
+ fRetval = ((10.0 / 1.0) / 1000.0);
+ psUnit = gpsMM;
+ break;
+ }
+ case MeasureUnit::CM:
+ {
+ // 0.001mm = 1 mm/100 (exactly)
+ fRetval = ((10.0 / 1.0) / 10000.0);
+ psUnit = gpsCM;
+ break;
+ }
+ case MeasureUnit::POINT:
+ {
+ // 0.01pt = 0.35 mm/100 (exactly)
+ fRetval = ((72000.0 / 2540.0) / 1000.0);
+ psUnit = gpsPT;
+ break;
+ }
+ case MeasureUnit::INCH:
+ default:
+ {
+ OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
+ // 0.0001in = 0.254 mm/100 (exactly)
+ fRetval = ((100000.0 / 2540.0) / 100000.0);
+ psUnit = gpsINCH;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if( psUnit )
+ rUnit.appendAscii( psUnit );
+ }
+
+ return fRetval;
+}
+
+sal_Int16 Converter::GetUnitFromString(const ::rtl::OUString& rString, sal_Int16 nDefaultUnit)
+{
+ sal_Int32 nPos = 0L;
+ sal_Int32 nLen = rString.getLength();
+ sal_Int16 nRetUnit = nDefaultUnit;
+
+ // skip white space
+ while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
+ nPos++;
+
+ // skip negative
+ if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
+ nPos++;
+
+ // skip number
+ while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
+ nPos++;
+
+ if( nPos < nLen && sal_Unicode('.') == rString[nPos] )
+ {
+ nPos++;
+ while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
+ nPos++;
+ }
+
+ // skip white space
+ while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
+ nPos++;
+
+ if( nPos < nLen )
+ {
+ switch(rString[nPos])
+ {
+ case sal_Unicode('%') :
+ {
+ nRetUnit = MeasureUnit::PERCENT;
+ break;
+ }
+ case sal_Unicode('c'):
+ case sal_Unicode('C'):
+ {
+ if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
+ || rString[nPos+1] == sal_Unicode('M')))
+ nRetUnit = MeasureUnit::CM;
+ break;
+ }
+ case sal_Unicode('e'):
+ case sal_Unicode('E'):
+ {
+ // CSS1_EMS or CSS1_EMX later
+ break;
+ }
+ case sal_Unicode('i'):
+ case sal_Unicode('I'):
+ {
+ if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('n')
+ || rString[nPos+1] == sal_Unicode('n')))
+ nRetUnit = MeasureUnit::INCH;
+ break;
+ }
+ case sal_Unicode('m'):
+ case sal_Unicode('M'):
+ {
+ if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
+ || rString[nPos+1] == sal_Unicode('M')))
+ nRetUnit = MeasureUnit::MM;
+ break;
+ }
+ case sal_Unicode('p'):
+ case sal_Unicode('P'):
+ {
+ if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('t')
+ || rString[nPos+1] == sal_Unicode('T')))
+ nRetUnit = MeasureUnit::POINT;
+ if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('c')
+ || rString[nPos+1] == sal_Unicode('C')))
+ nRetUnit = MeasureUnit::TWIP;
+ break;
+ }
+ }
+ }
+
+ return nRetUnit;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sax/source/tools/fastattribs.cxx b/sax/source/tools/fastattribs.cxx
new file mode 100644
index 000000000000..53fc40350022
--- /dev/null
+++ b/sax/source/tools/fastattribs.cxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include <algorithm>
+#include <boost/bind.hpp>
+
+#include <sax/fastattribs.hxx>
+
+using ::rtl::OUString;
+using ::rtl::OString;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::xml;
+using namespace ::com::sun::star::xml::sax;
+namespace sax_fastparser
+{
+
+UnknownAttribute::UnknownAttribute( const OUString& rNamespaceURL, const OString& rName, const OString& rValue )
+ : maNamespaceURL( rNamespaceURL ), maName( rName ), maValue( rValue )
+{
+}
+
+UnknownAttribute::UnknownAttribute( const OString& rName, const OString& rValue )
+ : maName( rName ), maValue( rValue )
+{
+}
+
+void UnknownAttribute::FillAttribute( Attribute* pAttrib ) const
+{
+ if( pAttrib )
+ {
+ pAttrib->Name = OStringToOUString( maName, RTL_TEXTENCODING_UTF8 );
+ pAttrib->NamespaceURL = maNamespaceURL;
+ pAttrib->Value = OStringToOUString( maValue, RTL_TEXTENCODING_UTF8 );
+ }
+}
+
+FastAttributeList::FastAttributeList( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& xTokenHandler )
+: mxTokenHandler( xTokenHandler )
+{
+ maLastIter = maAttributes.end();
+}
+
+FastAttributeList::~FastAttributeList()
+{
+}
+
+void FastAttributeList::clear()
+{
+ maAttributes.clear();
+ maUnknownAttributes.clear();
+ maLastIter = maAttributes.end();
+}
+
+void FastAttributeList::add( sal_Int32 nToken, const OString& rValue )
+{
+ maAttributes[nToken] = rValue;
+}
+
+void FastAttributeList::addUnknown( const OUString& rNamespaceURL, const OString& rName, const OString& rValue )
+{
+ maUnknownAttributes.push_back( UnknownAttribute( rNamespaceURL, rName, rValue ) );
+}
+
+void FastAttributeList::addUnknown( const OString& rName, const OString& rValue )
+{
+ maUnknownAttributes.push_back( UnknownAttribute( rName, rValue ) );
+}
+
+// XFastAttributeList
+sal_Bool FastAttributeList::hasAttribute( ::sal_Int32 Token ) throw (RuntimeException)
+{
+ maLastIter = maAttributes.find( Token );
+ return ( maLastIter != maAttributes.end() ) ? sal_True : sal_False;
+}
+
+sal_Int32 FastAttributeList::getValueToken( ::sal_Int32 Token ) throw (SAXException, RuntimeException)
+{
+ if( ( maLastIter == maAttributes.end() ) || ( ( *maLastIter ).first != Token ) )
+ maLastIter = maAttributes.find( Token );
+
+ if( maLastIter == maAttributes.end() )
+ throw SAXException();
+
+ Sequence< sal_Int8 > aSeq( (sal_Int8*)(*maLastIter).second.getStr(), (*maLastIter).second.getLength() ) ;
+ return mxTokenHandler->getTokenFromUTF8( aSeq );
+}
+
+sal_Int32 FastAttributeList::getOptionalValueToken( ::sal_Int32 Token, ::sal_Int32 Default ) throw (RuntimeException)
+{
+ if( ( maLastIter == maAttributes.end() ) || ( ( *maLastIter ).first != Token ) )
+ maLastIter = maAttributes.find( Token );
+
+ if( maLastIter == maAttributes.end() )
+ return Default;
+
+ Sequence< sal_Int8 > aSeq( (sal_Int8*)(*maLastIter).second.getStr(), (*maLastIter).second.getLength() ) ;
+ return mxTokenHandler->getTokenFromUTF8( aSeq );
+}
+
+OUString FastAttributeList::getValue( ::sal_Int32 Token ) throw (SAXException, RuntimeException)
+{
+ if( ( maLastIter == maAttributes.end() ) || ( ( *maLastIter ).first != Token ) )
+ maLastIter = maAttributes.find( Token );
+
+ if( maLastIter == maAttributes.end() )
+ throw SAXException();
+
+ return OStringToOUString( (*maLastIter).second, RTL_TEXTENCODING_UTF8 );
+}
+
+OUString FastAttributeList::getOptionalValue( ::sal_Int32 Token ) throw (RuntimeException)
+{
+ if( ( maLastIter == maAttributes.end() ) || ( ( *maLastIter ).first != Token ) )
+ maLastIter = maAttributes.find( Token );
+
+ OUString aRet;
+ if( maLastIter != maAttributes.end() )
+ aRet = OStringToOUString( (*maLastIter).second, RTL_TEXTENCODING_UTF8 );
+
+ return aRet;
+}
+Sequence< Attribute > FastAttributeList::getUnknownAttributes( ) throw (RuntimeException)
+{
+ Sequence< Attribute > aSeq( maUnknownAttributes.size() );
+ Attribute* pAttr = aSeq.getArray();
+ for( UnknownAttributeList::iterator attrIter = maUnknownAttributes.begin(); attrIter != maUnknownAttributes.end(); ++attrIter )
+ (*attrIter).FillAttribute( pAttr++ );
+ return aSeq;
+}
+Sequence< FastAttribute > FastAttributeList::getFastAttributes( ) throw (RuntimeException)
+{
+ Sequence< FastAttribute > aSeq( maAttributes.size() );
+ FastAttribute* pAttr = aSeq.getArray();
+ FastAttributeMap::iterator fastAttrIter = maAttributes.begin();
+ for(; fastAttrIter != maAttributes.end(); ++fastAttrIter )
+ {
+ pAttr->Token = fastAttrIter->first;
+ pAttr->Value = OStringToOUString( fastAttrIter->second, RTL_TEXTENCODING_UTF8 );
+ pAttr++;
+ }
+ return aSeq;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sax/source/tools/fastserializer.cxx b/sax/source/tools/fastserializer.cxx
new file mode 100644
index 000000000000..e894c2ca0d13
--- /dev/null
+++ b/sax/source/tools/fastserializer.cxx
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "fastserializer.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <rtl/byteseq.hxx>
+
+#include <comphelper/sequenceasvector.hxx>
+
+#include <com/sun/star/xml/Attribute.hpp>
+#include <com/sun/star/xml/FastAttribute.hpp>
+#include <com/sun/star/xml/sax/XFastAttributeList.hpp>
+
+#include <string.h>
+
+#if DEBUG
+#include <cstdio>
+#endif
+
+using ::comphelper::SequenceAsVector;
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OUStringToOString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::toUnoSequence;
+using ::com::sun::star::xml::FastAttribute;
+using ::com::sun::star::xml::Attribute;
+using ::com::sun::star::xml::sax::SAXException;
+using ::com::sun::star::xml::sax::XFastAttributeList;
+using ::com::sun::star::xml::sax::XFastTokenHandler;
+using ::com::sun::star::xml::sax::XFastSerializer;
+using ::com::sun::star::io::XOutputStream;
+using ::com::sun::star::io::NotConnectedException;
+using ::com::sun::star::io::IOException;
+using ::com::sun::star::io::BufferSizeExceededException;
+
+static rtl::ByteSequence aClosingBracket((const sal_Int8 *)">", 1);
+static rtl::ByteSequence aSlashAndClosingBracket((const sal_Int8 *)"/>", 2);
+static rtl::ByteSequence aColon((const sal_Int8 *)":", 1);
+static rtl::ByteSequence aOpeningBracket((const sal_Int8 *)"<", 1);
+static rtl::ByteSequence aOpeningBracketAndSlash((const sal_Int8 *)"</", 2);
+static rtl::ByteSequence aQuote((const sal_Int8 *)"\"", 1);
+static rtl::ByteSequence aEqualSignAndQuote((const sal_Int8 *)"=\"", 2);
+static rtl::ByteSequence aSpace((const sal_Int8 *)" ", 1);
+static rtl::ByteSequence aXmlHeader((const sal_Int8*) "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n", 56);
+
+#define HAS_NAMESPACE(x) ((x & 0xffff0000) != 0)
+#define NAMESPACE(x) (x >> 16)
+#define TOKEN(x) (x & 0xffff)
+
+namespace sax_fastparser {
+ FastSaxSerializer::FastSaxSerializer( ) : mxOutputStream(), mxFastTokenHandler(), maMarkStack() {}
+ FastSaxSerializer::~FastSaxSerializer() {}
+
+ void SAL_CALL FastSaxSerializer::startDocument( ) throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+ writeBytes(toUnoSequence(aXmlHeader));
+ }
+
+ OUString FastSaxSerializer::escapeXml( const OUString& s )
+ {
+ ::rtl::OUStringBuffer sBuf( s.getLength() );
+ const sal_Unicode* pStr = s.getStr();
+ sal_Int32 nLen = s.getLength();
+ for( sal_Int32 i = 0; i < nLen; ++i)
+ {
+ sal_Unicode c = pStr[ i ];
+ switch( c )
+ {
+ case '<': sBuf.appendAscii( "&lt;" ); break;
+ case '>': sBuf.appendAscii( "&gt;" ); break;
+ case '&': sBuf.appendAscii( "&amp;" ); break;
+ case '\'': sBuf.appendAscii( "&apos;" ); break;
+ case '"': sBuf.appendAscii( "&quot;" ); break;
+ default: sBuf.append( c ); break;
+ }
+ }
+ return sBuf.makeStringAndClear();
+ }
+
+ void FastSaxSerializer::write( const OUString& s )
+ {
+ OString sOutput( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ) );
+ writeBytes( Sequence< sal_Int8 >(
+ reinterpret_cast< const sal_Int8*>( sOutput.getStr() ),
+ sOutput.getLength() ) );
+ }
+
+ void SAL_CALL FastSaxSerializer::endDocument( ) throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+ }
+
+ void SAL_CALL FastSaxSerializer::writeId( ::sal_Int32 nElement )
+ {
+ if( HAS_NAMESPACE( nElement ) ) {
+ writeBytes(mxFastTokenHandler->getUTF8Identifier(NAMESPACE(nElement)));
+ writeBytes(toUnoSequence(aColon));
+ writeBytes(mxFastTokenHandler->getUTF8Identifier(TOKEN(nElement)));
+ } else
+ writeBytes(mxFastTokenHandler->getUTF8Identifier(nElement));
+ }
+
+ void SAL_CALL FastSaxSerializer::startFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
+ throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+
+ if ( !maMarkStack.empty() )
+ maMarkStack.top()->setCurrentElement( Element );
+
+ writeBytes(toUnoSequence(aOpeningBracket));
+
+ writeId(Element);
+ writeFastAttributeList(Attribs);
+
+ writeBytes(toUnoSequence(aClosingBracket));
+ }
+
+ void SAL_CALL FastSaxSerializer::startUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs )
+ throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+
+ writeBytes(toUnoSequence(aOpeningBracket));
+
+ if (Namespace.getLength())
+ {
+ write(Namespace);
+ writeBytes(toUnoSequence(aColon));
+ }
+
+ write(Name);
+
+ writeFastAttributeList(Attribs);
+
+ writeBytes(toUnoSequence(aClosingBracket));
+ }
+
+ void SAL_CALL FastSaxSerializer::endFastElement( ::sal_Int32 Element )
+ throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+
+ writeBytes(toUnoSequence(aOpeningBracketAndSlash));
+
+ writeId(Element);
+
+ writeBytes(toUnoSequence(aClosingBracket));
+ }
+
+ void SAL_CALL FastSaxSerializer::endUnknownElement( const OUString& Namespace, const OUString& Name )
+ throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+
+ writeBytes(toUnoSequence(aOpeningBracketAndSlash));
+
+ if (Namespace.getLength())
+ {
+ write(Namespace);
+ writeBytes(toUnoSequence(aColon));
+ }
+
+ write(Name);
+
+ writeBytes(toUnoSequence(aClosingBracket));
+ }
+
+ void SAL_CALL FastSaxSerializer::singleFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
+ throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+
+ if ( !maMarkStack.empty() )
+ maMarkStack.top()->setCurrentElement( Element );
+
+ writeBytes(toUnoSequence(aOpeningBracket));
+
+ writeId(Element);
+ writeFastAttributeList(Attribs);
+
+ writeBytes(toUnoSequence(aSlashAndClosingBracket));
+ }
+
+ void SAL_CALL FastSaxSerializer::singleUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs )
+ throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+
+ writeBytes(toUnoSequence(aOpeningBracket));
+
+ if (Namespace.getLength())
+ {
+ write(Namespace);
+ writeBytes(toUnoSequence(aColon));
+ }
+
+ write(Name);
+
+ writeFastAttributeList(Attribs);
+
+ writeBytes(toUnoSequence(aSlashAndClosingBracket));
+ }
+
+ void SAL_CALL FastSaxSerializer::characters( const OUString& aChars )
+ throw (SAXException, RuntimeException)
+ {
+ if (!mxOutputStream.is())
+ return;
+
+ write( aChars );
+ }
+
+ void SAL_CALL FastSaxSerializer::setOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutputStream )
+ throw (::com::sun::star::uno::RuntimeException)
+ {
+ mxOutputStream = xOutputStream;
+ }
+
+ void SAL_CALL FastSaxSerializer::setFastTokenHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& xFastTokenHandler )
+ throw (::com::sun::star::uno::RuntimeException)
+ {
+ mxFastTokenHandler = xFastTokenHandler;
+ }
+ void FastSaxSerializer::writeFastAttributeList( const Reference< XFastAttributeList >& Attribs )
+ {
+ Sequence< Attribute > aAttrSeq = Attribs->getUnknownAttributes();
+ const Attribute *pAttr = aAttrSeq.getConstArray();
+ sal_Int32 nAttrLength = aAttrSeq.getLength();
+ for (sal_Int32 i = 0; i < nAttrLength; i++)
+ {
+ writeBytes(toUnoSequence(aSpace));
+
+ write(pAttr[i].Name);
+ writeBytes(toUnoSequence(aEqualSignAndQuote));
+ write(escapeXml(pAttr[i].Value));
+ writeBytes(toUnoSequence(aQuote));
+ }
+
+ Sequence< FastAttribute > aFastAttrSeq = Attribs->getFastAttributes();
+ const FastAttribute *pFastAttr = aFastAttrSeq.getConstArray();
+ sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
+ for (sal_Int32 j = 0; j < nFastAttrLength; j++)
+ {
+ writeBytes(toUnoSequence(aSpace));
+
+ sal_Int32 nToken = pFastAttr[j].Token;
+ writeId(nToken);
+
+ writeBytes(toUnoSequence(aEqualSignAndQuote));
+
+ write(escapeXml(Attribs->getValue(pFastAttr[j].Token)));
+
+ writeBytes(toUnoSequence(aQuote));
+ }
+ }
+
+ // XServiceInfo
+ OUString FastSaxSerializer::getImplementationName() throw (RuntimeException)
+ {
+ return OUString(RTL_CONSTASCII_USTRINGPARAM( SERIALIZER_IMPLEMENTATION_NAME ));
+ }
+
+ // XServiceInfo
+ sal_Bool FastSaxSerializer::supportsService(const OUString& ServiceName) throw (RuntimeException)
+ {
+ Sequence< OUString > aSNL = getSupportedServiceNames();
+ const OUString * pArray = aSNL.getConstArray();
+
+ for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
+ if( pArray[i] == ServiceName )
+ return sal_True;
+
+ return sal_False;
+ }
+
+ // XServiceInfo
+ Sequence< OUString > FastSaxSerializer::getSupportedServiceNames(void) throw (RuntimeException)
+ {
+ Sequence<OUString> seq(1);
+ seq.getArray()[0] = OUString(RTL_CONSTASCII_USTRINGPARAM( SERIALIZER_SERVICE_NAME ));
+ return seq;
+ }
+
+ OUString FastSaxSerializer::getImplementationName_Static()
+ {
+ return OUString(RTL_CONSTASCII_USTRINGPARAM( SERIALIZER_IMPLEMENTATION_NAME ));
+ }
+
+ Sequence< OUString > FastSaxSerializer::getSupportedServiceNames_Static(void)
+ {
+ Sequence<OUString> aRet(1);
+ aRet.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(SERIALIZER_SERVICE_NAME) );
+ return aRet;
+ }
+
+ void FastSaxSerializer::mark( Int32Sequence aOrder )
+ {
+ if ( aOrder.hasElements() )
+ {
+ boost::shared_ptr< ForMerge > pSort( new ForSort( aOrder ) );
+ maMarkStack.push( pSort );
+ }
+ else
+ {
+ boost::shared_ptr< ForMerge > pMerge( new ForMerge( ) );
+ maMarkStack.push( pMerge );
+ }
+ }
+
+#if DEBUG
+ void FastSaxSerializer::printMarkStack( )
+ {
+ ::std::stack< boost::shared_ptr< ForMerge > > aCopy( maMarkStack );
+ int nSize = aCopy.size();
+ int i = 0;
+ while ( !aCopy.empty() )
+ {
+ fprintf( stderr, "%d\n", nSize - i );
+
+ aCopy.top( )->print( );
+
+ fprintf( stderr, "\n" );
+
+ aCopy.pop( );
+ i++;
+ }
+ }
+#endif
+
+ void FastSaxSerializer::mergeTopMarks( sax_fastparser::MergeMarksEnum eMergeType )
+ {
+ if ( maMarkStack.empty() )
+ return;
+
+ if ( maMarkStack.size() == 1 )
+ {
+ mxOutputStream->writeBytes( maMarkStack.top()->getData() );
+ maMarkStack.pop();
+ return;
+ }
+
+ const Int8Sequence aMerge( maMarkStack.top()->getData() );
+ maMarkStack.pop();
+
+ switch ( eMergeType )
+ {
+ case MERGE_MARKS_APPEND: maMarkStack.top()->append( aMerge ); break;
+ case MERGE_MARKS_PREPEND: maMarkStack.top()->prepend( aMerge ); break;
+ case MERGE_MARKS_POSTPONE: maMarkStack.top()->postpone( aMerge ); break;
+ }
+ }
+
+ void FastSaxSerializer::writeBytes( const Sequence< ::sal_Int8 >& aData ) throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
+ {
+ if ( maMarkStack.empty() )
+ mxOutputStream->writeBytes( aData );
+ else
+ maMarkStack.top()->append( aData );
+ }
+
+ FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForMerge::getData()
+ {
+ merge( maData, maPostponed, true );
+ maPostponed.realloc( 0 );
+
+ return maData;
+ }
+
+#if DEBUG
+ void FastSaxSerializer::ForMerge::print( )
+ {
+ fprintf( stderr, "Data: " );
+ for ( sal_Int32 i=0, len=maData.getLength(); i < len; i++ )
+ {
+ fprintf( stderr, "%c", maData[i] );
+ }
+
+ fprintf( stderr, "\nPostponed: " );
+ for ( sal_Int32 i=0, len=maPostponed.getLength(); i < len; i++ )
+ {
+ fprintf( stderr, "%c", maPostponed[i] );
+ }
+
+ fprintf( stderr, "\n" );
+ }
+#endif
+
+ void FastSaxSerializer::ForMerge::prepend( const Int8Sequence &rWhat )
+ {
+ merge( maData, rWhat, false );
+ }
+
+ void FastSaxSerializer::ForMerge::append( const Int8Sequence &rWhat )
+ {
+ merge( maData, rWhat, true );
+ }
+
+ void FastSaxSerializer::ForMerge::postpone( const Int8Sequence &rWhat )
+ {
+ merge( maPostponed, rWhat, true );
+ }
+
+ void FastSaxSerializer::ForMerge::merge( Int8Sequence &rTop, const Int8Sequence &rMerge, bool bAppend )
+ {
+ sal_Int32 nMergeLen = rMerge.getLength();
+ if ( nMergeLen > 0 )
+ {
+ sal_Int32 nTopLen = rTop.getLength();
+
+ rTop.realloc( nTopLen + nMergeLen );
+ if ( bAppend )
+ {
+ // append the rMerge to the rTop
+ memcpy( rTop.getArray() + nTopLen, rMerge.getConstArray(), nMergeLen );
+ }
+ else
+ {
+ // prepend the rMerge to the rTop
+ memmove( rTop.getArray() + nMergeLen, rTop.getConstArray(), nTopLen );
+ memcpy( rTop.getArray(), rMerge.getConstArray(), nMergeLen );
+ }
+ }
+ }
+
+ void FastSaxSerializer::ForMerge::resetData( )
+ {
+ maData = Int8Sequence();
+ }
+
+ void FastSaxSerializer::ForSort::setCurrentElement( sal_Int32 nElement )
+ {
+ SequenceAsVector< sal_Int32 > aOrder( maOrder );
+ if( std::find( aOrder.begin(), aOrder.end(), nElement ) != aOrder.end() )
+ {
+ mnCurrentElement = nElement;
+ if ( maData.find( nElement ) == maData.end() )
+ maData[ nElement ] = Int8Sequence();
+ }
+ }
+
+ void FastSaxSerializer::ForSort::prepend( const Int8Sequence &rWhat )
+ {
+ append( rWhat );
+ }
+
+ void FastSaxSerializer::ForSort::append( const Int8Sequence &rWhat )
+ {
+ merge( maData[mnCurrentElement], rWhat, true );
+ }
+
+ void FastSaxSerializer::ForSort::sort()
+ {
+ // Clear the ForMerge data to avoid duplicate items
+ resetData();
+
+ // Sort it all
+ std::map< sal_Int32, Int8Sequence >::iterator iter;
+ for ( sal_Int32 i=0, len=maOrder.getLength(); i < len; i++ )
+ {
+ iter = maData.find( maOrder[i] );
+ if ( iter != maData.end() )
+ ForMerge::append( iter->second );
+ }
+ }
+
+ FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForSort::getData()
+ {
+ sort( );
+ return ForMerge::getData();
+ }
+
+#if DEBUG
+ void FastSaxSerializer::ForSort::print( )
+ {
+ std::map< sal_Int32, Int8Sequence >::iterator iter = maData.begin();
+ while ( iter != maData.end( ) )
+ {
+ fprintf( stderr, "pair: %d, ", iter->first );
+ for ( sal_Int32 i=0, len=iter->second.getLength(); i < len; ++i )
+ fprintf( stderr, "%c", iter->second[i] );
+ fprintf( stderr, "\n" );
+ ++iter;
+ }
+
+ sort( );
+ ForMerge::print();
+ }
+#endif
+
+} // namespace sax_fastparser
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sax/source/tools/fastserializer.hxx b/sax/source/tools/fastserializer.hxx
new file mode 100644
index 000000000000..961875194a20
--- /dev/null
+++ b/sax/source/tools/fastserializer.hxx
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SAX_FASTSERIALIZER_HXX
+#define SAX_FASTSERIALIZER_HXX
+
+#include <com/sun/star/xml/sax/XFastSerializer.hpp>
+#include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <cppuhelper/implbase2.hxx>
+
+#include <stack>
+#include <map>
+
+#include <boost/shared_ptr.hpp>
+
+#include "sax/dllapi.h"
+#include "sax/fshelper.hxx"
+
+#define SERIALIZER_IMPLEMENTATION_NAME "com.sun.star.comp.extensions.xml.sax.FastSerializer"
+#define SERIALIZER_SERVICE_NAME "com.sun.star.xml.sax.FastSerializer"
+
+namespace sax_fastparser {
+
+class SAX_DLLPUBLIC FastSaxSerializer : public ::cppu::WeakImplHelper2< ::com::sun::star::xml::sax::XFastSerializer, ::com::sun::star::lang::XServiceInfo >
+{
+ typedef ::com::sun::star::uno::Sequence< ::sal_Int8 > Int8Sequence;
+ typedef ::com::sun::star::uno::Sequence< ::sal_Int32 > Int32Sequence;
+
+public:
+ explicit FastSaxSerializer( );
+ virtual ~FastSaxSerializer();
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > getOutputStream() {return mxOutputStream;}
+
+ // The implementation details
+ static ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static(void);
+ static ::rtl::OUString getImplementationName_Static();
+
+ // XFastSerializer
+ virtual void SAL_CALL startDocument( ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL endDocument( ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL startFastElement( ::sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs )
+ throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL startUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs )
+ throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL endFastElement( ::sal_Int32 Element )
+ throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL endUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name )
+ throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL singleFastElement( ::sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs )
+ throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL singleUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs )
+ throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL characters( const ::rtl::OUString& aChars )
+ throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutputStream )
+ throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setFastTokenHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& xFastTokenHandler )
+ throw (::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw ( ::com::sun::star::uno::RuntimeException );
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw ( ::com::sun::star::uno::RuntimeException );
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw ( ::com::sun::star::uno::RuntimeException );
+
+ // C++ helpers
+ virtual void SAL_CALL writeId( ::sal_Int32 Element );
+
+ static ::rtl::OUString escapeXml( const ::rtl::OUString& s );
+
+public:
+ /** From now on, don't write directly to the stream, but to top of a stack.
+
+ This is to be able to change the order of the data being written.
+ If you need to write eg.
+ p, r, rPr, [something], /rPr, t, [text], /r, /p,
+ but get it in order
+ p, r, t, [text], /t, rPr, [something], /rPr, /r, /p,
+ simply do
+ p, r, mark(), t, [text], /t, mark(), rPr, [something], /rPr,
+ mergeTopMarks( true ), mergeTopMarks(), /r, /p
+ and you are done.
+ */
+ void mark( Int32Sequence aOrder = Int32Sequence() );
+
+ /** Merge 2 topmost marks.
+
+ There are 3 possibilities - prepend the top before the second top-most
+ mark, append it, or append it later; prepending brings the possibility
+ to switch parts of the output, appending later allows to write some
+ output in advance.
+
+ Writes the result to the output stream if the mark stack becomes empty
+ by the operation.
+
+ When the MERGE_MARKS_POSTPONE is specified, the merge happens just
+ before the next merge.
+
+ @see mark()
+ */
+ void mergeTopMarks( sax_fastparser::MergeMarksEnum eMergeType = sax_fastparser::MERGE_MARKS_APPEND );
+
+private:
+ ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > mxOutputStream;
+ ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler > mxFastTokenHandler;
+
+ class ForMerge
+ {
+ Int8Sequence maData;
+ Int8Sequence maPostponed;
+
+ public:
+ ForMerge() : maData(), maPostponed() {}
+ virtual ~ForMerge() {}
+
+ virtual void setCurrentElement( ::sal_Int32 /*nToken*/ ) {}
+ virtual Int8Sequence& getData();
+#if DEBUG
+ virtual void print();
+#endif
+
+ virtual void prepend( const Int8Sequence &rWhat );
+ virtual void append( const Int8Sequence &rWhat );
+ void postpone( const Int8Sequence &rWhat );
+
+ protected:
+ void resetData( );
+ static void merge( Int8Sequence &rTop, const Int8Sequence &rMerge, bool bAppend );
+ };
+
+ class ForSort : public ForMerge
+ {
+ std::map< ::sal_Int32, Int8Sequence > maData;
+ sal_Int32 mnCurrentElement;
+
+ Int32Sequence maOrder;
+
+ public:
+ ForSort( Int32Sequence aOrder ) :
+ ForMerge(),
+ maData(),
+ mnCurrentElement( 0 ),
+ maOrder( aOrder ) {}
+
+ void setCurrentElement( ::sal_Int32 nToken );
+
+ virtual Int8Sequence& getData();
+
+#if DEBUG
+ virtual void print();
+#endif
+
+ virtual void prepend( const Int8Sequence &rWhat );
+ virtual void append( const Int8Sequence &rWhat );
+ private:
+ void sort();
+ };
+
+#if DEBUG
+ void printMarkStack( );
+#endif
+
+ ::std::stack< boost::shared_ptr< ForMerge > > maMarkStack;
+
+ void writeFastAttributeList( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs );
+ void write( const ::rtl::OUString& s );
+
+protected:
+ /** Forward the call to the output stream, or write to the stack.
+
+ The latter in the case that we are inside a mark().
+ */
+ void writeBytes( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
+};
+
+} // namespace sax_fastparser
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sax/source/tools/fshelper.cxx b/sax/source/tools/fshelper.cxx
new file mode 100644
index 000000000000..239096ae8a05
--- /dev/null
+++ b/sax/source/tools/fshelper.cxx
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+#include <sax/fshelper.hxx>
+#include "fastserializer.hxx"
+#include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
+#include <comphelper/processfactory.hxx>
+#include <rtl/ustrbuf.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sax_fastparser {
+
+FastSerializerHelper::FastSerializerHelper(const Reference< io::XOutputStream >& xOutputStream, bool bWriteHeader ) :
+ mpSerializer(new FastSaxSerializer())
+{
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext(), UNO_SET_THROW );
+ Reference< lang::XMultiComponentFactory > xFactory( xContext->getServiceManager(), UNO_SET_THROW );
+ mxTokenHandler.set( xFactory->createInstanceWithContext( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.FastTokenHandler") ), xContext ), UNO_QUERY_THROW );
+
+ mpSerializer->setFastTokenHandler( mxTokenHandler );
+ mpSerializer->setOutputStream( xOutputStream );
+ if( bWriteHeader )
+ mpSerializer->startDocument();
+}
+
+FastSerializerHelper::~FastSerializerHelper()
+{
+ mpSerializer->endDocument();
+ delete mpSerializer;
+}
+
+void FastSerializerHelper::startElement(const char* elementName, ...)
+{
+ FastAttributeList* pAttrList = new FastAttributeList( mxTokenHandler );
+ va_list args;
+ va_start(args, elementName);
+ while (true)
+ {
+ const char* pName = va_arg(args, const char*);
+ if (!pName)
+ break;
+ const char* pValue = va_arg(args, const char*);
+ if (pValue)
+ pAttrList->addUnknown(pName, pValue);
+ }
+ va_end(args);
+ const com::sun::star::uno::Reference<com::sun::star::xml::sax::XFastAttributeList> xAttrList(pAttrList);
+ mpSerializer->startUnknownElement(::rtl::OUString(), ::rtl::OUString::createFromAscii(elementName), xAttrList);
+}
+
+void FastSerializerHelper::singleElement(const char* elementName, ...)
+{
+ FastAttributeList* pAttrList = new FastAttributeList( mxTokenHandler );
+ va_list args;
+ va_start(args, elementName);
+ while (true)
+ {
+ const char* pName = va_arg(args, const char*);
+ if (!pName)
+ break;
+ const char* pValue = va_arg(args, const char*);
+ if (pValue)
+ pAttrList->addUnknown(pName, pValue);
+ }
+ va_end(args);
+ const com::sun::star::uno::Reference<com::sun::star::xml::sax::XFastAttributeList> xAttrList(pAttrList);
+ mpSerializer->singleUnknownElement(::rtl::OUString(), ::rtl::OUString::createFromAscii(elementName), xAttrList);
+}
+
+void FastSerializerHelper::endElement(const char* elementName)
+{
+ mpSerializer->endUnknownElement(::rtl::OUString(), ::rtl::OUString::createFromAscii(elementName));
+}
+
+void FastSerializerHelper::startElementV(sal_Int32 elementTokenId, va_list args)
+{
+ FastAttributeList* pAttrList = new FastAttributeList( mxTokenHandler );
+
+ while (true)
+ {
+ sal_Int32 nName = va_arg(args, sal_Int32);
+ if (nName == FSEND)
+ break;
+ const char* pValue = va_arg(args, const char*);
+ if (pValue)
+ pAttrList->add(nName, pValue);
+ }
+
+ const com::sun::star::uno::Reference<com::sun::star::xml::sax::XFastAttributeList> xAttrList(pAttrList);
+ mpSerializer->startFastElement(elementTokenId, xAttrList);
+}
+
+void FastSerializerHelper::singleElementV(sal_Int32 elementTokenId, va_list args)
+{
+ FastAttributeList* pAttrList = new FastAttributeList( mxTokenHandler );
+
+ while (true)
+ {
+ sal_Int32 nName = va_arg(args, sal_Int32);
+ if (nName == FSEND)
+ break;
+ const char* pValue = va_arg(args, const char*);
+ if (pValue)
+ pAttrList->add(nName, pValue);
+ }
+
+ const com::sun::star::uno::Reference<com::sun::star::xml::sax::XFastAttributeList> xAttrList(pAttrList);
+ mpSerializer->singleFastElement(elementTokenId, xAttrList);
+}
+
+void FastSerializerHelper::endElement(sal_Int32 elementTokenId)
+{
+ mpSerializer->endFastElement(elementTokenId);
+}
+
+void FastSerializerHelper::startElementV(sal_Int32 elementTokenId, XFastAttributeListRef xAttrList)
+{
+ mpSerializer->startFastElement(elementTokenId, xAttrList);
+}
+
+
+void FastSerializerHelper::singleElement(const char* elementName, XFastAttributeListRef xAttrList)
+{
+ mpSerializer->singleUnknownElement(::rtl::OUString(), ::rtl::OUString::createFromAscii(elementName), xAttrList);
+}
+
+void FastSerializerHelper::singleElementV(sal_Int32 elementTokenId, XFastAttributeListRef xAttrList)
+{
+ mpSerializer->singleFastElement(elementTokenId, xAttrList);
+}
+
+FastSerializerHelper* FastSerializerHelper::write(const char* value)
+{
+ return write(rtl::OUString::createFromAscii(value));
+}
+
+FastSerializerHelper* FastSerializerHelper::write(const rtl::OUString& value)
+{
+ mpSerializer->characters(value);
+ return this;
+}
+
+FastSerializerHelper* FastSerializerHelper::write(sal_Int32 value)
+{
+ return write(::rtl::OUString::valueOf(value));
+}
+
+FastSerializerHelper* FastSerializerHelper::write(sal_Int64 value)
+{
+ return write(::rtl::OUString::valueOf(value));
+}
+
+FastSerializerHelper* FastSerializerHelper::write(float value)
+{
+ return write(::rtl::OUString::valueOf(value));
+}
+
+FastSerializerHelper* FastSerializerHelper::write(double value)
+{
+ return write(::rtl::OUString::valueOf(value));
+}
+
+FastSerializerHelper* FastSerializerHelper::writeEscaped(const char* value)
+{
+ return writeEscaped(::rtl::OUString::createFromAscii(value));
+}
+
+FastSerializerHelper* FastSerializerHelper::writeEscaped(const ::rtl::OUString& value)
+{
+ return write(FastSaxSerializer::escapeXml(value));
+}
+
+FastSerializerHelper* FastSerializerHelper::writeId(sal_Int32 tokenId)
+{
+ mpSerializer->writeId(tokenId);
+ return this;
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > FastSerializerHelper::getOutputStream()
+{
+ return mpSerializer->getOutputStream();
+}
+
+void FastSerializerHelper::mark( Sequence< sal_Int32 > aOrder )
+{
+ mpSerializer->mark( aOrder );
+}
+
+void FastSerializerHelper::mergeTopMarks( MergeMarksEnum eMergeType )
+{
+ mpSerializer->mergeTopMarks( eMergeType );
+}
+
+FastAttributeList * FastSerializerHelper::createAttrList()
+{
+ return new FastAttributeList( mxTokenHandler );
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sax/source/tools/makefile.mk b/sax/source/tools/makefile.mk
new file mode 100644
index 000000000000..5923fc5a7785
--- /dev/null
+++ b/sax/source/tools/makefile.mk
@@ -0,0 +1,67 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=sax
+TARGET=sax
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES = \
+ $(SLO)$/converter.obj \
+ $(SLO)$/fastattribs.obj \
+ $(SLO)$/fastserializer.obj \
+ $(SLO)$/fshelper.obj
+
+SHL1TARGET= $(TARGET)$(DLLPOSTFIX)
+SHL1IMPLIB= i$(TARGET)
+
+SHL1STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB)\
+ $(COMPHELPERLIB)\
+ $(RTLLIB) \
+ $(SALLIB) \
+ $(ONELIB)
+
+SHL1DEPN=
+SHL1OBJS= $(SLOFILES)
+SHL1USE_EXPORTS=name
+SHL1DEF= $(MISC)$/$(SHL1TARGET).def
+DEF1NAME= $(SHL1TARGET)
+DEFLIB1NAME= $(TARGET)
+
+# --- Targets -------------------------------------------------------
+
+.INCLUDE : target.mk