summaryrefslogtreecommitdiff
path: root/tools/source
diff options
context:
space:
mode:
Diffstat (limited to 'tools/source')
-rw-r--r--tools/source/communi/geninfo.cxx408
-rw-r--r--tools/source/communi/makefile.mk50
-rw-r--r--tools/source/communi/parser.cxx469
-rw-r--r--tools/source/datetime/datetime.cxx442
-rw-r--r--tools/source/datetime/makefile.mk50
-rw-r--r--tools/source/datetime/tdate.cxx494
-rw-r--r--tools/source/datetime/ttime.cxx445
-rw-r--r--tools/source/debug/debug.cxx1812
-rw-r--r--tools/source/debug/makefile.mk53
-rw-r--r--tools/source/debug/stcktree.cxx320
-rw-r--r--tools/source/fsys/comdep.cxx44
-rw-r--r--tools/source/fsys/comdep.hxx156
-rw-r--r--tools/source/fsys/dirent.cxx3213
-rw-r--r--tools/source/fsys/filecopy.cxx486
-rw-r--r--tools/source/fsys/fstat.cxx419
-rw-r--r--tools/source/fsys/makefile.mk67
-rw-r--r--tools/source/fsys/os2.cxx1014
-rw-r--r--tools/source/fsys/os2.hxx93
-rw-r--r--tools/source/fsys/tdir.cxx768
-rw-r--r--tools/source/fsys/tempfile.cxx301
-rw-r--r--tools/source/fsys/unx.cxx660
-rw-r--r--tools/source/fsys/unx.hxx95
-rw-r--r--tools/source/fsys/urlobj.cxx5572
-rw-r--r--tools/source/fsys/wldcrd.cxx143
-rw-r--r--tools/source/fsys/wntmsc.cxx1081
-rw-r--r--tools/source/fsys/wntmsc.hxx102
-rw-r--r--tools/source/generic/b3dtrans.cxx1014
-rw-r--r--tools/source/generic/bigint.cxx1141
-rw-r--r--tools/source/generic/color.cxx510
-rw-r--r--tools/source/generic/config.cxx1304
-rw-r--r--tools/source/generic/fract.cxx736
-rw-r--r--tools/source/generic/gen.cxx661
-rw-r--r--tools/source/generic/line.cxx363
-rw-r--r--tools/source/generic/link.cxx58
-rw-r--r--tools/source/generic/makefile.mk71
-rw-r--r--tools/source/generic/poly.cxx2380
-rw-r--r--tools/source/generic/poly2.cxx891
-rw-r--r--tools/source/generic/svborder.cxx77
-rw-r--r--tools/source/generic/svlibrary.cxx129
-rw-r--r--tools/source/generic/toolsin.cxx95
-rw-r--r--tools/source/inet/inetmime.cxx4563
-rw-r--r--tools/source/inet/inetmsg.cxx1653
-rw-r--r--tools/source/inet/inetstrm.cxx1821
-rw-r--r--tools/source/inet/makefile.mk45
-rw-r--r--tools/source/makefile.mk58
-rw-r--r--tools/source/memtools/contnr.cxx1708
-rw-r--r--tools/source/memtools/makefile.mk56
-rw-r--r--tools/source/memtools/mempool.cxx83
-rw-r--r--tools/source/memtools/multisel.cxx1162
-rw-r--r--tools/source/memtools/table.cxx413
-rw-r--r--tools/source/memtools/unqidx.cxx601
-rw-r--r--tools/source/misc/appendunixshellword.cxx76
-rw-r--r--tools/source/misc/extendapplicationenvironment.cxx103
-rw-r--r--tools/source/misc/getprocessworkingdir.cxx64
-rw-r--r--tools/source/misc/makefile.mk47
-rw-r--r--tools/source/misc/pathutils.cxx219
-rw-r--r--tools/source/misc/solarmutex.cxx60
-rw-r--r--tools/source/rc/isofallback.cxx67
-rw-r--r--tools/source/rc/makefile.mk53
-rw-r--r--tools/source/rc/rc.cxx97
-rw-r--r--tools/source/rc/resary.cxx78
-rw-r--r--tools/source/rc/resmgr.cxx2074
-rw-r--r--tools/source/ref/errinf.cxx462
-rw-r--r--tools/source/ref/globname.cxx453
-rw-r--r--tools/source/ref/makefile.mk53
-rw-r--r--tools/source/ref/pstm.cxx915
-rw-r--r--tools/source/ref/ref.cxx51
-rw-r--r--tools/source/solar/makefile.mk63
-rw-r--r--tools/source/solar/solar.c562
-rw-r--r--tools/source/stream/cachestr.cxx290
-rw-r--r--tools/source/stream/makefile.mk58
-rw-r--r--tools/source/stream/stream.cxx2841
-rw-r--r--tools/source/stream/strmos2.cxx864
-rw-r--r--tools/source/stream/strmsys.cxx37
-rw-r--r--tools/source/stream/strmunx.cxx920
-rw-r--r--tools/source/stream/strmwnt.cxx689
-rw-r--r--tools/source/stream/vcompat.cxx80
-rw-r--r--tools/source/string/debugprint.cxx48
-rw-r--r--tools/source/string/makefile.mk79
-rw-r--r--tools/source/string/strascii.cxx637
-rw-r--r--tools/source/string/strcvt.cxx613
-rw-r--r--tools/source/string/strimp.cxx2115
-rw-r--r--tools/source/string/strucvt.cxx213
-rw-r--r--tools/source/string/tenccvt.cxx97
-rw-r--r--tools/source/string/tstring.cxx295
-rw-r--r--tools/source/string/tustring.cxx162
-rw-r--r--tools/source/testtoolloader/makefile.mk45
-rw-r--r--tools/source/testtoolloader/testtoolloader.cxx185
-rw-r--r--tools/source/zcodec/makefile.mk47
-rw-r--r--tools/source/zcodec/zcodec.cxx488
90 files changed, 56650 insertions, 0 deletions
diff --git a/tools/source/communi/geninfo.cxx b/tools/source/communi/geninfo.cxx
new file mode 100644
index 000000000000..97326836de2d
--- /dev/null
+++ b/tools/source/communi/geninfo.cxx
@@ -0,0 +1,408 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include "tools/geninfo.hxx"
+#include <stdio.h>
+
+//
+// class GenericInformation
+//
+
+/*****************************************************************************/
+GenericInformation::GenericInformation( const ByteString &rKey,
+ const ByteString &rValue,
+ GenericInformationList *pParentList,
+ GenericInformationList *pSubInfos )
+/*****************************************************************************/
+ : ByteString( rKey ),
+ sValue( rValue ),
+ pInfoList( pSubInfos ),
+ pParent( pParentList )
+{
+ // if a ParentList exists, insert this object into it
+ if ( pParent )
+ pParent->InsertInfo( this );
+ // make myself owner of pInfoList
+ if ( pInfoList )
+ pInfoList->SetOwner( this );
+}
+
+/*****************************************************************************/
+GenericInformation::GenericInformation( const GenericInformation& rInf,
+ BOOL bCopySubs)
+/*****************************************************************************/
+ : ByteString( rInf ),
+ sValue( rInf.sValue ),
+ pInfoList( 0L ),
+ pParent(NULL)
+{
+ if(bCopySubs && rInf.pInfoList)
+ pInfoList = new GenericInformationList(*rInf.pInfoList, this);
+}
+
+/*****************************************************************************/
+GenericInformation::~GenericInformation()
+/*****************************************************************************/
+{
+ // remove pInfoList and all childs out of memory
+ delete pInfoList;
+ pInfoList = 0;
+
+ // remove this Info out of ParentList
+ if ( pParent )
+ pParent->RemoveInfo( this );
+}
+
+/*****************************************************************************/
+BOOL GenericInformation::InsertSubInfo( GenericInformation *pInfo )
+/*****************************************************************************/
+{
+ return ( pInfoList && pInfoList->InsertInfo( pInfo ));
+}
+
+/*****************************************************************************/
+BOOL GenericInformation::InsertSubInfo( const ByteString &rPathKey, const ByteString &rValue,
+ BOOL bSearchByPath, BOOL bNewPath )
+/*****************************************************************************/
+{
+ return (pInfoList && pInfoList->InsertInfo( rPathKey, rValue, bSearchByPath, bNewPath ));
+}
+
+/*****************************************************************************/
+void GenericInformation::RemoveSubInfo( GenericInformation *pInfo,
+ BOOL bDelete )
+/*****************************************************************************/
+{
+ pInfoList->RemoveInfo( pInfo, bDelete );
+}
+
+/*****************************************************************************/
+//void GenericInformation::RemoveSelf( BOOL bDelete )
+/*****************************************************************************/
+/*{
+ if ( pParent )
+ pParent->RemoveInfo( this, bDelete ); // loescht sich aus der Liste vom Parent und
+ // bei Bedarf auch mit obiger Methode alle Sublisten
+
+ // loescht sich bei Bedarf auch selbst
+ if ( bDelete )
+ delete this;
+}
+*/
+
+/*****************************************************************************/
+GenericInformation *GenericInformation::GetSubInfo( ByteString &rKey,
+ BOOL bSearchByPath,
+ BOOL bCreatePath )
+/*****************************************************************************/
+{
+ if ( !pInfoList && bCreatePath )
+ pInfoList = new GenericInformationList( this );
+ if ( pInfoList )
+ return pInfoList->GetInfo( rKey, bSearchByPath, bCreatePath );
+ return NULL;
+}
+
+
+//
+// class GenericInformationList
+//
+
+/*****************************************************************************/
+GenericInformationList::GenericInformationList( GenericInformation *pParent )
+/*****************************************************************************/
+ : pOwner( pParent )
+{
+}
+
+/*****************************************************************************/
+GenericInformationList::GenericInformationList(const GenericInformationList& rList,
+ GenericInformation *pParent)
+/*****************************************************************************/
+ : GenericInformationList_Impl()
+{
+ USHORT i;
+ GenericInformation* pTemp,*pWork;
+
+ pOwner = pParent;
+
+ for(i=0;i<rList.Count();i++)
+ {
+ pTemp = rList.GetObject(i);
+ pWork = new GenericInformation(*pTemp,TRUE);
+
+ Insert(pWork,LIST_APPEND);
+ }
+}
+
+/*****************************************************************************/
+GenericInformationList::~GenericInformationList()
+/*****************************************************************************/
+{
+ // delete all Informations stored in this List
+ // ### GH: Hier werden dann wohl etwa die H�lfte der Eintr�ge gel�scht
+/* for ( ULONG i = 0; i < Count(); i++ ) {
+ GetObject( i )->ListDeleted();
+ delete GetObject( i );
+ Remove( i );*/
+ // Neue Variante:
+ while ( Count() ) {
+ GetObject( 0 )->ListDeleted();
+ delete GetObject( 0 );
+ Remove( (ULONG)0 );
+ }
+}
+
+/*****************************************************************************/
+GenericInformation *GenericInformationList::Search( ULONG &rPos, ByteString sKey,
+ ULONG nStart, ULONG nEnd )
+/*****************************************************************************/
+{
+ if ( Count() == 0 ) {
+ rPos = 0;
+ return NULL;
+ }
+
+ if ( nStart == nEnd ) {
+ rPos = nStart;
+ ByteString sCandidate = ByteString( *GetObject( nStart ));
+ if ( sCandidate.ToUpperAscii() == sKey.ToUpperAscii()) {
+ return GetObject( nStart ); // found !!!
+ }
+ else {
+ // requested key not found
+ return NULL;
+ }
+ }
+
+ // search binary in existing list
+ ULONG nActPos = nStart + (( nEnd - nStart ) / 2 );
+ rPos = nActPos;
+ ByteString sCandidate = ByteString( *GetObject( nActPos ));
+
+ if ( sCandidate.ToUpperAscii() == sKey.ToUpperAscii())
+ return GetObject( nActPos ); // found !!!
+
+ // split the list at ActPos
+ if ( sCandidate < sKey )
+ return Search( rPos, sKey, nActPos + 1, nEnd );
+ else
+ return Search( rPos, sKey, nStart, nActPos );
+}
+
+/*****************************************************************************/
+GenericInformation *GenericInformationList::GetInfo( ByteString &rKey,
+ BOOL bSearchByPath,
+ BOOL bCreatePath )
+/*****************************************************************************/
+{
+
+ rKey.EraseLeadingChars( '/' );
+ rKey.EraseTrailingChars( '/' );
+
+ ByteString sKey;
+ if ( bSearchByPath )
+ sKey = rKey.GetToken( 0, '/' );
+ else
+ sKey = rKey;
+
+ ULONG nPos = 0;
+ GenericInformation *pReturnInfo = Search( nPos, sKey, 0, Count() - 1 );
+ /* wenn kein Searchpath gesetzt und kein Returninfo vorhanden,
+ * gib NULL zurueck
+ * wenn Searchpath gesetzt und returninfo vorhanden,
+ * suche weiter nach unten
+ * wenn searchpath gesetzt kein returninfo vorhanden und newpath gesetzt,
+ * mache neues Verzeichniss
+ */
+ USHORT nTokenCount = rKey.GetTokenCount('/');
+ // search for next key of path in next level of tree
+ if ( bSearchByPath && (nTokenCount > 1)) {
+ ByteString sPath = ByteString(rKey.Copy( sKey.Len() + 1 ));
+ if ( !pReturnInfo ) { // wenn kein Return, dann muss man es anlegen
+ if ( !bCreatePath ) // wenn aber kein Create, dann nicht anlegen
+ return NULL;
+ pReturnInfo = new GenericInformation( sKey, "", this, NULL);
+ pReturnInfo->SetSubList( new GenericInformationList( pReturnInfo ));
+ }
+ return pReturnInfo->GetSubInfo( sPath, TRUE, bCreatePath );
+ }
+ if ( !pReturnInfo && bCreatePath ) {
+ pReturnInfo = new GenericInformation ( sKey, "", this, NULL);
+ }
+
+ return pReturnInfo; // kann durchaus NULL sein.
+}
+
+/*****************************************************************************/
+ULONG GenericInformationList::InsertSorted( GenericInformation *pInfo,
+ BOOL bOverwrite,
+ ULONG nStart, ULONG nEnd )
+/*****************************************************************************/
+{
+ if ( Count() == 0 ) {
+ // empty list, so insert at first pos
+ Insert( pInfo, LIST_APPEND );
+ return 0;
+ }
+
+ ByteString sKey( pInfo->GetBuffer());
+ sKey.ToUpperAscii();
+
+ // Check to sppeed up reading a (partially) sorted list
+ if ( nStart == 0 && Count()-1 == nEnd )
+ {
+ ByteString sCandidate( *GetObject( nEnd ));
+ if ( sCandidate.ToUpperAscii() < sKey )
+ {
+ Insert( pInfo, LIST_APPEND );
+ return nEnd+1;
+ }
+ }
+
+// ### GH: dieser Block schein �berfl�ssig zu sein
+ if ( Count() == 1 ) {
+ ByteString sCandidate( *GetObject( 0 ));
+ if ( sCandidate.ToUpperAscii() == sKey ) {
+ // key allready exists in list
+ if ( bOverwrite )
+ Replace( pInfo, ULONG(0)); // ### Laut NF scheint hier ein Memory Leak zu sein
+ return 0;
+ }
+ else if ( sCandidate > sKey ) {
+ Insert( pInfo, ULONG(0));
+ return 0;
+ }
+ else {
+ Insert( pInfo, LIST_APPEND );
+ return 1;
+ }
+ }
+// ### GH: /ENDE/ dieser Block schein �berfl�ssig zu sein
+
+ ULONG nActPos = nStart + (( nEnd - nStart ) / 2 );
+ ByteString sCandidate = ByteString( *GetObject( nActPos ));
+
+ if ( sCandidate.ToUpperAscii() == sKey ) {
+ // key allready exists in list
+ if ( bOverwrite )
+ Replace( pInfo, nActPos ); // ### Laut NF scheint hier ein Memory Leak zu sein
+ return nActPos;
+ }
+
+ if ( nStart == nEnd ) {
+ // now more ways to search for key -> insert here
+ if ( sCandidate > sKey ) {
+ Insert( pInfo, nStart );
+ return nStart;
+ }
+ else {
+ Insert( pInfo, nStart + 1 );
+ return ( nStart + 1 );
+ }
+ }
+
+ if ( nActPos == Count() - 1 ) {
+ // reached end of list -> insert here
+ Insert( pInfo, LIST_APPEND );
+ return ( nActPos + 1 );
+ }
+
+ ByteString sSecondCand = ByteString( *GetObject( nActPos + 1 ));
+ if (( sCandidate < sKey ) && ( sSecondCand.ToUpperAscii() > sKey )) {
+ // optimal position to insert object
+ Insert( pInfo, nActPos + 1 );
+ return ( nActPos + 1 );
+ }
+
+ if ( sCandidate < sKey )
+ return InsertSorted( pInfo, bOverwrite, nActPos + 1, nEnd );
+ else
+ return InsertSorted( pInfo, bOverwrite, nStart, nActPos );
+}
+
+/*****************************************************************************/
+BOOL GenericInformationList::InsertInfo( GenericInformation *pInfo,
+ BOOL bOverwrite )
+/*****************************************************************************/
+{
+ if ( !pInfo->Len())
+ return FALSE;
+
+ InsertSorted( pInfo, bOverwrite, 0, Count() - 1 );
+ return TRUE;
+}
+
+
+/*****************************************************************************/
+BOOL GenericInformationList::InsertInfo( const ByteString &rPathKey, const ByteString &rValue,
+ BOOL bSearchByPath, BOOL bNewPath )
+/*****************************************************************************/
+{
+ GenericInformation *pInfo;
+ ByteString sPathKey ( rPathKey );
+ sPathKey.EraseLeadingChars( '/' );
+ sPathKey.EraseTrailingChars( '/' );
+
+ pInfo = GetInfo( sPathKey, bSearchByPath, bNewPath );
+
+ if ( pInfo ) {
+ pInfo->SetValue( rValue );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+void GenericInformationList::RemoveInfo( GenericInformation *pInfo,
+ BOOL bDelete )
+/*****************************************************************************/
+{
+ Remove( pInfo );
+ if ( bDelete )
+ delete pInfo;
+/* if ( Count() == 0 && pOwner ) // Leere Listen entfernen;
+ {
+ SetOwner( NULL );
+ delete this;
+ } Rausgepatched by GH */
+}
+
+GenericInformation* GenericInformationList::SetOwner( GenericInformation *pNewOwner )
+{
+ GenericInformation *pOldOwner = pOwner;
+ if ( pOwner ) // bei parent austragen;
+ pOwner->SetSubList( NULL );
+ if ( pNewOwner )
+ pNewOwner->SetSubList( this );
+ pOwner = pNewOwner;
+ return pOldOwner;
+}
+
+
diff --git a/tools/source/communi/makefile.mk b/tools/source/communi/makefile.mk
new file mode 100644
index 000000000000..1795081a9ec5
--- /dev/null
+++ b/tools/source/communi/makefile.mk
@@ -0,0 +1,50 @@
+#*************************************************************************
+#
+# 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=TOOLS
+TARGET=communi
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+OBJFILES= \
+ $(OBJ)$/parser.obj \
+ $(OBJ)$/geninfo.obj \
+
+SLOFILES= \
+ $(SLO)$/parser.obj \
+ $(SLO)$/geninfo.obj \
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/communi/parser.cxx b/tools/source/communi/parser.cxx
new file mode 100644
index 000000000000..20c2bb3ba059
--- /dev/null
+++ b/tools/source/communi/parser.cxx
@@ -0,0 +1,469 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <stdio.h>
+#include <tools/stream.hxx>
+#include <tools/fsys.hxx>
+
+#include "tools/iparser.hxx"
+#include "tools/geninfo.hxx"
+
+
+
+//
+// class InformationParser
+//
+
+#define cKeyLevelChar '\t'
+
+/*****************************************************************************/
+InformationParser::InformationParser( BOOL bReplace )
+/*****************************************************************************/
+ : bRecover( FALSE ),
+ sOldLine( "" ),
+ bReplaceVariables( bReplace ),
+ nLevel( 0 ),
+ sUPD( "" ),
+ sVersion( "" ),
+ pActStream( NULL ),
+ nErrorCode( 0 ),
+ nErrorLine( 0 ),
+ sErrorText( "" ),
+ nActLine( 0 )
+{
+}
+
+/*****************************************************************************/
+InformationParser::~InformationParser()
+/*****************************************************************************/
+{
+}
+
+/*****************************************************************************/
+ByteString &InformationParser::ReadLine()
+/*****************************************************************************/
+{
+ ByteString sLine;
+
+ if ( bRecover ) {
+ bRecover = FALSE;
+ }
+ else {
+ if ( !pActStream->IsEof()) {
+ pActStream->ReadLine( sLine );
+ xub_StrLen nStart = 0;
+ xub_StrLen nEnd = sLine.Len();
+ BOOL bCopy = FALSE;
+ while ( nStart < nEnd && ( sLine.GetChar( nStart ) == ' ' || sLine.GetChar( nStart ) == 0x09 ) )
+ {
+ nStart++;
+ bCopy = TRUE;
+ }
+
+ while ( nStart < nEnd && ( sLine.GetChar( nEnd-1 ) == ' ' || sLine.GetChar( nEnd-1 ) == 0x09 ) )
+ {
+ nEnd--;
+ bCopy = TRUE;
+ }
+
+ if ( bCopy )
+ sLine = sLine.Copy( nStart, nEnd - nStart );
+
+ if (( sLine.GetChar( 0 ) == '#' ) || ( !sLine.Len())) {
+ if ( sCurrentComment.Len())
+ sCurrentComment += "\n";
+ sCurrentComment += sLine;
+ return ReadLine();
+ }
+ else {
+ if ( bReplaceVariables ) {
+ sLine.SearchAndReplaceAll( "%UPD", sUPD );
+ sLine.SearchAndReplaceAll( "%VERSION", sVersion );
+ }
+ }
+ }
+ else {
+ if ( nLevel ) {
+ sLine = "}";
+ fprintf( stdout, "Reached EOF parsing %s. Suplying extra '}'\n",ByteString( sStreamName, gsl_getSystemTextEncoding()).GetBuffer() );
+ // nErrorCode = IP_UNEXPECTED_EOF;
+ // nErrorLine = nActLine;
+ }
+ else
+ sLine = "";
+ }
+
+ sOldLine = sLine;
+ nActLine++;
+ }
+
+ return sOldLine;
+}
+
+/*****************************************************************************/
+GenericInformation *InformationParser::ReadKey(
+ GenericInformationList *pExistingList )
+/*****************************************************************************/
+{
+ // this method has no error handling yet, but it works very fast.
+ // it is used to create whole informations and sub informations in
+ // a simple data format in memory, readed in a configuration file with
+ // following format:
+
+ /*
+
+ key [value]
+ {
+ key [value]
+ key [value]
+ {
+ key [value]
+ ...
+ ...
+ }
+ }
+ key [value]
+ ...
+ ...
+
+ */
+
+ GenericInformation *pInfo = NULL;
+
+ ByteString sLine( ReadLine());
+ ByteString sKey;
+ ByteString sValue;
+ ByteString sComment( sCurrentComment );
+ sCurrentComment = "";
+
+ // key separated from value by tab?
+ USHORT nWSPos = sLine.Search( ' ' );
+ if ( sLine.Search( '\t' ) < nWSPos ) {
+ nWSPos = sLine.Search( '\t' );
+ sLine.SearchAndReplace( "\t", " " );
+ }
+
+ if ( sLine.GetTokenCount( ' ' ) > 1 ) {
+ sKey = sLine.GetToken( 0, ' ' );
+ sValue = sLine.Copy( sKey.Len() + 1 );
+ while (( sValue.Search( ' ' ) == 0 ) || ( sValue.Search( '\t' ) == 0 )) {
+ sValue.Erase( 0, 1 );
+ }
+ }
+ else
+ sKey=sLine;
+
+ if ( bReplaceVariables && !nLevel ) {
+ sUPD = sKey.Copy( sKey.Len() - 3 );
+ sVersion = sKey;
+ }
+
+ if ( ReadLine() == "{" ) {
+ nLevel++;
+ GenericInformationList *pSubList = new GenericInformationList();
+ while ( ReadLine() != "}" ) {
+ Recover();
+ ReadKey( pSubList );
+ }
+ nLevel--;
+ pInfo = new GenericInformation( sKey, sValue,
+ pExistingList, pSubList );
+ pInfo->SetComment( sComment );
+ }
+ else {
+ Recover();
+ if ( !sKey.Equals( "}" ) && !sKey.Equals( "{" ) )
+ {
+ pInfo = new GenericInformation( sKey, sValue, pExistingList );
+ pInfo->SetComment( sComment );
+ }
+ }
+
+ return pInfo;
+}
+
+/*****************************************************************************/
+void InformationParser::Recover()
+/*****************************************************************************/
+{
+ bRecover = TRUE;
+}
+
+/*****************************************************************************/
+BOOL InformationParser::Save( SvStream &rOutStream,
+ const GenericInformationList *pSaveList,
+ USHORT level, BOOL bStripped )
+/*****************************************************************************/
+{
+ USHORT i;
+ ULONG nInfoListCount;
+ ByteString sTmpStr;
+ GenericInformation *pGenericInfo;
+ GenericInformationList *pGenericInfoList;
+
+ static ByteString aKeyLevel;
+ aKeyLevel.Expand( level, cKeyLevelChar );
+
+ for ( nInfoListCount = 0; nInfoListCount < pSaveList->Count(); nInfoListCount++) {
+ // Key-Value Paare schreiben
+ pGenericInfo = pSaveList->GetObject( nInfoListCount );
+ sTmpStr = "";
+ if ( !bStripped && level )
+ sTmpStr.Append( aKeyLevel.GetBuffer(), level );
+
+ if ( !bStripped )
+ for ( i = 0; i < pGenericInfo->GetComment().GetTokenCount( '\n' ); i++ ) {
+ sTmpStr += pGenericInfo->GetComment().GetToken( i, '\n' );
+ sTmpStr += "\n";
+ if ( level )
+ sTmpStr.Append( aKeyLevel.GetBuffer(), level );
+ }
+
+ sTmpStr += pGenericInfo->GetBuffer();
+ sTmpStr += ' ';
+ sTmpStr += pGenericInfo->GetValue();
+ if ( !rOutStream.WriteLine( sTmpStr ) )
+ return FALSE;
+
+ // wenn vorhanden, bearbeite recursive die Sublisten
+ if (( pGenericInfoList = pGenericInfo->GetSubList() ) != NULL ) {
+ // oeffnende Klammer
+ sTmpStr = "";
+ if ( !bStripped && level )
+ sTmpStr.Append( aKeyLevel.GetBuffer(), level );
+ sTmpStr += '{';
+ if ( !rOutStream.WriteLine( sTmpStr ) )
+ return FALSE;
+ // recursiv die sublist abarbeiten
+ if ( !Save( rOutStream, pGenericInfoList, level+1, bStripped ) )
+ return FALSE;
+ // schliessende Klammer
+ sTmpStr = "";
+ if ( !bStripped && level )
+ sTmpStr.Append( aKeyLevel.GetBuffer(), level );
+ sTmpStr += '}';
+ if ( !rOutStream.WriteLine( sTmpStr ) )
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*****************************************************************************/
+GenericInformationList *InformationParser::Execute(
+ SvStream &rSourceStream,
+ GenericInformationList *pExistingList )
+/*****************************************************************************/
+{
+ GenericInformationList *pList;
+ if ( pExistingList )
+ pList = pExistingList;
+ else
+ pList = new GenericInformationList();
+
+ pActStream = &rSourceStream;
+
+ // read all infos out of current file
+ while( !rSourceStream.IsEof()) {
+ nLevel = 0;
+ ReadKey( pList );
+ }
+
+ return pList;
+}
+
+/*****************************************************************************/
+GenericInformationList *InformationParser::Execute( SvMemoryStream &rSourceStream,
+ GenericInformationList *pExistingList )
+/*****************************************************************************/
+{
+ sStreamName = UniString( "Memory", gsl_getSystemTextEncoding());
+ return Execute( (SvStream &)rSourceStream, pExistingList );
+}
+
+/*****************************************************************************/
+GenericInformationList *InformationParser::Execute(
+ SvFileStream &rSourceStream,
+ GenericInformationList *pExistingList )
+/*****************************************************************************/
+{
+ if ( !rSourceStream.IsOpen())
+ return NULL;
+ sStreamName = rSourceStream.GetFileName();
+ return Execute( (SvStream &)rSourceStream, pExistingList );
+}
+
+/*****************************************************************************/
+GenericInformationList *InformationParser::Execute( UniString &rSourceFile,
+ GenericInformationList *pExistingList )
+/*****************************************************************************/
+{
+ DirEntry aDirEntry( rSourceFile );
+ if ( !aDirEntry.Exists())
+ return NULL;
+
+ GenericInformationList *pList;
+ if ( pExistingList )
+ pList = pExistingList;
+ else
+ pList = new GenericInformationList();
+
+ // reset status
+ nErrorCode = 0;
+ nErrorLine = 0;
+ nActLine = 0;
+
+ SvFileStream aActStream;
+ aActStream.Open( rSourceFile, STREAM_READ );
+ if( aActStream.GetError())
+ return NULL;
+
+ pActStream = &aActStream;
+ if ( !Execute( aActStream, pList )) {
+ delete pList;
+ pList = NULL;
+ }
+
+ // close the stream
+ aActStream.Close();
+ pActStream = NULL;
+
+ if ( !nErrorCode )
+ return pList;
+
+ return NULL;
+}
+
+/*****************************************************************************/
+GenericInformationList *InformationParser::Execute( Dir &rDir,
+ GenericInformationList *pExistingList )
+/*****************************************************************************/
+{
+ GenericInformationList *pList;
+
+ if ( pExistingList )
+ pList = pExistingList;
+ else
+ pList = new GenericInformationList();
+
+ for ( USHORT i = 0; i < rDir.Count(); i++ ) {
+
+ // execute this dir
+ UniString sNextFile( rDir[i].GetFull());
+ GenericInformationList *pSubList = Execute( sNextFile );
+
+ if ( !pSubList ) {
+ // any errors ?
+ delete pList;
+ return NULL;
+ }
+
+ // create new info and insert it into list
+ ByteString sFileKey( rDir[i].GetName(), RTL_TEXTENCODING_UTF8 );
+ new GenericInformation(
+ sFileKey,
+ ByteString( "" ),
+ pList, pSubList );
+ }
+
+ return pList;
+}
+
+/*****************************************************************************/
+BOOL InformationParser::Save( SvFileStream &rSourceStream,
+ const GenericInformationList *pSaveList )
+/*****************************************************************************/
+{
+ if ( !rSourceStream.IsOpen() || !Save( (SvStream &)rSourceStream, pSaveList, 0, FALSE ))
+ {
+ printf( "ERROR saving file \"%s\"\n",ByteString( rSourceStream.GetFileName(), gsl_getSystemTextEncoding()).GetBuffer() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+BOOL InformationParser::Save( SvMemoryStream &rSourceStream,
+ const GenericInformationList *pSaveList )
+/*****************************************************************************/
+{
+ Time a;
+ BOOL bRet = Save( (SvStream &)rSourceStream, pSaveList, 0, TRUE );
+ Time b;
+ b = b - a;
+ return bRet;
+}
+
+/*****************************************************************************/
+BOOL InformationParser::Save( const UniString &rSourceFile,
+ const GenericInformationList *pSaveList )
+/*****************************************************************************/
+{
+ SvFileStream *pOutFile = new SvFileStream( rSourceFile, STREAM_STD_WRITE | STREAM_TRUNC );
+
+ if ( !Save( *pOutFile, pSaveList )) {
+ delete pOutFile;
+ return FALSE;
+ }
+ delete pOutFile;
+ return TRUE;
+}
+
+/*****************************************************************************/
+USHORT InformationParser::GetErrorCode()
+/*****************************************************************************/
+{
+ return nErrorCode;
+}
+
+/*****************************************************************************/
+ByteString &InformationParser::GetErrorText()
+/*****************************************************************************/
+{
+ // sErrorText = pActStream->GetFileName();
+ sErrorText = ByteString( sStreamName, gsl_getSystemTextEncoding());
+ sErrorText += ByteString( " (" );
+ sErrorText += ByteString::CreateFromInt64(nErrorLine);
+ sErrorText += ByteString( "): " );
+
+ switch ( nErrorCode ) {
+ case IP_NO_ERROR:
+ sErrorText += ByteString( "Keine Fehler aufgetereten" );
+ break;
+ case IP_UNEXPECTED_EOF:
+ sErrorText += ByteString( "Ungültiges Dateiende!" );
+ break;
+ }
+
+ return sErrorText;
+}
+
+
diff --git a/tools/source/datetime/datetime.cxx b/tools/source/datetime/datetime.cxx
new file mode 100644
index 000000000000..8b679478c535
--- /dev/null
+++ b/tools/source/datetime/datetime.cxx
@@ -0,0 +1,442 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/datetime.hxx>
+#include <rtl/math.hxx>
+
+/*************************************************************************
+|*
+|* DateTime::IsBetween()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 18.05.92
+|* Letzte Aenderung TH 18.05.92
+|*
+*************************************************************************/
+
+BOOL DateTime::IsBetween( const DateTime& rFrom,
+ const DateTime& rTo ) const
+{
+ if ( (*this >= rFrom) && (*this <= rTo) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator >()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 18.05.92
+|* Letzte Aenderung TH 18.05.92
+|*
+*************************************************************************/
+
+BOOL DateTime::operator >( const DateTime& rDateTime ) const
+{
+ if ( (Date::operator>( rDateTime )) ||
+ (Date::operator==( rDateTime ) && Time::operator>( rDateTime )) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator <()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 18.05.92
+|* Letzte Aenderung TH 18.05.92
+|*
+*************************************************************************/
+
+BOOL DateTime::operator <( const DateTime& rDateTime ) const
+{
+ if ( (Date::operator<( rDateTime )) ||
+ (Date::operator==( rDateTime ) && Time::operator<( rDateTime )) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator >=()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 18.05.92
+|* Letzte Aenderung TH 18.05.92
+|*
+*************************************************************************/
+
+BOOL DateTime::operator >=( const DateTime& rDateTime ) const
+{
+ if ( (Date::operator>( rDateTime )) ||
+ (Date::operator==( rDateTime ) && Time::operator>=( rDateTime )) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator <=()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 18.05.92
+|* Letzte Aenderung TH 18.05.92
+|*
+*************************************************************************/
+
+BOOL DateTime::operator <=( const DateTime& rDateTime ) const
+{
+ if ( (Date::operator<( rDateTime )) ||
+ (Date::operator==( rDateTime ) && Time::operator<=( rDateTime )) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DateTime::GetSecFromDateTime()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 02.10.96
+|* Letzte Aenderung TH 02.10.96
+|*
+*************************************************************************/
+
+long DateTime::GetSecFromDateTime( const Date& rDate ) const
+{
+ if ( Date::operator<( rDate ) )
+ return 0;
+ else
+ {
+ long nSec = Date( *this ) - rDate;
+ nSec *= 24UL*60*60;
+ long nHour = GetHour();
+ long nMin = GetMin();
+ nSec += (nHour*3600)+(nMin*60)+GetSec();
+ return nSec;
+ }
+}
+
+/*************************************************************************
+|*
+|* DateTime::GetSecFromDateTime()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 02.10.96
+|* Letzte Aenderung TH 02.10.96
+|*
+*************************************************************************/
+
+void DateTime::MakeDateTimeFromSec( const Date& rDate, ULONG nSec )
+{
+ long nDays = nSec / (24UL*60*60);
+ ((Date*)this)->operator=( rDate );
+ nSec -= nDays * (24UL*60*60);
+ USHORT nMin = (USHORT)(nSec / 60);
+ nSec -= nMin * 60;
+ ((Time*)this)->operator=( Time( 0, nMin, (USHORT)nSec ) );
+ operator+=( nDays );
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator +=()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 02.10.96
+|* Letzte Aenderung TH 02.10.96
+|*
+*************************************************************************/
+
+DateTime& DateTime::operator +=( const Time& rTime )
+{
+ Time aTime = *this;
+ aTime += rTime;
+ USHORT nHours = aTime.GetHour();
+ if ( aTime.GetTime() > 0 )
+ {
+ while ( nHours >= 24 )
+ {
+ Date::operator++();
+ nHours -= 24;
+ }
+ aTime.SetHour( nHours );
+ }
+ else if ( aTime.GetTime() != 0 )
+ {
+ while ( nHours >= 24 )
+ {
+ Date::operator--();
+ nHours -= 24;
+ }
+ Date::operator--();
+ aTime = Time( 24, 0, 0 )+aTime;
+ }
+ Time::operator=( aTime );
+
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator -=()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 02.10.96
+|* Letzte Aenderung TH 02.10.96
+|*
+*************************************************************************/
+
+DateTime& DateTime::operator -=( const Time& rTime )
+{
+ Time aTime = *this;
+ aTime -= rTime;
+ USHORT nHours = aTime.GetHour();
+ if ( aTime.GetTime() > 0 )
+ {
+ while ( nHours >= 24 )
+ {
+ Date::operator++();
+ nHours -= 24;
+ }
+ aTime.SetHour( nHours );
+ }
+ else if ( aTime.GetTime() != 0 )
+ {
+ while ( nHours >= 24 )
+ {
+ Date::operator--();
+ nHours -= 24;
+ }
+ Date::operator--();
+ aTime = Time( 24, 0, 0 )+aTime;
+ }
+ Time::operator=( aTime );
+
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator+()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 02.10.96
+|* Letzte Aenderung TH 02.10.96
+|*
+*************************************************************************/
+
+DateTime operator +( const DateTime& rDateTime, long nDays )
+{
+ DateTime aDateTime( rDateTime );
+ aDateTime += nDays;
+ return aDateTime;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator-()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 02.10.96
+|* Letzte Aenderung TH 02.10.96
+|*
+*************************************************************************/
+
+DateTime operator -( const DateTime& rDateTime, long nDays )
+{
+ DateTime aDateTime( rDateTime );
+ aDateTime -= nDays;
+ return aDateTime;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator+()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 02.10.96
+|* Letzte Aenderung TH 02.10.96
+|*
+*************************************************************************/
+
+DateTime operator +( const DateTime& rDateTime, const Time& rTime )
+{
+ DateTime aDateTime( rDateTime );
+ aDateTime += rTime;
+ return aDateTime;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator-()
+|*
+|* Beschreibung DATETIME.SDW
+|* Ersterstellung TH 02.10.96
+|* Letzte Aenderung TH 02.10.96
+|*
+*************************************************************************/
+
+DateTime operator -( const DateTime& rDateTime, const Time& rTime )
+{
+ DateTime aDateTime( rDateTime );
+ aDateTime -= rTime;
+ return aDateTime;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator +=( double )
+|*
+*************************************************************************/
+
+DateTime& DateTime::operator +=( double fTimeInDays )
+{
+ double fInt, fFrac;
+ if ( fTimeInDays < 0.0 )
+ {
+ fInt = ::rtl::math::approxCeil( fTimeInDays );
+ fFrac = fInt <= fTimeInDays ? 0.0 : fTimeInDays - fInt;
+ }
+ else
+ {
+ fInt = ::rtl::math::approxFloor( fTimeInDays );
+ fFrac = fInt >= fTimeInDays ? 0.0 : fTimeInDays - fInt;
+ }
+ Date::operator+=( long(fInt) ); // full days
+ if ( fFrac )
+ {
+ Time aTime(0); // default ctor calls system time, we don't need that
+ fFrac *= 24UL * 60 * 60 * 1000; // time expressed in milliseconds
+ aTime.MakeTimeFromMS( long(fFrac) ); // method handles negative ms
+ operator+=( aTime );
+ }
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator +( double )
+|*
+*************************************************************************/
+
+DateTime operator +( const DateTime& rDateTime, double fTimeInDays )
+{
+ DateTime aDateTime( rDateTime );
+ aDateTime += fTimeInDays;
+ return aDateTime;
+}
+
+/*************************************************************************
+|*
+|* DateTime::operator -()
+|*
+*************************************************************************/
+
+double operator -( const DateTime& rDateTime1, const DateTime& rDateTime2 )
+{
+ long nDays = (const Date&) rDateTime1 - (const Date&) rDateTime2;
+ long nTime = rDateTime1.GetMSFromTime() - rDateTime2.GetMSFromTime();
+ if ( nTime )
+ {
+ double fTime = double(nTime);
+ fTime /= 24UL * 60 * 60 * 1000; // convert from milliseconds to fraction
+ if ( nDays < 0 && fTime > 0.0 )
+ fTime = 1.0 - fTime;
+ return double(nDays) + fTime;
+ }
+ return double(nDays);
+}
+
+void DateTime::GetWin32FileDateTime( sal_uInt32 & rLower, sal_uInt32 & rUpper )
+{
+ const sal_Int64 a100nPerSecond = SAL_CONST_INT64( 10000000 );
+ const sal_Int64 a100nPerDay = a100nPerSecond * sal_Int64( 60 * 60 * 24 );
+
+ sal_Int64 nYears = GetYear() - 1601;
+ sal_Int64 nDays =
+ nYears * 365 +
+ nYears / 4 - nYears / 100 + nYears / 400 +
+ GetDayOfYear() - 1;
+
+ sal_Int64 aTime =
+ a100nPerDay * nDays +
+ a100nPerSecond * (
+ sal_Int64( GetSec() ) +
+ 60 * sal_Int64( GetMin() ) +
+ 60 * 60 * sal_Int64( GetHour() ) );
+
+ rLower = sal_uInt32( aTime % SAL_CONST_UINT64( 0x100000000 ) );
+ rUpper = sal_uInt32( aTime / SAL_CONST_UINT64( 0x100000000 ) );
+}
+
+DateTime DateTime::CreateFromWin32FileDateTime( const sal_uInt32 & rLower, const sal_uInt32 & rUpper )
+{
+ const sal_Int64 a100nPerSecond = SAL_CONST_INT64( 10000000 );
+ const sal_Int64 a100nPerDay = a100nPerSecond * sal_Int64( 60 * 60 * 24 );
+
+ sal_Int64 aTime = sal_Int64(
+ sal_uInt64( rUpper ) * SAL_CONST_UINT64( 0x100000000 ) +
+ sal_uInt64( rLower ) );
+
+ sal_Int64 nDays = aTime / a100nPerDay;
+ sal_Int64 nYears =
+ ( nDays -
+ ( nDays / ( 4 * 365 ) ) +
+ ( nDays / ( 100 * 365 ) ) -
+ ( nDays / ( 400 * 365 ) ) ) / 365;
+ nDays -= nYears * 365 + nYears / 4 - nYears / 100 + nYears / 400;
+
+ USHORT nMonths = 0;
+ for( sal_Int64 nDaysCount = nDays; nDaysCount >= 0; )
+ {
+ nDays = nDaysCount;
+ nMonths ++;
+ nDaysCount -= Date(
+ 1, nMonths, sal::static_int_cast< USHORT >(1601 + nYears) ).
+ GetDaysInMonth();
+ }
+
+ Date _aDate(
+ (USHORT)( nDays + 1 ), nMonths,
+ sal::static_int_cast< USHORT >(nYears + 1601) );
+ Time _aTime( ULONG( ( aTime / ( a100nPerSecond * 60 * 60 ) ) % sal_Int64( 24 ) ),
+ ULONG( ( aTime / ( a100nPerSecond * 60 ) ) % sal_Int64( 60 ) ),
+ ULONG( ( aTime / ( a100nPerSecond ) ) % sal_Int64( 60 ) ) );
+
+ return DateTime( _aDate, _aTime );
+}
diff --git a/tools/source/datetime/makefile.mk b/tools/source/datetime/makefile.mk
new file mode 100644
index 000000000000..3d46cc6ce1b0
--- /dev/null
+++ b/tools/source/datetime/makefile.mk
@@ -0,0 +1,50 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=datetime
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/tdate.obj \
+ $(SLO)$/ttime.obj \
+ $(SLO)$/datetime.obj
+
+OBJFILES= $(OBJ)$/tdate.obj \
+ $(OBJ)$/ttime.obj \
+ $(OBJ)$/datetime.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/datetime/tdate.cxx b/tools/source/datetime/tdate.cxx
new file mode 100644
index 000000000000..e6bb4345d9f9
--- /dev/null
+++ b/tools/source/datetime/tdate.cxx
@@ -0,0 +1,494 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#if defined( OS2 )
+#define INCL_DOSDATETIME
+#include <svpm.h>
+#elif defined( WNT )
+#ifdef _MSC_VER
+#pragma warning (push,1)
+#endif
+#include <tools/svwin.h>
+#ifdef _MSC_VER
+#pragma warning (pop)
+#endif
+#else
+#include <time.h>
+#endif
+
+#include <tools/debug.hxx>
+#include <tools/date.hxx>
+#ifdef MACOSX
+extern "C" {
+struct tm *localtime_r(const time_t *timep, struct tm *buffer);
+}
+#endif
+
+// =======================================================================
+
+static USHORT aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 };
+
+#define MAX_DAYS 3636532
+
+// =======================================================================
+
+inline BOOL ImpIsLeapYear( USHORT nYear )
+{
+ return (
+ ( ((nYear % 4) == 0) && ((nYear % 100) != 0) ) ||
+ ( (nYear % 400) == 0 )
+ );
+}
+
+// -----------------------------------------------------------------------
+
+inline USHORT DaysInMonth( USHORT nMonth, USHORT nYear )
+{
+ if ( nMonth != 2 )
+ return aDaysInMonth[nMonth-1];
+ else
+ {
+ if (ImpIsLeapYear(nYear))
+ return aDaysInMonth[nMonth-1] + 1;
+ else
+ return aDaysInMonth[nMonth-1];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long Date::DateToDays( USHORT nDay, USHORT nMonth, USHORT nYear )
+{
+ long nDays;
+
+ nDays = ((ULONG)nYear-1) * 365;
+ nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
+ for( USHORT i = 1; i < nMonth; i++ )
+ nDays += DaysInMonth(i,nYear);
+ nDays += nDay;
+ return nDays;
+}
+
+// -----------------------------------------------------------------------
+
+static void DaysToDate( long nDays,
+ USHORT& rDay, USHORT& rMonth, USHORT& rYear )
+{
+ long nTempDays;
+ long i = 0;
+ BOOL bCalc;
+
+ do
+ {
+ nTempDays = (long)nDays;
+ rYear = (USHORT)((nTempDays / 365) - i);
+ nTempDays -= ((ULONG)rYear-1) * 365;
+ nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
+ bCalc = FALSE;
+ if ( nTempDays < 1 )
+ {
+ i++;
+ bCalc = TRUE;
+ }
+ else
+ {
+ if ( nTempDays > 365 )
+ {
+ if ( (nTempDays != 366) || !ImpIsLeapYear( rYear ) )
+ {
+ i--;
+ bCalc = TRUE;
+ }
+ }
+ }
+ }
+ while ( bCalc );
+
+ rMonth = 1;
+ while ( (ULONG)nTempDays > DaysInMonth( rMonth, rYear ) )
+ {
+ nTempDays -= DaysInMonth( rMonth, rYear );
+ rMonth++;
+ }
+ rDay = (USHORT)nTempDays;
+}
+
+// =======================================================================
+
+Date::Date()
+{
+#if defined( OS2 )
+ DATETIME aDateTime;
+ DosGetDateTime( &aDateTime );
+
+ // Datum zusammenbauen
+ nDate = ((ULONG)aDateTime.day) +
+ (((ULONG)aDateTime.month)*100) +
+ (((ULONG)aDateTime.year)*10000);
+#elif defined WNT
+ SYSTEMTIME aDateTime;
+ GetLocalTime( &aDateTime );
+
+ // Datum zusammenbauen
+ nDate = ((ULONG)aDateTime.wDay) +
+ (((ULONG)aDateTime.wMonth)*100) +
+ (((ULONG)aDateTime.wYear)*10000);
+#else
+ time_t nTmpTime;
+ struct tm aTime;
+
+ // Zeit ermitteln
+ nTmpTime = time( 0 );
+
+ // Datum zusammenbauen
+ if ( localtime_r( &nTmpTime, &aTime ) )
+ {
+ nDate = ((ULONG)aTime.tm_mday) +
+ (((ULONG)(aTime.tm_mon+1))*100) +
+ (((ULONG)(aTime.tm_year+1900))*10000);
+ }
+ else
+ nDate = 1 + 100 + (((ULONG)1900)*10000);
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+void Date::SetDay( USHORT nNewDay )
+{
+ ULONG nMonth = GetMonth();
+ ULONG nYear = GetYear();
+
+ nDate = ((ULONG)(nNewDay%100)) + (nMonth*100) + (nYear*10000);
+}
+
+// -----------------------------------------------------------------------
+
+void Date::SetMonth( USHORT nNewMonth )
+{
+ ULONG nDay = GetDay();
+ ULONG nYear = GetYear();
+
+ nDate = nDay + (((ULONG)(nNewMonth%100))*100) + (nYear*10000);
+}
+
+// -----------------------------------------------------------------------
+
+void Date::SetYear( USHORT nNewYear )
+{
+ ULONG nDay = GetDay();
+ ULONG nMonth = GetMonth();
+
+ nDate = nDay + (nMonth*100) + (((ULONG)(nNewYear%10000))*10000);
+}
+
+// -----------------------------------------------------------------------
+
+DayOfWeek Date::GetDayOfWeek() const
+{
+ return (DayOfWeek)((ULONG)(DateToDays( GetDay(), GetMonth(), GetYear() )-1) % 7);
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Date::GetDayOfYear() const
+{
+ USHORT nDay = GetDay();
+ for( USHORT i = 1; i < GetMonth(); i++ )
+ nDay = nDay + ::DaysInMonth( i, GetYear() ); // += yields a warning on MSVC, so don't use it
+ return nDay;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Date::GetWeekOfYear( DayOfWeek eStartDay,
+ sal_Int16 nMinimumNumberOfDaysInWeek ) const
+{
+ short nWeek;
+ short n1WDay = (short)Date( 1, 1, GetYear() ).GetDayOfWeek();
+ short nDayOfYear = (short)GetDayOfYear();
+
+ // Wochentage beginnen bei 0, deshalb einen abziehen
+ nDayOfYear--;
+ // StartDay beruecksichtigen
+ n1WDay = (n1WDay+(7-(short)eStartDay)) % 7;
+
+ if (nMinimumNumberOfDaysInWeek < 1 || 7 < nMinimumNumberOfDaysInWeek)
+ {
+ DBG_ERRORFILE("Date::GetWeekOfYear: invalid nMinimumNumberOfDaysInWeek");
+ nMinimumNumberOfDaysInWeek = 4;
+ }
+
+ if ( nMinimumNumberOfDaysInWeek == 1 )
+ {
+ nWeek = ((n1WDay+nDayOfYear)/7) + 1;
+ // 53te-Woche nur dann, wenn wir nicht schon in der ersten
+ // Woche des neuen Jahres liegen
+ if ( nWeek == 54 )
+ nWeek = 1;
+ else if ( nWeek == 53 )
+ {
+ short nDaysInYear = (short)GetDaysInYear();
+ short nDaysNextYear = (short)Date( 1, 1, GetYear()+1 ).GetDayOfWeek();
+ nDaysNextYear = (nDaysNextYear+(7-(short)eStartDay)) % 7;
+ if ( nDayOfYear > (nDaysInYear-nDaysNextYear-1) )
+ nWeek = 1;
+ }
+ }
+ else if ( nMinimumNumberOfDaysInWeek == 7 )
+ {
+ nWeek = ((n1WDay+nDayOfYear)/7);
+ // Erste Woche eines Jahres entspricht der letzen Woche des
+ // vorherigen Jahres
+ if ( nWeek == 0 )
+ {
+ Date aLastDatePrevYear( 31, 12, GetYear()-1 );
+ nWeek = aLastDatePrevYear.GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
+ }
+ }
+ else // ( nMinimumNumberOfDaysInWeek == somehing_else, commentary examples for 4 )
+ {
+ // x_monday - thursday
+ if ( n1WDay < nMinimumNumberOfDaysInWeek )
+ nWeek = 1;
+ // friday
+ else if ( n1WDay == nMinimumNumberOfDaysInWeek )
+ nWeek = 53;
+ // saturday
+ else if ( n1WDay == nMinimumNumberOfDaysInWeek + 1 )
+ {
+ // Jahr nach Schaltjahr
+ if ( Date( 1, 1, GetYear()-1 ).IsLeapYear() )
+ nWeek = 53;
+ else
+ nWeek = 52;
+ }
+ // sunday
+ else
+ nWeek = 52;
+
+ if ( (nWeek == 1) || (nDayOfYear + n1WDay > 6) )
+ {
+ if ( nWeek == 1 )
+ nWeek += (nDayOfYear + n1WDay) / 7;
+ else
+ nWeek = (nDayOfYear + n1WDay) / 7;
+ if ( nWeek == 53 )
+ {
+ // naechster x_Sonntag == erster x_Sonntag im neuen Jahr
+ // == noch gleiche Woche
+ long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
+ nTempDays += 6 - (GetDayOfWeek()+(7-(short)eStartDay)) % 7;
+ USHORT nDay;
+ USHORT nMonth;
+ USHORT nYear;
+ DaysToDate( nTempDays, nDay, nMonth, nYear );
+ nWeek = Date( nDay, nMonth, nYear ).GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
+ }
+ }
+ }
+
+ return (USHORT)nWeek;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Date::GetDaysInMonth() const
+{
+ return DaysInMonth( GetMonth(), GetYear() );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Date::IsLeapYear() const
+{
+ USHORT nYear = GetYear();
+ return ImpIsLeapYear( nYear );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Date::IsValid() const
+{
+ USHORT nDay = GetDay();
+ USHORT nMonth = GetMonth();
+ USHORT nYear = GetYear();
+
+ if ( !nMonth || (nMonth > 12) )
+ return FALSE;
+ if ( !nDay || (nDay > DaysInMonth( nMonth, nYear )) )
+ return FALSE;
+ else if ( nYear <= 1582 )
+ {
+ if ( nYear < 1582 )
+ return FALSE;
+ else if ( nMonth < 10 )
+ return FALSE;
+ else if ( (nMonth == 10) && (nDay < 15) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+Date& Date::operator +=( long nDays )
+{
+ USHORT nDay;
+ USHORT nMonth;
+ USHORT nYear;
+ long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
+
+ nTempDays += nDays;
+ if ( nTempDays > MAX_DAYS )
+ nDate = 31 + (12*100) + (((ULONG)9999)*10000);
+ else if ( nTempDays <= 0 )
+ nDate = 1 + 100;
+ else
+ {
+ DaysToDate( nTempDays, nDay, nMonth, nYear );
+ nDate = ((ULONG)nDay) + (((ULONG)nMonth)*100) + (((ULONG)nYear)*10000);
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+Date& Date::operator -=( long nDays )
+{
+ USHORT nDay;
+ USHORT nMonth;
+ USHORT nYear;
+ long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
+
+ nTempDays -= nDays;
+ if ( nTempDays > MAX_DAYS )
+ nDate = 31 + (12*100) + (((ULONG)9999)*10000);
+ else if ( nTempDays <= 0 )
+ nDate = 1 + 100;
+ else
+ {
+ DaysToDate( nTempDays, nDay, nMonth, nYear );
+ nDate = ((ULONG)nDay) + (((ULONG)nMonth)*100) + (((ULONG)nYear)*10000);
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+Date& Date::operator ++()
+{
+ USHORT nDay;
+ USHORT nMonth;
+ USHORT nYear;
+ long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
+
+ if ( nTempDays < MAX_DAYS )
+ {
+ nTempDays++;
+ DaysToDate( nTempDays, nDay, nMonth, nYear );
+ nDate = ((ULONG)nDay) + (((ULONG)nMonth)*100) + (((ULONG)nYear)*10000);
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+Date& Date::operator --()
+{
+ USHORT nDay;
+ USHORT nMonth;
+ USHORT nYear;
+ long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
+
+ if ( nTempDays > 1 )
+ {
+ nTempDays--;
+ DaysToDate( nTempDays, nDay, nMonth, nYear );
+ nDate = ((ULONG)nDay) + (((ULONG)nMonth)*100) + (((ULONG)nYear)*10000);
+ }
+ return *this;
+}
+
+#ifndef MPW33
+
+// -----------------------------------------------------------------------
+
+Date Date::operator ++( int )
+{
+ Date aOldDate = *this;
+ Date::operator++();
+ return aOldDate;
+}
+
+// -----------------------------------------------------------------------
+
+Date Date::operator --( int )
+{
+ Date aOldDate = *this;
+ Date::operator--();
+ return aOldDate;
+}
+
+#endif
+
+// -----------------------------------------------------------------------
+
+Date operator +( const Date& rDate, long nDays )
+{
+ Date aDate( rDate );
+ aDate += nDays;
+ return aDate;
+}
+
+// -----------------------------------------------------------------------
+
+Date operator -( const Date& rDate, long nDays )
+{
+ Date aDate( rDate );
+ aDate -= nDays;
+ return aDate;
+}
+
+// -----------------------------------------------------------------------
+
+long operator -( const Date& rDate1, const Date& rDate2 )
+{
+ ULONG nTempDays1 = Date::DateToDays( rDate1.GetDay(), rDate1.GetMonth(),
+ rDate1.GetYear() );
+ ULONG nTempDays2 = Date::DateToDays( rDate2.GetDay(), rDate2.GetMonth(),
+ rDate2.GetYear() );
+ return nTempDays1 - nTempDays2;
+}
diff --git a/tools/source/datetime/ttime.cxx b/tools/source/datetime/ttime.cxx
new file mode 100644
index 000000000000..9483cc10065e
--- /dev/null
+++ b/tools/source/datetime/ttime.cxx
@@ -0,0 +1,445 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _TOOLS_TIME_CXX
+
+#if defined( OS2 )
+#define INCL_DOSMISC
+#define INCL_DOSDATETIME
+#include <svpm.h>
+#elif defined( WNT )
+#ifdef _MSC_VER
+#pragma warning (push,1)
+#endif
+#include <tools/svwin.h>
+#ifdef _MSC_VER
+#pragma warning (pop)
+#endif
+#elif defined UNX
+#include <unistd.h>
+#include <limits.h>
+#include <math.h>
+#include <sys/time.h>
+#endif
+
+#include <time.h>
+#include <tools/time.hxx>
+
+#if defined(SOLARIS) && defined(__GNUC__)
+extern long altzone;
+#endif
+
+// =======================================================================
+
+static sal_Int32 TimeToSec100( const Time& rTime )
+{
+ short nSign = (rTime.GetTime() >= 0) ? +1 : -1;
+ sal_Int32 nHour = rTime.GetHour();
+ sal_Int32 nMin = rTime.GetMin();
+ sal_Int32 nSec = rTime.GetSec();
+ sal_Int32 n100Sec = rTime.Get100Sec();
+
+// Wegen Interal Compiler Error bei MSC, etwas komplizierter
+// return (n100Sec + (nSec*100) + (nMin*60*100) + (nHour*60*60*100) * nSign);
+
+ sal_Int32 nRet = n100Sec;
+ nRet += nSec*100;
+ nRet += nMin*60*100;
+ nRet += nHour*60*60*100;
+
+ return (nRet * nSign);
+}
+
+// -----------------------------------------------------------------------
+
+static Time Sec100ToTime( sal_Int32 nSec100 )
+{
+ short nSign;
+ if ( nSec100 < 0 )
+ {
+ nSec100 *= -1;
+ nSign = -1;
+ }
+ else
+ nSign = 1;
+
+ Time aTime( 0, 0, 0, nSec100 );
+ aTime.SetTime( aTime.GetTime() * nSign );
+ return aTime;
+}
+
+// =======================================================================
+
+Time::Time()
+{
+#if defined( OS2 )
+ DATETIME aDateTime;
+ DosGetDateTime( &aDateTime );
+
+ // Zeit zusammenbauen
+ nTime = (((sal_Int32)aDateTime.hours)*1000000) +
+ (((sal_Int32)aDateTime.minutes)*10000) +
+ (((sal_Int32)aDateTime.seconds)*100) +
+ ((sal_Int32)aDateTime.hundredths);
+#elif defined( WNT )
+ SYSTEMTIME aDateTime;
+ GetLocalTime( &aDateTime );
+
+ // Zeit zusammenbauen
+ nTime = (((sal_Int32)aDateTime.wHour)*1000000) +
+ (((sal_Int32)aDateTime.wMinute)*10000) +
+ (((sal_Int32)aDateTime.wSecond)*100) +
+ ((sal_Int32)aDateTime.wMilliseconds/10);
+#else
+ time_t nTmpTime;
+ struct tm aTime;
+
+ // Zeit ermitteln
+ nTmpTime = time( 0 );
+
+ // Zeit zusammenbauen
+ if ( localtime_r( &nTmpTime, &aTime ) )
+ {
+ nTime = (((sal_Int32)aTime.tm_hour)*1000000) +
+ (((sal_Int32)aTime.tm_min)*10000) +
+ (((sal_Int32)aTime.tm_sec)*100);
+ }
+ else
+ nTime = 0;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+Time::Time( const Time& rTime )
+{
+ nTime = rTime.nTime;
+}
+
+// -----------------------------------------------------------------------
+
+Time::Time( ULONG nHour, ULONG nMin, ULONG nSec, ULONG n100Sec )
+{
+ // Zeit normalisieren
+ nSec += n100Sec / 100;
+ n100Sec = n100Sec % 100;
+ nMin += nSec / 60;
+ nSec = nSec % 60;
+ nHour += nMin / 60;
+ nMin = nMin % 60;
+
+ // Zeit zusammenbauen
+ nTime = (sal_Int32)(n100Sec + (nSec*100) + (nMin*10000) + (nHour*1000000));
+}
+
+// -----------------------------------------------------------------------
+
+void Time::SetHour( USHORT nNewHour )
+{
+ short nSign = (nTime >= 0) ? +1 : -1;
+ sal_Int32 nMin = GetMin();
+ sal_Int32 nSec = GetSec();
+ sal_Int32 n100Sec = Get100Sec();
+
+ nTime = (n100Sec + (nSec*100) + (nMin*10000) +
+ (((sal_Int32)nNewHour)*1000000)) * nSign;
+}
+
+// -----------------------------------------------------------------------
+
+void Time::SetMin( USHORT nNewMin )
+{
+ short nSign = (nTime >= 0) ? +1 : -1;
+ sal_Int32 nHour = GetHour();
+ sal_Int32 nSec = GetSec();
+ sal_Int32 n100Sec = Get100Sec();
+
+ // kein Ueberlauf
+ nNewMin = nNewMin % 60;
+
+ nTime = (n100Sec + (nSec*100) + (((sal_Int32)nNewMin)*10000) +
+ (nHour*1000000)) * nSign;
+}
+
+// -----------------------------------------------------------------------
+
+void Time::SetSec( USHORT nNewSec )
+{
+ short nSign = (nTime >= 0) ? +1 : -1;
+ sal_Int32 nHour = GetHour();
+ sal_Int32 nMin = GetMin();
+ sal_Int32 n100Sec = Get100Sec();
+
+ // kein Ueberlauf
+ nNewSec = nNewSec % 60;
+
+ nTime = (n100Sec + (((sal_Int32)nNewSec)*100) + (nMin*10000) +
+ (nHour*1000000)) * nSign;
+}
+
+// -----------------------------------------------------------------------
+
+void Time::Set100Sec( USHORT nNew100Sec )
+{
+ short nSign = (nTime >= 0) ? +1 : -1;
+ sal_Int32 nHour = GetHour();
+ sal_Int32 nMin = GetMin();
+ sal_Int32 nSec = GetSec();
+
+ // kein Ueberlauf
+ nNew100Sec = nNew100Sec % 100;
+
+ nTime = (((sal_Int32)nNew100Sec) + (nSec*100) + (nMin*10000) +
+ (nHour*1000000)) * nSign;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int32 Time::GetMSFromTime() const
+{
+ short nSign = (nTime >= 0) ? +1 : -1;
+ sal_Int32 nHour = GetHour();
+ sal_Int32 nMin = GetMin();
+ sal_Int32 nSec = GetSec();
+ sal_Int32 n100Sec = Get100Sec();
+
+ return (((nHour*3600000)+(nMin*60000)+(nSec*1000)+(n100Sec*10))*nSign);
+}
+
+// -----------------------------------------------------------------------
+
+void Time::MakeTimeFromMS( sal_Int32 nMS )
+{
+ short nSign;
+ if ( nMS < 0 )
+ {
+ nMS *= -1;
+ nSign = -1;
+ }
+ else
+ nSign = 1;
+
+ Time aTime( 0, 0, 0, nMS/10 );
+ SetTime( aTime.GetTime() * nSign );
+}
+
+// -----------------------------------------------------------------------
+
+double Time::GetTimeInDays() const
+{
+ short nSign = (nTime >= 0) ? +1 : -1;
+ double nHour = GetHour();
+ double nMin = GetMin();
+ double nSec = GetSec();
+ double n100Sec = Get100Sec();
+
+ return (nHour+(nMin/60)+(nSec/(60*60))+(n100Sec/(60*60*100))) / 24 * nSign;
+}
+
+// -----------------------------------------------------------------------
+
+Time& Time::operator =( const Time& rTime )
+{
+ nTime = rTime.nTime;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+Time& Time::operator +=( const Time& rTime )
+{
+ nTime = Sec100ToTime( TimeToSec100( *this ) +
+ TimeToSec100( rTime ) ).GetTime();
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+Time& Time::operator -=( const Time& rTime )
+{
+ nTime = Sec100ToTime( TimeToSec100( *this ) -
+ TimeToSec100( rTime ) ).GetTime();
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+Time operator +( const Time& rTime1, const Time& rTime2 )
+{
+ return Sec100ToTime( TimeToSec100( rTime1 ) +
+ TimeToSec100( rTime2 ) );
+}
+
+// -----------------------------------------------------------------------
+
+Time operator -( const Time& rTime1, const Time& rTime2 )
+{
+ return Sec100ToTime( TimeToSec100( rTime1 ) -
+ TimeToSec100( rTime2 ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Time::IsEqualIgnore100Sec( const Time& rTime ) const
+{
+ sal_Int32 n1 = (nTime < 0 ? -Get100Sec() : Get100Sec() );
+ sal_Int32 n2 = (rTime.nTime < 0 ? -rTime.Get100Sec() : rTime.Get100Sec() );
+ return (nTime - n1) == (rTime.nTime - n2);
+}
+
+// -----------------------------------------------------------------------
+
+Time Time::GetUTCOffset()
+{
+#if defined( OS2 )
+#undef timezone
+ DATETIME aDateTime;
+ DosGetDateTime( &aDateTime );
+
+ // Zeit zusammenbauen
+ if ( aDateTime.timezone != -1 )
+ {
+ short nTempTime = (short)Abs( aDateTime.timezone );
+ Time aTime( 0, (USHORT)nTempTime );
+ if ( aDateTime.timezone > 0 )
+ aTime = -aTime;
+ return aTime;
+ }
+ else
+ return Time( 0 );
+#elif defined( WNT )
+ TIME_ZONE_INFORMATION aTimeZone;
+ aTimeZone.Bias = 0;
+ DWORD nTimeZoneRet = GetTimeZoneInformation( &aTimeZone );
+ sal_Int32 nTempTime = aTimeZone.Bias;
+ if ( nTimeZoneRet == TIME_ZONE_ID_STANDARD )
+ nTempTime += aTimeZone.StandardBias;
+ else if ( nTimeZoneRet == TIME_ZONE_ID_DAYLIGHT )
+ nTempTime += aTimeZone.DaylightBias;
+ Time aTime( 0, (USHORT)Abs( nTempTime ) );
+ if ( nTempTime > 0 )
+ aTime = -aTime;
+ return aTime;
+#else
+ static ULONG nCacheTicks = 0;
+ static sal_Int32 nCacheSecOffset = -1;
+ ULONG nTicks = Time::GetSystemTicks();
+ time_t nTime;
+ tm aTM;
+ sal_Int32 nLocalTime;
+ sal_Int32 nUTC;
+ short nTempTime;
+
+ // Evt. Wert neu ermitteln
+ if ( (nCacheSecOffset == -1) ||
+ ((nTicks - nCacheTicks) > 360000) ||
+ ( nTicks < nCacheTicks ) // handle overflow
+ )
+ {
+ nTime = time( 0 );
+ localtime_r( &nTime, &aTM );
+ nLocalTime = mktime( &aTM );
+#if defined( SOLARIS )
+ // Solaris gmtime_r() seems not to handle daylight saving time
+ // flags correctly
+ nUTC = nLocalTime + ( aTM.tm_isdst == 0 ? timezone : altzone );
+#elif defined( LINUX )
+ // Linux mktime() seems not to handle tm_isdst correctly
+ nUTC = nLocalTime - aTM.tm_gmtoff;
+#else
+ gmtime_r( &nTime, &aTM );
+ nUTC = mktime( &aTM );
+#endif
+ nCacheTicks = nTicks;
+ nCacheSecOffset = (nLocalTime-nUTC) / 60;
+ }
+
+ nTempTime = (short)Abs( nCacheSecOffset );
+ Time aTime( 0, (USHORT)nTempTime );
+ if ( nCacheSecOffset < 0 )
+ aTime = -aTime;
+ return aTime;
+#endif
+}
+
+
+// -----------------------------------------------------------------------
+
+ULONG Time::GetSystemTicks()
+{
+#if defined WNT
+ return (ULONG)GetTickCount();
+#elif defined( OS2 )
+ ULONG nClock;
+ DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) );
+ return (ULONG)nClock;
+#else
+ timeval tv;
+ gettimeofday (&tv, 0);
+
+ double fTicks = tv.tv_sec;
+ fTicks *= 1000;
+ fTicks += ((tv.tv_usec + 500) / 1000);
+
+ fTicks = fmod (fTicks, double(ULONG_MAX));
+ return ULONG(fTicks);
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Time::GetProcessTicks()
+{
+#if defined WNT
+ return (ULONG)GetTickCount();
+#elif defined( OS2 )
+ ULONG nClock;
+ DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) );
+ return (ULONG)nClock;
+#else
+ static ULONG nImplTicksPerSecond = 0;
+ static double dImplTicksPerSecond;
+ static double dImplTicksULONGMAX;
+ ULONG nTicks = (ULONG)clock();
+
+ if ( !nImplTicksPerSecond )
+ {
+ nImplTicksPerSecond = CLOCKS_PER_SEC;
+ dImplTicksPerSecond = nImplTicksPerSecond;
+ dImplTicksULONGMAX = (double)(ULONG)ULONG_MAX;
+ }
+
+ double fTicks = nTicks;
+ fTicks *= 1000;
+ fTicks /= dImplTicksPerSecond;
+ fTicks = fmod (fTicks, dImplTicksULONGMAX);
+ return (ULONG)fTicks;
+#endif
+}
diff --git a/tools/source/debug/debug.cxx b/tools/source/debug/debug.cxx
new file mode 100644
index 000000000000..ab1f414b0972
--- /dev/null
+++ b/tools/source/debug/debug.cxx
@@ -0,0 +1,1812 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _TOOLS_DEBUG_CXX
+
+#if defined (UNX) || defined (GCC)
+#include <unistd.h>
+#else
+#include <direct.h>
+#endif
+
+#include <time.h>
+#include <cstdarg> // combinations
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef OS2
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSMISC
+#define INCL_WINDIALOGS
+#define INCL_WINSHELLDATA
+#include <svpm.h>
+#endif
+
+#if defined ( WNT )
+#ifdef _MSC_VER
+#pragma warning (push,1)
+#endif
+#include <tools/svwin.h>
+#ifdef _MSC_VER
+#pragma warning (pop)
+#endif
+#endif
+
+#include <tools/debug.hxx>
+#include <rtl/string.h>
+
+#include <vector>
+
+#include <osl/diagnose.h>
+
+// =======================================================================
+
+#ifdef DBG_UTIL
+
+// --- DbgErrors ---
+
+static sal_Char const DbgError_ProfEnd1[] = "DBG_PROF...() without DBG_PROFSTART(): ";
+static sal_Char const DbgError_Xtor1[] = "DBG_DTOR() or DBG_CHKTHIS() without DBG_CTOR(): ";
+
+static sal_Char const DbgError_CtorDtor1[] = "this == NULL in class ";
+static sal_Char const DbgError_CtorDtor2[] = "invalid this-Pointer %p in class ";
+static sal_Char const DbgError_CtorDtor3[] = "Error-Msg from Object %p in class ";
+
+static sal_Char const DbgTrace_EnterCtor[] = "Enter Ctor from class ";
+static sal_Char const DbgTrace_LeaveCtor[] = "Leave Ctor from class ";
+static sal_Char const DbgTrace_EnterDtor[] = "Enter Dtor from class ";
+static sal_Char const DbgTrace_LeaveDtor[] = "Leave Dtor from class ";
+static sal_Char const DbgTrace_EnterMeth[] = "Enter method from class ";
+static sal_Char const DbgTrace_LeaveMeth[] = "Leave method from class ";
+
+// --- PointerList ---
+
+#define PBLOCKCOUNT 1024
+
+struct PBlock
+{
+ void* aData[PBLOCKCOUNT];
+ USHORT nCount;
+ PBlock* pPrev;
+ PBlock* pNext;
+};
+
+class PointerList
+{
+private:
+ PBlock* pFirst;
+ PBlock* pLast;
+ ULONG nCount;
+
+public:
+ PointerList() { pFirst = NULL; pLast = NULL; nCount = 0; }
+ ~PointerList();
+
+ void Add( const void* p );
+ BOOL Remove( const void* p );
+
+ const void* Get( ULONG nPos ) const;
+ BOOL IsIn( const void* p ) const;
+ ULONG Count() const { return nCount; }
+};
+
+// --- Datentypen ---
+
+#define DBG_MAXNAME 28
+
+struct ProfType
+{
+ ULONG nCount;
+ ULONG nTime;
+ ULONG nMinTime;
+ ULONG nMaxTime;
+ ULONG nStart;
+ ULONG nContinueTime;
+ ULONG nContinueStart;
+ sal_Char aName[DBG_MAXNAME+1];
+};
+
+struct XtorType
+{
+ ULONG nCtorCalls;
+ ULONG nDtorCalls;
+ ULONG nMaxCount;
+ ULONG nStatics;
+ sal_Char aName[DBG_MAXNAME+1];
+ BOOL bTest;
+ PointerList aThisList;
+};
+
+struct DebugData
+{
+ DbgData aDbgData;
+ USHORT bInit;
+ DbgPrintLine pDbgPrintMsgBox;
+ DbgPrintLine pDbgPrintWindow;
+ DbgPrintLine pDbgPrintTestTool;
+ ::std::vector< DbgPrintLine >
+ aDbgPrintUserChannels;
+ PointerList* pProfList;
+ PointerList* pXtorList;
+ DbgTestSolarMutexProc pDbgTestSolarMutex;
+ pfunc_osl_printDetailedDebugMessage
+ pOldDebugMessageFunc;
+ bool bOslIsHooked;
+
+ DebugData()
+ :bInit( FALSE )
+ ,pDbgPrintMsgBox( FALSE )
+ ,pDbgPrintWindow( NULL )
+ ,pDbgPrintTestTool( NULL )
+ ,pProfList( NULL )
+ ,pXtorList( NULL )
+ ,pDbgTestSolarMutex( NULL )
+ ,pOldDebugMessageFunc( NULL )
+ ,bOslIsHooked( false )
+ {
+ aDbgData.nTestFlags = DBG_TEST_RESOURCE | DBG_TEST_MEM_INIT;
+ aDbgData.bOverwrite = TRUE;
+ aDbgData.nTraceOut = DBG_OUT_NULL;
+ aDbgData.nWarningOut = DBG_OUT_NULL;
+#ifdef UNX
+ aDbgData.nErrorOut = DBG_OUT_SHELL;
+#else
+ aDbgData.nErrorOut = DBG_OUT_MSGBOX;
+#endif
+ aDbgData.bMemInit = 0x77;
+ aDbgData.bMemBound = 0x55;
+ aDbgData.bMemFree = 0x33;
+ aDbgData.bHookOSLAssert = TRUE;
+ aDbgData.aDebugName[0] = 0;
+ aDbgData.aInclFilter[0] = 0;
+ aDbgData.aExclFilter[0] = 0;
+ aDbgData.aInclClassFilter[0] = 0;
+ aDbgData.aExclClassFilter[0] = 0;
+ aDbgData.aDbgWinState[0] = 0;
+ }
+};
+
+#define DBG_TEST_XTOR_EXTRA (DBG_TEST_XTOR_THIS | DBG_TEST_XTOR_FUNC | \
+ DBG_TEST_XTOR_EXIT | DBG_TEST_XTOR_REPORT )
+
+// ------------------------------
+// - statische Verwaltungsdaten -
+// ------------------------------
+
+static DebugData aDebugData;
+
+static sal_Char aCurPath[260];
+
+static int bDbgImplInMain = FALSE;
+
+// =======================================================================
+
+#if defined( WNT )
+static CRITICAL_SECTION aImplCritDbgSection;
+#elif defined( OS2 )
+static HMTX hImplCritDbgSection = 0;
+#endif
+static BOOL bImplCritDbgSectionInit = FALSE;
+
+// -----------------------------------------------------------------------
+
+void ImplDbgInitLock()
+{
+#if defined( WNT )
+ InitializeCriticalSection( &aImplCritDbgSection );
+#elif defined( OS2 )
+ DosCreateMutexSem( NULL, &hImplCritDbgSection, 0, FALSE );
+#endif
+ bImplCritDbgSectionInit = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDbgDeInitLock()
+{
+#if defined( WNT )
+ DeleteCriticalSection( &aImplCritDbgSection );
+#elif defined( OS2 )
+ DosCloseMutexSem( hImplCritDbgSection );
+#endif
+ bImplCritDbgSectionInit = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDbgLock()
+{
+ if ( !bImplCritDbgSectionInit )
+ return;
+
+#if defined( WNT )
+ EnterCriticalSection( &aImplCritDbgSection );
+#elif defined( OS2 )
+ DosRequestMutexSem( hImplCritDbgSection, SEM_INDEFINITE_WAIT );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDbgUnlock()
+{
+ if ( !bImplCritDbgSectionInit )
+ return;
+
+#if defined( WNT )
+ LeaveCriticalSection( &aImplCritDbgSection );
+#elif defined( OS2 )
+ DosReleaseMutexSem( hImplCritDbgSection );
+#endif
+}
+
+// =======================================================================
+
+#if (defined WNT || defined OS2) && !defined SVX_LIGHT
+//#define SV_MEMMGR //
+#endif
+#ifdef SV_MEMMGR
+void DbgImpCheckMemory( void* p = NULL );
+void DbgImpCheckMemoryDeInit();
+void DbgImpMemoryInfo( sal_Char* pBuf );
+#endif
+
+#define FILE_LINEEND "\n"
+
+// =======================================================================
+
+static BOOL ImplActivateDebugger( const sal_Char* pMsg )
+{
+#if defined( WNT )
+ static sal_Char aImplDbgOutBuf[DBG_BUF_MAXLEN];
+ strcpy( aImplDbgOutBuf, pMsg );
+ strcat( aImplDbgOutBuf, "\r\n" );
+ OutputDebugString( aImplDbgOutBuf );
+ DebugBreak();
+ return TRUE;
+#else
+ (void) pMsg; // avoid warning about unused parameter
+ return FALSE;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplCoreDump()
+{
+#if defined( WNT )
+ DebugBreak();
+#else
+ long* pTemp = 0;
+ *pTemp = 0xCCCC;
+#endif
+ return TRUE;
+}
+
+// =======================================================================
+
+static ULONG ImplGetPerfTime()
+{
+#if defined( WNT )
+ return (ULONG)GetTickCount();
+#elif defined( OS2 )
+ ULONG nClock;
+ DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) );
+ return (ULONG)nClock;
+#else
+ static ULONG nImplTicksPerSecond = 0;
+ static double dImplTicksPerSecond;
+ ULONG nTicks = (ULONG)clock();
+
+ if ( !nImplTicksPerSecond )
+ {
+ nImplTicksPerSecond = CLOCKS_PER_SEC;
+ dImplTicksPerSecond = nImplTicksPerSecond;
+ }
+
+ double fTicks = nTicks;
+ fTicks *= 1000;
+ fTicks /= dImplTicksPerSecond;
+ return (ULONG)fTicks;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+typedef FILE* FILETYPE;
+#define FileOpen fopen
+#define FileRead fread
+#define FileWrite fwrite
+#define FilePrintF fprintf
+#define FileClose fclose
+
+// =======================================================================
+
+namespace
+{
+ enum ConfigSection
+ {
+ eOutput,
+ eMemory,
+ eGUI,
+ eObjects,
+ eTest,
+
+ eUnknown
+ };
+
+ void lcl_lineFeed( FILETYPE _pFile )
+ {
+ FilePrintF( _pFile, "%s", FILE_LINEEND );
+ }
+
+ const sal_Char* lcl_getSectionName( ConfigSection _eSection )
+ {
+ const sal_Char* pSectionName = NULL;
+ switch ( _eSection )
+ {
+ case eOutput : pSectionName = "output"; break;
+ case eMemory : pSectionName = "memory"; break;
+ case eGUI : pSectionName = "gui"; break;
+ case eObjects : pSectionName = "objects"; break;
+ case eTest : pSectionName = "test"; break;
+ case eUnknown:
+ OSL_ASSERT(false);
+ break;
+ }
+ return pSectionName;
+ }
+
+ ConfigSection lcl_getSectionFromName( const sal_Char* _pSectionName, size_t _nSectionNameLength )
+ {
+ if ( strncmp( _pSectionName, "output", _nSectionNameLength < 6 ? _nSectionNameLength : 6 ) == 0 )
+ return eOutput;
+ if ( strncmp( _pSectionName, "memory", _nSectionNameLength < 6 ? _nSectionNameLength : 6 ) == 0 )
+ return eMemory;
+ if ( strncmp( _pSectionName, "gui", _nSectionNameLength < 3 ? _nSectionNameLength : 3 ) == 0 )
+ return eGUI;
+ if ( strncmp( _pSectionName, "objects", _nSectionNameLength < 7 ? _nSectionNameLength : 7 ) == 0 )
+ return eObjects;
+ if ( strncmp( _pSectionName, "test", _nSectionNameLength < 4 ? _nSectionNameLength : 4 ) == 0 )
+ return eTest;
+ return eUnknown;
+ }
+
+ void lcl_startSection( FILETYPE _pFile, ConfigSection _eSection )
+ {
+ FilePrintF( _pFile, "[%s]%s", lcl_getSectionName( _eSection ), FILE_LINEEND );
+ }
+
+ void lcl_writeConfigString( FILETYPE _pFile, const sal_Char* _pKeyName, const sal_Char* _pValue )
+ {
+ FilePrintF( _pFile, "%s=%s%s", _pKeyName, _pValue, FILE_LINEEND );
+ }
+
+ void lcl_writeConfigBoolean( FILETYPE _pFile, const sal_Char* _pKeyName, bool _bValue )
+ {
+ lcl_writeConfigString( _pFile, _pKeyName, _bValue ? "1" : "0" );
+ }
+
+ void lcl_writeConfigFlag( FILETYPE _pFile, const sal_Char* _pKeyName, ULONG _nAllFlags, ULONG _nCheckFlag )
+ {
+ lcl_writeConfigBoolean( _pFile, _pKeyName, ( _nAllFlags & _nCheckFlag ) != 0 );
+ }
+
+ void lcl_writeConfigOutChannel( FILETYPE _pFile, const sal_Char* _pKeyName, ULONG _nValue )
+ {
+ const sal_Char* names[ DBG_OUT_COUNT ] =
+ {
+ "dev/null", "file", "window", "shell", "messagebox", "testtool", "debugger", "coredump"
+ };
+ lcl_writeConfigString( _pFile, _pKeyName, names[ _nValue ] );
+ }
+ void lcl_writeHexByte( FILETYPE _pFile, const sal_Char* _pKeyName, BYTE _nValue )
+ {
+ sal_Char buf[RTL_STR_MAX_VALUEOFINT32];
+ rtl_String* stringData = NULL;
+ rtl_string_newFromStr_WithLength( &stringData, buf, rtl_str_valueOfInt32( buf, _nValue, 16 ) );
+
+ lcl_writeConfigString( _pFile, _pKeyName, stringData->buffer );
+
+ rtl_string_release( stringData );
+ }
+ bool lcl_isConfigSection( const sal_Char* _pLine, size_t _nLineLen )
+ {
+ if ( _nLineLen < 2 )
+ // not even enough space for '[' and ']'
+ return false;
+ if ( ( _pLine[0] == '[' ) && ( _pLine[ _nLineLen - 1 ] == ']' ) )
+ return true;
+ return false;
+ }
+ bool lcl_isConfigKey( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName )
+ {
+ size_t nKeyLength = strlen( _pKeyName );
+ if ( nKeyLength + 1 >= _nLineLen )
+ // not even long enough for the key name plus "=" plus a one-character value
+ return false;
+ if ( ( strncmp( _pLine, _pKeyName, nKeyLength ) == 0 ) && ( _pLine[ nKeyLength ] == '=' ) )
+ return true;
+ return false;
+ }
+ sal_Int32 lcl_tryReadConfigString( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_Char* _pValue, size_t _nValueLen )
+ {
+ if ( !lcl_isConfigKey( _pLine, _nLineLen, _pKeyName ) )
+ return 0;
+ size_t nValuePos = strlen( _pKeyName ) + 1;
+ size_t nValueLen = _nLineLen - nValuePos;
+ const sal_Char* pValue = _pLine + nValuePos;
+ strncpy( _pValue, pValue, ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen );
+ _pValue[ ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen - 1 ] = 0;
+ return strlen( _pValue );
+ }
+ void lcl_tryReadConfigBoolean( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, ULONG* _out_pnValue )
+ {
+ sal_Char aBuf[2];
+ size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
+ if ( nValueLen )
+ *_out_pnValue = strcmp( aBuf, "1" ) == 0 ? TRUE : FALSE;
+ }
+ void lcl_tryReadOutputChannel( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, ULONG* _out_pnValue )
+ {
+ const sal_Char* names[ DBG_OUT_COUNT ] =
+ {
+ "dev/null", "file", "window", "shell", "messagebox", "testtool", "debugger", "coredump"
+ };
+ sal_Char aBuf[20];
+ size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
+ if ( nValueLen )
+ {
+ for ( ULONG name = 0; name < sizeof( names ) / sizeof( names[0] ); ++name )
+ {
+ if ( strcmp( aBuf, names[ name ] ) == 0 )
+ {
+ *_out_pnValue = name;
+ return;
+ }
+ }
+ }
+ }
+ void lcl_tryReadConfigFlag( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, ULONG* _out_pnAllFlags, ULONG _nCheckFlag )
+ {
+ sal_Char aBuf[2];
+ size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
+ if ( nValueLen )
+ if ( strcmp( aBuf, "1" ) == 0 )
+ *_out_pnAllFlags |= _nCheckFlag;
+ else
+ *_out_pnAllFlags &= ~_nCheckFlag;
+ }
+ void lcl_tryReadHexByte( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, BYTE* _out_pnValue )
+ {
+ sal_Char aBuf[3];
+ size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
+ if ( nValueLen )
+ *_out_pnValue = (BYTE)rtl_str_toInt32( aBuf, 16 );
+ }
+}
+
+// =======================================================================
+
+PointerList::~PointerList()
+{
+ PBlock* pBlock = pFirst;
+ while ( pBlock )
+ {
+ PBlock* pNextBlock = pBlock->pNext;
+ delete pBlock;
+ pBlock = pNextBlock;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PointerList::Add( const void* p )
+{
+ if ( !pFirst )
+ {
+ pFirst = new PBlock;
+ memset( pFirst->aData, 0, PBLOCKCOUNT * sizeof( void* ) );
+ pFirst->nCount = 0;
+ pFirst->pPrev = NULL;
+ pFirst->pNext = NULL;
+ pLast = pFirst;
+ }
+
+ PBlock* pBlock = pFirst;
+ while ( pBlock && (pBlock->nCount == PBLOCKCOUNT) )
+ pBlock = pBlock->pNext;
+
+ if ( !pBlock )
+ {
+ pBlock = new PBlock;
+ memset( pBlock->aData, 0, PBLOCKCOUNT * sizeof( void* ) );
+ pBlock->nCount = 0;
+ pBlock->pPrev = pLast;
+ pBlock->pNext = NULL;
+ pLast->pNext = pBlock;
+ pLast = pBlock;
+ }
+
+ USHORT i = 0;
+ while ( pBlock->aData[i] )
+ i++;
+
+ pBlock->aData[i] = (void*)p;
+ pBlock->nCount++;
+ nCount++;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PointerList::Remove( const void* p )
+{
+ if ( !p )
+ return FALSE;
+
+ PBlock* pBlock = pFirst;
+ while ( pBlock )
+ {
+ USHORT i = 0;
+ while ( i < PBLOCKCOUNT )
+ {
+ if ( ((ULONG)p) == ((ULONG)pBlock->aData[i]) )
+ {
+ pBlock->aData[i] = NULL;
+ pBlock->nCount--;
+ nCount--;
+
+ if ( !pBlock->nCount )
+ {
+ if ( pBlock->pPrev )
+ pBlock->pPrev->pNext = pBlock->pNext;
+ if ( pBlock->pNext )
+ pBlock->pNext->pPrev = pBlock->pPrev;
+ if ( pBlock == pFirst )
+ pFirst = pBlock->pNext;
+ if ( pBlock == pLast )
+ pLast = pBlock->pPrev;
+ delete pBlock;
+ }
+
+ return TRUE;
+ }
+ i++;
+ }
+
+ pBlock = pBlock->pNext;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+const void* PointerList::Get( ULONG nPos ) const
+{
+ if ( nCount <= nPos )
+ return NULL;
+
+ PBlock* pBlock = pFirst;
+ ULONG nStart = 0;
+ while ( pBlock )
+ {
+ USHORT i = 0;
+ while ( i < PBLOCKCOUNT )
+ {
+ if ( pBlock->aData[i] )
+ {
+ nStart++;
+ if ( (nStart-1) == nPos )
+ return pBlock->aData[i];
+ }
+
+ i++;
+ }
+
+ pBlock = pBlock->pNext;
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PointerList::IsIn( const void* p ) const
+{
+ if ( !p )
+ return FALSE;
+
+ PBlock* pBlock = pFirst;
+ while ( pBlock )
+ {
+ USHORT i = 0;
+ while ( i < PBLOCKCOUNT )
+ {
+ if ( ((ULONG)p) == ((ULONG)pBlock->aData[i]) )
+ return TRUE;
+ i++;
+ }
+
+ pBlock = pBlock->pNext;
+ }
+
+ return FALSE;
+}
+
+
+// =======================================================================
+
+static void DbgGetDbgFileName( sal_Char* pStr, sal_Int32 nMaxLen )
+{
+#if defined( UNX )
+ const sal_Char* pName = getenv("DBGSV_INIT");
+ if ( !pName )
+ pName = ".dbgsv.init";
+ strncpy( pStr, pName, nMaxLen );
+#elif defined( WNT )
+ const sal_Char* pName = getenv("DBGSV_INIT");
+ if ( pName )
+ strncpy( pStr, pName, nMaxLen );
+ else
+ GetProfileStringA( "sv", "dbgsv", "dbgsv.ini", pStr, nMaxLen );
+#elif defined( OS2 )
+ PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSV",
+ "dbgsv.ini", (PSZ)pStr, nMaxLen );
+#else
+ strncpy( pStr, "dbgsv.ini", nMaxLen );
+#endif
+ pStr[ nMaxLen - 1 ] = 0;
+}
+
+// -----------------------------------------------------------------------
+
+static void DbgGetLogFileName( sal_Char* pStr )
+{
+#if defined( UNX )
+ const sal_Char* pName = getenv("DBGSV_LOG");
+ if ( !pName )
+ pName = "dbgsv.log";
+ strcpy( pStr, pName );
+#elif defined( WNT )
+ const sal_Char* pName = getenv("DBGSV_LOG");
+ if ( pName )
+ strcpy( pStr, pName );
+ else
+ GetProfileStringA( "sv", "dbgsvlog", "dbgsv.log", pStr, 200 );
+#elif defined( OS2 )
+ PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSVLOG",
+ "dbgsv.log", (PSZ)pStr, 200 );
+#else
+ strcpy( pStr, "dbgsv.log" );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+static void DbgDebugBeep()
+{
+#if defined( WNT )
+ MessageBeep( MB_ICONHAND );
+#elif defined( OS2 )
+ WinAlarm( HWND_DESKTOP, WA_ERROR );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+static DebugData* GetDebugData()
+{
+ if ( !aDebugData.bInit )
+ {
+ aDebugData.bInit = TRUE;
+
+ // Default Debug-Namen setzen
+ DbgGetLogFileName( aDebugData.aDbgData.aDebugName );
+
+ // DEBUG.INI-File
+ sal_Char aBuf[ 4096 ];
+ DbgGetDbgFileName( aBuf, sizeof( aBuf ) );
+ FILETYPE pIniFile = FileOpen( aBuf, "r" );
+ if ( pIniFile != NULL )
+ {
+ ConfigSection eCurrentSection = eUnknown;
+
+ // no sophisticated algorithm here, assume that the whole file fits into aBuf ...
+ ULONG nReallyRead = FileRead( aBuf, 1, sizeof( aBuf ) / sizeof( sal_Char ) - 1, pIniFile );
+ aBuf[ nReallyRead ] = 0;
+ const sal_Char* pLine = aBuf;
+ while ( const sal_Char* pNextLine = strstr( pLine, FILE_LINEEND ) )
+ {
+ size_t nLineLength = pNextLine - pLine;
+
+ if ( lcl_isConfigSection( pLine, nLineLength ) )
+ eCurrentSection = lcl_getSectionFromName( pLine + 1, nLineLength - 2 );
+
+ // elements of the [output] section
+ if ( eCurrentSection == eOutput )
+ {
+ lcl_tryReadConfigString( pLine, nLineLength, "log_file", aDebugData.aDbgData.aDebugName, sizeof( aDebugData.aDbgData.aDebugName ) );
+ lcl_tryReadConfigBoolean( pLine, nLineLength, "overwrite", &aDebugData.aDbgData.bOverwrite );
+ lcl_tryReadConfigString( pLine, nLineLength, "include", aDebugData.aDbgData.aInclFilter, sizeof( aDebugData.aDbgData.aInclFilter ) );
+ lcl_tryReadConfigString( pLine, nLineLength, "exclude", aDebugData.aDbgData.aExclFilter, sizeof( aDebugData.aDbgData.aExclFilter ) );
+ lcl_tryReadConfigString( pLine, nLineLength, "include_class", aDebugData.aDbgData.aInclClassFilter, sizeof( aDebugData.aDbgData.aInclClassFilter ) );
+ lcl_tryReadConfigString( pLine, nLineLength, "exclude_class", aDebugData.aDbgData.aExclClassFilter, sizeof( aDebugData.aDbgData.aExclClassFilter ) );
+ lcl_tryReadOutputChannel( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTraceOut );
+ lcl_tryReadOutputChannel( pLine, nLineLength, "warning", &aDebugData.aDbgData.nWarningOut );
+ lcl_tryReadOutputChannel( pLine, nLineLength, "error", &aDebugData.aDbgData.nErrorOut );
+ lcl_tryReadConfigBoolean( pLine, nLineLength, "oslhook", &aDebugData.aDbgData.bHookOSLAssert );
+ }
+
+ // elements of the [memory] section
+ if ( eCurrentSection == eMemory )
+ {
+ lcl_tryReadConfigFlag( pLine, nLineLength, "initialize", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_INIT );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "overwrite", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_OVERWRITE );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "overwrite_free", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_OVERWRITEFREE );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "pointer", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_POINTER );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_REPORT );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_TRACE );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "new_and_delete", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_NEWDEL );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "object_test", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_XTOR );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "sys_alloc", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_SYSALLOC );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "leak_report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_LEAKREPORT );
+
+ lcl_tryReadHexByte( pLine, nLineLength, "init_byte", &aDebugData.aDbgData.bMemInit );
+ lcl_tryReadHexByte( pLine, nLineLength, "bound_byte", &aDebugData.aDbgData.bMemBound );
+ lcl_tryReadHexByte( pLine, nLineLength, "free_byte", &aDebugData.aDbgData.bMemFree );
+ }
+
+ // elements of the [gui] section
+ if ( eCurrentSection == eGUI )
+ {
+ lcl_tryReadConfigString( pLine, nLineLength, "debug_window_state", aDebugData.aDbgData.aDbgWinState, sizeof( aDebugData.aDbgData.aDbgWinState ) );
+ }
+
+ // elements of the [objects] section
+ if ( eCurrentSection == eObjects )
+ {
+ lcl_tryReadConfigFlag( pLine, nLineLength, "check_this", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_THIS );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "check_function", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_FUNC );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "check_exit", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_EXIT );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "generate_report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_REPORT );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_TRACE );
+ }
+
+ // elements of the [test] section
+ if ( eCurrentSection == eTest )
+ {
+ lcl_tryReadConfigFlag( pLine, nLineLength, "profiling", &aDebugData.aDbgData.nTestFlags, DBG_TEST_PROFILING );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "resources", &aDebugData.aDbgData.nTestFlags, DBG_TEST_RESOURCE );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "dialog", &aDebugData.aDbgData.nTestFlags, DBG_TEST_DIALOG );
+ lcl_tryReadConfigFlag( pLine, nLineLength, "bold_app_font", &aDebugData.aDbgData.nTestFlags, DBG_TEST_BOLDAPPFONT );
+ }
+
+ pLine = pNextLine + strlen( FILE_LINEEND );
+ }
+
+ FileClose( pIniFile );
+ }
+
+ getcwd( aCurPath, sizeof( aCurPath ) );
+
+ // Daten initialisieren
+ if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_XTOR )
+ aDebugData.pXtorList = new PointerList;
+ if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_PROFILING )
+ aDebugData.pProfList = new PointerList;
+ }
+
+ return &aDebugData;
+}
+
+// -----------------------------------------------------------------------
+
+inline DebugData* ImplGetDebugData()
+{
+ if ( !aDebugData.bInit )
+ return GetDebugData();
+ else
+ return &aDebugData;
+}
+
+// -----------------------------------------------------------------------
+
+static FILETYPE ImplDbgInitFile()
+{
+ static BOOL bFileInit = FALSE;
+
+ sal_Char aBuf[4096];
+ getcwd( aBuf, sizeof( aBuf ) );
+ chdir( aCurPath );
+
+ DebugData* pData = GetDebugData();
+ FILETYPE pDebugFile;
+
+ if ( !bFileInit )
+ {
+ bFileInit = TRUE;
+
+ if ( pData->aDbgData.bOverwrite )
+ pDebugFile = FileOpen( pData->aDbgData.aDebugName, "w" );
+ else
+ pDebugFile = FileOpen( pData->aDbgData.aDebugName, "a" );
+
+ if ( pDebugFile )
+ {
+ time_t nTime = time( 0 );
+ tm* pTime;
+#ifdef UNX
+ tm aTime;
+ pTime = localtime_r( &nTime, &aTime );
+#else
+ pTime = localtime( &nTime );
+#endif
+
+ // Header ausgeben
+ FilePrintF( pDebugFile, "******************************************************************************%s", FILE_LINEEND );
+ FilePrintF( pDebugFile, "%s%s", pData->aDbgData.aDebugName, FILE_LINEEND );
+ if ( pTime )
+ FilePrintF( pDebugFile, "%s%s", asctime( pTime ), FILE_LINEEND );
+ }
+ }
+ else
+ pDebugFile = FileOpen( pData->aDbgData.aDebugName, "a" );
+
+ chdir( aBuf );
+
+ return pDebugFile;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDbgPrintFile( const sal_Char* pLine )
+{
+ FILETYPE pDebugFile = ImplDbgInitFile();
+
+ if ( pDebugFile )
+ {
+ FilePrintF( pDebugFile, "%s%s", pLine, FILE_LINEEND );
+ FileClose( pDebugFile );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplStrSearch( const sal_Char* pSearchStr, int nSearchLen,
+ const sal_Char* pStr, int nLen )
+{
+ int nPos = 0;
+ while ( nPos+nSearchLen <= nLen )
+ {
+ if ( strncmp( pStr+nPos, pSearchStr, nSearchLen ) == 0 )
+ return 1;
+ nPos++;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplDbgFilter( const sal_Char* pFilter, const sal_Char* pMsg,
+ int bEmpty )
+{
+ int nStrLen = strlen( pFilter );
+ if ( !nStrLen )
+ return bEmpty;
+
+ int nMsgLen = strlen( pMsg );
+ const sal_Char* pTok = pFilter;
+ int nTok = 0;
+ while ( pTok[nTok] )
+ {
+ if ( pTok[nTok] == ';' )
+ {
+ if ( nTok && ImplStrSearch( pTok, nTok, pMsg, nMsgLen ) )
+ return TRUE;
+
+ pTok += nTok+1;
+ nTok = 0;
+ }
+
+ nTok++;
+ }
+
+ if ( nTok && ImplStrSearch( pTok, nTok, pMsg, nMsgLen ) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+extern "C"
+void SAL_CALL dbg_printOslDebugMessage( const sal_Char * pszFileName, sal_Int32 nLine, const sal_Char * pszMessage )
+{
+ DbgOut( pszMessage ? pszMessage : "assertion failed!", DBG_OUT_ERROR, pszFileName, (USHORT)nLine );
+}
+
+// -----------------------------------------------------------------------
+
+static void DebugInit()
+{
+ bDbgImplInMain = TRUE;
+ ImplDbgInitLock();
+
+ DebugData* pData = GetDebugData();
+ if( pData->aDbgData.bHookOSLAssert && ! pData->bOslIsHooked )
+ {
+ pData->pOldDebugMessageFunc = osl_setDetailedDebugMessageFunc( &dbg_printOslDebugMessage );
+ pData->bOslIsHooked = true;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void DebugDeInit()
+{
+ DebugData* pData = GetDebugData();
+ ULONG i;
+ ULONG nCount;
+ ULONG nOldOut;
+
+ if( pData->bOslIsHooked )
+ {
+ osl_setDetailedDebugMessageFunc( pData->pOldDebugMessageFunc );
+ pData->bOslIsHooked = FALSE;
+ }
+
+ // Statistik-Ausgaben immer in File
+ nOldOut = pData->aDbgData.nTraceOut;
+ pData->aDbgData.nTraceOut = DBG_OUT_FILE;
+
+ // Xtor-Liste ausgeben
+ if ( pData->pXtorList && pData->pXtorList->Count() &&
+ (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_REPORT) )
+ {
+ DbgOutf( "------------------------------------------------------------------------------" );
+ DbgOutf( "Object Report" );
+ DbgOutf( "------------------------------------------------------------------------------" );
+ DbgOutf( "%-27s : %-9s : %-9s : %-7s : %-3s : %-6s :",
+ "XTor-List", "Ctor", "Dtor", "MaxInst", "St.", "Diff." );
+ DbgOutf( "----------------------------:-----------:-----------:---------:----:---------:" );
+ for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
+ {
+ XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
+ if ( pXtorData->bTest )
+ {
+ // Static-Objekte dazurechnen
+ pXtorData->nDtorCalls += pXtorData->nStatics;
+ if ( pXtorData->nStatics && (pXtorData->nDtorCalls > pXtorData->nCtorCalls) )
+ pXtorData->nDtorCalls = pXtorData->nCtorCalls;
+ DbgOutf( "%-27s : %9lu : %9lu : %7lu : %3lu : %4lu %-1s :",
+ pXtorData->aName, pXtorData->nCtorCalls, pXtorData->nDtorCalls,
+ pXtorData->nMaxCount, pXtorData->nStatics,
+ pXtorData->nCtorCalls - pXtorData->nDtorCalls,
+ (pXtorData->nCtorCalls - pXtorData->nDtorCalls) ? "!" : " " );
+ }
+ }
+ DbgOutf( "==============================================================================" );
+ }
+
+ // Aufraeumen
+ if ( pData->pXtorList )
+ {
+ for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
+ {
+ XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
+ delete pXtorData;
+ }
+ delete pData->pXtorList;
+ pData->pXtorList = NULL;
+ }
+
+ // Alles auf FALSE setzen, damit globale Variablen nicht das
+ // System zum Abstuerzen bringt. Dabei muessen aber die
+ // Memory-Flags erhalten bleiben, da sonst new/delete in globalen
+ // Variablen abstuerzen, da die Pointeranpassung dann nicht mehr richtig
+ // funktioniert
+ pData->aDbgData.nTraceOut = nOldOut;
+ pData->aDbgData.nTestFlags &= (DBG_TEST_MEM | DBG_TEST_PROFILING);
+ pData->aDbgPrintUserChannels.clear();
+ pData->pDbgPrintTestTool = NULL;
+ pData->pDbgPrintWindow = NULL;
+ pData->pOldDebugMessageFunc = NULL;
+ ImplDbgDeInitLock();
+}
+
+// -----------------------------------------------------------------------
+
+static void DebugGlobalDeInit()
+{
+ DebugData* pData = GetDebugData();
+ ULONG i;
+ ULONG nCount;
+ ULONG nOldOut;
+
+ // Statistik-Ausgaben immer in File
+ nOldOut = pData->aDbgData.nTraceOut;
+ pData->aDbgData.nTraceOut = DBG_OUT_FILE;
+
+ // Profileliste ausgeben
+ if ( pData->pProfList && pData->pProfList->Count() )
+ {
+ DbgOutf( "------------------------------------------------------------------------------" );
+ DbgOutf( "Profiling Report" );
+ DbgOutf( "------------------------------------------------------------------------------" );
+ DbgOutf( "%-25s : %-9s : %-6s : %-6s : %-6s : %-9s :",
+ "Prof-List (ms)", "Time", "Min", "Max", "Ave", "Count" );
+ DbgOutf( "--------------------------:-----------:--------:--------:--------:-----------:" );
+ for( i = 0, nCount = pData->pProfList->Count(); i < nCount; i++ )
+ {
+ ProfType* pProfData = (ProfType*)pData->pProfList->Get( i );
+ ULONG nAve = pProfData->nTime / pProfData->nCount;
+ DbgOutf( "%-25s : %9lu : %6lu : %6lu : %6lu : %9lu :",
+ pProfData->aName, pProfData->nTime,
+ pProfData->nMinTime, pProfData->nMaxTime, nAve,
+ pProfData->nCount );
+ }
+ DbgOutf( "==============================================================================" );
+ }
+
+ // Aufraeumen
+ if ( pData->pProfList )
+ {
+ for( i = 0, nCount = pData->pProfList->Count(); i < nCount; i++ )
+ {
+ ProfType* pProfData = (ProfType*)pData->pProfList->Get( i );
+ delete pProfData;
+ }
+ delete pData->pProfList;
+ pData->pProfList = NULL;
+ }
+
+#ifdef SV_MEMMGR
+ DbgImpCheckMemoryDeInit();
+#endif
+
+ // Profiling-Flags ausschalten
+ pData->aDbgData.nTraceOut = nOldOut;
+ pData->aDbgData.nTestFlags &= ~DBG_TEST_PROFILING;
+}
+
+// -----------------------------------------------------------------------
+
+void ImpDbgOutfBuf( sal_Char* pBuf, const sal_Char* pFStr, ... )
+{
+ va_list pList;
+
+ va_start( pList, pFStr );
+ sal_Char aBuf[DBG_BUF_MAXLEN];
+ vsprintf( aBuf, pFStr, pList );
+ va_end( pList );
+
+ strcat( pBuf, aBuf );
+ strcat( pBuf, "\n" );
+}
+
+// -----------------------------------------------------------------------
+
+static void DebugXTorInfo( sal_Char* pBuf )
+{
+ DebugData* pData = GetDebugData();
+ ULONG i;
+ ULONG nCount;
+
+ // Xtor-Liste ausgeben
+ if ( pData->pXtorList && pData->pXtorList->Count() &&
+ (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_REPORT) )
+ {
+ ImpDbgOutfBuf( pBuf, "------------------------------------------------------------------------------" );
+ ImpDbgOutfBuf( pBuf, "Object Report" );
+ ImpDbgOutfBuf( pBuf, "------------------------------------------------------------------------------" );
+ ImpDbgOutfBuf( pBuf, "%-27s : %-9s : %-9s : %-7s : %-3s : %-6s :",
+ "XTor-List", "Ctor", "Dtor", "MaxInst", "St.", "Diff." );
+ ImpDbgOutfBuf( pBuf, "----------------------------:-----------:-----------:---------:----:---------:" );
+ for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
+ {
+ XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
+ if ( pXtorData->bTest )
+ {
+ ImpDbgOutfBuf( pBuf, "%-27s : %9lu : %9lu : %7lu : %3lu : %6lu :",
+ pXtorData->aName, pXtorData->nCtorCalls, pXtorData->nDtorCalls,
+ pXtorData->nMaxCount, pXtorData->nStatics,
+ pXtorData->nCtorCalls - pXtorData->nDtorCalls );
+ }
+ }
+ ImpDbgOutfBuf( pBuf, "==============================================================================" );
+ ImpDbgOutfBuf( pBuf, "" );
+ }
+}
+
+// -----------------------------------------------------------------------
+BOOL ImplDbgFilterMessage( const sal_Char* pMsg )
+{
+ DebugData* pData = GetDebugData();
+ if ( !ImplDbgFilter( pData->aDbgData.aInclFilter, pMsg, TRUE ) )
+ return TRUE;
+ if ( ImplDbgFilter( pData->aDbgData.aExclFilter, pMsg, FALSE ) )
+ return TRUE;
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void* DbgFunc( USHORT nAction, void* pParam )
+{
+ DebugData* pDebugData = ImplGetDebugData();
+
+ if ( nAction == DBG_FUNC_GETDATA )
+ return (void*)&(pDebugData->aDbgData);
+ else if ( nAction == DBG_FUNC_GETPRINTMSGBOX )
+ return (void*)(long)(pDebugData->pDbgPrintMsgBox);
+ else if ( nAction == DBG_FUNC_FILTERMESSAGE )
+ if ( ImplDbgFilterMessage( (const sal_Char*) pParam ) )
+ return (void*) -1;
+ else
+ return (void*) 0; // aka NULL
+ else
+
+ {
+ switch ( nAction )
+ {
+ case DBG_FUNC_DEBUGSTART:
+ DebugInit();
+ break;
+
+ case DBG_FUNC_DEBUGEND:
+ DebugDeInit();
+ break;
+
+ case DBG_FUNC_GLOBALDEBUGEND:
+ DebugGlobalDeInit();
+ break;
+
+ case DBG_FUNC_SETPRINTMSGBOX:
+ pDebugData->pDbgPrintMsgBox = (DbgPrintLine)(long)pParam;
+ break;
+
+ case DBG_FUNC_SETPRINTWINDOW:
+ pDebugData->pDbgPrintWindow = (DbgPrintLine)(long)pParam;
+ break;
+
+ case DBG_FUNC_SETPRINTTESTTOOL:
+ pDebugData->pDbgPrintTestTool = (DbgPrintLine)(long)pParam;
+ break;
+
+ case DBG_FUNC_SAVEDATA:
+ {
+ const DbgData* pData = static_cast< const DbgData* >( pParam );
+
+ sal_Char aBuf[ 4096 ];
+ DbgGetDbgFileName( aBuf, sizeof( aBuf ) );
+ FILETYPE pIniFile = FileOpen( aBuf, "w" );
+ if ( pIniFile == NULL )
+ break;
+
+ lcl_startSection( pIniFile, eOutput );
+ lcl_writeConfigString( pIniFile, "log_file", pData->aDebugName );
+ lcl_writeConfigBoolean( pIniFile, "overwrite", pData->bOverwrite );
+ lcl_writeConfigString( pIniFile, "include", pData->aInclFilter );
+ lcl_writeConfigString( pIniFile, "exclude", pData->aExclFilter );
+ lcl_writeConfigString( pIniFile, "include_class", pData->aInclClassFilter );
+ lcl_writeConfigString( pIniFile, "exclude_class", pData->aExclClassFilter );
+ lcl_writeConfigOutChannel( pIniFile, "trace", pData->nTraceOut );
+ lcl_writeConfigOutChannel( pIniFile, "warning", pData->nWarningOut );
+ lcl_writeConfigOutChannel( pIniFile, "error", pData->nErrorOut );
+ lcl_writeConfigBoolean( pIniFile, "oslhook", pData->bHookOSLAssert );
+
+ lcl_lineFeed( pIniFile );
+ lcl_startSection( pIniFile, eMemory );
+ lcl_writeConfigFlag( pIniFile, "initialize", pData->nTestFlags, DBG_TEST_MEM_INIT );
+ lcl_writeConfigFlag( pIniFile, "overwrite", pData->nTestFlags, DBG_TEST_MEM_OVERWRITE );
+ lcl_writeConfigFlag( pIniFile, "overwrite_free", pData->nTestFlags, DBG_TEST_MEM_OVERWRITEFREE );
+ lcl_writeConfigFlag( pIniFile, "pointer", pData->nTestFlags, DBG_TEST_MEM_POINTER );
+ lcl_writeConfigFlag( pIniFile, "report", pData->nTestFlags, DBG_TEST_MEM_REPORT );
+ lcl_writeConfigFlag( pIniFile, "trace", pData->nTestFlags, DBG_TEST_MEM_TRACE );
+ lcl_writeConfigFlag( pIniFile, "new_and_delete", pData->nTestFlags, DBG_TEST_MEM_NEWDEL );
+ lcl_writeConfigFlag( pIniFile, "object_test", pData->nTestFlags, DBG_TEST_MEM_XTOR );
+ lcl_writeConfigFlag( pIniFile, "sys_alloc", pData->nTestFlags, DBG_TEST_MEM_SYSALLOC );
+ lcl_writeConfigFlag( pIniFile, "leak_report", pData->nTestFlags, DBG_TEST_MEM_LEAKREPORT );
+
+ lcl_lineFeed( pIniFile );
+ lcl_writeHexByte( pIniFile, "init_byte", pData->bMemInit );
+ lcl_writeHexByte( pIniFile, "bound_byte", pData->bMemBound );
+ lcl_writeHexByte( pIniFile, "free_byte", pData->bMemFree );
+
+ lcl_lineFeed( pIniFile );
+ lcl_startSection( pIniFile, eGUI );
+ lcl_writeConfigString( pIniFile, "debug_window_state", pData->aDbgWinState );
+
+ lcl_lineFeed( pIniFile );
+ lcl_startSection( pIniFile, eObjects );
+ lcl_writeConfigFlag( pIniFile, "check_this", pData->nTestFlags, DBG_TEST_XTOR_THIS );
+ lcl_writeConfigFlag( pIniFile, "check_function", pData->nTestFlags, DBG_TEST_XTOR_FUNC );
+ lcl_writeConfigFlag( pIniFile, "check_exit", pData->nTestFlags, DBG_TEST_XTOR_EXIT );
+ lcl_writeConfigFlag( pIniFile, "generate_report", pData->nTestFlags, DBG_TEST_XTOR_REPORT );
+ lcl_writeConfigFlag( pIniFile, "trace", pData->nTestFlags, DBG_TEST_XTOR_TRACE );
+
+ lcl_lineFeed( pIniFile );
+ lcl_startSection( pIniFile, eTest );
+ lcl_writeConfigFlag( pIniFile, "profiling", pData->nTestFlags, DBG_TEST_PROFILING );
+ lcl_writeConfigFlag( pIniFile, "resources", pData->nTestFlags, DBG_TEST_RESOURCE );
+ lcl_writeConfigFlag( pIniFile, "dialog", pData->nTestFlags, DBG_TEST_DIALOG );
+ lcl_writeConfigFlag( pIniFile, "bold_app_font", pData->nTestFlags, DBG_TEST_BOLDAPPFONT );
+
+ FileClose( pIniFile );
+ }
+ break;
+
+ case DBG_FUNC_MEMTEST:
+#ifdef SV_MEMMGR
+ DbgImpCheckMemory( pParam );
+#endif
+ break;
+
+ case DBG_FUNC_XTORINFO:
+ DebugXTorInfo( (sal_Char*)pParam );
+ break;
+
+ case DBG_FUNC_MEMINFO:
+#ifdef SV_MEMMGR
+ DbgImpMemoryInfo( (sal_Char*)pParam );
+#endif
+ break;
+
+ case DBG_FUNC_COREDUMP:
+ ImplCoreDump();
+ break;
+
+ case DBG_FUNC_ALLERROROUT:
+ return (void*)(ULONG)TRUE;
+
+ case DBG_FUNC_SETTESTSOLARMUTEX:
+ pDebugData->pDbgTestSolarMutex = (DbgTestSolarMutexProc)(long)pParam;
+ break;
+
+ case DBG_FUNC_TESTSOLARMUTEX:
+ if ( pDebugData->pDbgTestSolarMutex )
+ pDebugData->pDbgTestSolarMutex();
+ break;
+
+ case DBG_FUNC_PRINTFILE:
+ ImplDbgPrintFile( (const sal_Char*)pParam );
+ break;
+ case DBG_FUNC_UPDATEOSLHOOK:
+ {
+ const DbgData* pData = static_cast< const DbgData* >( pParam );
+ pDebugData->aDbgData.bHookOSLAssert = pData->bHookOSLAssert;
+ if( pDebugData->bOslIsHooked && ! pData->bHookOSLAssert )
+ {
+ osl_setDetailedDebugMessageFunc( pDebugData->pOldDebugMessageFunc );
+ pDebugData->bOslIsHooked = FALSE;
+ }
+ else if( ! pDebugData->bOslIsHooked && pData->bHookOSLAssert )
+ {
+ pDebugData->pOldDebugMessageFunc = osl_setDetailedDebugMessageFunc( &dbg_printOslDebugMessage );
+ pDebugData->bOslIsHooked = TRUE;
+ }
+ }
+ break;
+ }
+
+ return NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+DbgChannelId DbgRegisterUserChannel( DbgPrintLine pProc )
+{
+ DebugData* pData = ImplGetDebugData();
+ pData->aDbgPrintUserChannels.push_back( pProc );
+ return (DbgChannelId)( pData->aDbgPrintUserChannels.size() - 1 + DBG_OUT_USER_CHANNEL_0 );
+}
+
+// -----------------------------------------------------------------------
+
+void DbgProf( USHORT nAction, DbgDataType* pDbgData )
+{
+ // Ueberhaupt Profiling-Test an
+ DebugData* pData = ImplGetDebugData();
+
+ if ( !(pData->aDbgData.nTestFlags & DBG_TEST_PROFILING) )
+ return;
+
+ sal_Char aBuf[DBG_BUF_MAXLEN];
+ ProfType* pProfData = (ProfType*)pDbgData->pData;
+ ULONG nTime;
+ if ( (nAction != DBG_PROF_START) && !pProfData )
+ {
+ strcpy( aBuf, DbgError_ProfEnd1 );
+ strcat( aBuf, pDbgData->pName );
+ DbgError( aBuf );
+ return;
+ }
+
+ switch ( nAction )
+ {
+ case DBG_PROF_START:
+ if ( !pDbgData->pData )
+ {
+ pDbgData->pData = (void*)new ProfType;
+ pProfData = (ProfType*)pDbgData->pData;
+ strncpy( pProfData->aName, pDbgData->pName, DBG_MAXNAME );
+ pProfData->aName[DBG_MAXNAME] = '\0';
+ pProfData->nCount = 0;
+ pProfData->nTime = 0;
+ pProfData->nMinTime = 0xFFFFFFFF;
+ pProfData->nMaxTime = 0;
+ pProfData->nStart = 0xFFFFFFFF;
+ pProfData->nContinueTime = 0;
+ pProfData->nContinueStart = 0xFFFFFFFF;
+ pData->pProfList->Add( (void*)pProfData );
+ }
+
+ if ( pProfData->nStart == 0xFFFFFFFF )
+ {
+ pProfData->nStart = ImplGetPerfTime();
+ pProfData->nCount++;
+ }
+ break;
+
+ case DBG_PROF_STOP:
+ nTime = ImplGetPerfTime();
+
+ if ( pProfData->nStart == 0xFFFFFFFF )
+ {
+ DbgError( DbgError_ProfEnd1 );
+ return;
+ }
+
+ if ( pProfData->nContinueStart != 0xFFFFFFFF )
+ {
+ pProfData->nContinueTime += ImplGetPerfTime() - pProfData->nContinueStart;
+ pProfData->nContinueStart = 0xFFFFFFFF;
+ }
+
+ nTime -= pProfData->nStart;
+ nTime -= pProfData->nContinueTime;
+
+ if ( nTime < pProfData->nMinTime )
+ pProfData->nMinTime = nTime;
+
+ if ( nTime > pProfData->nMaxTime )
+ pProfData->nMaxTime = nTime;
+
+ pProfData->nTime += nTime;
+
+ pProfData->nStart = 0xFFFFFFFF;
+ pProfData->nContinueTime = 0;
+ pProfData->nContinueStart = 0xFFFFFFFF;
+ break;
+
+ case DBG_PROF_CONTINUE:
+ if ( pProfData->nContinueStart != 0xFFFFFFFF )
+ {
+ pProfData->nContinueTime += ImplGetPerfTime() - pProfData->nContinueStart;
+ pProfData->nContinueStart = 0xFFFFFFFF;
+ }
+ break;
+
+ case DBG_PROF_PAUSE:
+ if ( pProfData->nContinueStart == 0xFFFFFFFF )
+ pProfData->nContinueStart = ImplGetPerfTime();
+ break;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DbgXtor( DbgDataType* pDbgData, USHORT nAction, const void* pThis,
+ DbgUsr fDbgUsr )
+{
+ DebugData* pData = ImplGetDebugData();
+
+ // Verbindung zu Debug-Memory-Manager testen
+#ifdef SV_MEMMGR
+ if ( pData->aDbgData.nTestFlags & DBG_TEST_MEM_XTOR )
+ DbgImpCheckMemory();
+#endif
+
+ // Schnell-Test
+ if ( !(pData->aDbgData.nTestFlags & DBG_TEST_XTOR) )
+ return;
+
+ XtorType* pXtorData = (XtorType*)pDbgData->pData;
+ if ( !pXtorData )
+ {
+ pDbgData->pData = (void*)new XtorType;
+ pXtorData = (XtorType*)pDbgData->pData;
+ strncpy( pXtorData->aName, pDbgData->pName, DBG_MAXNAME );
+ pXtorData->aName[DBG_MAXNAME] = '\0';
+ pXtorData->nCtorCalls = 0;
+ pXtorData->nDtorCalls = 0;
+ pXtorData->nMaxCount = 0;
+ pXtorData->nStatics = 0;
+ pXtorData->bTest = TRUE;
+ pData->pXtorList->Add( (void*)pXtorData );
+
+ if ( !ImplDbgFilter( pData->aDbgData.aInclClassFilter, pXtorData->aName, TRUE ) )
+ pXtorData->bTest = FALSE;
+ if ( ImplDbgFilter( pData->aDbgData.aExclClassFilter, pXtorData->aName, FALSE ) )
+ pXtorData->bTest = FALSE;
+ }
+ if ( !pXtorData->bTest )
+ return;
+
+ sal_Char aBuf[DBG_BUF_MAXLEN];
+ USHORT nAct = nAction & ~DBG_XTOR_DTOROBJ;
+
+ // Trace (Enter)
+ if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_TRACE) &&
+ !(nAction & DBG_XTOR_DTOROBJ) )
+ {
+ if ( nAct != DBG_XTOR_CHKOBJ )
+ {
+ if ( nAct == DBG_XTOR_CTOR )
+ strcpy( aBuf, DbgTrace_EnterCtor );
+ else if ( nAct == DBG_XTOR_DTOR )
+ strcpy( aBuf, DbgTrace_EnterDtor );
+ else
+ strcpy( aBuf, DbgTrace_EnterMeth );
+ strcat( aBuf, pDbgData->pName );
+ DbgTrace( aBuf );
+ }
+ }
+
+ // Sind noch Xtor-Tests als Trace an
+ if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXTRA )
+ {
+ // DBG_CTOR-Aufruf vor allen anderen DBG_XTOR-Aufrufen
+ if ( ((nAction & ~DBG_XTOR_DTOROBJ) != DBG_XTOR_CTOR) && !pDbgData->pData )
+ {
+ strcpy( aBuf, DbgError_Xtor1 );
+ strcat( aBuf, pDbgData->pName );
+ DbgError( aBuf );
+ return;
+ }
+
+ // Testen, ob This-Pointer gueltig
+ if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
+ {
+ if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) ||
+ !(nAction & DBG_XTOR_DTOROBJ) )
+ {
+ // This-Pointer == NULL
+ if ( !pThis )
+ {
+ strcpy( aBuf, DbgError_CtorDtor1 );
+ strcat( aBuf, pDbgData->pName );
+ DbgError( aBuf );
+ return;
+ }
+
+ if ( (nAction & ~DBG_XTOR_DTOROBJ) != DBG_XTOR_CTOR )
+ {
+ if ( !pXtorData->aThisList.IsIn( pThis ) )
+ {
+ sprintf( aBuf, DbgError_CtorDtor2, pThis );
+ strcat( aBuf, pDbgData->pName );
+ DbgError( aBuf );
+ }
+ }
+ }
+ }
+
+ // Function-Test durchfuehren und Verwaltungsdaten updaten
+ const sal_Char* pMsg = NULL;
+ switch ( nAction & ~DBG_XTOR_DTOROBJ )
+ {
+ case DBG_XTOR_CTOR:
+ if ( nAction & DBG_XTOR_DTOROBJ )
+ {
+ if ( fDbgUsr &&
+ (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) &&
+ (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
+ pMsg = fDbgUsr( pThis );
+ }
+ else
+ {
+ pXtorData->nCtorCalls++;
+ if ( !bDbgImplInMain )
+ pXtorData->nStatics++;
+ if ( (pXtorData->nCtorCalls-pXtorData->nDtorCalls) > pXtorData->nMaxCount )
+ pXtorData->nMaxCount = pXtorData->nCtorCalls - pXtorData->nDtorCalls;
+
+ if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
+ pXtorData->aThisList.Add( pThis );
+ }
+ break;
+
+ case DBG_XTOR_DTOR:
+ if ( nAction & DBG_XTOR_DTOROBJ )
+ {
+ pXtorData->nDtorCalls++;
+ if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
+ pXtorData->aThisList.Remove( pThis );
+ }
+ else
+ {
+ if ( fDbgUsr &&
+ (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
+ pMsg = fDbgUsr( pThis );
+ }
+ break;
+
+ case DBG_XTOR_CHKTHIS:
+ case DBG_XTOR_CHKOBJ:
+ if ( nAction & DBG_XTOR_DTOROBJ )
+ {
+ if ( fDbgUsr &&
+ (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) &&
+ (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
+ pMsg = fDbgUsr( pThis );
+ }
+ else
+ {
+ if ( fDbgUsr &&
+ (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
+ pMsg = fDbgUsr( pThis );
+ }
+ break;
+ }
+
+ // Gegebenenfalls Fehlermeldung ausgeben
+ if ( pMsg )
+ {
+ sprintf( aBuf, DbgError_CtorDtor3, pThis );
+ strcat( aBuf, pDbgData->pName );
+ strcat( aBuf, ": \n" );
+ strcat( aBuf, pMsg );
+ DbgError( aBuf );
+ }
+ }
+
+ // Trace (Leave)
+ if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_TRACE) &&
+ (nAction & DBG_XTOR_DTOROBJ) )
+ {
+ if ( nAct != DBG_XTOR_CHKOBJ )
+ {
+ if ( nAct == DBG_XTOR_CTOR )
+ strcpy( aBuf, DbgTrace_LeaveCtor );
+ else if ( nAct == DBG_XTOR_DTOR )
+ strcpy( aBuf, DbgTrace_LeaveDtor );
+ else
+ strcpy( aBuf, DbgTrace_LeaveMeth );
+ strcat( aBuf, pDbgData->pName );
+ DbgTrace( aBuf );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DbgOut( const sal_Char* pMsg, USHORT nDbgOut, const sal_Char* pFile, USHORT nLine )
+{
+ static BOOL bIn = FALSE;
+ if ( bIn )
+ return;
+ bIn = TRUE;
+
+ DebugData* pData = GetDebugData();
+ sal_Char const * pStr;
+ ULONG nOut;
+ int nBufLen = 0;
+
+ if ( nDbgOut == DBG_OUT_ERROR )
+ {
+ nOut = pData->aDbgData.nErrorOut;
+ pStr = "Error: ";
+ if ( pData->aDbgData.nErrorOut == DBG_OUT_FILE )
+ DbgDebugBeep();
+ }
+ else if ( nDbgOut == DBG_OUT_WARNING )
+ {
+ nOut = pData->aDbgData.nWarningOut;
+ pStr = "Warning: ";
+ }
+ else
+ {
+ nOut = pData->aDbgData.nTraceOut;
+ pStr = NULL;
+ }
+
+ if ( nOut == DBG_OUT_NULL )
+ {
+ bIn = FALSE;
+ return;
+ }
+
+ if ( ImplDbgFilterMessage( pMsg ) )
+ {
+ bIn = FALSE;
+ return;
+ }
+
+ ImplDbgLock();
+
+ sal_Char aBufOut[DBG_BUF_MAXLEN];
+ if ( pStr )
+ {
+ strcpy( aBufOut, pStr );
+ nBufLen = strlen( pStr );
+ }
+ else
+ aBufOut[0] = '\0';
+
+ int nMsgLen = strlen( pMsg );
+ if ( nBufLen+nMsgLen > DBG_BUF_MAXLEN )
+ {
+ int nCopyLen = DBG_BUF_MAXLEN-nBufLen-3;
+ strncpy( &(aBufOut[nBufLen]), pMsg, nCopyLen );
+ strcpy( &(aBufOut[nBufLen+nCopyLen]), "..." );
+ }
+ else
+ strcpy( &(aBufOut[nBufLen]), pMsg );
+
+ if ( pFile && nLine && (nBufLen+nMsgLen < DBG_BUF_MAXLEN) )
+ {
+ if ( nOut == DBG_OUT_MSGBOX )
+ strcat( aBufOut, "\n" );
+ else
+ strcat( aBufOut, " " );
+ strcat( aBufOut, "From File " );
+ strcat( aBufOut, pFile );
+ strcat( aBufOut, " at Line " );
+
+ // Line in String umwandeln und dranhaengen
+ sal_Char aLine[9];
+ sal_Char* pLine = &aLine[7];
+ USHORT i;
+ memset( aLine, 0, sizeof( aLine ) );
+ do
+ {
+ i = nLine % 10;
+ pLine--;
+ *(pLine) = (sal_Char)i + 48;
+ nLine /= 10;
+ }
+ while ( nLine );
+ strcat( aBufOut, pLine );
+ }
+
+ if ( ( nOut >= DBG_OUT_USER_CHANNEL_0 ) && ( nOut - DBG_OUT_USER_CHANNEL_0 < pData->aDbgPrintUserChannels.size() ) )
+ {
+ DbgPrintLine pPrinter = pData->aDbgPrintUserChannels[ nOut - DBG_OUT_USER_CHANNEL_0 ];
+ if ( pPrinter )
+ pPrinter( aBufOut );
+ else
+ nOut = DBG_OUT_DEBUGGER;
+ }
+
+ if ( nOut == DBG_OUT_COREDUMP )
+ {
+ if ( !ImplCoreDump() )
+ nOut = DBG_OUT_DEBUGGER;
+ }
+
+ if ( nOut == DBG_OUT_DEBUGGER )
+ {
+ if ( !ImplActivateDebugger( aBufOut ) )
+ nOut = DBG_OUT_TESTTOOL;
+ }
+
+ if ( nOut == DBG_OUT_TESTTOOL )
+ {
+ if ( pData->pDbgPrintTestTool )
+ pData->pDbgPrintTestTool( aBufOut );
+ else
+ nOut = DBG_OUT_MSGBOX;
+ }
+
+ if ( nOut == DBG_OUT_MSGBOX )
+ {
+ if ( pData->pDbgPrintMsgBox )
+ pData->pDbgPrintMsgBox( aBufOut );
+ else
+ nOut = DBG_OUT_WINDOW;
+ }
+
+ if ( nOut == DBG_OUT_WINDOW )
+ {
+ if ( pData->pDbgPrintWindow )
+ pData->pDbgPrintWindow( aBufOut );
+ else
+ nOut = DBG_OUT_FILE;
+ }
+
+ switch ( nOut )
+ {
+ case DBG_OUT_SHELL:
+ DbgPrintShell( aBufOut );
+ break;
+ case DBG_OUT_FILE:
+ ImplDbgPrintFile( aBufOut );
+ break;
+ }
+
+ ImplDbgUnlock();
+
+ bIn = FALSE;
+}
+
+void DbgPrintShell(char const * message) {
+ fprintf(stderr, "%s\n", message);
+#if defined WNT
+ OutputDebugStringA(message);
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+void DbgOutTypef( USHORT nDbgOut, const sal_Char* pFStr, ... )
+{
+ va_list pList;
+
+ va_start( pList, pFStr );
+ sal_Char aBuf[DBG_BUF_MAXLEN];
+ vsprintf( aBuf, pFStr, pList );
+ va_end( pList );
+
+ DbgOut( aBuf, nDbgOut );
+}
+
+// -----------------------------------------------------------------------
+
+void DbgOutf( const sal_Char* pFStr, ... )
+{
+ va_list pList;
+
+ va_start( pList, pFStr );
+ sal_Char aBuf[DBG_BUF_MAXLEN];
+ vsprintf( aBuf, pFStr, pList );
+ va_end( pList );
+
+ DbgOut( aBuf );
+}
+
+// =======================================================================
+
+#else
+
+void* DbgFunc( USHORT, void* ) { return NULL; }
+
+void DbgProf( USHORT, DbgDataType* ) {}
+void DbgXtor( DbgDataType*, USHORT, const void*, DbgUsr ) {}
+
+void DbgOut( const sal_Char*, USHORT, const sal_Char*, USHORT ) {}
+void DbgOutTypef( USHORT, const sal_Char*, ... ) {}
+void DbgOutf( const sal_Char*, ... ) {}
+
+#endif
diff --git a/tools/source/debug/makefile.mk b/tools/source/debug/makefile.mk
new file mode 100644
index 000000000000..925ae90f333d
--- /dev/null
+++ b/tools/source/debug/makefile.mk
@@ -0,0 +1,53 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=debug
+
+ENABLE_EXCEPTIONS := TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+CXXFILES= debug.cxx \
+ stcktree.cxx
+
+SLOFILES= $(SLO)$/debug.obj \
+ $(SLO)$/stcktree.obj
+
+OBJFILES= $(OBJ)$/debug.obj \
+ $(OBJ)$/stcktree.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/debug/stcktree.cxx b/tools/source/debug/stcktree.cxx
new file mode 100644
index 000000000000..dccc4c198852
--- /dev/null
+++ b/tools/source/debug/stcktree.cxx
@@ -0,0 +1,320 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <string.h>
+
+#include <tools/debug.hxx>
+
+// -----------------------------------------------------------------------
+
+#if defined( DBG_UTIL ) && defined( WNT ) && defined( INTEL )
+
+struct ImpDbgStackTree
+{
+ ImpDbgStackTree* pLeft_;
+ ImpDbgStackTree* pRight_;
+ ImpDbgStackTree* pCaller_;
+ ImpDbgStackTree* pSub_;
+ ULONG nIP_;
+ ULONG nBytesLeak_;
+ ULONG nBytesPeak_;
+ ULONG nBytes_;
+ ULONG nCountLeak_;
+ ULONG nCountPeak_;
+ ULONG nCount_;
+ ULONG nMax_;
+ ULONG nMin_;
+
+ ImpDbgStackTree( ImpDbgStackTree* pSub, ULONG nIP );
+ ~ImpDbgStackTree();
+
+ ImpDbgStackTree* Add( ULONG nAlloc, ULONG* pBP, ULONG nIP );
+ void Print( int nLevel, ULONG nCount, ULONG nCountLeak );
+ void Print( int nLevel );
+};
+
+static ImpDbgStackTree* pImpDbgStackTreeRoot = NULL;
+static ULONG* pImpDbgStackTreeBP = NULL;
+static ULONG nImpDbgStackTreeMain = 0;
+static int nImpDbgStackTreeSem = 0;
+
+// -----------------------------------------------------------------------
+
+ImpDbgStackTree::ImpDbgStackTree( ImpDbgStackTree* pSub, ULONG nIP )
+{
+ pSub_ = pSub;
+ nIP_ = nIP;
+ pLeft_ = pRight_ = pCaller_ = NULL;
+ nBytesLeak_ = nBytesPeak_ = nBytes_ = 0;
+ nCountLeak_ = nCountPeak_ = nCount_ = 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImpDbgStackTree::~ImpDbgStackTree()
+{
+ if ( pLeft_ )
+ delete pLeft_;
+ if ( pRight_ )
+ delete pRight_;
+ if ( pCaller_ )
+ delete pCaller_;
+}
+
+// -----------------------------------------------------------------------
+
+void ImpDbgStackTree::Print( int nLevel, ULONG nCount, ULONG nCountLeak )
+{
+ if ( pLeft_ )
+ pLeft_->Print( nLevel, nCount, nCountLeak );
+
+ if ( nCount_ >= nCount && nCountLeak_ >= nCountLeak )
+ {
+ if ( nMax_ == nMin_ )
+ {
+ ULONG nTemp = nCountLeak_ * nMin_;
+ DbgOutf( "%*c%08lx Count=%lu/%lu/%lu Bytes=%lu/%lu/%lu Size=%lu",
+ nLevel, ' ', nIP_,
+ nCount_, nCountPeak_, nCountLeak_,
+ nBytes_, nBytesPeak_, nTemp,
+ nMin_ );
+ }
+ else
+ {
+ DbgOutf( "%*c%08lx Count=%lu/%lu/%lu Bytes=%lu/%lu/%lu Size=%lu-%lu",
+ nLevel, ' ', nIP_,
+ nCount_, nCountPeak_, nCountLeak_,
+ nBytes_, nBytesPeak_, nBytesLeak_,
+ nMin_, nMax_ );
+ }
+
+ if ( pCaller_ )
+ if( nLevel > 3 && nCountLeak )
+ pCaller_->Print( nLevel + 1, nCount, 1 );
+ else
+ pCaller_->Print( nLevel + 1, nCount, nCountLeak );
+ }
+
+ if ( pRight_ )
+ pRight_->Print( nLevel, nCount, nCountLeak );
+}
+
+// -----------------------------------------------------------------------
+
+void ImpDbgStackTree::Print( int nLevel )
+{
+ if ( pSub_ )
+ pSub_->Print( nLevel + 1 );
+ DbgOutf( "%*c%08lx", nLevel, ' ',nIP_ );
+}
+
+// -----------------------------------------------------------------------
+
+ImpDbgStackTree* ImpDbgStackTree::Add( ULONG nAlloc, ULONG *pBP, ULONG nIP )
+{
+ if ( nIP < nIP_ )
+ {
+ if ( !pLeft_ )
+ pLeft_ = new ImpDbgStackTree( pSub_, nIP );
+ return pLeft_->Add( nAlloc, pBP, nIP );
+ }
+ if ( nIP > nIP_ )
+ {
+ if ( !pRight_ )
+ pRight_ = new ImpDbgStackTree( pSub_, nIP );
+ return pRight_->Add( nAlloc, pBP, nIP );
+ }
+
+ nCount_++;
+ nCountLeak_++;
+ if ( nCountLeak_ > nCountPeak_ )
+ nCountPeak_ = nCountLeak_;
+ nBytes_ += nAlloc;
+ nBytesLeak_ += nAlloc;
+ if ( nBytesLeak_ > nBytesPeak_ )
+ nBytesPeak_ = nBytesLeak_;
+ if ( nCount_ == 1 )
+ nMax_ = nMin_ = nAlloc;
+ else if ( nMax_ < nAlloc )
+ nMax_ = nAlloc;
+ else if ( nMin_ > nAlloc )
+ nMin_ = nAlloc;
+
+ if ( !(pBP[0] & 3) && (ULONG)pBP < pBP[0] && pBP[0] < (ULONG)pImpDbgStackTreeBP )
+ {
+ pBP = (ULONG*)pBP[0];
+ nIP = pBP[1];
+ if ( 0x01100000 <= nIP && nIP < 0x20000000 && nIP != nImpDbgStackTreeMain )
+ {
+ if ( !pCaller_ )
+ pCaller_ = new ImpDbgStackTree( this, nIP );
+ return pCaller_->Add( nAlloc, pBP, nIP );
+ }
+ else
+ return this;
+ }
+
+ return this;
+}
+
+// -----------------------------------------------------------------------
+
+void DbgStartStackTree()
+{
+ if ( !nImpDbgStackTreeMain )
+ {
+ ULONG* pBP;
+ __asm mov pBP, ebp;
+
+ pImpDbgStackTreeBP = (ULONG*)pBP[0];
+ nImpDbgStackTreeMain = pImpDbgStackTreeBP[1];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DbgEndStackTree()
+{
+ if ( nImpDbgStackTreeMain )
+ {
+ nImpDbgStackTreeMain = 0;
+ if ( pImpDbgStackTreeRoot )
+ {
+ // Ausgaben ins File umleiten
+ DbgData* pData = DbgGetData();
+ ULONG nOldOut = pData->nTraceOut;
+ pData->nTraceOut = DBG_OUT_FILE;
+
+ DbgOutf( "Leak-Report" );
+ DbgOutf( "===========" );
+ DbgOutf( "Mem-StackTree:" );
+ DbgOutf( "{" );
+ pImpDbgStackTreeRoot->Print( 1, 1, 2 );
+ DbgOutf( "}" );
+
+ DbgOutf( "Alloc-Report" );
+ DbgOutf( "===========" );
+ DbgOutf( "Mem-StackTree:" );
+ DbgOutf( "{" );
+ pImpDbgStackTreeRoot->Print( 1, 1000, 0 ); // ???
+ DbgOutf( "}" );
+
+ pData->nTraceOut = nOldOut;
+
+ nImpDbgStackTreeSem++;
+ delete pImpDbgStackTreeRoot;
+ pImpDbgStackTreeRoot = NULL;
+ nImpDbgStackTreeSem--;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void* DbgGetStackTree( ULONG nAlloc )
+{
+ ImpDbgStackTree* pReturn = NULL;
+
+ if ( nImpDbgStackTreeMain && !nImpDbgStackTreeSem )
+ {
+ nImpDbgStackTreeSem++;
+
+ ULONG* pBP;
+ __asm mov pBP, ebp;
+
+ ULONG nIP = pBP[1];
+ if ( !pImpDbgStackTreeRoot )
+ pImpDbgStackTreeRoot = new ImpDbgStackTree( NULL, nIP );
+ pReturn = pImpDbgStackTreeRoot->Add( nAlloc, pBP, nIP );
+ nImpDbgStackTreeSem--;
+ }
+
+ return pReturn;
+}
+
+// -----------------------------------------------------------------------
+
+void DbgFreeStackTree( void* pVoid, ULONG nAlloc )
+{
+ ImpDbgStackTree* p = (ImpDbgStackTree*)pVoid;
+
+ if ( p && nImpDbgStackTreeMain && !nImpDbgStackTreeSem )
+ {
+ if ( nAlloc < p->nMin_ )
+ nAlloc = p->nMin_;
+
+ p->nCountLeak_--;
+ p->nBytesLeak_ -= nAlloc;
+
+ if ( p->nMax_ && 0xFFFFFFFF / p->nMax_ > p->nCountLeak_ )
+ {
+ if ( p->nBytesLeak_ > p->nMax_ * p->nCountLeak_ )
+ {
+ nAlloc += p->nBytesLeak_ - p->nMax_ * p->nCountLeak_;
+ p->nBytesLeak_ = p->nMax_ * p->nCountLeak_;
+ }
+ }
+
+ if ( p->pSub_ )
+ DbgFreeStackTree( (void*)(p->pSub_), nAlloc );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DbgPrintStackTree( void* pVoid )
+{
+ ImpDbgStackTree* p = (ImpDbgStackTree*)pVoid;
+
+ if ( p && nImpDbgStackTreeMain && !nImpDbgStackTreeSem )
+ {
+ // Ausgaben ins File umleiten
+ DbgData* pData = DbgGetData();
+ ULONG nOldOut = pData->nTraceOut;
+ pData->nTraceOut = DBG_OUT_FILE;
+
+ DbgOutf( "Mem-StackTree:" );
+ DbgOutf( "{" );
+ p->Print( 1 );
+ DbgOutf( "}" );
+
+ pData->nTraceOut = nOldOut;
+ }
+}
+
+#else
+
+void DbgStartStackTree() {}
+void DbgEndStackTree() {}
+void* DbgGetStackTree( ULONG ) { return NULL; }
+void DbgFreeStackTree( void*, ULONG ) {}
+void DbgPrintStackTree( void* ) {}
+
+#endif
diff --git a/tools/source/fsys/comdep.cxx b/tools/source/fsys/comdep.cxx
new file mode 100644
index 000000000000..fa1009ad5fd3
--- /dev/null
+++ b/tools/source/fsys/comdep.cxx
@@ -0,0 +1,44 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include "comdep.hxx"
+#include <tools/debug.hxx>
+#include <tools/list.hxx>
+#include <tools/fsys.hxx>
+
+DBG_NAMEEX( DirEntry )
+
+#if defined UNX
+#include "unx.cxx"
+#elif defined WNT
+#include "wntmsc.cxx"
+#elif defined OS2
+#include "os2.cxx"
+#endif
diff --git a/tools/source/fsys/comdep.hxx b/tools/source/fsys/comdep.hxx
new file mode 100644
index 000000000000..043c5815f764
--- /dev/null
+++ b/tools/source/fsys/comdep.hxx
@@ -0,0 +1,156 @@
+/*************************************************************************
+ *
+ * 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 _COMDEP_HXX
+#define _COMDEP_HXX
+
+#include <tools/fsys.hxx>
+
+#define ACCESSDELIM(e) ( (e == FSYS_STYLE_MAC) ? ":" : \
+ ( ( e == FSYS_STYLE_VFAT || e == FSYS_STYLE_HPFS || \
+ e == FSYS_STYLE_FAT ) || e == FSYS_STYLE_NTFS ) \
+ ? "\\" : "/" )
+#define ACCESSDELIM_C(e)(char)\
+ ( (e == FSYS_STYLE_MAC) ? ':' : \
+ ( ( e == FSYS_STYLE_VFAT || e == FSYS_STYLE_HPFS || \
+ e == FSYS_STYLE_FAT ) || e == FSYS_STYLE_NTFS ) \
+ ? '\\' : '/' )
+#define SEARCHDELIM(e) ( (e == FSYS_STYLE_SYSV || e == FSYS_STYLE_BSD) ? ":" \
+ : ";" )
+#define SEARCHDELIM_C(e)(char)\
+ ( (e == FSYS_STYLE_SYSV || e == FSYS_STYLE_BSD) ? ':' \
+ : ';' )
+#define ACTPARENT(e) ( (e == FSYS_STYLE_MAC) ? ":" : ".." )
+#define ACTCURRENT(e) ( (e == FSYS_STYLE_MAC) ? "" : "." )
+
+#if defined UNX
+#include "unx.hxx"
+#elif defined WNT
+#include "wntmsc.hxx"
+#elif defined OS2
+#include "os2.hxx"
+#endif
+
+//--------------------------------------------------------------------
+
+#ifndef LINUX
+DIR *opendir( const char* pPfad );
+dirent *readdir( DIR *pDir );
+int closedir( DIR *pDir );
+char *volumeid( const char* pPfad );
+#endif
+
+//--------------------------------------------------------------------
+
+struct DirReader_Impl
+{
+ Dir* pDir;
+ DIR* pDosDir;
+ dirent* pDosEntry;
+ DirEntry* pParent;
+ String aPath;
+ ByteString aBypass;
+ BOOL bReady;
+ BOOL bInUse;
+
+ DirReader_Impl( Dir &rDir )
+ : pDir( &rDir ),
+ pDosEntry( 0 ),
+ pParent( 0 ),
+ aPath( GUI2FSYS(rDir.GetFull()) ),
+ bReady ( FALSE ),
+ bInUse( FALSE )
+ {
+#ifndef BOOTSTRAP
+ // Redirection
+ FSysRedirector::DoRedirect( aPath );
+#endif
+
+ // nur den String der Memer-Var nehmen!
+
+#if defined(UNX) || defined(OS2) //for further exlpanation see DirReader_Impl::Read() in unx.cxx
+ pDosDir = NULL;
+#else
+ aBypass = ByteString(aPath, osl_getThreadTextEncoding());
+ pDosDir = opendir( (char*) aBypass.GetBuffer() );
+#endif
+
+ // Parent f"ur die neuen DirEntries ermitteln
+ pParent = pDir->GetFlag() == FSYS_FLAG_NORMAL ||
+ pDir->GetFlag() == FSYS_FLAG_ABSROOT
+ ? pDir
+ : pDir->GetParent();
+
+ }
+
+ ~DirReader_Impl()
+ { if( pDosDir ) closedir( pDosDir ); }
+
+ // die folgenden sind systemabh"angig implementiert
+ USHORT Init(); // initialisiert, liest ggf. devices
+ USHORT Read(); // liest 1 Eintrag, F2ugt ein falls ok
+};
+
+//--------------------------------------------------------------------
+
+struct FileCopier_Impl
+{
+ FSysAction nActions; // was zu tun ist (Copy/Move/recur)
+ Link aErrorLink; // bei Fehlern zu rufen
+ ErrCode eErr; // aktueller Fehlercode im Error-Handler
+ const DirEntry* pErrSource; // fuer Error-Handler falls Source-Fehler
+ const DirEntry* pErrTarget; // fuer Error-Handler falls Target-Fehler
+
+ FileCopier_Impl()
+ : nActions( 0 ), eErr( 0 ),
+ pErrSource( 0 ), pErrTarget( 0 )
+ {}
+ FileCopier_Impl( const FileCopier_Impl &rOrig )
+ : nActions( rOrig.nActions ), eErr( 0 ),
+ pErrSource( 0 ), pErrTarget( 0 )
+ {}
+
+ FileCopier_Impl& operator=( const FileCopier_Impl &rOrig )
+ {
+ nActions = rOrig.nActions;
+ eErr = 0; pErrSource = 0; pErrTarget = 0;
+ return *this;
+ }
+};
+
+//--------------------------------------------------------------------
+
+#if defined WNT || defined OS2
+BOOL IsRedirectable_Impl( const ByteString &rPath );
+#else
+#define IsRedirectable_Impl( rPath ) TRUE
+#endif
+
+//--------------------------------------------------------------------
+
+
+#endif
diff --git a/tools/source/fsys/dirent.cxx b/tools/source/fsys/dirent.cxx
new file mode 100644
index 000000000000..1bd43bffc4e7
--- /dev/null
+++ b/tools/source/fsys/dirent.cxx
@@ -0,0 +1,3213 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+
+#if !defined UNX
+#include <io.h>
+#include <process.h>
+#endif
+
+#if defined(UNX) || defined(OS2)
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <tools/debug.hxx>
+#include <tools/list.hxx>
+#include "comdep.hxx"
+#include <tools/fsys.hxx>
+#define _TOOLS_HXX
+#include <tools/urlobj.hxx>
+
+#ifdef UNX
+#define _MAX_PATH 260
+#endif
+#include <tools/stream.hxx>
+
+#ifndef _VOS_MUTEX_HXX
+#include <vos/mutex.hxx>
+#endif
+
+#include <osl/file.hxx>
+#include <rtl/instance.hxx>
+
+
+using namespace osl;
+using namespace rtl;
+
+int ApiRet2ToSolarError_Impl( int nApiRet );
+
+//--------------------------------------------------------------------
+int Sys2SolarError_Impl( int nSysErr )
+{
+ switch ( nSysErr )
+ {
+#ifdef WNT
+ case NO_ERROR: return ERRCODE_NONE;
+ case ERROR_INVALID_FUNCTION: return ERRCODE_IO_GENERAL;
+ case ERROR_FILE_NOT_FOUND: return ERRCODE_IO_NOTEXISTS;
+ case ERROR_PATH_NOT_FOUND: return ERRCODE_IO_NOTEXISTSPATH;
+ case ERROR_TOO_MANY_OPEN_FILES: return ERRCODE_IO_TOOMANYOPENFILES;
+ case ERROR_ACCESS_DENIED: return ERRCODE_IO_ACCESSDENIED;
+ case ERROR_INVALID_HANDLE: return ERRCODE_IO_GENERAL;
+ case ERROR_NOT_ENOUGH_MEMORY: return ERRCODE_IO_OUTOFMEMORY;
+ case ERROR_INVALID_BLOCK: return ERRCODE_IO_GENERAL;
+// case ERROR_BAD_ENVIRONMENT: return ERRCODE_IO_;
+ case ERROR_BAD_FORMAT: return ERRCODE_IO_WRONGFORMAT;
+ case ERROR_INVALID_ACCESS: return ERRCODE_IO_ACCESSDENIED;
+// case ERROR_INVALID_DATA: return ERRCODE_IO_;
+ case ERROR_INVALID_DRIVE: return ERRCODE_IO_INVALIDDEVICE;
+ case ERROR_CURRENT_DIRECTORY: return ERRCODE_IO_CURRENTDIR;
+ case ERROR_NOT_SAME_DEVICE: return ERRCODE_IO_NOTSAMEDEVICE;
+// case ERROR_NO_MORE_FILES: return ERRCODE_IO_;
+ case ERROR_WRITE_PROTECT: return ERRCODE_IO_CANTWRITE;
+ case ERROR_BAD_UNIT: return ERRCODE_IO_INVALIDDEVICE;
+ case ERROR_NOT_READY: return ERRCODE_IO_DEVICENOTREADY;
+ case ERROR_BAD_COMMAND: return ERRCODE_IO_GENERAL;
+ case ERROR_CRC: return ERRCODE_IO_BADCRC;
+ case ERROR_BAD_LENGTH: return ERRCODE_IO_INVALIDLENGTH;
+ case ERROR_SEEK: return ERRCODE_IO_CANTSEEK;
+ case ERROR_NOT_DOS_DISK: return ERRCODE_IO_WRONGFORMAT;
+ case ERROR_SECTOR_NOT_FOUND: return ERRCODE_IO_GENERAL;
+ case ERROR_WRITE_FAULT: return ERRCODE_IO_CANTWRITE;
+ case ERROR_READ_FAULT: return ERRCODE_IO_CANTREAD;
+ case ERROR_GEN_FAILURE: return ERRCODE_IO_GENERAL;
+ case ERROR_SHARING_VIOLATION: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_LOCK_VIOLATION: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_WRONG_DISK: return ERRCODE_IO_INVALIDDEVICE;
+ case ERROR_NOT_SUPPORTED: return ERRCODE_IO_NOTSUPPORTED;
+#else
+ case 0: return ERRCODE_NONE;
+ case ENOENT: return ERRCODE_IO_NOTEXISTS;
+ case EACCES: return ERRCODE_IO_ACCESSDENIED;
+ case EEXIST: return ERRCODE_IO_ALREADYEXISTS;
+ case EINVAL: return ERRCODE_IO_INVALIDPARAMETER;
+ case EMFILE: return ERRCODE_IO_TOOMANYOPENFILES;
+ case ENOMEM: return ERRCODE_IO_OUTOFMEMORY;
+ case ENOSPC: return ERRCODE_IO_OUTOFSPACE;
+#endif
+ }
+
+ DBG_TRACE1( "FSys: unknown system error %d occured", nSysErr );
+ return FSYS_ERR_UNKNOWN;
+}
+
+//--------------------------------------------------------------------
+
+#ifndef BOOTSTRAP
+
+FSysRedirector* FSysRedirector::_pRedirector = 0;
+BOOL FSysRedirector::_bEnabled = TRUE;
+#ifdef UNX
+BOOL bInRedirection = TRUE;
+#else
+BOOL bInRedirection = FALSE;
+#endif
+static NAMESPACE_VOS( OMutex )* pRedirectMutex = 0;
+
+//------------------------------------------------------------------------
+void FSysRedirector::Register( FSysRedirector *pRedirector )
+{
+ if ( pRedirector )
+ pRedirectMutex = new NAMESPACE_VOS( OMutex );
+ else
+ DELETEZ( pRedirectMutex );
+ _pRedirector = pRedirector;
+}
+
+//------------------------------------------------------------------------
+
+void FSysRedirector::DoRedirect( String &rPath )
+{
+ String aURL(rPath);
+
+ // if redirection is disabled or not even registered do nothing
+ if ( !_bEnabled || !pRedirectMutex )
+ return;
+
+ // redirect only removable or remote volumes
+ if ( !IsRedirectable_Impl( ByteString( aURL, osl_getThreadTextEncoding() ) ) )
+ return;
+
+ // Redirection is acessible only by one thread per time
+ // dont move the guard behind the bInRedirection check!!!
+ // think of nested calls (when called from callback)
+ NAMESPACE_VOS( OGuard ) aGuard( pRedirectMutex );
+
+ // if already in redirection, dont redirect
+ if ( bInRedirection )
+ return;
+
+ // dont redirect on nested calls
+ bInRedirection = TRUE;
+
+ // convert to URL
+#ifndef UNX
+ for ( sal_Unicode *p = (sal_Unicode*)aURL.GetBuffer(); *p; ++p )
+ if ( '\\' == *p ) *p = '/';
+ else if ( ':' == *p ) *p = '|';
+#endif
+
+ aURL.Insert( String("file:///", osl_getThreadTextEncoding()), 0 );
+
+ // do redirection
+ Redirector();
+
+ bInRedirection = FALSE;
+ return;
+}
+
+//------------------------------------------------------------------------
+
+FSysRedirector* FSysRedirector::Redirector()
+{
+ if ( !_pRedirector )
+ Register( new FSysRedirector );
+ return _pRedirector;
+}
+
+#endif // BOOTSTRAP
+
+//--------------------------------------------------------------------
+
+class DirEntryStack: public List
+{
+public:
+ DirEntryStack() {};
+ ~DirEntryStack();
+
+ inline void Push( DirEntry *pEntry );
+ inline DirEntry* Pop();
+ inline DirEntry* Top();
+ inline DirEntry* Bottom();
+};
+
+inline void DirEntryStack::Push( DirEntry *pEntry )
+{
+ List::Insert( pEntry, LIST_APPEND );
+}
+
+inline DirEntry* DirEntryStack::Pop()
+{
+ return (DirEntry*) List::Remove( Count() - 1 );
+}
+
+inline DirEntry* DirEntryStack::Top()
+{
+ return (DirEntry*) List::GetObject( Count() - 1 );
+}
+
+inline DirEntry* DirEntryStack::Bottom()
+{
+ return (DirEntry*) List::GetObject( 0 );
+}
+
+//--------------------------------------------------------------------
+
+DBG_NAME( DirEntry );
+
+/*************************************************************************
+|*
+|* DirEntry::~DirEntryStack()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 04.07.91
+|*
+*************************************************************************/
+
+DirEntryStack::~DirEntryStack()
+{
+ while ( Count() )
+ delete Pop();
+}
+
+/*************************************************************************
+|*
+|* ImpCheckDirEntry()
+|*
+|* Beschreibung Pruefung eines DirEntry fuer DBG_UTIL
+|* Parameter void* p Zeiger auf den DirEntry
+|* Return-Wert char* Fehlermeldungs-TExtension oder NULL
+|* Ersterstellung MI 16.07.91
+|* Letzte Aenderung MI 26.05.93
+|*
+*************************************************************************/
+
+#ifdef DBG_UTIL
+const char* ImpCheckDirEntry( const void* p )
+{
+ DirEntry* p0 = (DirEntry*)p;
+
+ if ( p0->pParent )
+ DBG_CHKOBJ( p0->pParent, DirEntry, ImpCheckDirEntry );
+
+ return NULL;
+}
+#endif
+
+/*************************************************************************
+|*
+|* ImplCutPath()
+|*
+|* Beschreibung Fuegt ... ein, damit maximal nMaxChars lang
+|* Ersterstellung MI 06.04.94
+|* Letzte Aenderung DV 24.06.96
+|*
+*************************************************************************/
+
+ByteString ImplCutPath( const ByteString& rStr, USHORT nMax, char cAccDel )
+{
+ USHORT nMaxPathLen = nMax;
+ ByteString aCutPath( rStr );
+ BOOL bInsertPrefix = FALSE;
+ USHORT nBegin = aCutPath.Search( cAccDel );
+
+ if( nBegin == STRING_NOTFOUND )
+ nBegin = 0;
+ else
+ nMaxPathLen += 2; // fuer Prefix <Laufwerk>:
+
+ while( aCutPath.Len() > nMaxPathLen )
+ {
+ USHORT nEnd = aCutPath.Search( cAccDel, nBegin + 1 );
+ USHORT nCount;
+
+ if ( nEnd != STRING_NOTFOUND )
+ {
+ nCount = nEnd - nBegin;
+ aCutPath.Erase( nBegin, nCount );
+ bInsertPrefix = TRUE;
+ }
+ else
+ break;
+ }
+
+ if ( aCutPath.Len() > nMaxPathLen )
+ {
+ for ( USHORT n = nMaxPathLen; n > nMaxPathLen/2; --n )
+ if ( !ByteString(aCutPath.GetChar(n)).IsAlphaNumericAscii() )
+ {
+ aCutPath.Erase( n );
+ aCutPath += "...";
+ break;
+ }
+ }
+
+ if ( bInsertPrefix )
+ {
+ ByteString aIns( cAccDel );
+ aIns += "...";
+ aCutPath.Insert( aIns, nBegin );
+ }
+
+ return aCutPath;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpParseOs2Name()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 23.06.95
+|*
+*************************************************************************/
+
+FSysError DirEntry::ImpParseOs2Name( const ByteString& rPfad, FSysPathStyle eStyle )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ // die einzelnen Namen auf einen Stack packen
+ String aPfad( rPfad, osl_getThreadTextEncoding() );
+ DirEntryStack aStack;
+
+ do
+ {
+ // den Namen vor dem ersten "\\" abspalten,
+ // falls '\\' am Anfang, ist der Name '\\',
+ // der Rest immer ohne die fuehrenden '\\'.
+ // ein ":" trennt ebenfalls, gehoert aber zum Namen
+ // den ersten '\\', '/' oder ':' suchen
+ USHORT nPos;
+ for ( nPos = 0;
+ nPos < aPfad.Len() && //?O
+ aPfad.GetChar(nPos) != '\\' && aPfad.GetChar(nPos) != '/' && //?O
+ aPfad.GetChar(nPos) != ':'; //?O
+ nPos++ )
+ /* do nothing */;
+
+ // ist der Name ein UNC Pathname?
+ if ( nPos == 0 && aPfad.Len() > 1 &&
+ ( ( aPfad.GetChar(0) == '\\' && aPfad.GetChar(1) == '\\' ) ||
+ ( aPfad.GetChar(0) == '/' && aPfad.GetChar(1) == '/' ) ) )
+ {
+ for ( nPos = 2; aPfad.Len() > nPos; ++nPos )
+ if ( aPfad.GetChar(nPos) == '\\' || aPfad.GetChar(nPos) == '/' )
+ break;
+ aName = ByteString( aPfad.Copy( 2, nPos-2 ), osl_getThreadTextEncoding() );
+ aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT, eStyle ) );
+ }
+ // ist der Name die Root des aktuellen Drives?
+ else if ( nPos == 0 && aPfad.Len() > 0 &&
+ ( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) )
+ {
+ // Root-Directory des aktuellen Drives
+ aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) );
+ }
+ else
+ {
+ // ist der Name ein Drive?
+ if ( nPos < aPfad.Len() && aPfad.GetChar(nPos) == ':' )
+ {
+ aName = ByteString( aPfad.Copy( 0, nPos + 1 ), osl_getThreadTextEncoding() );
+
+ // ist der Name die Root des Drives
+ if ( (nPos + 1) < aPfad.Len() &&
+ ( aPfad.GetChar(nPos+1) == '\\' || aPfad.GetChar(nPos+1) == '/' ) )
+ {
+ // schon was auf dem Stack?
+ // oder Novell-Format? (not supported wegen URLs)
+ if ( aStack.Count() || aName.Len() > 2 )
+ {
+ aName = rPfad;
+ return FSYS_ERR_MISPLACEDCHAR;
+ }
+ // Root-Directory des Drive
+ aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT, eStyle ) );
+ }
+ else
+ {
+ // liegt ein anderes Drive auf dem Stack?
+ if ( aStack.Count() &&
+ COMPARE_EQUAL != aStack.Bottom()->aName.CompareIgnoreCaseToAscii(aName) )
+ aStack.Clear();
+
+ // liegt jetzt nichts mehr auf dem Stack?
+ if ( !aStack.Count() )
+ aStack.Push( new DirEntry( aName, FSYS_FLAG_RELROOT, eStyle ) );
+ }
+ }
+
+ // es ist kein Drive
+ else
+ {
+ // den Namen ohne Trenner abspalten
+ aName = ByteString( aPfad.Copy( 0, nPos ), osl_getThreadTextEncoding() );
+
+ // stellt der Name die aktuelle Directory dar?
+ if ( aName == "." )
+ /* do nothing */;
+
+ // stellt der Name die Parent-Directory dar?
+ else if ( aName == ".." )
+ {
+ // ist nichts, ein Parent oder eine relative Root
+ // auf dem Stack?
+ if ( ( aStack.Count() == 0 ) ||
+ ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) ||
+ ( aStack.Top()->eFlag == FSYS_FLAG_RELROOT ) )
+ // fuehrende Parents kommen auf den Stack
+ aStack.Push( new DirEntry( FSYS_FLAG_PARENT ) );
+
+ // ist es eine absolute Root
+ else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT )
+ {
+ // die hat keine Parent-Directory
+ aName = rPfad;
+ return FSYS_ERR_NOTEXISTS;
+ }
+ else
+ // sonst hebt der Parent den TOS auf
+ delete aStack.Pop();
+ }
+
+ else
+ {
+ if ( eStyle == FSYS_STYLE_FAT )
+ {
+ // ist der Name grundsaetzlich ungueltig?
+ int nPunkte = 0;
+ const char *pChar;
+ for ( pChar = aName.GetBuffer();
+ nPunkte < 2 && *pChar != 0;
+ pChar++ )
+ {
+ if ( *pChar == ';' )
+ nPunkte = 0;
+ else
+ nPunkte += ( *pChar == '.' ) ? 1 : 0;
+ }
+ if ( nPunkte > 1 )
+ {
+ aName = rPfad;
+ return FSYS_ERR_MISPLACEDCHAR;
+ }
+ }
+
+ // normalen Entries kommen auf den Stack
+ DirEntry *pNew = new DirEntry( aName, FSYS_FLAG_NORMAL, eStyle );
+ if ( !pNew->IsValid() )
+ {
+ aName = rPfad;
+ ErrCode eErr = pNew->GetError();
+ delete pNew;
+ return eErr;
+ }
+ aStack.Push( pNew );
+ }
+ }
+ }
+
+ // den Restpfad bestimmen
+ aPfad.Erase( 0, nPos + 1 );
+ while ( aPfad.Len() && ( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) )
+ aPfad.Erase( 0, 1 );
+ }
+ while ( aPfad.Len() );
+
+ ULONG nErr = ERRCODE_NONE;
+ // Haupt-Entry (selbst) zuweisen
+ if ( aStack.Count() == 0 )
+ {
+ eFlag = FSYS_FLAG_CURRENT;
+ aName.Erase();
+ }
+ else
+ {
+ eFlag = aStack.Top()->eFlag;
+ aName = aStack.Top()->aName;
+ nErr = aStack.Top()->nError;
+ delete aStack.Pop();
+ }
+
+ // die Parent-Entries vom Stack holen
+ DirEntry** pTemp = &pParent; // Zeiger auf den Member pParent setzen
+ while ( aStack.Count() )
+ {
+ *pTemp = aStack.Pop();
+
+ // Zeiger auf den Member pParent des eigenen Parent setzen
+ pTemp = &( (*pTemp)->pParent );
+ }
+
+ // wird damit ein Volume beschrieben?
+ if ( !pParent && eFlag == FSYS_FLAG_RELROOT && aName.Len() )
+ eFlag = FSYS_FLAG_VOLUME;
+
+ // bei gesetztem ErrorCode den Namen komplett "ubernehmen
+ if ( nErr )
+ aName = rPfad;
+ return nErr;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpParseName()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.08.91
+|* Letzte Aenderung MI 26.05.93
+|*
+*************************************************************************/
+
+FSysError DirEntry::ImpParseName( const ByteString& rbInitName,
+ FSysPathStyle eStyle )
+{
+ String rInitName( rbInitName, osl_getThreadTextEncoding() );
+ if ( eStyle == FSYS_STYLE_HOST )
+ eStyle = DEFSTYLE;
+
+ // KI-Division of FSys
+ if ( eStyle == FSYS_STYLE_DETECT )
+ {
+ sal_Unicode cFirst = rInitName.GetChar(0);
+ if ( rInitName.Len() == 2 && rInitName.GetChar(1) == ':' &&
+ ((cFirst >= 'A' && cFirst <= 'Z') ||
+ (cFirst >= 'a' && cFirst <= 'z')))
+ eStyle = FSYS_STYLE_HPFS;
+ else if ( rInitName.Len() > 2 && rInitName.GetChar(1) == ':' )
+ {
+ if ( rInitName.Search( ':', 2 ) == STRING_NOTFOUND )
+ eStyle = FSYS_STYLE_HPFS;
+ else
+ eStyle = FSYS_STYLE_MAC;
+ }
+ else if ( rInitName.Search( '/' ) != STRING_NOTFOUND )
+ eStyle = FSYS_STYLE_BSD;
+ else if ( rInitName.Search( '\\' ) != STRING_NOTFOUND )
+ eStyle = FSYS_STYLE_HPFS;
+ else if ( rInitName.Search( ':' ) != STRING_NOTFOUND )
+ eStyle = FSYS_STYLE_MAC;
+ else
+ eStyle = FSYS_STYLE_HPFS;
+ }
+
+ switch ( eStyle )
+ {
+ case FSYS_STYLE_FAT:
+ case FSYS_STYLE_VFAT:
+ case FSYS_STYLE_HPFS:
+ case FSYS_STYLE_NTFS:
+ case FSYS_STYLE_NWFS:
+ return ImpParseOs2Name( rbInitName, eStyle );
+
+ case FSYS_STYLE_BSD:
+ case FSYS_STYLE_SYSV:
+ return ImpParseUnixName( rbInitName, eStyle );
+
+ case FSYS_STYLE_MAC:
+ return FSYS_ERR_OK;
+
+ default:
+ return FSYS_ERR_UNKNOWN;
+ }
+}
+
+/*************************************************************************
+|*
+|* GetStyle()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 15.11.91
+|* Letzte Aenderung MI 15.11.91
+|*
+*************************************************************************/
+
+static FSysPathStyle GetStyle( FSysPathStyle eStyle )
+{
+ if ( eStyle == FSYS_STYLE_HOST || eStyle == FSYS_STYLE_DETECT )
+ return DEFSTYLE;
+ else
+ return eStyle;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpTrim()
+|*
+|* Beschreibung bringt den Namen auf Betriebssystem-Norm
+|* z.B. 8.3 lower beim MS-DOS Formatter
+|* wirkt nicht rekursiv
+|* Ersterstellung MI 12.08.91
+|* Letzte Aenderung MI 21.05.92
+|*
+*************************************************************************/
+
+void DirEntry::ImpTrim( FSysPathStyle eStyle )
+{
+ // Wildcards werden nicht geclipt
+ if ( ( aName.Search( '*' ) != STRING_NOTFOUND ) ||
+ ( aName.Search( '?' ) != STRING_NOTFOUND ) ||
+ ( aName.Search( ';' ) != STRING_NOTFOUND ) )
+ return;
+
+ switch ( eStyle )
+ {
+ case FSYS_STYLE_FAT:
+ {
+ USHORT nPunktPos = aName.Search( '.' );
+ if ( nPunktPos == STRING_NOTFOUND )
+ {
+ if ( aName.Len() > 8 )
+ {
+ nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
+ aName.Erase( 8 );
+ }
+ }
+ else
+ {
+ if ( nPunktPos > 8 )
+ {
+ nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
+ aName.Erase( 8, nPunktPos - 8 );
+ nPunktPos = 8;
+ }
+ if ( aName.Len() > nPunktPos + 3 )
+ {
+ if ( aName.Len() - nPunktPos > 4 )
+ {
+ nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
+ aName.Erase( nPunktPos + 4 );
+ }
+ }
+ }
+ aName.ToLowerAscii();
+ break;
+ }
+
+ case FSYS_STYLE_VFAT:
+ case FSYS_STYLE_HPFS:
+ case FSYS_STYLE_NTFS:
+ case FSYS_STYLE_NWFS:
+ if ( aName.Len() > 254 )
+ {
+ nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
+ aName.Erase( 254 );
+ }
+
+ if ( eStyle == FSYS_STYLE_HPFS &&
+ ( eFlag == FSYS_FLAG_ABSROOT || eFlag == FSYS_FLAG_RELROOT ) )
+ aName.ToUpperAscii();
+ break;
+
+ case FSYS_STYLE_SYSV:
+ if ( aName.Len() > 14 )
+ {
+ nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
+ aName.Erase( 14 );
+ }
+ break;
+
+ case FSYS_STYLE_BSD:
+ if ( aName.Len() > 250 )
+ {
+ nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
+ aName.Erase( 250 );
+ }
+ break;
+
+ case FSYS_STYLE_MAC:
+ if ( eFlag & ( FSYS_FLAG_ABSROOT | FSYS_FLAG_VOLUME ) )
+ {
+ if ( aName.Len() > 27 )
+ {
+ nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
+ aName.Erase( 27 );
+ }
+ }
+ else
+ {
+ if ( aName.Len() > 31 )
+ {
+ nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
+ aName.Erase( 31 );
+ }
+ }
+ break;
+
+ default:
+ /* kann nicht sein */;
+ }
+}
+
+/*************************************************************************
+|*
+|* DirEntry::DirEntry()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry::DirEntry( const ByteString& rName, DirEntryFlag eDirFlag,
+ FSysPathStyle eStyle ) :
+#ifdef FEAT_FSYS_DOUBLESPEED
+ pStat( 0 ),
+#endif
+ aName( rName )
+{
+ DBG_CTOR( DirEntry, ImpCheckDirEntry );
+
+ pParent = NULL;
+ eFlag = eDirFlag;
+ nError = FSYS_ERR_OK;
+
+ ImpTrim( eStyle );
+}
+
+/*************************************************************************
+|*
+|* DirEntry::DirEntry()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry::DirEntry( const DirEntry& rOrig ) :
+#ifdef FEAT_FSYS_DOUBLESPEED
+ pStat( rOrig.pStat ? new FileStat(*rOrig.pStat) : 0 ),
+#endif
+ aName( rOrig.aName )
+{
+ DBG_CTOR( DirEntry, ImpCheckDirEntry );
+
+ eFlag = rOrig.eFlag;
+ nError = rOrig.nError;
+
+ if ( rOrig.pParent )
+ {
+ pParent = new DirEntry( *rOrig.pParent );
+ }
+ else
+ {
+ pParent = NULL;
+ }
+}
+
+/*************************************************************************
+|*
+|* DirEntry::DirEntry()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry::DirEntry( const String& rInitName, FSysPathStyle eStyle )
+#ifdef FEAT_FSYS_DOUBLESPEED
+ : pStat( 0 )
+#endif
+{
+ DBG_CTOR( DirEntry, ImpCheckDirEntry );
+
+ pParent = NULL;
+
+ // schnelle Loesung fuer Leerstring
+ if ( !rInitName.Len())
+ {
+ eFlag = FSYS_FLAG_CURRENT;
+ nError = FSYS_ERR_OK;
+ return;
+ }
+
+ ByteString aTmpName(rInitName, osl_getThreadTextEncoding());
+ if( eStyle == FSYS_STYLE_URL || aTmpName.CompareIgnoreCaseToAscii("file:",5 ) == COMPARE_EQUAL )
+ {
+#ifndef BOOTSTRAP
+ DBG_WARNING( "File URLs are not permitted but accepted" );
+ aTmpName = ByteString(String(INetURLObject( rInitName ).PathToFileName()), osl_getThreadTextEncoding());
+ eStyle = FSYS_STYLE_HOST;
+#endif // BOOTSTRAP
+ }
+ else
+ {
+ ::rtl::OUString aTmp;
+ ::rtl::OUString aOInitName;
+ if ( FileBase::getFileURLFromSystemPath( OUString( rInitName ), aTmp ) == FileBase::E_None )
+ {
+ aOInitName = OUString( rInitName );
+ aTmpName = ByteString( String(aOInitName), osl_getThreadTextEncoding() );
+ }
+
+#ifdef DBG_UTIL
+ // ASF nur bei Default eStyle, nicht z.B. aus MakeShortName()
+ if( eStyle == FSYS_STYLE_HOST &&
+ aTmpName.Search( "://" ) != STRING_NOTFOUND )
+ {
+ ByteString aErr = "DirEntries akzeptieren nur File URLS: ";
+ aErr += aTmpName;
+ DBG_WARNING( aErr.GetBuffer() );
+ }
+#endif
+ }
+
+ nError = ImpParseName( aTmpName, eStyle );
+
+ if ( nError != FSYS_ERR_OK )
+ eFlag = FSYS_FLAG_INVALID;
+}
+
+/*************************************************************************/
+
+DirEntry::DirEntry( const ByteString& rInitName, FSysPathStyle eStyle )
+#ifdef FEAT_FSYS_DOUBLESPEED
+ : pStat( 0 )
+#endif
+{
+ DBG_CTOR( DirEntry, ImpCheckDirEntry );
+
+ pParent = NULL;
+
+ // schnelle Loesung fuer Leerstring
+ if ( !rInitName.Len() )
+ {
+ eFlag = FSYS_FLAG_CURRENT;
+ nError = FSYS_ERR_OK;
+ return;
+ }
+
+ ByteString aTmpName( rInitName );
+ if( eStyle == FSYS_STYLE_URL || rInitName.CompareIgnoreCaseToAscii("file:",5 ) == COMPARE_EQUAL )
+ {
+#ifndef BOOTSTRAP
+ DBG_WARNING( "File URLs are not permitted but accepted" );
+ aTmpName = ByteString(String(INetURLObject( rInitName ).PathToFileName()), osl_getThreadTextEncoding());
+ eStyle = FSYS_STYLE_HOST;
+#endif
+ }
+#ifdef DBG_UTIL
+ else
+ // ASF nur bei Default eStyle, nicht z.B. aus MakeShortName()
+ if( eStyle == FSYS_STYLE_HOST &&
+ rInitName.Search( "://" ) != STRING_NOTFOUND )
+ {
+ ByteString aErr = "DirEntries akzeptieren nur File URLS: ";
+ aErr += rInitName;
+ DBG_WARNING( aErr.GetBuffer() );
+ }
+#endif
+
+ nError = ImpParseName( aTmpName, eStyle );
+
+ if ( nError != FSYS_ERR_OK )
+ eFlag = FSYS_FLAG_INVALID;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::DirEntry()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry::DirEntry( DirEntryFlag eDirFlag )
+#ifdef FEAT_FSYS_DOUBLESPEED
+ : pStat( 0 )
+#endif
+{
+ DBG_CTOR( DirEntry, ImpCheckDirEntry );
+
+ eFlag = eDirFlag;
+ nError = ( eFlag == FSYS_FLAG_INVALID ) ? FSYS_ERR_UNKNOWN : FSYS_ERR_OK;
+ pParent = NULL;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::~DirEntry()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry::~DirEntry()
+{
+ DBG_DTOR( DirEntry, ImpCheckDirEntry );
+
+ delete pParent;
+#ifdef FEAT_FSYS_DOUBLESPEED
+ delete pStat;
+#endif
+
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpGetTopPtr() const
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+const DirEntry* DirEntry::ImpGetTopPtr() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ const DirEntry *pTemp = this;
+ while ( pTemp->pParent )
+ pTemp = pTemp->pParent;
+
+ return pTemp;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpGetTopPtr()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 13.11.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry* DirEntry::ImpGetTopPtr()
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry *pTemp = this;
+ while ( pTemp->pParent )
+ pTemp = pTemp->pParent;
+
+ return pTemp;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpGetPreTopPtr()
+|*
+|* Beschreibung liefert einen Pointer auf den vorletzten Entry
+|* Ersterstellung MI 01.11.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry* DirEntry::ImpGetPreTopPtr()
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry *pTemp = this;
+ if ( pTemp->pParent )
+ {
+ while ( pTemp->pParent->pParent )
+ pTemp = pTemp->pParent;
+ }
+
+ return pTemp;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpChangeParent()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 21.05.92
+|*
+*************************************************************************/
+
+DirEntry* DirEntry::ImpChangeParent( DirEntry* pNewParent, BOOL bNormalize )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry *pTemp = pParent;
+ if ( bNormalize && pNewParent &&
+ pNewParent->eFlag == FSYS_FLAG_RELROOT && !pNewParent->aName.Len() )
+ {
+ pParent = 0;
+ delete pNewParent;
+ }
+ else
+ pParent = pNewParent;
+
+ return pTemp;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::Exists()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 24.09.91
+|*
+*************************************************************************/
+
+BOOL DirEntry::Exists( FSysAccess nAccess ) const
+{
+#ifndef BOOTSTRAP
+ static NAMESPACE_VOS(OMutex) aLocalMutex;
+ NAMESPACE_VOS(OGuard) aGuard( aLocalMutex );
+#endif
+ if ( !IsValid() )
+ return FALSE;
+
+#if defined WNT || defined OS2
+ // spezielle Filenamen sind vom System da
+ if ( ( aName.CompareIgnoreCaseToAscii("CLOCK$") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("CON") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("AUX") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("COM1") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("COM2") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("COM3") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("COM4") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("LPT1") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("LPT2") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("LPT3") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("NUL") == COMPARE_EQUAL ||
+ aName.CompareIgnoreCaseToAscii("PRN") == COMPARE_EQUAL ) )
+ return TRUE;
+#endif
+
+ FSysFailOnErrorImpl();
+ DirEntryKind eKind = FileStat( *this, nAccess ).GetKind();
+ if ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) )
+ {
+ return TRUE;
+ }
+
+#if defined WNT || defined OS2
+ if ( 0 != ( eKind & FSYS_KIND_DEV ) )
+ {
+ return DRIVE_EXISTS( ImpGetTopPtr()->aName.GetChar(0) );
+ }
+#endif
+
+ return 0 != ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) );
+}
+
+/*************************************************************************
+|*
+|* DirEntry::First()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 15.01.92
+|*
+*************************************************************************/
+
+BOOL DirEntry::First()
+{
+ FSysFailOnErrorImpl();
+
+ String aUniPathName( GetPath().GetFull() );
+#ifndef BOOTSTRAP
+ FSysRedirector::DoRedirect( aUniPathName );
+ ByteString aPathName(aUniPathName, osl_getThreadTextEncoding());
+#else
+ ByteString aPathName(aUniPathName, gsl_getSystemTextEncoding());
+#endif
+ aPathName = GUI2FSYS( aPathName );
+
+ DIR *pDir = opendir( (char*) aPathName.GetBuffer() );
+ if ( pDir )
+ {
+#ifndef BOOTSTRAP
+ WildCard aWildeKarte( String(CMP_LOWER( aName ), osl_getThreadTextEncoding()) );
+#else
+ WildCard aWildeKarte( String(CMP_LOWER( aName ), gsl_getSystemTextEncoding()) );
+#endif
+ for ( dirent* pEntry = readdir( pDir );
+ pEntry;
+ pEntry = readdir( pDir ) )
+ {
+ ByteString aFound( FSYS2GUI( ByteString( pEntry->d_name ) ) );
+ if ( aWildeKarte.Matches( String(CMP_LOWER( aFound ), osl_getThreadTextEncoding())))
+ {
+ aName = aFound;
+ closedir( pDir );
+ return TRUE;
+ }
+ }
+ closedir( pDir );
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetFull()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+String DirEntry::GetFull( FSysPathStyle eStyle, BOOL bWithDelimiter,
+ USHORT nMaxChars ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ ByteString aRet;
+ eStyle = GetStyle( eStyle );
+ if ( pParent )
+ {
+ if ( ( pParent->eFlag == FSYS_FLAG_ABSROOT ||
+ pParent->eFlag == FSYS_FLAG_RELROOT ||
+ pParent->eFlag == FSYS_FLAG_VOLUME ) )
+ {
+ aRet = ByteString(pParent->GetName( eStyle ), osl_getThreadTextEncoding());
+ aRet += ByteString(GetName( eStyle ), osl_getThreadTextEncoding());
+ }
+ else
+ {
+ aRet = ByteString(pParent->GetFull( eStyle ), osl_getThreadTextEncoding());
+ aRet += ACCESSDELIM_C(eStyle);
+ aRet += ByteString(GetName( eStyle ), osl_getThreadTextEncoding());
+ }
+ }
+ else
+ {
+ aRet = ByteString(GetName( eStyle ), osl_getThreadTextEncoding());
+ }
+
+ if ( ( eStyle == FSYS_STYLE_MAC ) &&
+ ( ImpGetTopPtr()->eFlag != FSYS_FLAG_VOLUME ) &&
+ ( ImpGetTopPtr()->eFlag != FSYS_FLAG_ABSROOT ) &&
+ ( aRet.GetChar(0) != ':' ) )
+ aRet.Insert( ACCESSDELIM_C(eStyle), 0 );
+
+ //! Hack
+ if ( bWithDelimiter )
+ if ( aRet.GetChar( aRet.Len()-1 ) != ACCESSDELIM_C(eStyle) )
+ aRet += ACCESSDELIM_C(eStyle);
+
+ //! noch ein Hack
+ if ( nMaxChars < STRING_MAXLEN )
+ aRet = ImplCutPath( aRet, nMaxChars, ACCESSDELIM_C(eStyle) );
+
+ return String(aRet, osl_getThreadTextEncoding());
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetPath()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry DirEntry::GetPath() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ if ( pParent )
+ return DirEntry( *pParent );
+
+ return DirEntry();
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetExtension()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+String DirEntry::GetExtension( char cSep ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ const char *p0 = ( aName.GetBuffer() );
+ const char *p1 = p0 + aName.Len() - 1;
+ while ( p1 >= p0 && *p1 != cSep )
+ p1--;
+
+ if ( p1 >= p0 )
+ // es wurde ein cSep an der Position p1 gefunden
+ return String(
+ aName.Copy( static_cast< xub_StrLen >(p1 - p0 + 1) ),
+ osl_getThreadTextEncoding());
+ return String();
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetBase()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+String DirEntry::GetBase( char cSep ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ const char *p0 = ( aName.GetBuffer() );
+ const char *p1 = p0 + aName.Len() - 1;
+ while ( p1 >= p0 && *p1 != cSep )
+ p1--;
+
+ if ( p1 >= p0 )
+ // es wurde ein cSep an der Position p1 gefunden
+ return String(
+ aName.Copy( 0, static_cast< xub_StrLen >(p1 - p0) ),
+ osl_getThreadTextEncoding());
+
+ else
+ // es wurde kein cSep gefunden
+ return String(aName, osl_getThreadTextEncoding());
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetName()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91 13:47
+|*
+*************************************************************************/
+
+String DirEntry::GetName( FSysPathStyle eStyle ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ ByteString aRet;
+ eStyle = GetStyle( eStyle );
+
+ switch( eFlag )
+ {
+ case FSYS_FLAG_PARENT:
+ aRet = ACTPARENT(eStyle);
+ break;
+
+ case FSYS_FLAG_ABSROOT:
+ {
+ if ( eStyle == FSYS_STYLE_URL )
+ {
+ aRet = "file:///";
+ aRet += aName;
+
+#ifndef UNX
+ if ( aName.Len())
+ {
+ if ( aName.GetChar(aName.Len()-1) == ':' )
+ {
+ aRet.SetChar(aRet.Len()-1, '|');
+ }
+ else
+ {
+ aRet.Insert( '/', 5 );
+ }
+ aRet += "/";
+ }
+#endif
+ }
+ else if ( eStyle != FSYS_STYLE_MAC &&
+ aName.Len() > 1 && aName.GetChar( 1 ) != ':' )
+ {
+ // UNC-Pathname
+ aRet = ACCESSDELIM_C(eStyle);
+ aRet += ACCESSDELIM_C(eStyle);
+ aRet += aName ;
+ aRet += ACCESSDELIM_C(eStyle);
+ }
+ else
+ {
+ aRet = aName;
+ aRet += ACCESSDELIM_C(eStyle);
+ }
+ break;
+ }
+
+ case FSYS_FLAG_INVALID:
+ case FSYS_FLAG_VOLUME:
+ {
+ if ( eStyle == FSYS_STYLE_URL )
+ {
+ aRet = "file:///";
+ aRet += aName;
+#ifndef UNX
+ if ( aName.Len() && aName.GetChar(aName.Len()-1) == ':' )
+ {
+ aRet.SetChar(aRet.Len()-1, '|');
+ }
+#endif
+ }
+ else
+ {
+ aRet = aName;
+ }
+
+ break;
+ }
+
+ case FSYS_FLAG_RELROOT:
+ if ( !aName.Len() )
+ {
+ aRet = ACTCURRENT(eStyle);
+ break;
+ }
+
+ default:
+ aRet = aName;
+ }
+
+ return String(aRet, osl_getThreadTextEncoding());
+}
+
+/*************************************************************************
+|*
+|* DirEntry::IsAbs()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+bool DirEntry::IsAbs() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+#ifdef UNX
+ return ( pParent ? pParent->IsAbs() : eFlag == FSYS_FLAG_ABSROOT );
+#else
+ return ( pParent ? pParent->IsAbs() : eFlag == FSYS_FLAG_ABSROOT && aName.Len() > 0 );
+#endif
+}
+
+/*************************************************************************
+|*
+|* DirEntry::CutName()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+String DirEntry::CutName( FSysPathStyle eStyle )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ eStyle = GetStyle( eStyle );
+
+ String aOldName( GetName( eStyle ) );
+
+ if ( pParent )
+ {
+ DirEntry *pOldParent = pParent;
+ if ( pOldParent )
+ {
+ pParent = pOldParent->pParent;
+ eFlag = pOldParent->eFlag;
+ aName = pOldParent->aName;
+ pOldParent->pParent = NULL;
+ delete pOldParent;
+ }
+ else
+ {
+ eFlag = FSYS_FLAG_CURRENT;
+ aName.Erase();
+ }
+ }
+ else
+ {
+ eFlag = FSYS_FLAG_CURRENT;
+ aName.Erase();
+ delete pParent;
+ pParent = NULL;
+ }
+
+ return aOldName;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::NameCompare
+|*
+|* Beschreibung Vergleich nur die Namen (ohne Pfad, aber mit Gross/Klein)
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+StringCompare DirEntry::NameCompare( const DirEntry &rWith ) const
+{
+ ByteString aThisName;
+ ByteString aParameterName;
+
+#ifdef UNX
+ aThisName = aName;
+ aParameterName = rWith.aName;
+#else
+ aThisName = ByteString(aName).ToLowerAscii();
+ aParameterName = ByteString(rWith.aName).ToLowerAscii();
+#endif
+
+ return aThisName.CompareTo( aParameterName );
+}
+
+
+/*************************************************************************
+|*
+|* DirEntry::operator==()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+BOOL DirEntry::operator==( const DirEntry& rEntry ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ // test wheather the contents are textual the same
+
+ if ( nError && ( nError == rEntry.nError ) )
+ return TRUE;
+ if ( nError || rEntry.nError ||
+ ( eFlag == FSYS_FLAG_INVALID ) ||
+ ( rEntry.eFlag == FSYS_FLAG_INVALID ) )
+ return FALSE;
+
+#ifndef OS2
+ const
+#endif
+ DirEntry *pThis = (DirEntry *)this;
+#ifndef OS2
+ const
+#endif
+ DirEntry *pWith = (DirEntry *)&rEntry;
+ while( pThis && pWith && (pThis->eFlag == pWith->eFlag) )
+ {
+ if ( CMP_LOWER(pThis->aName) != CMP_LOWER(pWith->aName) )
+ break;
+ pThis = pThis->pParent;
+ pWith = pWith->pParent;
+ }
+
+ return ( !pThis && !pWith );
+}
+
+/*************************************************************************
+|*
+|* DirEntry::operator=()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry& DirEntry::operator=( const DirEntry& rEntry )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ if ( this == &rEntry )
+ return *this;
+ if ( rEntry.nError != FSYS_ERR_OK ) {
+ DBG_ERROR("Zuweisung mit invalidem DirEntry");
+ nError = rEntry.nError;
+ return *this;
+ }
+
+ // Name und Typ uebernehmen, Refs beibehalten
+ aName = rEntry.aName;
+ eFlag = rEntry.eFlag;
+ nError = FSYS_ERR_OK;
+
+ DirEntry *pOldParent = pParent;
+ if ( rEntry.pParent )
+ pParent = new DirEntry( *rEntry.pParent );
+ else
+ pParent = NULL;
+
+ if ( pOldParent )
+ delete pOldParent;
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::operator+()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry DirEntry::operator+( const DirEntry& rEntry ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+#ifdef DBG_UTIL
+ static BOOL bTested = FALSE;
+ if ( !bTested )
+ {
+ bTested = TRUE;
+ FSysTest();
+ }
+#endif
+
+ const DirEntry *pEntryTop = rEntry.ImpGetTopPtr();
+ const DirEntry *pThisTop = ImpGetTopPtr();
+
+ // "." + irgendwas oder irgendwas + "d:irgendwas"
+/* TPF:org
+ if ( ( eFlag == FSYS_FLAG_RELROOT && !aName ) ||
+ ( pEntryTop->aName.Len() &&
+ ( pEntryTop->eFlag == FSYS_FLAG_ABSROOT ||
+ pEntryTop->eFlag == FSYS_FLAG_RELROOT ||
+ pEntryTop->eFlag == FSYS_FLAG_VOLUME ) ) )
+ return rEntry;
+*/
+
+ if (
+ (eFlag == FSYS_FLAG_RELROOT && !aName.Len()) ||
+ (
+ (pEntryTop->aName.Len() ||
+ ((rEntry.Level()>1)?(rEntry[rEntry.Level()-2].aName.CompareIgnoreCaseToAscii(RFS_IDENTIFIER)==COMPARE_EQUAL):FALSE))
+ &&
+ (pEntryTop->eFlag == FSYS_FLAG_ABSROOT ||
+ pEntryTop->eFlag == FSYS_FLAG_RELROOT ||
+ pEntryTop->eFlag == FSYS_FLAG_VOLUME)
+ )
+ )
+ {
+ return rEntry;
+ }
+
+ // irgendwas + "." (=> pEntryTop == &rEntry)
+ if ( pEntryTop->eFlag == FSYS_FLAG_RELROOT && !pEntryTop->aName.Len() )
+ {
+ DBG_ASSERT( pEntryTop == &rEntry, "DirEntry::op+ buggy" );
+ return *this;
+ }
+
+ // root += ".." (=> unmoeglich)
+ if ( pEntryTop->eFlag == FSYS_FLAG_PARENT && pThisTop == this &&
+ ( eFlag == FSYS_FLAG_ABSROOT ) )
+ return DirEntry( FSYS_FLAG_INVALID );
+
+ // irgendwas += abs (=> nur Device uebernehmen falls vorhanden)
+ if ( pEntryTop->eFlag == FSYS_FLAG_ABSROOT )
+ {
+ ByteString aDevice;
+ if ( pThisTop->eFlag == FSYS_FLAG_ABSROOT )
+ aDevice = pThisTop->aName;
+ DirEntry aRet = rEntry;
+ if ( aDevice.Len() )
+ aRet.ImpGetTopPtr()->aName = aDevice;
+ return aRet;
+ }
+
+ // irgendwas += ".." (=> aufloesen)
+ if ( eFlag == FSYS_FLAG_NORMAL && pEntryTop->eFlag == FSYS_FLAG_PARENT )
+ {
+ String aConcated( GetFull() );
+ aConcated += ACCESSDELIM_C(FSYS_STYLE_HOST);
+ aConcated += rEntry.GetFull();
+ return DirEntry( aConcated );
+ }
+
+ // sonst einfach hintereinander haengen
+ DirEntry aRet( rEntry );
+ DirEntry *pTop = aRet.ImpGetTopPtr();
+ pTop->pParent = new DirEntry( *this );
+
+ return aRet;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::operator+=()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+DirEntry &DirEntry::operator+=( const DirEntry& rEntry )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ return *this = *this + rEntry;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetAccessDelimiter()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 27.05.93
+|* Letzte Aenderung MI 10.06.93
+|*
+*************************************************************************/
+
+String DirEntry::GetAccessDelimiter( FSysPathStyle eFormatter )
+{
+ return String( ACCESSDELIM_C( GetStyle( eFormatter ) ) );
+}
+
+/*************************************************************************
+|*
+|* DirEntry::SetExtension()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 02.08.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+void DirEntry::SetExtension( const String& rExtension, char cSep )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ // do not set extensions for drives
+ if(eFlag == FSYS_FLAG_ABSROOT)
+ {
+ nError = FSYS_ERR_NOTSUPPORTED;
+ return;
+ }
+
+ // cSep im Namen suchen
+ const char *p0 = ( aName.GetBuffer() );
+ const char *p1 = p0 + aName.Len() - 1;
+ while ( p1 >= p0 && *p1 != cSep )
+ p1--;
+ if ( p1 >= p0 )
+ {
+ // es wurde ein cSep an der Position p1 gefunden
+ aName.Erase(
+ static_cast< xub_StrLen >(
+ p1 - p0 + 1 - ( rExtension.Len() ? 0 : 1 )) );
+ aName += ByteString(rExtension, osl_getThreadTextEncoding());
+ }
+ else if ( rExtension.Len() )
+ {
+ // es wurde kein cSep gefunden
+ aName += cSep;
+ aName += ByteString(rExtension, osl_getThreadTextEncoding());
+ }
+}
+
+/*************************************************************************
+|*
+|* DirEntry::CutExtension()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 23.07.93
+|* Letzte Aenderung MI 23.07.93
+|*
+*************************************************************************/
+
+String DirEntry::CutExtension( char cSep )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ const char *p0 = ( aName.GetBuffer() );
+ const char *p1 = p0 + aName.Len() - 1;
+ while ( p1 >= p0 && *p1 != cSep )
+ p1--;
+
+ if ( p1 >= p0 )
+ {
+ // es wurde ein cSep an der Position p1 gefunden
+ aName.Erase( static_cast< xub_StrLen >(p1-p0) );
+ return String(p1 + 1, osl_getThreadTextEncoding());
+ }
+
+ return String();
+}
+
+/*************************************************************************
+|*
+|* DirEntry::SetName()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 04.09.93
+|* Letzte Aenderung MI 04.09.93
+|*
+*************************************************************************/
+
+void DirEntry::SetName( const String& rName, FSysPathStyle eFormatter )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ if ( eFormatter == FSYS_STYLE_HOST || eFormatter == FSYS_STYLE_DETECT )
+ eFormatter = DEFSTYLE;
+ ByteString aAccDelim( ACCESSDELIM_C( eFormatter ) );
+
+ if ( (eFlag != FSYS_FLAG_NORMAL) ||
+ (aName.Search( ':' ) != STRING_NOTFOUND) ||
+ (aName.Search( aAccDelim ) != STRING_NOTFOUND) ||
+ (eFormatter == FSYS_STYLE_FAT && (aName.GetTokenCount( '.' ) > 2) ) )
+ {
+ eFlag = FSYS_FLAG_INVALID;
+ }
+ else
+ {
+ aName = ByteString(rName, osl_getThreadTextEncoding());
+ }
+}
+
+/*************************************************************************
+|*
+|* DirEntry::Find()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+BOOL DirEntry::Find( const String& rPfad, char cDelim )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ if ( ImpGetTopPtr()->eFlag == FSYS_FLAG_ABSROOT )
+ return TRUE;
+
+ BOOL bWild = aName.Search( '*' ) != STRING_NOTFOUND ||
+ aName.Search( '?' ) != STRING_NOTFOUND;
+ if ( !cDelim )
+ cDelim = SEARCHDELIM(DEFSTYLE)[0];
+
+ USHORT nTokenCount = rPfad.GetTokenCount( cDelim );
+ USHORT nIndex = 0;
+ ByteString aThis = ACCESSDELIM(DEFSTYLE);
+ aThis += ByteString(GetFull(), osl_getThreadTextEncoding());
+ for ( USHORT nToken = 0; nToken < nTokenCount; ++nToken )
+ {
+ ByteString aPath = ByteString(rPfad, osl_getThreadTextEncoding()).GetToken( 0, cDelim, nIndex );
+
+ if ( aPath.Len() )
+ {
+ if (aPath.GetChar(aPath.Len()-1)== ACCESSDELIM(DEFSTYLE)[0])
+ aPath.Erase(aPath.Len()-1);
+ aPath += aThis;
+ DirEntry aEntry( String(aPath, osl_getThreadTextEncoding()));
+ if ( aEntry.ToAbs() &&
+ ( ( !bWild && aEntry.Exists() ) || ( bWild && aEntry.First() ) ) )
+ {
+ (*this) = aEntry;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpToRel()
+|*
+|* Beschreibung
+|* Ersterstellung MI 17.06.93
+|* Letzte Aenderung MI 17.06.93
+|*
+*************************************************************************/
+
+BOOL DirEntry::ImpToRel( String aCurStr )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry aThis(*this);
+ aThis.ToAbs();
+ String aThisStr( aThis.GetFull( FSYS_STYLE_HPFS ) );
+
+ // #109512 preserve case of path even if caseinsensitive
+ String aThisCompareStr( aThisStr ), aCurCompareStr( aCurStr );
+ if ( ! IsCaseSensitive() )
+ {
+ aThisCompareStr.ToLowerAscii();
+ aCurCompareStr.ToLowerAscii();
+ }
+
+ // "Ubereinstimmung pr"ufen
+ USHORT nPos = aThisCompareStr.Match( aCurCompareStr );
+ if ( nPos == STRING_MATCH && aThisStr.Len() != aCurStr.Len() )
+ nPos = Min( aThisStr.Len(), aCurStr.Len() );
+
+ // Sonderfall, die DirEntries sind identisch
+ if ( nPos == STRING_MATCH )
+ {
+ // dann ist der relative Pfad das aktuelle Verzeichnis
+ *this = DirEntry();
+ return TRUE;
+ }
+
+ // Sonderfall, die DirEntries sind total verschieden
+ if ( nPos == 0 )
+ {
+ // dann ist der relativste Pfad absolut
+ *this = aThis;
+ return FALSE;
+ }
+
+ // sonst nehmen wir die identischen Einzelteile vorne weg
+ while ( nPos > 0 && aThisStr.GetChar(nPos) != '\\' )
+ --nPos;
+ aThisStr.Erase( 0, nPos + ( ( aThisStr.GetChar(nPos) == '\\' ) ? 1 : 0 ) );
+ aCurStr.Erase( 0, nPos + ( ( aCurStr.GetChar(nPos) == '\\' ) ? 1 : 0 ) );
+
+ // und fuellen mit dem Level der Directories auf
+ for ( nPos = 0; nPos < aCurStr.Len(); ++nPos )
+ if ( aCurStr.GetChar(nPos) == '\\' )
+ aThisStr.Insert( String( "..\\", osl_getThreadTextEncoding() ), 0 );
+
+ // das ist dann unser relativer Pfad
+ *this = DirEntry( aThisStr, FSYS_STYLE_HPFS );
+ return TRUE;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::CutRelParents()
+|*
+|* Beschreibung
+|* Ersterstellung MI 01.08.95
+|* Letzte Aenderung MI 01.08.95
+|*
+*************************************************************************/
+
+USHORT DirEntry::CutRelParents()
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ // erstes '..' finden
+ DirEntry *pDir = 0;
+ DirEntry *pPar;
+
+ for ( pPar = this;
+ pPar && pPar->eFlag != FSYS_FLAG_PARENT;
+ pPar = pPar->pParent )
+ pDir = pPar;
+
+ // '..' zaehlen
+ USHORT nParCount = 0;
+ while ( pPar && pPar->eFlag == FSYS_FLAG_PARENT )
+ {
+ ++nParCount;
+ pPar = pPar->pParent;
+ }
+
+ // cutten
+ if ( pDir )
+ DELETEZ(pDir->pParent);
+ else
+ eFlag = FSYS_FLAG_CURRENT;
+
+ return nParCount;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ToRel()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.06.93
+|* Letzte Aenderung MI 17.06.93
+|*
+*************************************************************************/
+
+BOOL DirEntry::ToRel()
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry aCur;
+ aCur.ToAbs();
+ return ImpToRel( aCur.GetFull( FSYS_STYLE_HPFS ) );
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ToRel()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+BOOL DirEntry::ToRel( const DirEntry& rStart )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry aStart( rStart );
+ aStart.ToAbs();
+ return ImpToRel( aStart.GetFull( FSYS_STYLE_HPFS ) );
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetDevice()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+#ifndef UNX
+
+DirEntry DirEntry::GetDevice() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ const DirEntry *pTop = ImpGetTopPtr();
+
+ if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT || pTop->eFlag == FSYS_FLAG_RELROOT ) &&
+ pTop->aName.Len() )
+ return DirEntry( pTop->aName, FSYS_FLAG_VOLUME, FSYS_STYLE_HOST );
+ else
+ return DirEntry( ByteString(), FSYS_FLAG_INVALID, FSYS_STYLE_HOST );
+}
+
+#endif
+
+/*************************************************************************
+|*
+|* DirEntry::SetBase()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 23.10.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+void DirEntry::SetBase( const String& rBase, char cSep )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ const char *p0 = ( aName.GetBuffer() );
+ const char *p1 = p0 + aName.Len() - 1;
+ while ( p1 >= p0 && *p1 != cSep )
+ p1--;
+
+ if ( p1 >= p0 )
+ {
+ // es wurde ein cSep an der Position p1 gefunden
+ aName.Erase( 0, static_cast< xub_StrLen >(p1 - p0) );
+ aName.Insert( ByteString(rBase, osl_getThreadTextEncoding()), 0 );
+ }
+ else
+ aName = ByteString(rBase, osl_getThreadTextEncoding());
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetSearchDelimiter()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 10.06.93
+|* Letzte Aenderung MI 10.06.93
+|*
+*************************************************************************/
+
+String DirEntry::GetSearchDelimiter( FSysPathStyle eFormatter )
+{
+ return String( ByteString(SEARCHDELIM( GetStyle( eFormatter ) ) ), osl_getThreadTextEncoding());
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetMaxNameLen()
+|*
+|* Beschreibung Liefert die maximale Anzahl von Zeichen in
+|* einzelnen Namensteile. Bei FileSystmen mit
+|* fester Extension (FAT) zaehlt diese nicht mit.
+|* Bei unbekannten FileSytemen und FSYS_STYLE_URL
+|* wird USHRT_MAX zurueckgegeben.
+|* Ersterstellung MI 17.06.97
+|* Letzte Aenderung MI 17.06.97
+|*
+*************************************************************************/
+
+USHORT DirEntry::GetMaxNameLen( FSysPathStyle eFormatter )
+{
+ eFormatter = GetStyle( eFormatter );
+ switch ( eFormatter )
+ {
+ case FSYS_STYLE_MAC: return 31;
+
+ case FSYS_STYLE_FAT: return 8;
+
+ case FSYS_STYLE_VFAT:
+ case FSYS_STYLE_NTFS:
+ case FSYS_STYLE_NWFS:
+ case FSYS_STYLE_HPFS: return 255;
+
+
+ case FSYS_STYLE_SYSV: return 14;
+
+ case FSYS_STYLE_BSD: return 250;
+
+ default:
+ return USHRT_MAX;
+ }
+}
+
+/*************************************************************************
+|*
+|* DirEntry::TempName()
+|*
+|* Beschreibung FSYS.SDW - Aha, wo?
+|* Ersterstellung VB 06.09.93 (im SWG)
+|* Letzte Aenderung MI 06.02.98
+|*
+*************************************************************************/
+namespace { struct TempNameBase_Impl : public rtl::Static< DirEntry, TempNameBase_Impl > {}; }
+
+const DirEntry& DirEntry::SetTempNameBase( const String &rBase )
+{
+ DirEntry aTempDir = DirEntry().TempName().GetPath();
+ aTempDir += DirEntry( rBase );
+#ifdef UNX
+ ByteString aName( aTempDir.GetFull(), osl_getThreadTextEncoding());
+ if ( access( aName.GetBuffer(), W_OK | X_OK | R_OK ) )
+ {
+ // Create the directory and only on success give all rights to
+ // everyone. Use mkdir instead of DirEntry::MakeDir because
+ // this returns TRUE even if directory already exists.
+
+ if ( !mkdir( aName.GetBuffer(), S_IRWXU | S_IRWXG | S_IRWXO ) )
+ chmod( aName.GetBuffer(), S_IRWXU | S_IRWXG | S_IRWXO );
+
+ // This will not create a directory but perhaps FileStat called
+ // there modifies the DirEntry
+
+ aTempDir.MakeDir();
+ }
+#else
+ aTempDir.MakeDir();
+#endif
+ DirEntry &rEntry = TempNameBase_Impl::get();
+ rEntry = aTempDir.TempName( FSYS_KIND_DIR );
+ return rEntry;
+}
+
+DirEntry DirEntry::TempName( DirEntryKind eKind ) const
+{
+ // ggf. Base-Temp-Dir verwenden (macht Remote keinen Sinn => vorher)
+ const DirEntry &rEntry = TempNameBase_Impl::get();
+ if ( !pParent && FSYS_FLAG_CURRENT != rEntry.eFlag && FSYS_FLAG_ABSROOT != eFlag )
+
+ {
+ DirEntry aFactory( rEntry );
+ aFactory += GetName();
+ return aFactory.TempName();
+ }
+
+ ByteString aDirName; // hiermit hatte MPW C++ Probleme - immmer noch??
+ char *ret_val;
+ size_t i;
+
+ // dertermine Directory, Prefix and Extension
+ char pfx[6];
+ char ext[5];
+ const char *dir;
+ const char *pWild = strchr( aName.GetBuffer(), '*' );
+ if ( !pWild )
+ pWild = strchr( aName.GetBuffer(), '?' );
+
+ if ( pWild )
+ {
+ if ( pParent )
+ aDirName = ByteString(pParent->GetFull(), osl_getThreadTextEncoding());
+ strncpy( pfx, aName.GetBuffer(), Min( (int)5, (int)(pWild-aName.GetBuffer()) ) );
+ pfx[ pWild-aName.GetBuffer() ] = 0;
+ const char *pExt = strchr( pWild, '.' );
+ if ( pExt )
+ {
+ strncpy( ext, pExt, 4 );
+ ext[4] = 0;
+ }
+ else
+ strcpy( ext, ".tmp" );
+ }
+ else
+ {
+ aDirName = ByteString(GetFull(), osl_getThreadTextEncoding());
+ strcpy( pfx, "sv" );
+ strcpy( ext, ".tmp" );
+ }
+ dir = aDirName.GetBuffer();
+
+ // wurde kein Dir angegeben, dann nehmen wir ein passendes TEMP-Verz.
+ char sBuf[_MAX_PATH];
+ if ( eFlag == FSYS_FLAG_CURRENT || ( !pParent && pWild ) )
+ dir = TempDirImpl(sBuf);
+
+ // ab hier leicht modifizierter Code von VB
+ DirEntry aRet(FSYS_FLAG_INVALID);
+ i = strlen(dir);
+ // need to add ?\\? + prefix + number + pid + .ext + '\0'
+# define TMPNAME_SIZE ( 1 + 5 + 5 + 10 + 4 + 1 )
+ ret_val = new char[i + TMPNAME_SIZE ];
+ if (ret_val)
+ {
+ strcpy(ret_val,dir);
+
+ /* Make sure directory ends with a separator */
+#if defined(WNT) || defined(OS2)
+ if ( i>0 && ret_val[i-1] != '\\' && ret_val[i-1] != '/' &&
+ ret_val[i-1] != ':')
+ ret_val[i++] = '\\';
+#elif defined UNX
+ if (i>0 && ret_val[i-1] != '/')
+ ret_val[i++] = '/';
+#else
+#error unknown operating system
+#endif
+
+ strncpy(ret_val + i, pfx, 5);
+ ret_val[i + 5] = '\0'; /* strncpy doesn't put a 0 if more */
+ i = strlen(ret_val); /* than 'n' chars. */
+
+ /* Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576
+ * Welcome to the 21st century, we can have longer filenames now ;)
+ * New format: pfx + "5 char milli/micro second res" + "current pid" + ".tmp"
+ */
+#if (defined MSC || defined __MINGW32__) && defined WNT
+ /* Milliseconds !! */
+ static unsigned long u = GetTickCount();
+ unsigned long mypid = static_cast<unsigned long>(_getpid());
+#else
+ /* Microseconds !! */
+ static unsigned long u = clock();
+ unsigned long mypid = static_cast<unsigned long>(getpid());
+#endif
+ for ( unsigned long nOld = u; ++u != nOld; ) /* Hae??? */
+ {
+ u %= 100000; /* on *NIX repeats every 100ms, maybe less if CLOCKS_PER_SEC > 10^6 */
+ snprintf(ret_val+i, TMPNAME_SIZE, "%05lu%lu", u, mypid);
+
+ strcat(ret_val,ext);
+
+ if ( FSYS_KIND_FILE == eKind )
+ {
+ SvFileStream aStream( String( ret_val, osl_getThreadTextEncoding()),
+ STREAM_WRITE|STREAM_SHARE_DENYALL );
+ if ( aStream.IsOpen() )
+ {
+ aStream.Seek( STREAM_SEEK_TO_END );
+ if ( 0 == aStream.Tell() )
+ {
+ aRet = DirEntry( String( ret_val, osl_getThreadTextEncoding()));
+ break;
+ }
+ aStream.Close();
+ }
+ }
+ else
+ {
+ // Redirect
+ String aRetVal(ret_val, osl_getThreadTextEncoding());
+ String aRedirected (aRetVal);
+#ifndef BOOTSTRAP
+ FSysRedirector::DoRedirect( aRedirected );
+#endif
+ if ( FSYS_KIND_DIR == eKind )
+ {
+ if ( 0 == _mkdir( ByteString(aRedirected.GetBuffer(), osl_getThreadTextEncoding()).GetBuffer() ) )
+ {
+ aRet = DirEntry( aRetVal );
+ break;
+ }
+ }
+ else
+ {
+#if defined(UNX) || defined(OS2)
+ if( access( ByteString(aRedirected, osl_getThreadTextEncoding()).GetBuffer(), F_OK ) )
+ {
+ aRet = DirEntry( aRetVal );
+ break;
+ }
+#else
+ struct stat aStat;
+ if ( stat( ByteString(aRedirected, osl_getThreadTextEncoding()).GetBuffer(), &aStat ) )
+ {
+ aRet = DirEntry( aRetVal );
+ break;
+ }
+#endif
+ }
+ }
+ }
+
+ delete[] ret_val;
+ ret_val = 0;
+ }
+
+ return aRet;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::operator[]()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 03.03.92
+|* Letzte Aenderung MI 03.03.92
+|*
+*************************************************************************/
+
+const DirEntry &DirEntry::operator[]( USHORT nParentLevel ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ //TPF: maybe to be implemented (FastFSys)
+
+ const DirEntry *pRes = this;
+ while ( pRes && nParentLevel-- )
+ pRes = pRes->pParent;
+
+ return *pRes;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ImpParseUnixName()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 26.05.93
+|*
+*************************************************************************/
+
+FSysError DirEntry::ImpParseUnixName( const ByteString& rPfad, FSysPathStyle eStyle )
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ // die einzelnen Namen auf einen Stack packen
+ DirEntryStack aStack;
+ ByteString aPfad( rPfad );
+ do
+ {
+ // den Namen vor dem ersten "/" abspalten,
+ // falls '/' am Anfang, ist der Name '/',
+ // der Rest immer ohne die fuehrenden '/'.
+ // den ersten '/' suchen
+ USHORT nPos;
+ for ( nPos = 0;
+ nPos < aPfad.Len() && aPfad.GetChar(nPos) != '/';
+ nPos++ )
+ /* do nothing */;
+
+ // ist der Name die Root des aktuellen Drives?
+ if ( nPos == 0 && aPfad.Len() > 0 && ( aPfad.GetChar(0) == '/' ) )
+ {
+ // Root-Directory des aktuellen Drives
+ aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) );
+ }
+ else
+ {
+ // den Namen ohne Trenner abspalten
+ aName = aPfad.Copy( 0, nPos );
+
+ // stellt der Name die aktuelle Directory dar?
+ if ( aName == "." )
+ /* do nothing */;
+
+#ifdef UNX
+ // stellt der Name das User-Dir dar?
+ else if ( aName == "~" )
+ {
+ DirEntry aHome( String( (const char *) getenv( "HOME" ), osl_getThreadTextEncoding()) );
+ for ( USHORT n = aHome.Level(); n; --n )
+ aStack.Push( new DirEntry( aHome[ (USHORT) n-1 ] ) );
+ }
+#endif
+
+ // stellt der Name die Parent-Directory dar?
+ else if ( aName == ".." )
+ {
+ // ist nichts, ein Parent oder eine relative Root
+ // auf dem Stack?
+ if ( ( aStack.Count() == 0 ) ||
+ ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) )
+ // fuehrende Parents kommen auf den Stack
+ aStack.Push( new DirEntry( ByteString(), FSYS_FLAG_PARENT, eStyle ) );
+
+ // ist es eine absolute Root
+ else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT ) {
+ // die hat keine Parent-Directory
+ return FSYS_ERR_NOTEXISTS;
+ }
+ else
+ // sonst hebt der Parent den TOS auf
+ delete aStack.Pop();
+ }
+ else
+ {
+ DirEntry *pNew = NULL;
+ // normalen Entries kommen auf den Stack
+ pNew = new DirEntry( aName, FSYS_FLAG_NORMAL, eStyle );
+ if ( !pNew->IsValid() )
+ {
+ aName = rPfad;
+ ErrCode eErr = pNew->GetError();
+ delete pNew;
+ return eErr;
+ }
+ aStack.Push( pNew );
+ }
+ }
+
+ // den Restpfad bestimmen
+ aPfad.Erase( 0, nPos + 1 );
+ while ( aPfad.Len() && ( aPfad.GetChar(0) == '/' ) )
+ aPfad.Erase( 0, 1 );
+ }
+ while ( aPfad.Len() );
+
+ // Haupt-Entry (selbst) zuweisen
+ if ( aStack.Count() == 0 )
+ {
+ eFlag = FSYS_FLAG_CURRENT;
+ aName.Erase();
+ }
+ else
+ {
+ eFlag = aStack.Top()->eFlag;
+ aName = aStack.Top()->aName;
+ delete aStack.Pop();
+ }
+
+ // die Parent-Entries vom Stack holen
+ DirEntry** pTemp = &pParent;
+ while ( aStack.Count() )
+ {
+ *pTemp = aStack.Pop();
+ pTemp = &( (*pTemp)->pParent );
+ }
+
+ return FSYS_ERR_OK;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::MakeShortName()
+|*
+|* Beschreibung
+|* Ersterstellung TLX
+|* Letzte Aenderung PB 21.08.97 (in CreateEntry_Impl())
+|*
+*************************************************************************/
+
+ErrCode CreateEntry_Impl( const DirEntry &rPath, DirEntryKind eKind )
+{
+ // versuchen, anzulegen (ausser bei FSYS_KIND_ALL)
+ ErrCode eErr = ERRCODE_NONE;
+ if ( FSYS_KIND_FILE == eKind )
+ {
+ SvFileStream aStream( rPath.GetFull(), STREAM_STD_WRITE );
+ aStream.WriteLine( "" );
+ eErr = aStream.GetError();
+ }
+ else if ( FSYS_KIND_ALL != eKind )
+ eErr = rPath.MakeDir() ? ERRCODE_NONE : ERRCODE_IO_UNKNOWN;
+
+ // erfolgreich?
+ if ( !rPath.Exists() )
+ eErr = ERRCODE_IO_UNKNOWN; // Doch was schiefgegangen ?
+
+ // ggf. wieder l"oschen
+ if ( FSYS_KIND_NONE == eKind )
+ rPath.Kill();
+
+ // Fehlercode zur?ckliefern
+ return eErr;
+}
+
+BOOL IsValidEntry_Impl( const DirEntry &rPath,
+ const String &rLongName,
+ DirEntryKind eKind,
+ BOOL bIsShortened,
+ BOOL bUseDelim )
+{
+ // Parameter-Pr"uefung
+ DBG_ASSERT( eKind == FSYS_KIND_NONE || eKind == FSYS_KIND_ALL ||
+ eKind == FSYS_KIND_FILE || eKind == FSYS_KIND_DIR,
+ "invalid entry-kind" );
+
+ // Alle von MSDOS erreichbaren FSYS_STYLES muessen den
+ // MSDOS Filenamenanforderungen genuegen. Sonst wird probiert,
+ // ob sich eine Datei des gewuenschten Names anlegen laesst.
+ FSysPathStyle eStyle = DirEntry::GetPathStyle( rPath.GetDevice().GetName() );
+ DirEntry aPath(rPath);
+ DirEntry aName(rLongName, eStyle);
+ if ( !aName.IsValid() || aName.Level() != 1 )
+ return FALSE;
+ aPath += aName;
+ if ( 1 == aPath.Level() )
+ return FALSE;
+ if ( eStyle == FSYS_STYLE_FAT || eStyle == FSYS_STYLE_NWFS ||
+ eStyle == FSYS_STYLE_UNKNOWN )
+ {
+ DirEntry aDosEntry( rLongName, FSYS_STYLE_FAT );
+ if ( !aDosEntry.IsValid() )
+ return FALSE;
+ }
+
+ // Pfad-Trenner sind nicht erlaubt (bei ungek"urzten auch nicht FSYS_SHORTNAME_DELIMITER)
+ char cDelim = bUseDelim == 2 ? FSYS_SHORTNAME_DELIMITER : char(0);
+ if (
+ rLongName.Search(DirEntry::GetAccessDelimiter()) != STRING_NOTFOUND ||
+ (!bIsShortened && rLongName.Search(cDelim) != STRING_NOTFOUND)
+ )
+ {
+ return FALSE;
+ }
+
+ // MI: Abfrage nach 'CON:' etc. wird jetzt in Exists() mitgemacht
+ if ( aPath.Exists() )
+ return FALSE;
+
+ return (ERRCODE_NONE == CreateEntry_Impl( aPath, eKind ));
+}
+
+//-------------------------------------------------------------------------
+
+#define MAX_EXT_FAT 3
+#define MAX_LEN_FAT 8
+#define INVALID_CHARS_FAT "\\/\"':|^<>[]?* "
+
+#define MAX_EXT_MAC 16 // nur wegen sinnvoller Namensk"rzung
+#define MAX_LEN_MAC 31
+#define INVALID_CHARS_MAC "\":"
+
+#define MAX_EXT_MAX 250
+#define MAX_LEN_MAX 255
+#define INVALID_CHARS_DEF "\\/\"':|^<>?*"
+
+BOOL DirEntry::MakeShortName( const String& rLongName, DirEntryKind eKind,
+ BOOL bUseDelim, FSysPathStyle eStyle )
+{
+ String aLongName(rLongName);
+
+ // Alle '#' aus den Dateinamen entfernen, weil das INetURLObject
+ // damit Probleme hat. Siehe auch #51246#
+ aLongName.EraseAllChars( '#' );
+ ByteString bLongName(aLongName, osl_getThreadTextEncoding());
+
+ // Auf Novell-Servern (wegen der rottigen Clients) nur 7bit ASCII
+
+ // HRO: #69627# Weg mit dem Scheiss. Wenn es Client gibt, die so einen
+ // BUG haben, dann muss halt der Client ersetzt werden, aber doch nicht das
+ // Office kastrieren !!!
+
+#if 0
+ if ( FSYS_STYLE_NWFS == GetPathStyle( ImpGetTopPtr()->GetName() ) )
+ {
+ for ( USHORT n = aLongName.Len(); n; --n )
+ {
+ short nChar = aLongName(n-1);
+ if ( nChar < 32 || nChar >= 127 )
+ aLongName.Erase( n-1, 1 );
+ }
+ }
+#endif
+
+ // bei FSYS_KIND_ALL den alten Namen merken und abh"angen (rename)
+ ByteString aOldName;
+ if ( FSYS_KIND_ALL == eKind )
+ {
+ aOldName = ByteString(CutName(), osl_getThreadTextEncoding());
+ aOldName = CMP_LOWER(aOldName);
+ }
+
+ // ist der Langname direkt verwendbar?
+ if ( IsValidEntry_Impl( *this, aLongName, eKind, FALSE, bUseDelim ) )
+ {
+ operator+=( DirEntry(aLongName) );
+ return TRUE;
+ }
+
+ // max L"angen feststellen
+ USHORT nMaxExt, nMaxLen;
+ if ( FSYS_STYLE_DETECT == eStyle )
+ eStyle = DirEntry::GetPathStyle( GetDevice().GetName() );
+ ByteString aInvalidChars;
+ switch ( eStyle )
+ {
+ case FSYS_STYLE_FAT:
+ nMaxExt = MAX_EXT_FAT;
+ nMaxLen = MAX_LEN_FAT;
+ aInvalidChars = INVALID_CHARS_FAT;
+ break;
+
+ case FSYS_STYLE_MAC:
+ nMaxExt = MAX_EXT_MAC;
+ nMaxLen = MAX_LEN_MAC;
+ aInvalidChars = INVALID_CHARS_MAC;
+ break;
+
+ default:
+ nMaxExt = MAX_EXT_MAX;
+ nMaxLen = MAX_LEN_MAX;
+ aInvalidChars = INVALID_CHARS_DEF;
+ }
+
+ // Extension abschneiden und kuerzen
+ ByteString aExt;
+ ByteString aFName = bLongName;
+ if ( FSYS_STYLE_MAC != eStyle )
+ {
+ DirEntry aUnparsed;
+ aUnparsed.aName = bLongName;
+ aExt = ByteString(aUnparsed.CutExtension(), osl_getThreadTextEncoding());
+ aFName = aUnparsed.aName;
+ if ( aExt.Len() > nMaxExt )
+ {
+ char c = aExt.GetChar( aExt.Len() - 1 );
+ aExt.Erase(nMaxExt-1);
+ aExt += c;
+ }
+ }
+
+ if ( FSYS_STYLE_FAT != eStyle )
+ {
+ // ausser auf einem FAT-System geh"ort die Extension zur
+ // Maxl"ange. Muss also vorher mit dem Punkt abgezogen werden.
+ nMaxLen -= ( aExt.Len() + 1 );
+ }
+
+ // Name k"urzen
+ ByteString aSName;
+ for ( const char *pc = aFName.GetBuffer(); aSName.Len() < nMaxLen && *pc; ++pc )
+ {
+ if ( STRING_NOTFOUND == aInvalidChars.Search( *pc ) &&
+ (unsigned char) *pc >= (unsigned char) 32 &&
+ ( !aSName.Len() || *pc != ' ' || aSName.GetChar(aSName.Len()-1) != ' ' ) )
+ aSName += *pc;
+ }
+ aSName.EraseTrailingChars();
+
+ // HRO: #74246# Also cut leading spaces
+ aSName.EraseLeadingChars();
+
+ if ( !aSName.Len() )
+ aSName = "noname";
+
+ // kommt dabei der alte Name raus?
+ ByteString aNewName = aSName;
+ if ( aExt.Len() )
+ ( aNewName += '.' ) += aExt;
+ operator+=( DirEntry(String(aNewName, osl_getThreadTextEncoding())) );
+ if ( FSYS_KIND_ALL == eKind && CMP_LOWER(aName) == aOldName )
+ if ( FSYS_KIND_ALL == eKind && CMP_LOWER(ByteString(GetName(), osl_getThreadTextEncoding())) == aOldName )
+ return TRUE;
+
+ // kann der gek"urzte Name direkt verwendet werden?
+ if ( !Exists() && (ERRCODE_NONE == CreateEntry_Impl( *this, eKind )) )
+ return TRUE;
+
+ // darf '?##' verwendet werden, um eindeutigen Name zu erzeugen?
+ if ( bUseDelim )
+ {
+ // eindeutigen Namen per '?##' erzeugen
+ aSName.Erase( nMaxLen-3 );
+ if ( bUseDelim != 2 )
+ aSName += FSYS_SHORTNAME_DELIMITER;
+ for ( int n = 1; n < 99; ++n )
+ {
+ // Name zusammensetzen
+ ByteString aTmpStr( aSName );
+ aTmpStr += ByteString::CreateFromInt32(n);
+ if ( aExt.Len() )
+ ( aTmpStr += '.' ) += aExt;
+
+ // noch nicht vorhanden?
+ SetName( String(aTmpStr, osl_getThreadTextEncoding()) );
+
+ if ( !Exists() )
+ {
+ // Fehler setzen !!!
+ nError = CreateEntry_Impl( *this, eKind );
+ return (ERRCODE_NONE == nError);
+ }
+ }
+ }
+
+ // keine ## mehr frei / ?## soll nicht verwendet werden
+ nError = ERRCODE_IO_ALREADYEXISTS;
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::CreatePath()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+BOOL DirEntry::MakeDir( BOOL bSloppy ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ // Schnellpruefung, ob vorhanden
+ if ( FileStat( *this ).IsKind( FSYS_KIND_DIR ) )
+ return TRUE;
+ if ( bSloppy && pParent )
+ if ( FileStat( *pParent ).IsKind( FSYS_KIND_DIR ) )
+ return TRUE;
+
+ const DirEntry *pNewDir = bSloppy ? pParent : this;
+ if ( pNewDir )
+ {
+ // den Path zum Dir erzeugen
+ if ( pNewDir->pParent && !pNewDir->pParent->MakeDir(FALSE) )
+ return FALSE;
+
+ // das Dir selbst erzeugen
+ if ( pNewDir->eFlag == FSYS_FLAG_ABSROOT ||
+ pNewDir->eFlag == FSYS_FLAG_ABSROOT ||
+ pNewDir->eFlag == FSYS_FLAG_VOLUME )
+ return TRUE;
+ else
+ {
+ //? nError = ???
+ if ( FileStat( *pNewDir ).IsKind( FSYS_KIND_DIR ) )
+ return TRUE;
+ else
+ {
+ FSysFailOnErrorImpl();
+ String aDirName(pNewDir->GetFull());
+#ifndef BOOTSTRAP
+ FSysRedirector::DoRedirect( aDirName );
+#endif
+ ByteString bDirName( aDirName, osl_getThreadTextEncoding() );
+ bDirName = GUI2FSYS( bDirName );
+
+#ifdef WIN32
+ SetLastError(0);
+#endif
+ BOOL bResult = (0 == _mkdir( (char*) bDirName.GetBuffer() ));
+ if ( !bResult )
+ {
+ // Wer hat diese Methode const gemacht ?
+#ifdef WIN32
+ ((DirEntry *)this)->SetError( Sys2SolarError_Impl( GetLastError() ) );
+#else
+ ((DirEntry *)this)->SetError( Sys2SolarError_Impl( errno ) );
+#endif
+ }
+
+ return bResult;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::CopyTo()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 07.08.96
+|*
+*************************************************************************/
+
+FSysError DirEntry::CopyTo( const DirEntry& rDest, FSysAction nActions ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ if ( FSYS_ACTION_COPYFILE != (nActions & FSYS_ACTION_COPYFILE) )
+#ifdef UNX
+ {
+ // Hardlink anlegen
+ HACK(redirection missing)
+ ByteString aThis(GUI2FSYS(GetFull()), osl_getThreadTextEncoding());
+ ByteString aDest(GUI2FSYS(rDest.GetFull()), osl_getThreadTextEncoding());
+ if (link( aThis.GetBuffer(), aDest.GetBuffer() ) == -1)
+ return Sys2SolarError_Impl( errno );
+ else
+ return FSYS_ERR_OK;
+ }
+#else
+ return FSYS_ERR_NOTSUPPORTED;
+#endif
+
+ FileCopier fc(*this, rDest);
+ return fc.Execute(nActions);
+}
+
+/*************************************************************************
+|*
+|* DirEntry::MoveTo()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung HRO 24.03.99
+|*
+*************************************************************************/
+
+#if defined WNT || defined UNX || defined OS2
+
+FSysError DirEntry::MoveTo( const DirEntry& rNewName ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+/*
+ FileStat aSourceStat(*this);
+ if ( !aSourceStat.IsKind(FSYS_KIND_FILE) )
+ return FSYS_ERR_NOTAFILE;
+*/
+
+ DirEntry aDest(rNewName);
+ FileStat aDestStat(rNewName);
+ if ( aDestStat.IsKind(FSYS_KIND_DIR ) )
+ {
+ aDest += String(aName, osl_getThreadTextEncoding());
+ }
+ if ( aDest.Exists() )
+ {
+ return FSYS_ERR_ALREADYEXISTS;
+ }
+
+#if defined(OS2)
+ if ( FileStat(*this).IsKind(FSYS_KIND_DIR) && aDest.GetPath() != GetPath() )
+ {
+ return FSYS_ERR_NOTSUPPORTED;
+ }
+#endif
+
+ FSysFailOnErrorImpl();
+ String aFrom( GetFull() );
+
+#ifndef BOOTSTRAP
+ FSysRedirector::DoRedirect(aFrom);
+#endif
+
+ String aTo( aDest.GetFull() );
+
+#ifndef BOOTSTRAP
+ FSysRedirector::DoRedirect(aTo);
+#endif
+
+ ByteString bFrom(aFrom, osl_getThreadTextEncoding());
+ ByteString bTo(aTo, osl_getThreadTextEncoding());
+ bFrom = GUI2FSYS(bFrom);
+ bTo = GUI2FSYS(bTo);
+
+#ifdef WNT
+ // MoveTo nun atomar
+ SetLastError(0);
+
+ DirEntry aFromDevice(String(bFrom, osl_getThreadTextEncoding()));
+ DirEntry aToDevice(String(bTo,osl_getThreadTextEncoding()));
+ aFromDevice.ToAbs();
+ aToDevice.ToAbs();
+ aFromDevice=aFromDevice.GetDevice();
+ aToDevice=aToDevice.GetDevice();
+
+ //Quelle und Ziel auf gleichem device?
+ if (aFromDevice==aToDevice)
+ {
+ // ja, also intra-device-move mit MoveFile
+ MoveFile( bFrom.GetBuffer(), bTo.GetBuffer() );
+ // MoveFile ist buggy bei cross-device operationen.
+ // Der R?ckgabewert ist auch dann TRUE, wenn nur ein Teil der Operation geklappt hat.
+ // Zudem zeigt MoveFile unterschiedliches Verhalten bei unterschiedlichen NT-Versionen.
+ return Sys2SolarError_Impl( GetLastError() );
+ }
+ else
+ {
+ //nein, also inter-device-move mit copy/delete
+ FSysError nCopyError = CopyTo(rNewName, FSYS_ACTION_COPYFILE);
+
+ DirEntry aKill(String(bTo, osl_getThreadTextEncoding()));
+ FileStat aKillStat(String(bTo, osl_getThreadTextEncoding()));
+ if ( aKillStat.IsKind(FSYS_KIND_DIR ) )
+ {
+ aKill += String(aName, osl_getThreadTextEncoding());
+ }
+
+ if (nCopyError==FSYS_ERR_OK)
+ {
+ if (Kill()==FSYS_ERR_OK)
+ {
+ return FSYS_ERR_OK;
+ }
+ else
+ {
+ aKill.Kill();
+ return FSYS_ERR_ACCESSDENIED;
+ }
+ }
+ else
+ {
+ aKill.Kill();
+ return nCopyError;
+ }
+ }
+#else
+ // #68639#
+ // on some nfs connections rename with from == to
+ // leads to destruction of file
+ if ( ( aFrom != aTo ) && ( 0 != rename( bFrom.GetBuffer(), bTo.GetBuffer() ) ) )
+#if !defined(UNX) && !defined(OS2)
+ return Sys2SolarError_Impl( GetLastError() );
+#else
+ {
+ if( errno == EXDEV )
+// cross device geht latuernich nicht mit rename
+ {
+ FILE *fpIN = fopen( bFrom.GetBuffer(), "r" );
+ FILE *fpOUT = fopen( bTo.GetBuffer(), "w" );
+ if( fpIN && fpOUT )
+ {
+ char pBuf[ 16384 ];
+ int nBytes, nWritten, nErr = 0;
+ errno = 0;
+ while( ( nBytes = fread( pBuf, 1, sizeof(pBuf), fpIN ) ) && ! nErr )
+ {
+ nWritten = fwrite( pBuf, 1, nBytes, fpOUT );
+ // Fehler im fwrite ?
+ if( nWritten < nBytes )
+ {
+ nErr = errno;
+ break;
+ }
+ }
+ fclose( fpIN );
+ fclose( fpOUT );
+ if ( nErr )
+ {
+ unlink( bTo.GetBuffer() );
+ return Sys2SolarError_Impl( nErr );
+ }
+ else
+ {
+ unlink( bFrom.GetBuffer() );
+ }
+ }
+ else
+ {
+ return Sys2SolarError_Impl( EXDEV );
+ }
+ }
+ else
+ {
+ return Sys2SolarError_Impl( errno );
+ }
+ }
+#endif
+#endif
+ return ERRCODE_NONE;
+}
+
+#endif
+
+/*************************************************************************
+|*
+|* DirEntry::Kill()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 07.08.96
+|*
+*************************************************************************/
+
+FSysError DirEntry::Kill( FSysAction nActions ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ FSysError eError = FSYS_ERR_OK;
+ FSysFailOnErrorImpl();
+
+ // Name als doppelt 0-terminierter String
+ String aTmpName( GetFull() );
+#ifndef BOOTSTRAP
+ FSysRedirector::DoRedirect( aTmpName );
+#endif
+ ByteString bTmpName( aTmpName, osl_getThreadTextEncoding());
+ bTmpName = GUI2FSYS(bTmpName);
+
+ char *pName = new char[bTmpName.Len()+2];
+ strcpy( pName, bTmpName.GetBuffer() );
+ pName[bTmpName.Len()+1] = (char) 0;
+
+ //read-only files sollen auch geloescht werden koennen
+ BOOL isReadOnly = FileStat::GetReadOnlyFlag(*this);
+ if (isReadOnly)
+ {
+ FileStat::SetReadOnlyFlag(*this, FALSE);
+ }
+
+ // directory?
+ if ( FileStat( *this ).IsKind(FSYS_KIND_DIR) )
+ {
+ // Inhalte recursiv loeschen?
+ if ( FSYS_ACTION_RECURSIVE == (nActions & FSYS_ACTION_RECURSIVE) )
+ {
+ Dir aDir( *this, FSYS_KIND_DIR|FSYS_KIND_FILE );
+ for ( USHORT n = 0; eError == FSYS_ERR_OK && n < aDir.Count(); ++n )
+ {
+ const DirEntry &rSubDir = aDir[n];
+ DirEntryFlag flag = rSubDir.GetFlag();
+ if ( flag != FSYS_FLAG_CURRENT && flag != FSYS_FLAG_PARENT )
+ eError = rSubDir.Kill(nActions);
+ }
+ }
+
+ // das Dir selbst loeschen
+#ifdef WIN32
+ SetLastError(0);
+#endif
+ if ( eError == FSYS_ERR_OK && 0 != _rmdir( (char*) pName ) )
+ //
+ {
+ // falls L"oschen nicht ging, CWD umsetzen
+#ifdef WIN32
+ eError = Sys2SolarError_Impl( GetLastError() );
+#else
+ eError = Sys2SolarError_Impl( errno );
+#endif
+ if ( eError )
+ {
+ GetPath().SetCWD();
+#ifdef WIN32
+ SetLastError(0);
+#endif
+ if (_rmdir( (char*) pName) != 0)
+ {
+#ifdef WIN32
+ eError = Sys2SolarError_Impl( GetLastError() );
+#else
+ eError = Sys2SolarError_Impl( errno );
+#endif
+ }
+ else
+ {
+ eError = FSYS_ERR_OK;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( FSYS_ACTION_USERECYCLEBIN == (nActions & FSYS_ACTION_USERECYCLEBIN) )
+ {
+#ifdef OS2
+ eError = ApiRet2ToSolarError_Impl( DosDelete( (PSZ) pName ) );
+#elif defined(WNT)
+ SHFILEOPSTRUCT aOp;
+ aOp.hwnd = 0;
+ aOp.wFunc = FO_DELETE;
+ aOp.pFrom = pName;
+ aOp.pTo = 0;
+ aOp.fFlags = FOF_ALLOWUNDO|FOF_SILENT|FOF_NOCONFIRMATION;
+ aOp.hNameMappings = 0;
+ aOp.lpszProgressTitle = 0;
+ eError = Sys2SolarError_Impl( SHFileOperation( &aOp ) );
+#else
+ eError = ERRCODE_IO_NOTSUPPORTED;
+#endif
+ }
+ else
+ {
+#ifdef WIN32
+ SetLastError(0);
+#endif
+ if ( 0 != _unlink( (char*) pName ) )
+ {
+#ifdef WIN32
+ eError = Sys2SolarError_Impl( GetLastError() );
+#else
+ eError = Sys2SolarError_Impl( errno );
+#endif
+ }
+ else
+ {
+ eError = ERRCODE_NONE;
+ }
+ }
+ }
+
+ //falls Fehler, originales read-only flag wieder herstellen
+ if ( isReadOnly && (eError!=ERRCODE_NONE) )
+ {
+ FileStat::SetReadOnlyFlag(*this, isReadOnly);
+ }
+
+ delete[] pName;
+ return eError;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::Contains()
+|*
+|* Beschreibung ob rSubEntry direkt oder indirect in *this liegt
+|* Ersterstellung MI 20.03.97
+|* Letzte Aenderung MI 20.03.97
+|*
+*************************************************************************/
+
+BOOL DirEntry::Contains( const DirEntry &rSubEntry ) const
+{
+ DBG_ASSERT( IsAbs() && rSubEntry.IsAbs(), "must be absolute entries" );
+
+ USHORT nThisLevel = Level();
+ USHORT nSubLevel = rSubEntry.Level();
+ if ( nThisLevel < nSubLevel )
+ {
+ for ( ; nThisLevel; --nThisLevel, --nSubLevel )
+ if ( (*this)[nThisLevel-1] != rSubEntry[nSubLevel-1] )
+ return FALSE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::Level()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 03.03.92
+|* Letzte Aenderung MI 03.03.92
+|*
+*************************************************************************/
+
+USHORT DirEntry::Level() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ USHORT nLevel = 0;
+ const DirEntry *pRes = this;
+ while ( pRes )
+ {
+ pRes = pRes->pParent;
+ nLevel++;
+ }
+
+ return nLevel;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ConvertNameToSystem()
+|*
+|* Beschreibung
+|* Ersterstellung DV 29.03.96
+|* Letzte Aenderung DV 29.03.96
+|*
+*************************************************************************/
+
+String DirEntry::ConvertNameToSystem( const String &rName )
+{
+ return rName;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ConvertSystemToName()
+|*
+|* Beschreibung
+|* Ersterstellung DV 29.03.96
+|* Letzte Aenderung DV 29.03.96
+|*
+*************************************************************************/
+
+String DirEntry::ConvertSystemToName( const String &rName )
+{
+ return rName;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::IsValid()
+|*
+|* Beschreibung
+|* Ersterstellung MI 18.09.93
+|* Letzte Aenderung TPF 18.09.98
+|*
+*************************************************************************/
+
+BOOL DirEntry::IsValid() const
+{
+ return (nError == FSYS_ERR_OK);
+}
+
+/*************************************************************************
+|*
+|* DirEntry::IsRFSAvailable()
+|*
+|* Beschreibung
+|* Ersterstellung TPF 21.10.98
+|* Letzte Aenderung TPF 21.10.98
+|*
+*************************************************************************/
+
+BOOL DirEntry::IsRFSAvailable()
+{
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* IsLongNameOnFAT()
+|*
+|* Beschreibung ?berpr?ft , ob das DirEntry einen langen
+|* Filenamen auf einer FAT-Partition enth?lt (EAs).
+|* (eigentlich nur f?r OS2 interessant)
+|* Ersterstellung TPF 02.10.98
+|* Letzte Aenderung TPF 01.03.1999
+|*
+*************************************************************************/
+
+BOOL DirEntry::IsLongNameOnFAT() const
+{
+ // FAT-System?
+ DirEntry aTempDirEntry(*this);
+ aTempDirEntry.ToAbs();
+ if (DirEntry::GetPathStyle(aTempDirEntry.GetDevice().GetName().GetChar(0)) != FSYS_STYLE_FAT)
+ {
+ return FALSE; // nein, also false
+ }
+
+ // DirEntry-Kette auf lange Dateinamen pr?fen
+ for( USHORT iLevel = this->Level(); iLevel > 0; iLevel-- )
+ {
+ const DirEntry& rEntry = (const DirEntry&) (*this)[iLevel-1];
+ String aBase( rEntry.GetBase() );
+ String aExtension( rEntry.GetExtension() );
+
+ if (aBase.Len()>8) // Name > 8?
+ {
+ return TRUE;
+ }
+
+ if (aExtension.Len()>3) // Extension > 3?
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+//========================================================================
+
+#if defined(DBG_UTIL)
+
+void FSysTest()
+{
+}
+
+#endif
+
diff --git a/tools/source/fsys/filecopy.cxx b/tools/source/fsys/filecopy.cxx
new file mode 100644
index 000000000000..62d361aa4af4
--- /dev/null
+++ b/tools/source/fsys/filecopy.cxx
@@ -0,0 +1,486 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#if defined WNT
+#ifndef _SVWIN_H
+#include <io.h>
+#include <tools/svwin.h>
+#endif
+
+#elif defined(OS2)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <share.h>
+#include <io.h>
+
+#elif defined UNX
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdio.h>
+#include "comdep.hxx"
+#include <tools/fsys.hxx>
+#include <tools/stream.hxx>
+#include <osl/file.hxx>
+
+using namespace ::osl;
+
+/*************************************************************************
+|*
+|* FileCopier::FileCopier()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 13.04.94
+|* Letzte Aenderung MI 13.04.94
+|*
+*************************************************************************/
+
+FileCopier::FileCopier() :
+
+ nBytesTotal ( 0 ),
+ nBytesCopied( 0 ),
+ nBlockSize ( 4096 ),
+ pImp ( new FileCopier_Impl )
+
+{
+}
+
+// -----------------------------------------------------------------------
+
+FileCopier::FileCopier( const DirEntry& rSource, const DirEntry& rTarget ) :
+
+ aSource ( rSource ),
+ aTarget ( rTarget ),
+ nBytesTotal ( 0 ),
+ nBytesCopied( 0 ),
+ nBlockSize ( 4096 ),
+ pImp ( new FileCopier_Impl )
+
+{
+}
+
+// -----------------------------------------------------------------------
+
+FileCopier::FileCopier( const FileCopier& rCopier ) :
+
+ aSource ( rCopier.aSource ),
+ aTarget ( rCopier.aTarget ),
+ nBytesTotal ( 0 ),
+ nBytesCopied ( 0 ),
+ aProgressLink ( rCopier.aProgressLink ),
+ nBlockSize ( 4096 ),
+ pImp ( new FileCopier_Impl )
+
+{
+}
+
+/*************************************************************************
+|*
+|* FileCopier::~FileCopier()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 13.04.94
+|* Letzte Aenderung MI 13.04.94
+|*
+*************************************************************************/
+
+FileCopier::~FileCopier()
+{
+ delete pImp;
+}
+
+/*************************************************************************
+|*
+|* FileCopier::operator =()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 13.04.94
+|* Letzte Aenderung MI 13.04.94
+|*
+*************************************************************************/
+
+FileCopier& FileCopier::operator = ( const FileCopier &rCopier )
+{
+ aSource = rCopier.aSource;
+ aTarget = rCopier.aTarget;
+ nBytesTotal = rCopier.nBytesTotal;
+ nBytesCopied = rCopier.nBytesCopied;
+ nBytesCopied = rCopier.nBytesCopied;
+ nBlockSize = rCopier.nBlockSize;
+ aProgressLink = rCopier.aProgressLink;
+ *pImp = *(rCopier.pImp);
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* FileCopier::Progress()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 13.04.94
+|* Letzte Aenderung MI 13.04.94
+|*
+*************************************************************************/
+
+BOOL FileCopier::Progress()
+{
+ if ( !aProgressLink )
+ return TRUE;
+ else
+ {
+ if ( aProgressLink.Call( this ) )
+ return TRUE;
+ return ( 0 == Error( ERRCODE_ABORT, 0, 0 ) );
+ }
+}
+
+//---------------------------------------------------------------------------
+
+ErrCode FileCopier::Error( ErrCode eErr, const DirEntry* pSource, const DirEntry* pTarget )
+{
+ // kein Fehler oder kein ErrorHandler?
+ if ( !eErr || !pImp->aErrorLink )
+ // => Error beibehalten
+ return eErr;
+
+ // sonst gesetzten ErrorHandler fragen
+ pImp->pErrSource = pSource;
+ pImp->pErrTarget = pTarget;
+ pImp->eErr = eErr;
+ ErrCode eRet = (ErrCode) pImp->aErrorLink.Call( this );
+ pImp->pErrSource = 0;
+ pImp->pErrTarget = 0;
+ return eRet;
+}
+
+//---------------------------------------------------------------------------
+
+const DirEntry* FileCopier::GetErrorSource() const
+{
+ return pImp->pErrSource;
+}
+
+//---------------------------------------------------------------------------
+
+const DirEntry* FileCopier::GetErrorTarget() const
+{
+ return pImp->pErrTarget;
+}
+
+//---------------------------------------------------------------------------
+
+ErrCode FileCopier::GetError() const
+{
+ return pImp->eErr;
+}
+
+//---------------------------------------------------------------------------
+
+void FileCopier::SetErrorHdl( const Link &rLink )
+{
+ pImp->aErrorLink = rLink;
+}
+
+//---------------------------------------------------------------------------
+
+const Link& FileCopier::GetErrorHdl() const
+{
+ return pImp->aErrorLink ;
+}
+
+/*************************************************************************
+|*
+|* FileCopier::Execute()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 13.04.94
+|* Letzte Aenderung PB 16.06.00
+|*
+*************************************************************************/
+
+FSysError FileCopier::DoCopy_Impl(
+ const DirEntry &rSource, const DirEntry &rTarget )
+{
+ FSysError eRet = FSYS_ERR_OK;
+ ErrCode eWarn = FSYS_ERR_OK;
+
+ // HPFS->FAT?
+ FSysPathStyle eSourceStyle = DirEntry::GetPathStyle( rSource.ImpGetTopPtr()->GetName() );
+ FSysPathStyle eTargetStyle = DirEntry::GetPathStyle( rTarget.ImpGetTopPtr()->GetName() );
+ BOOL bMakeShortNames = ( eSourceStyle == FSYS_STYLE_HPFS && eTargetStyle == FSYS_STYLE_FAT );
+
+ // Zieldateiname ggf. kuerzen
+ DirEntry aTgt;
+ if ( bMakeShortNames )
+ {
+ aTgt = rTarget.GetPath();
+ aTgt.MakeShortName( rTarget.GetName() );
+ }
+ else
+ aTgt = rTarget;
+
+ // kein Move wenn Namen gekuerzt werden muessten
+ if ( bMakeShortNames && FSYS_ACTION_MOVE == ( pImp->nActions & FSYS_ACTION_MOVE ) && aTgt != rTarget )
+ return ERRCODE_IO_NAMETOOLONG;
+
+ // source is directory?
+ FileStat aSourceFileStat( rSource );
+ if ( aSourceFileStat.IsKind( FSYS_KIND_DIR ) )
+ {
+#ifdef OS2
+ CHAR szSource[CCHMAXPATHCOMP];
+ HOBJECT hSourceObject;
+
+ strcpy(szSource, ByteString(rSource.GetFull(), osl_getThreadTextEncoding()).GetBuffer());
+ hSourceObject = WinQueryObject(szSource);
+
+ if ( hSourceObject )
+ {
+ PSZ pszSourceName;
+ PSZ pszTargetName;
+ CHAR szTarget[CCHMAXPATHCOMP];
+ HOBJECT hTargetObject;
+ HOBJECT hReturn = NULLHANDLE;
+
+ strcpy(szTarget, ByteString(rTarget.GetFull(), osl_getThreadTextEncoding()).GetBuffer());
+ pszTargetName = strrchr(szTarget, '\\');
+ pszSourceName = strrchr(szSource, '\\');
+
+ hTargetObject = WinQueryObject(szTarget);
+
+ if ( hTargetObject )
+ WinDestroyObject(hTargetObject);
+
+ if ( pszTargetName && pszSourceName )
+ {
+ *pszTargetName = '\0';
+ pszSourceName++;
+ pszTargetName++;
+
+ if(strcmp(pszSourceName, pszTargetName) == 0)
+ {
+ hTargetObject = WinQueryObject(szTarget);
+
+ if(pImp->nActions & FSYS_ACTION_MOVE)
+ {
+ hReturn = WinMoveObject(hSourceObject, hTargetObject, 0);
+ }
+ else
+ {
+ hReturn = WinCopyObject(hSourceObject, hTargetObject, 0);
+ }
+ if ( bMakeShortNames && aTarget.Exists() )
+ aTarget.Kill();
+ return hReturn ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN;
+ }
+ }
+ }
+#endif
+ // recursive copy
+ eRet = Error( aTgt.MakeDir() ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN, 0, &aTgt );
+ Dir aSourceDir( rSource, FSYS_KIND_DIR|FSYS_KIND_FILE );
+ for ( USHORT n = 0; ERRCODE_TOERROR(eRet) == FSYS_ERR_OK && n < aSourceDir.Count(); ++n )
+ {
+ const DirEntry &rSubSource = aSourceDir[n];
+ DirEntryFlag eFlag = rSubSource.GetFlag();
+ if ( eFlag != FSYS_FLAG_CURRENT && eFlag != FSYS_FLAG_PARENT )
+ {
+ DirEntry aSubTarget( aTgt );
+ aSubTarget += rSubSource.GetName();
+ eRet = DoCopy_Impl( rSubSource, aSubTarget );
+ if ( eRet && !eWarn )
+ eWarn = eRet;
+ }
+ }
+ }
+ else if ( aSourceFileStat.IsKind(FSYS_KIND_FILE) )
+ {
+ if ( ( FSYS_ACTION_KEEP_EXISTING == ( pImp->nActions & FSYS_ACTION_KEEP_EXISTING ) ) &&
+ aTgt.Exists() )
+ {
+ // Do not overwrite existing file in target folder.
+ return ERRCODE_NONE;
+ }
+
+ // copy file
+ nBytesCopied = 0;
+ nBytesTotal = FileStat( rSource ).GetSize();
+
+ ::rtl::OUString aFileName;
+ FileBase::getFileURLFromSystemPath( ::rtl::OUString(rSource.GetFull()), aFileName );
+ SvFileStream aSrc( aFileName, STREAM_READ|STREAM_NOCREATE|STREAM_SHARE_DENYNONE );
+
+ if ( !aSrc.GetError() )
+ {
+#ifdef UNX
+ struct stat buf;
+ if ( fstat( aSrc.GetFileHandle(), &buf ) == -1 )
+ eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt );
+#endif
+ ::rtl::OUString aTargetFileName;
+ FileBase::getFileURLFromSystemPath( ::rtl::OUString(aTgt.GetFull()), aTargetFileName );
+
+ SvFileStream aTargetStream( aTargetFileName, STREAM_WRITE | STREAM_TRUNC | STREAM_SHARE_DENYWRITE );
+ if ( !aTargetStream.GetError() )
+ {
+#ifdef UNX
+ if ( fchmod( aTargetStream.GetFileHandle(), buf.st_mode ) == -1 )
+ eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt );
+#endif
+ size_t nAllocSize = 0, nSize = 0;
+ char *pBuf = 0;
+ while ( Progress() && nSize == nAllocSize && eRet == FSYS_ERR_OK )
+ {
+ // adjust the block-size
+ if ( nBlockSize > nAllocSize )
+ {
+ delete[] pBuf;
+ nAllocSize = nBlockSize;
+ pBuf = new char[nAllocSize];
+ }
+
+ // copy one block
+ nSize = aSrc.Read( pBuf, nBlockSize );
+ aTargetStream.Write( pBuf, nSize );
+ if ( aTargetStream.GetError() )
+ eRet = Error( aTargetStream.GetError(), 0, &aTgt );
+
+ // adjust counters
+ nBytesCopied += nSize;
+ if ( nBytesCopied > nBytesTotal )
+ nBytesTotal = nBytesCopied;
+ }
+ delete[] pBuf;
+ }
+ else
+ eRet = Error( aTargetStream.GetError(), 0, &aTgt );
+
+ // unvollstaendiges File wieder loeschen
+ aTargetStream.Close();
+
+ if ( nBytesCopied != nBytesTotal )
+ {
+ aTgt.Kill();
+ }
+ }
+ else
+ eRet = Error( aSrc.GetError(), &rSource, 0 );
+ }
+ else if ( aSourceFileStat.IsKind(FSYS_KIND_NONE) )
+ eRet = Error( ERRCODE_IO_NOTEXISTS, &rSource, 0 );
+ else
+ eRet = Error( ERRCODE_IO_NOTSUPPORTED, &rSource, 0 );
+
+#ifdef WNT
+ // Set LastWriteTime and Attributes of the target identical with the source
+
+ if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) )
+ {
+ WIN32_FIND_DATA fdSource;
+ ByteString aFullSource(aSource.GetFull(), osl_getThreadTextEncoding());
+ ByteString aFullTarget(aTgt.GetFull(), osl_getThreadTextEncoding());
+ HANDLE hFind = FindFirstFile( aFullSource.GetBuffer() , &fdSource );
+ if ( hFind != INVALID_HANDLE_VALUE )
+ {
+ FindClose( hFind );
+
+ HANDLE hFile = CreateFile( aFullTarget.GetBuffer(), GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
+
+ if ( hFile != INVALID_HANDLE_VALUE )
+ {
+ SetFileTime( hFile, NULL, NULL, &fdSource.ftLastWriteTime );
+ CloseHandle( hFile );
+ }
+
+ SetFileAttributes( aFullTarget.GetBuffer(), fdSource.dwFileAttributes );
+ }
+ }
+#endif
+ // bei Move ggf. das File/Dir loeschen
+ if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) && ( pImp->nActions & FSYS_ACTION_MOVE ) )
+ {
+ ErrCode eKillErr = Error( rSource.Kill() | ERRCODE_WARNING_MASK, &rSource, 0 );
+ if ( eKillErr != ERRCODE_WARNING_MASK )
+ {
+ if ( rSource.Exists() )
+ // loeschen ging nicht => dann die Kopie wieder loeschen
+ aTgt.Kill( pImp->nActions );
+ if ( !eWarn )
+ eWarn = eKillErr;
+ }
+ }
+
+ return !eRet ? eWarn : eRet;
+}
+
+// -----------------------------------------------------------------------
+
+FSysError FileCopier::Execute( FSysAction nActions )
+{
+ return ExecuteExact( nActions );
+}
+
+// -----------------------------------------------------------------------
+
+FSysError FileCopier::ExecuteExact( FSysAction nActions, FSysExact eExact )
+{
+ DirEntry aAbsSource = DirEntry( aSource);
+ DirEntry aAbsTarget = DirEntry( aTarget );
+ pImp->nActions = nActions;
+
+ // check if both pathes are accessible and source and target are different
+ if ( !aAbsTarget.ToAbs() || !aAbsSource.ToAbs() || aAbsTarget == aAbsSource )
+ return FSYS_ERR_ACCESSDENIED;
+
+ // check if copy would be endless recursive into itself
+ if ( FSYS_ACTION_RECURSIVE == ( nActions & FSYS_ACTION_RECURSIVE ) &&
+ aAbsSource.Contains( aAbsTarget ) )
+ return ERRCODE_IO_RECURSIVE;
+
+ // target is directory?
+ if ( eExact == FSYS_NOTEXACT &&
+ FileStat( aAbsTarget ).IsKind(FSYS_KIND_DIR) && FileStat( aAbsSource ).IsKind(FSYS_KIND_FILE) )
+ // append name of source
+ aAbsTarget += aSource.GetName();
+
+ // recursive copy
+ return DoCopy_Impl( aAbsSource, aAbsTarget );
+}
diff --git a/tools/source/fsys/fstat.cxx b/tools/source/fsys/fstat.cxx
new file mode 100644
index 000000000000..acdbe6bae510
--- /dev/null
+++ b/tools/source/fsys/fstat.cxx
@@ -0,0 +1,419 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#if defined( WIN)
+#include <stdio.h>
+#include <dos.h>
+#endif
+
+#ifdef UNX
+#include <errno.h>
+#endif
+
+#include <limits.h>
+#include <string.h>
+
+#include "comdep.hxx"
+#include <tools/fsys.hxx>
+
+/*************************************************************************
+|*
+|* FileStat::FileStat()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 11.06.91
+|* Letzte Aenderung MI 11.06.91
+|*
+*************************************************************************/
+
+FileStat::FileStat()
+: // don't use Default-Ctors!
+ aDateCreated( ULONG(0) ),
+ aTimeCreated( ULONG(0) ),
+ aDateModified( ULONG(0) ),
+ aTimeModified( ULONG(0) ),
+ aDateAccessed( ULONG(0) ),
+ aTimeAccessed( ULONG(0) )
+{
+ nSize = 0;
+ nKindFlags = FSYS_KIND_UNKNOWN;
+ nError = FSYS_ERR_OK;
+}
+
+/*************************************************************************
+|*
+|* FileStat::FileStat()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 11.06.91
+|* Letzte Aenderung MI 11.06.91
+|*
+*************************************************************************/
+
+FileStat::FileStat( const DirEntry& rDirEntry, FSysAccess nAccess )
+: // don't use Default-Ctors!
+ aDateCreated( ULONG(0) ),
+ aTimeCreated( ULONG(0) ),
+ aDateModified( ULONG(0) ),
+ aTimeModified( ULONG(0) ),
+ aDateAccessed( ULONG(0) ),
+ aTimeAccessed( ULONG(0) )
+{
+ BOOL bCached = FSYS_ACCESS_CACHED == (nAccess & FSYS_ACCESS_CACHED);
+ BOOL bFloppy = FSYS_ACCESS_FLOPPY == (nAccess & FSYS_ACCESS_FLOPPY);
+
+#ifdef FEAT_FSYS_DOUBLESPEED
+ const FileStat *pStatFromDir = bCached ? rDirEntry.ImpGetStat() : 0;
+ if ( pStatFromDir )
+ {
+ nError = pStatFromDir->nError;
+ nKindFlags = pStatFromDir->nKindFlags;
+ nSize = pStatFromDir->nSize;
+ aCreator = pStatFromDir->aCreator;
+ aType = pStatFromDir->aType;
+ aDateCreated = pStatFromDir->aDateCreated;
+ aTimeCreated = pStatFromDir->aTimeCreated;
+ aDateModified = pStatFromDir->aDateModified;
+ aTimeModified = pStatFromDir->aTimeModified;
+ aDateAccessed = pStatFromDir->aDateAccessed;
+ aTimeAccessed = pStatFromDir->aTimeAccessed;
+ }
+ else
+#endif
+ Update( rDirEntry, bFloppy );
+}
+
+/*************************************************************************
+|*
+|* FileStat::IsYounger()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MA 11.11.91
+|* Letzte Aenderung MA 11.11.91
+|*
+*************************************************************************/
+
+// TRUE wenn die Instanz j"unger als rIsOlder ist.
+// FALSE wenn die Instanz "alter oder gleich alt wie rIsOlder ist.
+
+BOOL FileStat::IsYounger( const FileStat& rIsOlder ) const
+{
+ if ( aDateModified > rIsOlder.aDateModified )
+ return TRUE;
+ if ( ( aDateModified == rIsOlder.aDateModified ) &&
+ ( aTimeModified > rIsOlder.aTimeModified ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* FileStat::IsKind()
+|*
+|* Ersterstellung MA 11.11.91 (?)
+|* Letzte Aenderung KH 16.01.95
+|*
+*************************************************************************/
+
+BOOL FileStat::IsKind( DirEntryKind nKind ) const
+{
+ BOOL bRet = ( ( nKind == FSYS_KIND_UNKNOWN ) &&
+ ( nKindFlags == FSYS_KIND_UNKNOWN ) ) ||
+ ( ( nKindFlags & nKind ) == nKind );
+ return bRet;
+}
+
+/*************************************************************************
+|*
+|* FileStat::HasReadOnlyFlag()
+|*
+|* Ersterstellung MI 06.03.97
+|* Letzte Aenderung UT 01.07.98
+|*
+*************************************************************************/
+
+BOOL FileStat::HasReadOnlyFlag()
+{
+#if defined WNT || defined UNX || defined OS2
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/*************************************************************************
+|*
+|* FileStat::GetReadOnlyFlag()
+|*
+|* Ersterstellung MI 06.03.97
+|* Letzte Aenderung UT 02.07.98
+|*
+*************************************************************************/
+
+BOOL FileStat::GetReadOnlyFlag( const DirEntry &rEntry )
+{
+
+ ByteString aFPath(rEntry.GetFull(), osl_getThreadTextEncoding());
+#if defined WNT
+ DWORD nRes = GetFileAttributes( (LPCTSTR) aFPath.GetBuffer() );
+ return ULONG_MAX != nRes &&
+ ( FILE_ATTRIBUTE_READONLY & nRes ) == FILE_ATTRIBUTE_READONLY;
+#elif defined OS2
+ FILESTATUS3 aFileStat;
+ APIRET nRet = DosQueryPathInfo( (PSZ)aFPath.GetBuffer(), 1, &aFileStat, sizeof(aFileStat) );
+ switch ( nRet )
+ {
+ case NO_ERROR:
+ return FILE_READONLY == ( aFileStat.attrFile & FILE_READONLY );
+ default:
+ return FALSE;
+ }
+#elif defined UNX
+ /* could we stat the object? */
+ struct stat aBuf;
+ if (stat(aFPath.GetBuffer(), &aBuf))
+ return FALSE;
+ /* jupp, is writable for user? */
+ return((aBuf.st_mode & S_IWUSR) != S_IWUSR);
+#else
+ return FALSE;
+#endif
+}
+
+/*************************************************************************
+|*
+|* FileStat::SetReadOnlyFlag()
+|*
+|* Ersterstellung MI 06.03.97
+|* Letzte Aenderung UT 01.07.98
+|*
+*************************************************************************/
+
+ULONG FileStat::SetReadOnlyFlag( const DirEntry &rEntry, BOOL bRO )
+{
+
+ ByteString aFPath(rEntry.GetFull(), osl_getThreadTextEncoding());
+
+#if defined WNT
+ DWORD nRes = GetFileAttributes( (LPCTSTR) aFPath.GetBuffer() );
+ if ( ULONG_MAX != nRes )
+ nRes = SetFileAttributes( (LPCTSTR) aFPath.GetBuffer(),
+ ( nRes & ~FILE_ATTRIBUTE_READONLY ) |
+ ( bRO ? FILE_ATTRIBUTE_READONLY : 0 ) );
+ return ( ULONG_MAX == nRes ) ? ERRCODE_IO_UNKNOWN : 0;
+#elif defined OS2
+ FILESTATUS3 aFileStat;
+ APIRET nRet = DosQueryPathInfo( (PSZ)aFPath.GetBuffer(), 1, &aFileStat, sizeof(aFileStat) );
+ if ( !nRet )
+ {
+ aFileStat.attrFile = ( aFileStat.attrFile & ~FILE_READONLY ) |
+ ( bRO ? FILE_READONLY : 0 );
+ nRet = DosSetPathInfo( (PSZ)aFPath.GetBuffer(), 1, &aFileStat, sizeof(aFileStat), 0 );
+ }
+ switch ( nRet )
+ {
+ case NO_ERROR:
+ return ERRCODE_NONE;
+
+ case ERROR_SHARING_VIOLATION:
+ return ERRCODE_IO_LOCKVIOLATION;
+
+ default:
+ return ERRCODE_IO_NOTEXISTS;
+ }
+#elif defined UNX
+ /* first, stat the object to get permissions */
+ struct stat aBuf;
+ if (stat(aFPath.GetBuffer(), &aBuf))
+ return ERRCODE_IO_NOTEXISTS;
+ /* set or clear write bit for user */
+ mode_t nMode;
+ if (bRO)
+ {
+ nMode = aBuf.st_mode & ~S_IWUSR;
+ nMode = aBuf.st_mode & ~S_IWGRP;
+ nMode = aBuf.st_mode & ~S_IWOTH;
+ }
+ else
+ nMode = aBuf.st_mode | S_IWUSR;
+ /* change it on fs */
+ if (chmod(aFPath.GetBuffer(), nMode))
+ {
+ switch (errno)
+ {
+ case EPERM :
+ case EROFS :
+ return ERRCODE_IO_ACCESSDENIED;
+ default :
+ return ERRCODE_IO_NOTEXISTS;
+ }
+ }
+ else
+ return ERRCODE_NONE;
+#else
+ return ERRCODE_IO_NOTSUPPORTED;
+#endif
+}
+
+/*************************************************************************
+|*
+|* FileStat::SetDateTime
+|*
+|* Ersterstellung PB 27.06.97
+|* Letzte Aenderung
+|*
+*************************************************************************/
+#if defined WNT || defined OS2
+
+void FileStat::SetDateTime( const String& rFileName,
+ const DateTime& rNewDateTime )
+{
+ ByteString aFileName(rFileName, osl_getThreadTextEncoding());
+
+ Date aNewDate = rNewDateTime;
+ Time aNewTime = rNewDateTime;
+
+#if defined WNT
+ TIME_ZONE_INFORMATION aTZI;
+ DWORD dwTZI = GetTimeZoneInformation( &aTZI );
+
+ if ( dwTZI != (DWORD)-1 && dwTZI != TIME_ZONE_ID_UNKNOWN )
+ {
+ // 1. Korrektur der Zeitzone
+ LONG nDiff = aTZI.Bias;
+ Time aOldTime = aNewTime; // alte Zeit merken
+
+ // 2. evt. Korrektur Sommer-/Winterzeit
+ if ( dwTZI == TIME_ZONE_ID_DAYLIGHT )
+ nDiff += aTZI.DaylightBias;
+
+ Time aDiff( abs( nDiff / 60 /*Min -> Std*/ ), 0 );
+
+ if ( nDiff > 0 )
+ {
+ aNewTime += aDiff; // Stundenkorrektur
+
+ // bei "Uberlauf korrigieren
+ if ( aNewTime >= Time( 24, 0 ) )
+ aNewTime -= Time( 24, 0 );
+
+ // Tages"uberlauf?
+ if ( aOldTime == Time( 0, 0 ) || // 00:00 -> 01:00
+ aNewTime < aOldTime ) // 23:00 -> 00:00 | 01:00 ...
+ aNewDate++;
+ }
+ else if ( nDiff < 0 )
+ {
+ aNewTime -= aDiff; // Stundenkorrektur
+
+ // negative Zeit (-1:00) korrigieren: 23:00
+ if (aNewTime < Time( 0, 0 ) )
+ aNewTime += Time( 24, 0 );
+
+ // Tagesunterlauf ?
+ if ( aOldTime == Time( 0, 0 ) || // 00:00 -> 23:00
+ aNewTime > aOldTime ) // 01:00 -> 23:00 | 22:00 ...
+ aNewDate--;
+ }
+ }
+
+
+ SYSTEMTIME aTime;
+ aTime.wYear = aNewDate.GetYear();
+ aTime.wMonth = aNewDate.GetMonth();
+ aTime.wDayOfWeek = 0;
+ aTime.wDay = aNewDate.GetDay();
+ aTime.wHour = aNewTime.GetHour();
+ aTime.wMinute = aNewTime.GetMin();
+ aTime.wSecond = aNewTime.GetSec();
+ aTime.wMilliseconds = 0;
+ FILETIME aFileTime;
+ SystemTimeToFileTime( &aTime, &aFileTime );
+
+ HANDLE hFile = CreateFile( aFileName.GetBuffer(), GENERIC_WRITE, 0, 0,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
+
+ if ( hFile != INVALID_HANDLE_VALUE )
+ {
+ SetFileTime( hFile, &aFileTime, &aFileTime, &aFileTime );
+ CloseHandle( hFile );
+ }
+#elif defined OS2
+
+ // open file
+ ULONG nAction = FILE_EXISTED;
+ HFILE hFile = 0;
+ ULONG nFlags = OPEN_FLAGS_WRITE_THROUGH |
+ OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE |
+ OPEN_FLAGS_RANDOM | OPEN_FLAGS_NOINHERIT |
+ OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE;
+
+ APIRET nRet = DosOpen((PSZ)aFileName.GetBuffer(), &hFile, (PULONG)&nAction,
+ 0/*size*/, FILE_NORMAL,
+ OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
+ nFlags, 0/*ea*/);
+
+ if ( nRet == 0 )
+ {
+ FILESTATUS3 FileInfoBuffer;
+
+ nRet = DosQueryFileInfo(
+ hFile, 1, &FileInfoBuffer, sizeof(FileInfoBuffer));
+
+ if ( nRet == 0 )
+ {
+ FDATE aNewDate;
+ FTIME aNewTime;
+
+ // create date and time words
+ aNewDate.day = rNewDateTime.GetDay();
+ aNewDate.month = rNewDateTime.GetMonth();
+ aNewDate.year = rNewDateTime.GetYear() - 1980;
+ aNewTime.twosecs = rNewDateTime.GetSec() / 2;
+ aNewTime.minutes = rNewDateTime.GetMin();
+ aNewTime.hours = rNewDateTime.GetHour();
+
+ // set file date and time
+ FileInfoBuffer.fdateCreation = aNewDate;
+ FileInfoBuffer.ftimeCreation = aNewTime;
+ FileInfoBuffer.fdateLastAccess = aNewDate;
+ FileInfoBuffer.ftimeLastAccess = aNewTime;
+ FileInfoBuffer.fdateLastWrite = aNewDate;
+ FileInfoBuffer.ftimeLastWrite = aNewTime;
+
+ DosSetFileInfo(hFile, 1, &FileInfoBuffer, sizeof(FileInfoBuffer));
+ }
+ DosClose(hFile);
+ }
+#endif
+
+}
+#endif
diff --git a/tools/source/fsys/makefile.mk b/tools/source/fsys/makefile.mk
new file mode 100644
index 000000000000..b1d34d6347f3
--- /dev/null
+++ b/tools/source/fsys/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=tools
+TARGET=fsys
+ENABLE_EXCEPTIONS=true
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+.IF "$(COM)"=="GCC"
+CFLAGSCXX+=-fexceptions
+.ENDIF
+
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= \
+ $(SLO)$/tempfile.obj \
+ $(SLO)$/wldcrd.obj \
+ $(SLO)$/fstat.obj \
+ $(SLO)$/comdep.obj \
+ $(SLO)$/filecopy.obj \
+ $(SLO)$/dirent.obj \
+ $(SLO)$/tdir.obj \
+ $(SLO)$/urlobj.obj
+
+OBJFILES= $(OBJ)$/wldcrd.obj \
+ $(OBJ)$/fstat.obj \
+ $(OBJ)$/comdep.obj \
+ $(OBJ)$/filecopy.obj \
+ $(OBJ)$/dirent.obj \
+ $(OBJ)$/tdir.obj \
+ $(OBJ)$/urlobj.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/tools/source/fsys/os2.cxx b/tools/source/fsys/os2.cxx
new file mode 100644
index 000000000000..03f8f9eb46ce
--- /dev/null
+++ b/tools/source/fsys/os2.cxx
@@ -0,0 +1,1014 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#define INCL_DOSEXCEPTIONS
+
+#include <stdlib.h>
+
+#ifdef __BORLANDC__
+#include <alloc.h>
+#else
+#include <malloc.h>
+#endif
+#include <tools/debug.hxx>
+#include <tools/list.hxx>
+#include <tools/bigint.hxx>
+#include <tools/fsys.hxx>
+#include "comdep.hxx"
+
+#ifdef OS2
+#ifndef _VOS_MUTEX_HXX //autogen
+#include <vos/mutex.hxx>
+#endif
+#endif
+
+int Sys2SolarError_Impl( int nSysErr );
+
+DECLARE_LIST( DirEntryList, DirEntry* );
+DECLARE_LIST( FSysSortList, FSysSort* );
+DECLARE_LIST( FileStatList, FileStat* );
+
+static char sCaseMap[256];
+static BOOL bCaseMap = FALSE;
+static BOOL bDriveMap = FALSE;
+
+struct DriveMapItem
+{
+ DirEntryKind nKind;
+ char cName;
+ FSysPathStyle nStyle;
+};
+
+void CreateCaseMapImpl();
+void CreateDriveMapImpl();
+
+static DriveMapItem aDriveMap[26];
+
+static BOOL bLastCaseSensitive = FALSE;
+
+//====================================================================
+
+int ApiRet2ToSolarError_Impl( int nApiRet )
+{
+ switch ( nApiRet )
+ {
+ case NO_ERROR: return ERRCODE_NONE;
+ case ERROR_FILE_NOT_FOUND: return ERRCODE_IO_NOTEXISTS;
+ case ERROR_PATH_NOT_FOUND: return ERRCODE_IO_NOTEXISTSPATH;
+ case ERROR_TOO_MANY_OPEN_FILES: return ERRCODE_IO_TOOMANYOPENFILES;
+ case ERROR_ACCESS_DENIED: return ERRCODE_IO_ACCESSDENIED;
+ case ERROR_NOT_ENOUGH_MEMORY: return ERRCODE_IO_OUTOFMEMORY;
+ case ERROR_BAD_FORMAT: return ERRCODE_IO_WRONGFORMAT;
+ case ERROR_NOT_SAME_DEVICE: return ERRCODE_IO_INVALIDDEVICE;
+ case ERROR_WRITE_PROTECT: return ERRCODE_IO_INVALIDDEVICE;
+ case ERROR_BAD_UNIT: return ERRCODE_IO_INVALIDDEVICE;
+ case ERROR_CRC: return ERRCODE_IO_INVALIDDEVICE;
+ case ERROR_NOT_DOS_DISK: return ERRCODE_IO_INVALIDDEVICE;
+ case ERROR_WRITE_FAULT: return ERRCODE_IO_CANTWRITE;
+ case ERROR_READ_FAULT: return ERRCODE_IO_CANTREAD;
+ case ERROR_SHARING_VIOLATION: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_LOCK_VIOLATION: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_WRONG_DISK: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_HANDLE_DISK_FULL: return ERRCODE_IO_OUTOFSPACE;
+ case ERROR_NOT_SUPPORTED: return ERRCODE_IO_NOTSUPPORTED;
+ case ERROR_DUP_NAME: return ERRCODE_IO_ALREADYEXISTS;
+ case ERROR_BAD_NETPATH: return ERRCODE_IO_NOTEXISTSPATH;
+ case ERROR_DEV_NOT_EXIST: return ERRCODE_IO_NOTEXISTS;
+ case ERROR_NETWORK_ACCESS_DENIED: return ERRCODE_IO_ACCESSDENIED;
+ case ERROR_INVALID_PARAMETER: return ERRCODE_IO_INVALIDPARAMETER;
+ case ERROR_NET_WRITE_FAULT: return ERRCODE_IO_CANTWRITE;
+ case ERROR_DEVICE_IN_USE: return ERRCODE_IO_INVALIDPARAMETER;
+ case ERROR_DISK_FULL: return ERRCODE_IO_OUTOFSPACE;
+ case ERROR_BAD_ARGUMENTS: return ERRCODE_IO_INVALIDPARAMETER;
+ case ERROR_BAD_PATHNAME: return ERRCODE_IO_NOTEXISTSPATH;
+ case ERROR_LOCK_FAILED: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_LOCKED: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_DUPLICATE_NAME: return ERRCODE_IO_ALREADYEXISTS;
+ case ERROR_DIRECTORY_IN_CDS: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_CURRENT_DIRECTORY: return ERRCODE_IO_LOCKVIOLATION;
+ case ERROR_FILENAME_EXCED_RANGE: return ERRCODE_IO_NAMETOOLONG;
+ }
+
+ DBG_TRACE1( "FSys: unknown apiret error %d occured", nApiRet );
+ return FSYS_ERR_UNKNOWN;
+}
+
+//--------------------------------------------------------------------
+
+char* volumeid( const char* pPfad )
+{
+ static FSINFO aFSInfoBuf;
+ ULONG ulFSInfoLevel = FSIL_VOLSER;
+ ULONG nDriveNumber;
+
+ nDriveNumber = toupper(*pPfad) - 'A' + 1;
+
+ if ( nDriveNumber >= 3 )
+ {
+ APIRET rc = DosQueryFSInfo(
+ nDriveNumber, ulFSInfoLevel, &aFSInfoBuf, sizeof(FSINFO) );
+ if ( rc )
+ return 0;
+ return (char*) aFSInfoBuf.vol.szVolLabel;
+ }
+ return 0;
+}
+
+//--------------------------------------------------------------------
+
+/*************************************************************************
+|*
+|* DirEntry::ToAbs()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91 13:30
+|*
+*************************************************************************/
+
+BOOL DirEntry::ToAbs()
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ if ( FSYS_FLAG_VOLUME == eFlag )
+ {
+ eFlag = FSYS_FLAG_ABSROOT;
+ return TRUE;
+ }
+
+ if ( IsAbs() )
+ return TRUE;
+
+ char sBuf[_MAX_PATH + 1];
+ *this = DirEntry( String( getcwd( sBuf, _MAX_PATH ), osl_getThreadTextEncoding() ) ) + *this;
+
+ return IsAbs();
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetVolume()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 04.03.92
+|* Letzte Aenderung MI 04.03.92
+|*
+*************************************************************************/
+
+String DirEntry::GetVolume() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ String aRet;
+ const DirEntry *pTop = ImpGetTopPtr();
+ ByteString aName = ByteString( pTop->aName ).ToLowerAscii();
+
+ if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT ||
+ pTop->eFlag == FSYS_FLAG_RELROOT ||
+ pTop->eFlag == FSYS_FLAG_VOLUME )
+ && aName != "a:" && aName != "b:" && Exists() )
+ {
+ const char *pVol;
+ pVol = volumeid( (char*) pTop->aName.GetBuffer() );
+ if (pVol)
+ aRet = String( pVol, osl_getThreadTextEncoding());
+ }
+
+ return aRet;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::SetCWD()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 21.05.92
+|*
+*************************************************************************/
+
+BOOL DirEntry::SetCWD( BOOL bSloppy ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ if ( eFlag == FSYS_FLAG_CURRENT && !aName.Len() )
+ return TRUE;
+
+ if ( !chdir(ByteString(GetFull(), osl_getThreadTextEncoding()).GetBuffer()) )
+ {
+ //nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ if ( bSloppy && pParent &&
+ !chdir(ByteString(pParent->GetFull(), osl_getThreadTextEncoding()).GetBuffer()) )
+ {
+ //nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ //nError = FSYS_ERR_NOTADIRECTORY;
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::MoveTo()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91 14:07
+|*
+*************************************************************************/
+
+#if 0 // YD see dirent.cxx
+BOOL createLongNameEA( const PCSZ pszPath, ULONG ulAttributes, const String& aLongName );
+
+FSysError DirEntry::MoveTo( const DirEntry& rDest ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry aTmpDest(rDest);
+ FileStat aTmpStat(aTmpDest);
+ if ( aTmpStat.IsKind(FSYS_KIND_DIR) )
+ aTmpDest += DirEntry( GetName() );
+
+ String aSource( GetFull() );
+ String aDest( aTmpDest.GetFull() );
+ String aShortSource("");
+ String aShortDest("");
+
+ if (Folder::IsAvailable())
+ {
+ if (IsLongNameOnFAT())
+ {
+ // in kurzen Pfad wandeln
+ ItemIDPath aItemIDPath(aSource);
+ aShortSource = aItemIDPath.GetHostNotationPath();
+ }
+ if (rDest.IsLongNameOnFAT())
+ {
+ // in kurzen Pfad wandeln
+ ItemIDPath aItemIDPath(aDest);
+ aShortDest = aItemIDPath.GetHostNotationPath();
+ }
+ }
+
+ APIRET nRet = DosMove( aShortSource.Len()>0?(PSZ)aShortSource.GetStr():(PSZ)aSource.GetStr(),
+ aShortDest.Len()>0?(PSZ)aShortDest.GetStr():(PSZ)aDest.GetStr());
+
+ if ( nRet == ERROR_DIRECTORY_IN_CDS ||
+ nRet == ERROR_CURRENT_DIRECTORY )
+ {
+ // 2nd chance with modified CWD
+ DosSetCurrentDir( (PSZ) "\\" );
+ nRet = DosMove( aShortSource.Len()>0?(PSZ)aShortSource.GetStr():(PSZ)aSource.GetStr(),
+ aShortDest.Len()>0?(PSZ)aShortDest.GetStr():(PSZ)aDest.GetStr());
+ }
+ else if ( nRet == ERROR_NOT_SAME_DEVICE )
+ {
+ // other volume => copy+delete
+ FileCopier aMover( *this, rDest );
+ nRet = aMover.Execute( FSYS_ACTION_MOVE|FSYS_ACTION_RECURSIVE );
+ return nRet;
+ }
+
+ if ( (nRet==NO_ERROR) && aShortDest.Len()>0)
+ {
+ createLongNameEA((const char*)aShortDest, FILE_NORMAL, rDest.GetName());
+ }
+
+ return ApiRet2ToSolarError_Impl( nRet );
+}
+#endif // 0
+
+//-------------------------------------------------------------------------
+
+USHORT DirReader_Impl::Init()
+{
+ // Block-Devices auflisten?
+ if ( pDir->eAttrMask & FSYS_KIND_BLOCK )
+ {
+ CreateDriveMapImpl();
+ // CWD merken
+ DirEntry aCurrentDir;
+ aCurrentDir.ToAbs();
+
+ // einzeln auf Existenz und Masken-konformit"at pr"ufen
+ USHORT nRead = 0;
+ char sDrive[3] = { '?', ':', 0 };
+ char sRoot[4] = { '?', ':', '\\', 0 };
+ for ( char c = 'a'; c <= 'z'; c++ )
+ {
+ sDrive[0] = c;
+ sRoot[0] = c;
+ DirEntry* pDrive = new DirEntry( sDrive, FSYS_FLAG_VOLUME, FSYS_STYLE_HOST );
+ if ( pDir->aNameMask.Matches( String( ByteString(sDrive), osl_getThreadTextEncoding()))
+ && aDriveMap[c-'a'].nKind != FSYS_KIND_UNKNOWN )
+ {
+ if ( pDir->pStatLst ) //Status fuer Sort gewuenscht?
+ {
+ FileStat *pNewStat = new FileStat( *pDrive );
+ pDir->ImpSortedInsert( pDrive, pNewStat );
+ }
+ else
+ pDir->ImpSortedInsert( pDrive, NULL );
+ ++nRead;
+ }
+ else
+ delete pDrive;
+ }
+
+ // CWD restaurieren
+ aCurrentDir.SetCWD();
+ return nRead;
+ }
+
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+
+USHORT DirReader_Impl::Read()
+{
+ if (!pDosDir)
+ {
+ pDosDir = opendir( (char*) ByteString(aPath, osl_getThreadTextEncoding()).GetBuffer() );
+ }
+
+ if (!pDosDir)
+ {
+ bReady = TRUE;
+ return 0;
+ }
+
+ // Directories und Files auflisten?
+ if ( ( pDir->eAttrMask & FSYS_KIND_DIR || pDir->eAttrMask & FSYS_KIND_FILE ) &&
+ ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) )
+ {
+ String aD_Name(pDosEntry->d_name, osl_getThreadTextEncoding());
+ if ( pDir->aNameMask.Matches( aD_Name ) )
+ {
+ DirEntryFlag eFlag =
+ 0 == strcmp( pDosEntry->d_name, "." ) ? FSYS_FLAG_CURRENT
+ : 0 == strcmp( pDosEntry->d_name, ".." ) ? FSYS_FLAG_PARENT
+ : FSYS_FLAG_NORMAL;
+ DirEntry *pTemp = new DirEntry( ByteString(pDosEntry->d_name), eFlag, FSYS_STYLE_UNX );
+ if ( pParent )
+ pTemp->ImpChangeParent( new DirEntry( *pParent ), FALSE);
+ FileStat aStat( *pTemp );
+ if ( ( ( ( pDir->eAttrMask & FSYS_KIND_DIR ) &&
+ ( aStat.IsKind( FSYS_KIND_DIR ) ) ) ||
+ ( ( pDir->eAttrMask & FSYS_KIND_FILE ) &&
+ !( aStat.IsKind( FSYS_KIND_DIR ) ) ) ) &&
+ !( pDir->eAttrMask & FSYS_KIND_VISIBLE &&
+ pDosEntry->d_name[0] == '.' ) )
+ {
+ if ( pDir->pStatLst ) //Status fuer Sort gewuenscht?
+ pDir->ImpSortedInsert( pTemp, new FileStat( aStat ) );
+ else
+ pDir->ImpSortedInsert( pTemp, NULL );;
+ return 1;
+ }
+ else
+ delete pTemp;
+ }
+ }
+ else
+ bReady = TRUE;
+ return 0;
+}
+
+/*************************************************************************
+|*
+|* FileStat::FileStat()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MA 05.11.91
+|* Letzte Aenderung MA 07.11.91
+|*
+*************************************************************************/
+
+FileStat::FileStat( const void *pInfo, // struct dirent
+ const void * ): // dummy
+ aDateCreated(0),
+ aTimeCreated(0),
+ aDateModified(0),
+ aTimeModified(0),
+ aDateAccessed(0),
+ aTimeAccessed(0)
+{
+ struct dirent *pDirent = (struct dirent*) pInfo;
+
+ nSize = pDirent->d_size;
+
+ aDateCreated = MsDos2Date( (FDATE*) &pDirent->d_date );
+ aTimeCreated = MsDos2Time( (FTIME*) &pDirent->d_time );
+ aDateModified = aDateModified;
+ aTimeModified = aTimeModified;
+ aDateAccessed = aDateModified;
+ aTimeAccessed = aTimeModified;
+
+ nKindFlags = FSYS_KIND_FILE;
+ if ( pDirent->d_type & DOS_DIRECT )
+ nKindFlags = FSYS_KIND_DIR;
+}
+
+/*************************************************************************
+|*
+|* FileStat::Update()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 11.06.91
+|* Letzte Aenderung MA 07.11.91
+|*
+*************************************************************************/
+
+struct _FSYS_FSQBUFFER
+{
+ FSQBUFFER2 aBuf;
+ UCHAR sBuf[256];
+};
+
+BOOL FileStat::Update( const DirEntry& rDirEntry, BOOL bAccessRemovableDevice )
+{
+ nSize = 0;
+ FSysPathStyle eStyle = FSYS_STYLE_UNKNOWN;
+ aCreator.Erase();
+ aType.Erase();
+ aDateCreated = Date(0);
+ aTimeCreated = Time(0);
+ aDateModified = Date(0);
+ aTimeModified = Time(0);
+ aDateAccessed = Date(0);
+ aTimeAccessed = Time(0);
+
+ if ( !rDirEntry.IsValid() )
+ {
+ nError = FSYS_ERR_NOTEXISTS;
+ return FALSE;
+ }
+
+ // Sonderbehandlung falls es sich um eine Root ohne Laufwerk handelt
+ if ( !rDirEntry.aName.Len() && rDirEntry.eFlag == FSYS_FLAG_ABSROOT )
+ {
+ nKindFlags = FSYS_KIND_DIR;
+ nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ // Sonderbehandlung falls es sich um eine Wildcard handelt
+ ByteString aTempName( rDirEntry.GetName(), osl_getThreadTextEncoding() );
+ if ( strchr( aTempName.GetBuffer(), '?' ) ||
+ strchr( aTempName.GetBuffer(), '*' ) ||
+ strchr( aTempName.GetBuffer(), ';' ) )
+ {
+ nKindFlags = FSYS_KIND_WILD;
+ nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ // Sonderbehandlung falls es sich um eine Root handelt
+ if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME ||
+ rDirEntry.eFlag == FSYS_FLAG_ABSROOT )
+ {
+ if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME )
+ nKindFlags = FSYS_KIND_DEV;
+ else
+ nKindFlags = FSYS_KIND_DIR;
+
+ if ( rDirEntry.aName.Len() == 2 )
+ {
+ if ( !bDriveMap )
+ CreateDriveMapImpl();
+
+ ByteString rDirEntryUpperCase = ByteString( rDirEntry.aName ).ToUpperAscii();
+ DriveMapItem &rItem = aDriveMap[rDirEntryUpperCase.GetChar(0) - 'A'];
+ if ( !rItem.nKind )
+ {
+ nError = ERRCODE_IO_INVALIDDEVICE;
+ nKindFlags = FSYS_KIND_UNKNOWN;
+ return FALSE;
+ }
+ else
+ {
+ if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME )
+ nKindFlags |= FSYS_KIND_BLOCK | rItem.nKind;
+ eStyle = rItem.nStyle;
+ }
+ }
+
+ nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ // disable error-boxes for hard-errors
+ DosError(FERR_DISABLEHARDERR);
+
+ // Statusinformation vom Betriebssystem holen
+ DirEntry aTempDirEntry( rDirEntry );
+ char* p;
+
+ aTempDirEntry.ToAbs();
+ ByteString aFullName( aTempDirEntry.GetFull(), osl_getThreadTextEncoding() );
+
+#if 0 // YD
+ if (Folder::IsAvailable() && aTempDirEntry.IsLongNameOnFAT())
+ {
+ // in String mit kurzem Pfad wandeln
+ ItemIDPath aItemIDPath(aTempDirEntry.GetFull());
+ aFullName = ByteString( aItemIDPath.GetHostNotationPath(), osl_getThreadTextEncoding() );
+ }
+#endif
+
+ p = (char *) aFullName.GetBuffer();
+
+ FILESTATUS3 filestat;
+ memset( &filestat, 0, sizeof( filestat ) );
+ if( DosQueryPathInfo( (PSZ)p, 1, &filestat, sizeof( filestat ) ) )
+ {
+ nError = FSYS_ERR_NOTEXISTS;
+ nKindFlags = FSYS_KIND_UNKNOWN;
+ return FALSE;
+ }
+
+ nError = FSYS_ERR_OK;
+ nSize = filestat.cbFile;
+
+ nKindFlags = FSYS_KIND_UNKNOWN;
+ if( filestat.attrFile & FILE_DIRECTORY )
+ nKindFlags |= FSYS_KIND_DIR;
+ if ( nKindFlags == FSYS_KIND_UNKNOWN )
+ nKindFlags = nKindFlags | FSYS_KIND_FILE;
+
+ aDateModified = Date( filestat.fdateLastWrite.day,
+ filestat.fdateLastWrite.month,
+ filestat.fdateLastWrite.year + 1980 );
+
+ aTimeModified = Time( filestat.ftimeLastWrite.hours,
+ filestat.ftimeLastWrite.minutes,
+ filestat.ftimeLastWrite.twosecs*2 );
+
+ if ( filestat.fdateCreation.day )
+ {
+ aDateCreated = Date( filestat.fdateCreation.day,
+ filestat.fdateCreation.month,
+ filestat.fdateCreation.year + 1980 );
+
+ aTimeCreated = Time( filestat.ftimeCreation.hours,
+ filestat.ftimeCreation.minutes,
+ filestat.ftimeCreation.twosecs*2 );
+ }
+ else
+ {
+ aDateCreated = aDateModified;
+ aTimeCreated = aTimeModified;
+ }
+
+ if ( filestat.fdateLastAccess.day > 0 )
+ {
+ aDateAccessed = Date( filestat.fdateLastAccess.day,
+ filestat.fdateLastAccess.month,
+ filestat.fdateLastAccess.year + 1980 );
+
+ aTimeAccessed = Time( filestat.ftimeLastAccess.hours,
+ filestat.ftimeLastAccess.minutes,
+ filestat.ftimeLastAccess.twosecs*2 );
+ }
+ else
+ {
+ aDateAccessed = aDateModified;
+ aTimeAccessed = aTimeModified;
+ }
+
+ return TRUE;
+}
+
+BOOL IsRedirectable_Impl( const ByteString &rPath )
+{
+ if ( rPath.Len() >= 3 && ':' == rPath.GetBuffer()[1] )
+ {
+ ByteString aVolume = rPath.Copy( 0, 3 );
+ DriveMapItem &rItem = aDriveMap[toupper(aVolume.GetChar(0)) - 'A'];
+ return FSYS_KIND_FIXED != rItem.nKind;
+ }
+ return FALSE;
+}
+
+#if 0
+BOOL IsRedirectable_Impl( const String &rPath )
+{
+ if ( rPath.Len() >= 3 && ':' == rPath.GetStr()[1] )
+ {
+ DriveMapItem &rItem = aDriveMap[toupper(rPath[0]) - 'A'];
+ return FSYS_KIND_FIXED != rItem.nKind;
+ }
+ return FALSE;
+}
+#endif
+
+
+/*************************************************************************
+|*
+|* TempDirImpl()
+|*
+|* Beschreibung liefert den Namens des Directories fuer temporaere
+|* Dateien
+|* Ersterstellung MI 16.03.94
+|* Letzte Aenderung MI 16.03.94
+|*
+*************************************************************************/
+
+const char* TempDirImpl( char *pBuf )
+{
+ PSZ pVar;
+ USHORT nRet;
+ BOOL bAppendTemp = FALSE; // mu\s noch \\temp angeh"angt werden
+
+ // Erstmal sehen, ob TEMP oder TMP gesetzt sind
+ nRet = DosScanEnv( (PSZ)"TEMP", &pVar );
+ if( nRet )
+ nRet = DosScanEnv( (PSZ)"temp", &pVar );
+ if( nRet )
+ nRet = DosScanEnv( (PSZ)"TMP", &pVar );
+ if( nRet )
+ nRet = DosScanEnv( (PSZ)"tmp", &pVar );
+ if( nRet )
+ nRet = DosScanEnv( (PSZ)"TMPDIR", &pVar );
+
+ // falls das geklappt hat, und ein Backslash dranhaengt,
+ // oder falls es bisher nicht geklappt hat,
+ // muessen wir nachher einen Backslash entfernen
+ BOOL bRemoveBS = nRet || *(pVar+strlen(pVar)-1) == '\\';
+
+ // Keine temp-Variable gefunden, dann gehen wir mal auf die Suche
+ // nach dem System-Laufwerk
+ if( nRet )
+ {
+ nRet = DosScanEnv( (PSZ)"USER_INI",&pVar );
+ bAppendTemp = (0 == nRet);
+ }
+ if( nRet )
+ {
+ nRet = DosScanEnv( (PSZ)"SYSTEM_INI", &pVar );
+ bAppendTemp = (0 == nRet);
+ }
+ if( nRet )
+ // Wenn das immer noch nicht reicht nehmen wir eben die Root von C:
+#ifdef __BORLANDC__
+ pVar = (PSZ)"c:\\temp\\";
+#else
+ pVar = (PCSZ)"c:\\temp\\";
+#endif
+ strcpy( pBuf, (const char*)pVar );
+
+ // jetzt haengt ggf. ein Backlash dran, den wir abschneiden,
+ // ggf. inklusive dahinter haengendem Dateinamen
+ if ( bRemoveBS )
+ {
+ char *pTail = pBuf + strlen(pBuf) - 1;
+ for ( char cLast = *pTail; cLast != '\\'; cLast = *(--pTail) )
+ *pTail = 0;
+ }
+
+ if ( bAppendTemp )
+ strcat( pBuf, "\\temp" );
+ DirEntry( pBuf ).MakeDir();
+
+ return pBuf;
+}
+
+#define CURRENT_COUNTRY 0
+#define NLS_CODEPAGE 850
+
+/*====================================================================
+ * CreateCaseMapImpl()
+ * creates a map of each character to convert to lower
+ *--------------------------------------------------------------------*/
+
+#if 0
+void CreateCaseMapImpl()
+{
+ // build a string starting with code 0 as first character upto 255
+ char sTemp[256];
+ USHORT n;
+
+ for ( n = 0; n < 256; ++n )
+ sTemp[n] = (char) n;
+
+ // convert string to upper case
+ COUNTRYCODE aCountry;
+ aCountry.country = CURRENT_COUNTRY; /* Country code */
+ aCountry.codepage = NLS_CODEPAGE; /* Code page */
+ DosMapCase( 255, &aCountry, sTemp+1 );
+
+ // fill a global buffer starting with code 0 as first character upto 255
+ for ( n = 0; n < 256; ++n )
+ sCaseMap[n] = (char) n;
+
+ // reorder by upper-code and store in a global buffer
+ for ( n = 255; n > 0; --n )
+ // was this character converted?
+ if ( sTemp[n] != (char) n )
+ // we found a convertion from upper to lower
+ sCaseMap[ (unsigned char) sTemp[n] ] = (char) n;
+
+ bCaseMap = TRUE;
+}
+
+String ToLowerImpl( const String& rSource )
+{
+ if ( !bCaseMap )
+ CreateCaseMapImpl();
+
+ // TH sagt: International ist zu langsam, also mit einer eigenen Map
+ ByteString aLower( rSource );
+ for ( USHORT n = 0; n < aLower.Len(); ++n )
+ aLower[n] = sCaseMap[ (unsigned char) aLower[n] ];
+ return aLower;
+}
+#endif // 0
+
+/*====================================================================
+ * CreateDriveMapImpl()
+ * creates a map of drive-infos like FileSystem (style) and Kind (remote)
+ *--------------------------------------------------------------------*/
+typedef struct _FSQBUFFER_
+{
+ FSQBUFFER2 aBuf;
+ UCHAR sBuf[64];
+} FSQBUFFER_;
+
+void CreateDriveMapImpl()
+{
+#ifdef POWERPC
+ // !!!!! Hack, da der untere Teil mit Beta 2 noch abstuertzt !!!!!
+ BYTE nFloppies = 1;
+ for ( USHORT nDrive = 0; nDrive < 26; ++nDrive )
+ {
+ if ( nDrive < nFloppies )
+ {
+ aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE;
+ aDriveMap[nDrive].nStyle = FSYS_STYLE_FAT;
+ }
+ else
+ {
+ aDriveMap[nDrive].nKind = FSYS_KIND_UNKNOWN;
+ aDriveMap[nDrive].nStyle = FSYS_STYLE_UNKNOWN;
+ }
+ }
+
+ aDriveMap[2].nKind = FSYS_KIND_FIXED;
+ aDriveMap[2].nStyle = FSYS_STYLE_FAT;
+#else
+ FSQBUFFER_ aBuf;
+ ULONG nBufLen;
+ APIRET nRet;
+ USHORT nDrive;
+
+ // disable error-boxes for hard-errors
+ DosError(FERR_DISABLEHARDERR);
+
+ // determine number of floppy-drives
+ BYTE nFloppies;
+ nRet = DosDevConfig( (void*) &nFloppies, DEVINFO_FLOPPY );
+
+ // reset the map
+ for ( nDrive = 0; nDrive < 26; ++nDrive )
+ {
+ if ( nDrive < nFloppies )
+ {
+ aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE;
+ aDriveMap[nDrive].nStyle = FSYS_STYLE_FAT;
+ }
+ else
+ {
+ aDriveMap[nDrive].nKind = FSYS_KIND_UNKNOWN;
+ aDriveMap[nDrive].nStyle = FSYS_STYLE_UNKNOWN;
+ }
+ }
+
+ // determine file-system via DosOpen/DocDevIOCtrl
+ for ( nDrive = 2; nDrive < 26; ++nDrive )
+ {
+ // open drive
+ BOOL bFixed;
+ HFILE nDevHandle;
+ char pDriveName[3] = "#:";
+ pDriveName[0] = nDrive+'a';
+ ULONG nAction;
+ nRet = DosOpen( (PSZ) pDriveName, &nDevHandle,
+ &nAction, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS,
+ OPEN_FLAGS_DASD|OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY,
+ 0 );
+
+ // exists?
+ if ( !nRet )
+ {
+ // removeable?
+ BYTE nDriveId = nDrive;
+ ULONG nParaOutLen, nDataOutLen;
+ nRet = DosDevIOCtl(nDevHandle, 8, 0x20,
+ &nDriveId, sizeof(nDriveId), &nParaOutLen,
+ &bFixed, sizeof(bFixed), &nDataOutLen );
+
+ // prepare the drive-map
+ if ( !nRet && !bFixed )
+ aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE;
+
+ // close drive
+ DosClose(nDevHandle);
+ }
+ else if ( nRet == ERROR_NOT_READY )
+ aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE | FSYS_KIND_CDROM;
+ }
+
+ // determine file-system via FSAttach
+ nRet = 0;
+ for ( USHORT n = 3; nRet != ERROR_NO_MORE_ITEMS; ++n )
+ {
+ nBufLen = sizeof( aBuf );
+ nRet = DosQueryFSAttach( 0, n, FSAIL_DRVNUMBER,
+ (_FSQBUFFER2*) &aBuf, &nBufLen );
+ if ( !nRet )
+ {
+ nDrive = toupper(aBuf.aBuf.szName[0]) - 'A';
+
+ if ( aDriveMap[nDrive].nKind == FSYS_KIND_UNKNOWN )
+ aDriveMap[nDrive].nKind =
+ aBuf.aBuf.iType == 3 ? FSYS_KIND_FIXED :
+ aBuf.aBuf.iType == 4 ? FSYS_KIND_REMOTE :
+ FSYS_KIND_UNKNOWN;
+
+ char *pType = (char*)(aBuf.aBuf.szName + aBuf.aBuf.cbName + 1);
+ aDriveMap[nDrive].nStyle =
+ strcmp( pType, "FAT" ) == 0 ? FSYS_STYLE_FAT :
+ strcmp( pType, "FAT32" ) == 0 ? FSYS_STYLE_VFAT :
+ strcmp( pType, "NTFS" ) == 0 ? FSYS_STYLE_NTFS :
+ strcmp( pType, "HPFS" ) == 0 ? FSYS_STYLE_HPFS :
+ strcmp( pType, "JFS" ) == 0 ? FSYS_STYLE_HPFS :
+ strcmp( pType, "RAMFS" ) == 0 ? FSYS_STYLE_HPFS :
+ strcmp( pType, "NDFS32" ) == 0 ? FSYS_STYLE_HPFS :
+ strcmp( pType, "NWFS" ) == 0 ? FSYS_STYLE_NWFS :
+ strcmp( pType, "EXT2" ) == 0 ? FSYS_STYLE_UNX :
+ strcmp( pType, "NFS" ) == 0 ? FSYS_STYLE_UNX :
+ FSYS_STYLE_UNKNOWN;
+ if ( strcmp( pType, "CDFS" ) == 0 )
+ aDriveMap[nDrive].nKind = FSYS_KIND_CDROM|FSYS_KIND_REMOVEABLE;
+ }
+ }
+#endif
+
+ bDriveMap = TRUE;
+}
+
+Time MsDos2Time( const time_t *pTimeT )
+{
+ tm *pTm = localtime( pTimeT );
+ if ( pTm )
+ return Time( pTm->tm_hour, pTm->tm_min, pTm->tm_sec );
+ else
+ return Time(0);
+}
+
+Date MsDos2Date( const time_t *pTimeT )
+{
+ tm *pTm = localtime( pTimeT );
+ if ( pTm )
+ return Date( pTm->tm_mday, pTm->tm_mon + 1, pTm->tm_year );
+ else
+ return Date(0);
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetPathStyle() const
+|*
+|* Beschreibung
+|* Ersterstellung MI 11.05.95
+|* Letzte Aenderung MI 11.05.95
+|*
+*************************************************************************/
+
+FSysPathStyle DirEntry::GetPathStyle( const String &rDevice )
+{
+ ByteString aRootDir(rDevice, osl_getThreadTextEncoding());
+ // UNC-Pathname?
+ if ( aRootDir.Len()==0 || ( aRootDir.Len() > 1 && aRootDir.GetChar(1) != ':' ) )
+ return FSYS_STYLE_UNKNOWN;
+
+ if ( !bDriveMap )
+ CreateDriveMapImpl();
+ return aDriveMap[toupper(aRootDir.GetChar(0)) - 'A'].nStyle;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::IsCaseSensitive() const
+|*
+|* Beschreibung
+|* Ersterstellung TPF 26.02.1999
+|* Letzte Aenderung
+|*
+*************************************************************************/
+
+BOOL DirEntry::IsCaseSensitive( FSysPathStyle eFormatter ) const
+{
+ if (eFormatter==FSYS_STYLE_HOST)
+ {
+ if (GetPathStyle(GetDevice().GetName()) == FSYS_STYLE_UNX)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ BOOL isCaseSensitive = FALSE; // ich bin unter OS2, also ist der default im Zweifelsfall case insensitiv
+ switch ( eFormatter )
+ {
+ case FSYS_STYLE_MAC:
+ case FSYS_STYLE_FAT:
+ case FSYS_STYLE_VFAT:
+ case FSYS_STYLE_NTFS:
+ case FSYS_STYLE_NWFS:
+ case FSYS_STYLE_HPFS:
+ case FSYS_STYLE_DETECT:
+ {
+ isCaseSensitive = FALSE;
+ break;
+ }
+ case FSYS_STYLE_SYSV:
+ case FSYS_STYLE_BSD:
+ {
+ isCaseSensitive = TRUE;
+ break;
+ }
+ default:
+ {
+ isCaseSensitive = FALSE; // ich bin unter OS2, also ist der default im Zweifelsfall case insensitiv
+ break;
+ }
+ }
+ return isCaseSensitive;
+ }
+}
+
+
+
+
+//=========================================================================
+
+ErrCode FileStat::QueryDiskSpace( const String &rPath,
+ BigInt &rFreeBytes, BigInt &rTotalBytes )
+{
+ FSALLOCATE aFSInfoBuf;
+ ByteString aVol( DirEntry(rPath).ImpGetTopPtr()->GetName(), osl_getThreadTextEncoding());
+ ULONG nDriveNumber = toupper( aVol.GetChar(0) ) - 'A' + 1;
+
+ APIRET rc = DosQueryFSInfo( nDriveNumber, FSIL_ALLOC,
+ &aFSInfoBuf, sizeof(aFSInfoBuf) );
+ if ( rc )
+ return Sys2SolarError_Impl( rc );
+
+ BigInt aBytesPerCluster( BigInt(aFSInfoBuf.cbSector) *
+ BigInt(aFSInfoBuf.cSectorUnit) );
+ rFreeBytes = aBytesPerCluster * BigInt(aFSInfoBuf.cUnitAvail);
+ rTotalBytes = aBytesPerCluster * BigInt(aFSInfoBuf.cUnit);
+ return 0;
+}
+
+//=========================================================================
+
+void FSysEnableSysErrorBox( BOOL bEnable )
+{
+ DosError( bEnable ? 0 : FERR_DISABLEHARDERR );
+}
+
diff --git a/tools/source/fsys/os2.hxx b/tools/source/fsys/os2.hxx
new file mode 100644
index 000000000000..c5e54ba0ad47
--- /dev/null
+++ b/tools/source/fsys/os2.hxx
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * 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 _os2_hxx
+#define _os2_hxx
+
+
+#define INCL_DOSEXCEPTIONS
+#define INCL_DOSFILEMGR
+#define INCL_DOSPROCESS
+#define INCL_DOSDEVICES
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#define INCL_DOSNLS /* National Language Support values */
+#include <svpm.h>
+
+#include <dirent.h>
+#include <string.h>
+
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <emx/syscalls.h>
+
+#define FSYS_UNIX FALSE
+
+#define DOS_DIRECT _A_SUBDIR
+#define DOS_VOLUMEID _A_VOLID
+
+#define _mkdir(p) mkdir(p, 0777)
+
+const char* TempDirImpl( char *pBuf );
+String ToLowerImpl( const String& );
+
+#define DEFSTYLE FSYS_STYLE_OS2
+#define MKDIR( p ) mkdir( (unsigned char*) p )
+#define CMP_LOWER(s) ( s.ToLowerAscii() )
+
+#define START_DRV 'a'
+
+inline BOOL DRIVE_EXISTS( char c )
+{
+ ULONG nCur, nMap;
+ APIRET nRet = DosQueryCurrentDisk( &nCur, &nMap );
+ return ( nMap & 1 << (c - 'a') ) != 0;
+}
+
+#include <time.h>
+//#include <datetime.hxx>
+
+inline Time MsDos2Time( FTIME* aTime )
+{
+ return Time( aTime->hours, aTime->minutes, 2*aTime->twosecs );
+}
+
+inline Date MsDos2Date( FDATE* aDate )
+{
+ return Date( aDate->day, aDate->month, aDate->year );
+}
+
+Time MsDos2Time( const time_t *pTimeT );
+
+Date MsDos2Date( const time_t *pTimeT );
+
+#define FSysFailOnErrorImpl()
+
+#endif
+
diff --git a/tools/source/fsys/tdir.cxx b/tools/source/fsys/tdir.cxx
new file mode 100644
index 000000000000..b6bf48a8cdf9
--- /dev/null
+++ b/tools/source/fsys/tdir.cxx
@@ -0,0 +1,768 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _DIR_CXX
+
+#include <stdlib.h>
+#include <cstdarg>
+#include <limits.h>
+#include <tools/debug.hxx>
+#include <tools/list.hxx>
+
+#ifndef _COMPED_HXX
+#include "comdep.hxx"
+#endif
+#include <tools/fsys.hxx>
+
+
+DBG_NAME( Dir )
+
+DECLARE_LIST( DirEntryList, DirEntry* )
+DECLARE_LIST( FSysSortList, FSysSort* )
+DECLARE_LIST( FileStatList, FileStat* )
+
+#define APPEND (USHORT) 65535
+
+/*************************************************************************
+|*
+|* Dir::InsertPointReached()
+|*
+|* Beschreibung stellt fest, ob eingefuegt werden musz
+|* Ersterstellung MA 05.11.91
+|* Letzte Aenderung MI 05.02.92
+|*
+*************************************************************************/
+
+BOOL Dir::ImpInsertPointReached( const DirEntry& rNewEntry,
+ const FileStat& rNewStat,
+ ULONG nCurPos, ULONG nSortIndex ) const
+{
+#define VALUE( nKindFlags ) \
+ ( ( FSYS_KIND_FILE | FSYS_KIND_DIR | FSYS_KIND_DEV | \
+ FSYS_KIND_CHAR | FSYS_KIND_BLOCK ) & nKindFlags )
+
+ // einfache Dinge erfordern einfache Loesungen
+ if ( !pLst->Count() )
+ return TRUE;
+
+ FSysSort nSort = *( pSortLst->GetObject( nSortIndex ) );
+ FileStat *pOldStat = NULL;
+ DirEntry *pCurLstObj = pLst->GetObject( nCurPos );
+ if ( pStatLst )
+ pOldStat = pStatLst->GetObject( nCurPos );
+
+ switch( nSort )
+ {
+ case FSYS_SORT_NAME:
+ case (FSYS_SORT_NAME | FSYS_SORT_ASCENDING):
+ if ( pCurLstObj->aName > rNewEntry.aName )
+ return TRUE;
+ if ( !(pCurLstObj->aName == rNewEntry.aName) )
+ return FALSE;
+ break;
+ case (FSYS_SORT_NAME | FSYS_SORT_DESCENDING):
+ if ( pCurLstObj->aName < rNewEntry.aName )
+ return TRUE;
+ if ( !(pCurLstObj->aName == rNewEntry.aName) )
+ return FALSE;
+ break;
+
+ case FSYS_SORT_EXT:
+ case (FSYS_SORT_EXT | FSYS_SORT_ASCENDING):
+ {
+ if ( pCurLstObj->GetExtension() > rNewEntry.GetExtension() )
+ return TRUE;
+ if ( !(pCurLstObj->GetExtension() == rNewEntry.GetExtension()) )
+ return FALSE;
+ break;
+ }
+ case (FSYS_SORT_EXT | FSYS_SORT_DESCENDING):
+ {
+ if ( pCurLstObj->GetExtension() < rNewEntry.GetExtension() )
+ return TRUE;
+ if ( !(pCurLstObj->GetExtension() == rNewEntry.GetExtension()) )
+ return FALSE;
+ break;
+ }
+
+ case FSYS_SORT_KIND:
+ case (FSYS_SORT_KIND | FSYS_SORT_ASCENDING ):
+ if ( VALUE(pOldStat->nKindFlags) > VALUE(rNewStat.nKindFlags) )
+ return TRUE;
+ if ( !(VALUE(pOldStat->nKindFlags) == VALUE(rNewStat.nKindFlags)) )
+ return FALSE;
+ break;
+ case (FSYS_SORT_KIND | FSYS_SORT_DESCENDING):
+ if ( VALUE(pOldStat->nKindFlags) < VALUE(rNewStat.nKindFlags) )
+ return TRUE;
+ if ( !(VALUE(pOldStat->nKindFlags) == VALUE(rNewStat.nKindFlags)) )
+ return FALSE;
+ break;
+
+ case FSYS_SORT_SIZE:
+ case (FSYS_SORT_SIZE | FSYS_SORT_ASCENDING):
+ if ( pOldStat->nSize > rNewStat.nSize )
+ return TRUE;
+ if ( !(pOldStat->nSize == rNewStat.nSize) )
+ return FALSE;
+ break;
+ case (FSYS_SORT_SIZE | FSYS_SORT_DESCENDING):
+ if ( pOldStat->nSize < rNewStat.nSize )
+ return TRUE;
+ if ( !(pOldStat->nSize == rNewStat.nSize) )
+ return FALSE;
+ break;
+
+ case FSYS_SORT_MODIFYED:
+ case (FSYS_SORT_MODIFYED | FSYS_SORT_ASCENDING):
+ if ( (pOldStat->aDateModified >= rNewStat.aDateModified) &&
+ (pOldStat->aTimeModified > rNewStat.aTimeModified) )
+ return TRUE;
+ if ( !((pOldStat->aDateModified == rNewStat.aDateModified) &&
+ (pOldStat->aTimeModified == rNewStat.aTimeModified)) )
+ return FALSE;
+ break;
+ case (FSYS_SORT_MODIFYED | FSYS_SORT_DESCENDING):
+ if ( (pOldStat->aDateModified <= rNewStat.aDateModified) &&
+ (pOldStat->aTimeModified < rNewStat.aTimeModified) )
+ return TRUE;
+ if ( !((pOldStat->aDateModified == rNewStat.aDateModified) &&
+ (pOldStat->aTimeModified == rNewStat.aTimeModified)) )
+ return FALSE;
+ break;
+
+ case FSYS_SORT_CREATED:
+ case (FSYS_SORT_CREATED | FSYS_SORT_ASCENDING):
+ if ( (pOldStat->aDateCreated >= rNewStat.aDateCreated) &&
+ (pOldStat->aTimeCreated > rNewStat.aTimeCreated) )
+ return TRUE;
+ if ( !((pOldStat->aDateCreated == rNewStat.aDateCreated) &&
+ (pOldStat->aTimeCreated == rNewStat.aTimeCreated)) )
+ return FALSE;
+ break;
+ case (FSYS_SORT_CREATED | FSYS_SORT_DESCENDING):
+ if ( (pOldStat->aDateCreated <= rNewStat.aDateCreated) &&
+ (pOldStat->aTimeCreated < rNewStat.aTimeCreated) )
+ return TRUE;
+ if ( !((pOldStat->aDateCreated == rNewStat.aDateCreated) &&
+ (pOldStat->aTimeCreated == rNewStat.aTimeCreated)) )
+ return FALSE;
+ break;
+
+ case FSYS_SORT_ACCESSED:
+ case (FSYS_SORT_ACCESSED | FSYS_SORT_ASCENDING):
+ if ( (pOldStat->aDateAccessed >= rNewStat.aDateAccessed) &&
+ (pOldStat->aTimeAccessed > rNewStat.aTimeAccessed) )
+ return TRUE;
+ if ( !((pOldStat->aDateAccessed == rNewStat.aDateAccessed) &&
+ (pOldStat->aTimeAccessed == rNewStat.aTimeAccessed)) )
+ return FALSE;
+ break;
+ case (FSYS_SORT_ACCESSED | FSYS_SORT_DESCENDING):
+ if ( (pOldStat->aDateAccessed <= rNewStat.aDateAccessed) &&
+ (pOldStat->aTimeAccessed < rNewStat.aTimeAccessed) )
+ return TRUE;
+ if ( !((pOldStat->aDateAccessed == rNewStat.aDateAccessed) &&
+ (pOldStat->aTimeAccessed == rNewStat.aTimeAccessed)) )
+ return FALSE;
+ break;
+ default: /* Kann nicht sein */;
+ }
+
+ if ( nSortIndex == ( pSortLst->Count() - 1 ) )
+ return TRUE;
+ else
+ //Rekursion
+ return ImpInsertPointReached( rNewEntry, rNewStat,
+ nCurPos, nSortIndex + 1 );
+#undef VALUE
+}
+
+/*************************************************************************
+|*
+|* Dir::ImpSortedInsert()
+|*
+|* Beschreibung fuegt sortiert ein
+|* Ersterstellung MA 05.11.91
+|* Letzte Aenderung MA 03.12.91
+|*
+*************************************************************************/
+
+void Dir::ImpSortedInsert( const DirEntry *pNewEntry, const FileStat *pNewStat )
+{
+ //Sonderfall, keine Sortierung gewuenscht.
+ if ( !pSortLst ) {
+ pLst->Insert( (DirEntry*)pNewEntry, APPEND );
+ return;
+ }
+
+ pLst->First();
+ do {
+ if ( ImpInsertPointReached( *pNewEntry, *pNewStat, pLst->GetCurPos(),
+ (ULONG)0 ) )
+ {
+ if ( pStatLst )
+ pStatLst->Insert( (FileStat*)pNewStat, pLst->GetCurPos() );
+ pLst->Insert( (DirEntry*)pNewEntry );
+ return;
+ }
+ } while( pLst->Next() );
+
+ if ( pStatLst )
+ pStatLst->Insert( (FileStat*)pNewStat, APPEND );
+ pLst->Insert( (DirEntry*)pNewEntry, APPEND );
+}
+
+/*************************************************************************
+|*
+|* Dir::Construct()
+|*
+|* Beschreibung gemeinsame Implementation der Ctoren
+|* Ersterstellung MI 02.06.93
+|* Letzte Aenderung MI 02.06.93
+|*
+*************************************************************************/
+
+void Dir::Construct( DirEntryKind nKindFlags )
+{
+ pLst = NULL;
+ pSortLst = NULL;
+ pStatLst = NULL;
+ eAttrMask = nKindFlags;
+ ByteString aTempName( GetName(), osl_getThreadTextEncoding() );
+ if ( aTempName.Search( "*" ) != STRING_NOTFOUND ||
+ aTempName.Search( "?" ) != STRING_NOTFOUND )
+#if defined( WNT ) && !defined( WTC )
+ {
+ ByteString aTStr(CutName(), osl_getThreadTextEncoding());
+ char* pBuffer = new char[aTStr.Len()+1];
+ strcpy( pBuffer, aTStr.GetBuffer() );
+ CharLowerBuff( pBuffer, aTStr.Len() );
+ aNameMask = WildCard( String(pBuffer, osl_getThreadTextEncoding()), ';' );
+ delete [] pBuffer;
+ }
+#else
+ aNameMask = WildCard( CutName(), ';' );
+#endif
+ else
+ aNameMask = String("*", osl_getThreadTextEncoding());
+}
+
+/*************************************************************************
+|*
+|* Dir::Update()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 16.05.91
+|* Letzte Aenderung MI 19.09.96
+|*
+*************************************************************************/
+
+BOOL Dir::Update()
+{
+ Reset();
+ return Scan( USHRT_MAX ) > 0;
+}
+
+/*************************************************************************
+|*
+|* Dir::Reset()
+|*
+|* Beschreibung
+|* Ersterstellung MI 22.10.96
+|* Letzte Aenderung MI 22.10.96
+|*
+*************************************************************************/
+
+void Dir::Reset()
+{
+ // ggf. alten Reader l"oschen
+ if ( pReader && pReader->bInUse )
+ DELETEZ(pReader);
+
+ // alle DirEntries aus der Liste entfernen und deren Speicher freigeben
+ if ( pLst )
+ {
+ DirEntry* pEntry = pLst->First();
+ while (pEntry)
+ {
+ DirEntry* pNext = pLst->Next();
+ delete pEntry;
+ pEntry = pNext;
+ }
+ pLst->Clear();
+ }
+ else
+ pLst = new DirEntryList();
+
+ // Alte File-Stat's Loeschen
+ if ( pStatLst )
+ {
+ //Erstmal die alten Loeschen
+ FileStat* pEntry = pStatLst->First();
+ while (pEntry)
+ {
+ FileStat* pNext = pStatLst->Next();
+ delete pEntry;
+ pEntry = pNext;
+ }
+ pStatLst->Clear();
+ delete pStatLst;
+ }
+
+ // Verlangen die Sortierkriterien FileStat's?
+ if ( pSortLst )
+ {
+ pSortLst->First();
+ do
+ {
+ if ( *( pSortLst->GetCurObject() ) &
+ ( FSYS_SORT_KIND | FSYS_SORT_SIZE |
+ FSYS_SORT_CREATED | FSYS_SORT_MODIFYED | FSYS_SORT_ACCESSED ) )
+ pStatLst = new FileStatList();
+ } while ( !pStatLst && pSortLst->Next() );
+ }
+
+#ifndef BOOTSTRAP
+ // ggf. einen neuen Reader aufsetzen
+ if ( !pReader )
+ pReader = new DirReader_Impl( *this );
+#endif
+
+ // gibt es das zu oeffnende Verzeichnis ueberhaupt?
+#if !defined(UNX) && !defined(OS2) //explanation: see DirReader_Impl::Read() in unx.cxx
+ if( !pReader->pDosDir )
+ {
+ nError = FSYS_ERR_NOTADIRECTORY;
+ DELETEZ( pReader );
+ return;
+ }
+#endif
+}
+
+/*************************************************************************
+|*
+|* Dir::Scan()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 18.09.96
+|* Letzte Aenderung MI 19.09.96
+|*
+*************************************************************************/
+
+USHORT Dir::Scan( USHORT nCount )
+{
+
+ USHORT nRead = 0; // Anzahl in dieser Runde gelesener Eintr"age
+ FSysFailOnErrorImpl();
+
+ // noch nicht fertig gewesen
+ if ( pReader )
+ {
+ // frischer Reader?
+ if ( !pLst->Count() )
+ {
+ // dann ggf. Laufwerke scannen
+ pReader->bInUse = TRUE;
+ nRead = pReader->Init();
+ }
+
+ // weiterlesen...
+ while ( nRead <= nCount && !pReader->bReady )
+ nRead = nRead + pReader->Read();
+
+ // fertig?
+ if ( pReader && pReader->bReady )
+ DELETEZ( pReader );
+ }
+
+ // Anzahl der gelesenen zur"uckgeben
+ return nRead;
+}
+
+/*************************************************************************
+|*
+|* Dir::Dir()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 16.05.91
+|* Letzte Aenderung MI 04.03.92
+|*
+*************************************************************************/
+
+Dir::Dir( const DirEntry& rDirEntry, DirEntryKind nKindFlags, FSysSort nSort, ... ):
+ DirEntry( rDirEntry ),
+ pReader( 0 )
+{
+ DBG_CTOR( Dir, NULL );
+
+ Construct( nKindFlags );
+
+ std::va_list pArgs;
+ va_start( pArgs, nSort );
+ ImpSetSort( pArgs, nSort );
+
+ Reset();
+}
+
+/*************************************************************************
+|*
+|* Dir::Dir()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 02.06.93
+|* Letzte Aenderung MI 02.06.93
+|*
+*************************************************************************/
+
+Dir::Dir( const DirEntry& rDirEntry, DirEntryKind nKindFlags ):
+ DirEntry( rDirEntry ),
+ pReader( 0 )
+{
+ DBG_CTOR( Dir, NULL );
+
+ Construct( nKindFlags );
+ Reset();
+}
+
+/*************************************************************************
+|*
+|* Dir::Dir()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 16.05.91
+|* Letzte Aenderung MA 04.11.91
+|*
+*************************************************************************/
+
+Dir::Dir():
+ pReader( 0 )
+{
+ DBG_CTOR( Dir, NULL );
+
+ pLst = NULL;
+ pSortLst = NULL;
+ pStatLst = NULL;
+ eAttrMask = FSYS_KIND_ALL;
+ aNameMask = String("*", osl_getThreadTextEncoding());
+}
+
+/*************************************************************************
+|*
+|* Dir::~Dir()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 16.05.91
+|* Letzte Aenderung MA 04.11.91
+|*
+*************************************************************************/
+
+Dir::~Dir()
+{
+ DBG_DTOR( Dir, NULL );
+
+ // alle DirEntries aus der Liste entfernen und deren Speicher freigeben
+ if ( pLst )
+ {
+ DirEntry* pEntry = pLst->First();
+ while (pEntry)
+ {
+ DirEntry* pNext = pLst->Next();
+ delete pEntry;
+ pEntry = pNext;
+ }
+ pLst->Clear();
+
+ delete pLst;
+ }
+
+ // alle Sorts aus der Liste entfernen und deren Speicher freigeben
+ if ( pSortLst )
+ {
+ FSysSort* pEntry = pSortLst->First();
+ while (pEntry)
+ {
+ FSysSort* pNext = pSortLst->Next();
+ delete pEntry;
+ pEntry = pNext;
+ }
+ pSortLst->Clear();
+
+ delete pSortLst;
+ }
+
+ // alle FileStat's aus der Liste entfernen und deren Speicher freigeben
+ if ( pStatLst )
+ {
+ FileStat* pEntry = pStatLst->First();
+ while (pEntry)
+ {
+ FileStat* pNext = pStatLst->Next();
+ delete pEntry;
+ pEntry = pNext;
+ }
+ pStatLst->Clear();
+ delete pStatLst;
+ }
+
+ // ggf. laufenden Reader freigeben
+ delete pReader;
+}
+
+/*************************************************************************
+|*
+|* Dir::ImpSetSort()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MA 04.11.91
+|* Letzte Aenderung MI 05.02.92
+|*
+*************************************************************************/
+
+FSysError Dir::ImpSetSort( std::va_list pArgs, int nFirstSort )
+{
+ BOOL bLast;
+ FSysSort *pSort;
+ FSysSortList *pNewSortLst = new FSysSortList;
+
+ *( pSort = new FSysSort ) = nFirstSort;
+ do
+ {
+ // letztes Kriterium?
+ bLast = FSYS_SORT_END == (*pSort & FSYS_SORT_END);
+ *pSort &= ~FSYS_SORT_END;
+
+ FSysSort nSort = *pSort & ~(USHORT)FSYS_SORT_ASCENDING
+ & ~(USHORT)FSYS_SORT_DESCENDING;
+
+ // g"utliges Sortierkriterium?
+ if ( ( nSort == FSYS_SORT_NAME ) ||
+ ( nSort == FSYS_SORT_SIZE ) ||
+ ( nSort == FSYS_SORT_EXT ) ||
+ ( nSort == FSYS_SORT_CREATED ) ||
+ ( nSort == FSYS_SORT_MODIFYED ) ||
+ ( nSort == FSYS_SORT_ACCESSED ) ||
+ ( nSort == FSYS_SORT_KIND ) )
+ {
+ pNewSortLst->Insert( pSort, APPEND );
+ *(pSort = new FSysSort) = va_arg( pArgs, FSysSort );
+ }
+ else
+ { // ungueltiger Sort oder FSYS_SORT_NONE
+ FSysSort* pEntry = pNewSortLst->First();
+ while (pEntry)
+ {
+ FSysSort* pNext = pNewSortLst->Next();
+ delete pEntry;
+ pEntry = pNext;
+ }
+ pNewSortLst->Clear();
+ delete pNewSortLst;
+ if ( *pSort == FSYS_SORT_NONE )
+ {
+ delete pSort;
+ if ( pSortLst )
+ delete pSortLst;
+ return FSYS_ERR_OK;
+ }
+ else
+ {
+ delete pSort;
+ return FSYS_ERR_NOTSUPPORTED;
+ }
+ }
+ } while ( !bLast );
+
+ va_end( pArgs );
+ delete pSort; // JP:6.3.00 - delete the initial pointer
+
+ //Enfernen der alten Sort-Elemente
+ if ( pSortLst )
+ {
+ FSysSort* pEntry = pSortLst->First();
+ while (pEntry)
+ {
+ FSysSort* pNext = pSortLst->Next();
+ delete pEntry;
+ pEntry = pNext;
+ }
+ pSortLst->Clear();
+ delete pSortLst;
+ }
+ pSortLst = pNewSortLst;
+
+ //Jetzt noch neu Sortieren...
+
+ //Wenn keine FileStats da sind, aber nun welche gebraucht werden,
+ //ist der Aufruf von Update() die einfachste Moeglichkeit
+ if ( !pStatLst && pSortLst )
+ {
+ pSortLst->First();
+ do
+ {
+ if ( *(pSortLst->GetCurObject()) &
+ ( FSYS_SORT_CREATED | FSYS_SORT_MODIFYED | FSYS_SORT_SIZE |
+ FSYS_SORT_ACCESSED | FSYS_SORT_KIND ) )
+ {
+ Update();
+ return FSYS_ERR_OK;
+ }
+ } while ( !pStatLst && pSortLst->Next() );
+ }
+
+ if ( pLst ) { //Keine DirEntry's, kein Sort.
+ DirEntryList *pOldLst = pLst; //alte Liste merken
+ pLst = new DirEntryList(); //neue Liste (zu Sortieren)
+
+ FileStatList *pOldStatLst = NULL; //alte StatListe merken
+ if ( pStatLst ) {
+ pOldStatLst = pStatLst;
+ pStatLst = new FileStatList(); //neue StatListe (zu Sortieren)
+ }
+ pOldLst->First();
+ do
+ {
+ //Sortiertes Einfuegen der Elemente aus den gemerkten Listen
+ //in die 'richtigen' Listen
+ if ( pOldStatLst )
+ ImpSortedInsert( pOldLst->GetCurObject(),
+ pOldStatLst->GetObject( pOldLst->GetCurPos() ) );
+ else
+ ImpSortedInsert( pOldLst->GetCurObject(), NULL );
+ } while( pOldLst->Next() );
+
+ delete pOldLst;
+ if ( pOldStatLst )
+ delete pOldStatLst;
+ }
+ return FSYS_ERR_OK;
+}
+
+/*************************************************************************
+|*
+|* Dir::SetSort()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MA 04.11.91
+|* Letzte Aenderung MI 05.02.92
+|*
+*************************************************************************/
+
+FSysError Dir::SetSort( FSysSort nSort, ... )
+{
+ std::va_list pArgs;
+ va_start( pArgs, nSort );
+ return ImpSetSort( pArgs, nSort );
+}
+
+/*************************************************************************
+|*
+|* Dir::operator[]()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 16.05.91
+|* Letzte Aenderung MI 16.05.91
+|*
+*************************************************************************/
+
+DirEntry& Dir::operator[] ( USHORT nIndex ) const
+{
+ DBG_ASSERT( nIndex < Count(), "Dir::operator[] : nIndex > Count()" );
+
+ DirEntry *pEntry = pLst->GetObject( nIndex );
+ return *pEntry;
+}
+
+/*************************************************************************
+|*
+|* Dir::operator+= ()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 16.05.91
+|* Letzte Aenderung MI 16.05.91
+|*
+*************************************************************************/
+
+Dir& Dir::operator+=( const Dir& rDir )
+{
+ // ggf. erst den Rest lesen
+ if ( pReader )
+ Scan( USHRT_MAX );
+ DBG_ASSERT( !rDir.pReader, "Dir::+= with incomplete Dir" );
+
+ // ggf. initiale Liste erzeugen
+ if ( !pLst )
+ pLst = new DirEntryList();
+
+ //Verlangen die Sortierkriterien FileStat's?
+ BOOL bStat = FALSE;
+ if ( pSortLst ) {
+ pSortLst->First();
+ do {
+ if ( *(pSortLst->GetCurObject()) &
+ ( FSYS_SORT_CREATED | FSYS_SORT_MODIFYED | FSYS_SORT_SIZE |
+ FSYS_SORT_ACCESSED | FSYS_SORT_KIND ) )
+ bStat = TRUE;
+ } while ( !bStat && pSortLst->Next() );
+ }
+ FileStat * stat = NULL;
+ for ( USHORT nNr = 0; nNr < rDir.Count(); nNr++ )
+ {
+ if ( bStat )
+ {
+ if ( rDir.pStatLst )
+ stat = new FileStat( *rDir.pStatLst->GetObject(nNr) );
+ else
+ stat = new FileStat( rDir[nNr] );
+ }
+ ImpSortedInsert( new DirEntry( rDir[nNr] ), stat );
+ }
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Dir::Count()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 16.05.91
+|* Letzte Aenderung MI 18.09.96
+|*
+*************************************************************************/
+
+
+USHORT Dir::Count( BOOL bUpdated ) const
+{
+ // ggf. erst den Rest lesen
+ if ( bUpdated && pReader )
+ ((Dir*)this)->Scan( USHRT_MAX );
+
+ return pLst == NULL ? 0 : (USHORT) pLst->Count();
+}
diff --git a/tools/source/fsys/tempfile.cxx b/tools/source/fsys/tempfile.cxx
new file mode 100644
index 000000000000..b3f53d882467
--- /dev/null
+++ b/tools/source/fsys/tempfile.cxx
@@ -0,0 +1,301 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/tempfile.hxx>
+#include "comdep.hxx"
+
+#include <rtl/ustring.hxx>
+#include <osl/file.hxx>
+#include <rtl/instance.hxx>
+#include <tools/time.hxx>
+#include <tools/debug.hxx>
+#include <stdio.h>
+
+#ifdef UNX
+#define _MAX_PATH 260
+#endif
+
+using namespace osl;
+
+namespace { struct TempNameBase_Impl : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {}; }
+
+struct TempFile_Impl
+{
+ String aName;
+ sal_Bool bIsDirectory;
+};
+
+String GetSystemTempDir_Impl()
+{
+ char sBuf[_MAX_PATH];
+ const char *pDir = TempDirImpl(sBuf);
+
+ ::rtl::OString aTmpA( pDir );
+ ::rtl::OUString aTmp = ::rtl::OStringToOUString( aTmpA, osl_getThreadTextEncoding() );
+ rtl::OUString aRet;
+ FileBase::getFileURLFromSystemPath( aTmp, aRet );
+ String aName = aRet;
+ if( aName.GetChar(aName.Len()-1) != '/' )
+ aName += '/';
+ return aName;
+}
+
+#define TMPNAME_SIZE ( 1 + 5 + 5 + 4 + 1 )
+String ConstructTempDir_Impl( const String* pParent )
+{
+ String aName;
+ if ( pParent && pParent->Len() )
+ {
+ // if parent given try to use it
+ rtl::OUString aTmp( *pParent );
+ rtl::OUString aRet;
+
+ // test for valid filename
+ {
+ ::osl::DirectoryItem aItem;
+ sal_Int32 i = aRet.getLength();
+ if ( aRet[i-1] == '/' )
+ i--;
+
+ if ( DirectoryItem::get( ::rtl::OUString( aRet, i ), aItem ) == FileBase::E_None )
+ aName = aRet;
+ }
+ }
+
+ if ( !aName.Len() )
+ {
+ // if no parent or invalid parent : use system directory
+ ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get();
+ if ( !rTempNameBase_Impl.getLength() )
+ rTempNameBase_Impl = GetSystemTempDir_Impl();
+ aName = rTempNameBase_Impl;
+ }
+
+ // Make sure that directory ends with a separator
+ xub_StrLen i = aName.Len();
+ if( i>0 && aName.GetChar(i-1) != '/' )
+ aName += '/';
+
+ return aName;
+}
+
+void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True )
+{
+ // add a suitable tempname
+ // Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576
+ // ER 13.07.00 why not radix 36 [0-9A-Z] ?!?
+ const unsigned nRadix = 26;
+ String aName( rName );
+ aName += String::CreateFromAscii( "sv" );
+
+ rName.Erase();
+ static unsigned long u = Time::GetSystemTicks();
+ for ( unsigned long nOld = u; ++u != nOld; )
+ {
+ u %= (nRadix*nRadix*nRadix);
+ String aTmp( aName );
+ aTmp += String::CreateFromInt32( (sal_Int32) (unsigned) u, nRadix );
+ aTmp += String::CreateFromAscii( ".tmp" );
+
+ if ( bDir )
+ {
+ FileBase::RC err = Directory::create( aTmp );
+ if ( err == FileBase::E_None )
+ {
+ // !bKeep: only for creating a name, not a file or directory
+ if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
+ rName = aTmp;
+ break;
+ }
+ else if ( err != FileBase::E_EXIST )
+ {
+ // if f.e. name contains invalid chars stop trying to create dirs
+ break;
+ }
+ }
+ else
+ {
+ DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
+ File aFile( aTmp );
+ FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
+ if ( err == FileBase::E_None )
+ {
+ rName = aTmp;
+ aFile.close();
+ break;
+ }
+ else if ( err != FileBase::E_EXIST )
+ {
+ // if f.e. name contains invalid chars stop trying to create files
+ break;
+ }
+ }
+ }
+}
+
+String TempFile::CreateTempName( const String* pParent )
+{
+ // get correct directory
+ String aName = ConstructTempDir_Impl( pParent );
+
+ // get TempFile name with default naming scheme
+ CreateTempName_Impl( aName, sal_False );
+
+ // convert to file URL
+ rtl::OUString aTmp;
+ if ( aName.Len() )
+ aTmp = aName;
+ return aTmp;
+}
+
+TempFile::TempFile( const String* pParent, sal_Bool bDirectory )
+ : pImp( new TempFile_Impl )
+ , bKillingFileEnabled( sal_False )
+{
+ pImp->bIsDirectory = bDirectory;
+
+ // get correct directory
+ pImp->aName = ConstructTempDir_Impl( pParent );
+
+ // get TempFile with default naming scheme
+ CreateTempName_Impl( pImp->aName, sal_True, bDirectory );
+}
+
+TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory )
+ : pImp( new TempFile_Impl )
+ , bKillingFileEnabled( sal_False )
+{
+ pImp->bIsDirectory = bDirectory;
+
+ // get correct directory
+ String aName = ConstructTempDir_Impl( pParent );
+
+ // now use special naming scheme ( name takes leading chars and an index counting up from zero
+ aName += rLeadingChars;
+ for ( sal_Int32 i=0;; i++ )
+ {
+ String aTmp( aName );
+ aTmp += String::CreateFromInt32( i );
+ if ( pExtension )
+ aTmp += *pExtension;
+ else
+ aTmp += String::CreateFromAscii( ".tmp" );
+ if ( bDirectory )
+ {
+ FileBase::RC err = Directory::create( aTmp );
+ if ( err == FileBase::E_None )
+ {
+ pImp->aName = aTmp;
+ break;
+ }
+ else if ( err != FileBase::E_EXIST )
+ // if f.e. name contains invalid chars stop trying to create dirs
+ break;
+ }
+ else
+ {
+ File aFile( aTmp );
+ FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
+ if ( err == FileBase::E_None )
+ {
+ pImp->aName = aTmp;
+ aFile.close();
+ break;
+ }
+ else if ( err != FileBase::E_EXIST )
+ // if f.e. name contains invalid chars stop trying to create dirs
+ break;
+ }
+ }
+}
+
+TempFile::~TempFile()
+{
+ if ( bKillingFileEnabled )
+ {
+ if ( pImp->bIsDirectory )
+ {
+ // at the moment no recursiv algorithm present
+ Directory::remove( pImp->aName );
+ }
+ else
+ {
+ File::remove( pImp->aName );
+ }
+ }
+
+ delete pImp;
+}
+
+sal_Bool TempFile::IsValid() const
+{
+ return pImp->aName.Len() != 0;
+}
+
+String TempFile::GetName() const
+{
+ rtl::OUString aTmp;
+ aTmp = pImp->aName;
+ return aTmp;
+}
+
+String TempFile::SetTempNameBaseDirectory( const String &rBaseName )
+{
+ String aName( rBaseName );
+
+ ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get();
+
+ FileBase::RC err= Directory::create( aName );
+ if ( err == FileBase::E_None || err == FileBase::E_EXIST )
+ {
+ rTempNameBase_Impl = aName;
+ rTempNameBase_Impl += String( '/' );
+
+ TempFile aBase( NULL, sal_True );
+ if ( aBase.IsValid() )
+ rTempNameBase_Impl = aBase.pImp->aName;
+ }
+
+ rtl::OUString aTmp;
+ aTmp = rTempNameBase_Impl;
+ return aTmp;
+}
+
+String TempFile::GetTempNameBaseDirectory()
+{
+ ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get();
+ if ( !rTempNameBase_Impl.getLength() )
+ rTempNameBase_Impl = GetSystemTempDir_Impl();
+
+ rtl::OUString aTmp;
+ aTmp = rTempNameBase_Impl;
+ return aTmp;
+}
+
diff --git a/tools/source/fsys/unx.cxx b/tools/source/fsys/unx.cxx
new file mode 100644
index 000000000000..13da80f6ccca
--- /dev/null
+++ b/tools/source/fsys/unx.cxx
@@ -0,0 +1,660 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#if defined HPUX || defined LINUX
+#include <mntent.h>
+#define mnttab mntent
+#elif defined SCO
+#include <mnttab.h>
+#elif defined AIX
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+extern "C" int mntctl( int cmd, size_t size, char* buf );
+#elif defined(NETBSD)
+#include <sys/mount.h>
+#elif defined(FREEBSD) || defined(MACOSX)
+#elif defined DECUNIX
+struct mnttab
+{
+ char *mnt_dir;
+ char *mnt_fsname;
+};
+#else
+#include <sys/mnttab.h>
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#include <tools/debug.hxx>
+#include <tools/list.hxx>
+#include <tools/fsys.hxx>
+#include "comdep.hxx"
+#include <rtl/instance.hxx>
+
+DECLARE_LIST( DirEntryList, DirEntry* )
+DECLARE_LIST( FSysSortList, FSysSort* )
+DECLARE_LIST( FileStatList, FileStat* )
+
+#if defined SOLARIS || defined SINIX
+#define MOUNTSPECIAL mnt_special
+#define MOUNTPOINT mnt_mountp
+#define MOUNTOPTS mnt_mntopts
+#define MOUNTFS mnt_fstype
+#elif defined SCO
+#define MNTTAB "/etc/mnttab"
+#define MOUNTSPECIAL mt_dev
+#define MOUNTPOINT mt_filsys
+#else
+#define MOUNTSPECIAL mnt_fsname
+#define MOUNTPOINT mnt_dir
+#define MOUNTFS mnt_type
+#endif
+
+struct mymnttab
+{
+ dev_t mountdevice;
+ ByteString mountspecial;
+ ByteString mountpoint;
+ ByteString mymnttab_filesystem;
+ mymnttab() { mountdevice = (dev_t) -1; }
+};
+
+
+#if defined(NETBSD) || defined(FREEBSD) || defined(MACOSX)
+BOOL GetMountEntry(dev_t /* dev */, struct mymnttab * /* mytab */ )
+{
+ DBG_WARNING( "Sorry, not implemented: GetMountEntry" );
+ return FALSE;
+}
+
+#elif defined AIX
+BOOL GetMountEntry(dev_t dev, struct mymnttab *mytab)
+{
+ int bufsize;
+ if (mntctl (MCTL_QUERY, sizeof bufsize, (char*) &bufsize))
+ return FALSE;
+
+ char* buffer = (char *)malloc( bufsize * sizeof(char) );
+ if (mntctl (MCTL_QUERY, bufsize, buffer) != -1)
+ for ( char* vmt = buffer;
+ vmt < buffer + bufsize;
+ vmt += ((struct vmount*)vmt)->vmt_length)
+ {
+ struct stat buf;
+ char *mountp = vmt2dataptr((struct vmount*)vmt, VMT_STUB);
+ if ((stat (mountp, &buf) != -1) && (buf.st_dev == dev))
+ {
+ mytab->mountpoint = mountp;
+ mytab->mountspecial
+ = vmt2dataptr((struct vmount*)vmt, VMT_HOSTNAME);
+ if (mytab->mountspecial.Len())
+ mytab->mountspecial += ':';
+ mytab->mountspecial
+ += vmt2dataptr((struct vmount*)vmt, VMT_OBJECT);
+ mytab->mountdevice = dev;
+ free( buffer );
+ return TRUE;
+ }
+ }
+ free( buffer );
+ return FALSE;
+}
+
+#else
+
+
+static BOOL GetMountEntry(dev_t dev, struct mymnttab *mytab)
+{
+#if defined SOLARIS || defined SINIX
+ FILE *fp = fopen (MNTTAB, "r");
+ if (! fp)
+ return FALSE;
+ struct mnttab mnt[1];
+ while (getmntent (fp, mnt) != -1)
+#elif defined SCO
+ FILE *fp = fopen (MNTTAB, "r");
+ if (! fp)
+ return FALSE;
+ struct mnttab mnt[1];
+ while (fread (&mnt, sizeof mnt, 1, fp) > 0)
+#elif defined DECUNIX || defined AIX
+ FILE *fp = NULL;
+ if (! fp)
+ return FALSE;
+ struct mnttab mnt[1];
+ while ( 0 )
+#else
+ FILE *fp = setmntent (MOUNTED, "r");
+ if (! fp)
+ return FALSE;
+ struct mnttab *mnt;
+ while ((mnt = getmntent (fp)) != NULL)
+#endif
+ {
+#ifdef SOLARIS
+ char *devopt = NULL;
+ if ( mnt->MOUNTOPTS != NULL )
+ devopt = strstr (mnt->MOUNTOPTS, "dev=");
+ if (devopt)
+ {
+ if (dev != (dev_t) strtoul (devopt+4, NULL, 16))
+ continue;
+ }
+ else
+#endif
+ {
+ struct stat buf;
+ if ((stat (mnt->MOUNTPOINT, &buf) == -1) || (buf.st_dev != dev))
+ continue;
+ }
+# ifdef LINUX
+ /* #61624# File mit setmntent oeffnen und mit fclose schliessen stoesst
+ bei der glibc-2.1 auf wenig Gegenliebe */
+ endmntent( fp );
+# else
+ fclose (fp);
+# endif
+ mytab->mountspecial = mnt->MOUNTSPECIAL;
+ mytab->mountpoint = mnt->MOUNTPOINT;
+ mytab->mountdevice = dev;
+#ifndef SCO
+ mytab->mymnttab_filesystem = mnt->MOUNTFS;
+#else
+ mytab->mymnttab_filesystem = "ext2"; //default ist case sensitiv unter unix
+#endif
+ return TRUE;
+ }
+# ifdef LINUX
+ /* #61624# dito */
+ endmntent( fp );
+# else
+ fclose (fp);
+# endif
+ return FALSE;
+}
+
+#endif
+
+/************************************************************************
+|*
+|* DirEntry::IsCaseSensitive()
+|*
+|* Beschreibung
+|* Ersterstellung TPF 25.02.1999
+|* Letzte Aenderung TPF 25.02.1999
+|*
+*************************************************************************/
+
+BOOL DirEntry::IsCaseSensitive( FSysPathStyle eFormatter ) const
+{
+
+ if (eFormatter==FSYS_STYLE_HOST)
+ {
+#ifdef NETBSD
+ return TRUE;
+#else
+ struct stat buf;
+ DirEntry aPath(*this);
+ aPath.ToAbs();
+
+ while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf))
+ {
+ if (aPath.Level() == 1)
+ {
+ return TRUE; // ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv
+ }
+ aPath = aPath [1];
+ }
+
+ struct mymnttab fsmnt;
+ GetMountEntry(buf.st_dev, &fsmnt);
+ if ((fsmnt.mymnttab_filesystem.CompareTo("msdos")==COMPARE_EQUAL) ||
+ (fsmnt.mymnttab_filesystem.CompareTo("umsdos")==COMPARE_EQUAL) ||
+ (fsmnt.mymnttab_filesystem.CompareTo("vfat")==COMPARE_EQUAL) ||
+ (fsmnt.mymnttab_filesystem.CompareTo("hpfs")==COMPARE_EQUAL) ||
+ (fsmnt.mymnttab_filesystem.CompareTo("smb") ==COMPARE_EQUAL) ||
+ (fsmnt.mymnttab_filesystem.CompareTo("ncpfs")==COMPARE_EQUAL))
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+#endif
+ }
+ else
+ {
+ BOOL isCaseSensitive = TRUE; // ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv
+ switch ( eFormatter )
+ {
+ case FSYS_STYLE_MAC:
+ case FSYS_STYLE_FAT:
+ case FSYS_STYLE_VFAT:
+ case FSYS_STYLE_NTFS:
+ case FSYS_STYLE_NWFS:
+ case FSYS_STYLE_HPFS:
+ {
+ isCaseSensitive = FALSE;
+ break;
+ }
+ case FSYS_STYLE_SYSV:
+ case FSYS_STYLE_BSD:
+ case FSYS_STYLE_DETECT:
+ {
+ isCaseSensitive = TRUE;
+ break;
+ }
+ default:
+ {
+ isCaseSensitive = TRUE; // ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv
+ break;
+ }
+ }
+ return isCaseSensitive;
+ }
+}
+
+/************************************************************************
+|*
+|* DirEntry::ToAbs()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91 13:30
+|*
+*************************************************************************/
+
+BOOL DirEntry::ToAbs()
+{
+ if ( FSYS_FLAG_VOLUME == eFlag )
+ {
+ eFlag = FSYS_FLAG_ABSROOT;
+ return TRUE;
+ }
+
+ if ( IsAbs() )
+ return TRUE;
+
+ char sBuf[MAXPATHLEN + 1];
+ *this = DirEntry( String( getcwd( sBuf, MAXPATHLEN ), osl_getThreadTextEncoding() ) ) + *this;
+ return IsAbs();
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetVolume()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 04.03.92
+|* Letzte Aenderung
+|*
+*************************************************************************/
+
+namespace { struct mymnt : public rtl::Static< mymnttab, mymnt > {}; }
+
+String DirEntry::GetVolume() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry aPath( *this );
+ aPath.ToAbs();
+
+ struct stat buf;
+ while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf))
+ {
+ if (aPath.Level() <= 1)
+ return String();
+ aPath = aPath [1];
+ }
+ mymnttab &rMnt = mymnt::get();
+ return ((buf.st_dev == rMnt.mountdevice ||
+ GetMountEntry(buf.st_dev, &rMnt)) ?
+ String(rMnt.mountspecial, osl_getThreadTextEncoding()) :
+ String());
+}
+
+DirEntry DirEntry::GetDevice() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ DirEntry aPath( *this );
+ aPath.ToAbs();
+
+ struct stat buf;
+ while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf))
+ {
+ if (aPath.Level() <= 1)
+ return String();
+ aPath = aPath [1];
+ }
+ mymnttab &rMnt = mymnt::get();
+ return ((buf.st_dev == rMnt.mountdevice ||
+ GetMountEntry(buf.st_dev, &rMnt)) ?
+ String( rMnt.mountpoint, osl_getThreadTextEncoding()) :
+ String());
+}
+
+/*************************************************************************
+|*
+|* DirEntry::SetCWD()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung DV 04.11.92
+|*
+*************************************************************************/
+
+BOOL DirEntry::SetCWD( BOOL bSloppy ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+
+ ByteString aPath( GetFull(), osl_getThreadTextEncoding());
+ if ( !chdir( aPath.GetBuffer() ) )
+ {
+ return TRUE;
+ }
+ else
+ {
+ if ( bSloppy && !chdir(aPath.GetBuffer()) )
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+
+USHORT DirReader_Impl::Init()
+{
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+
+USHORT DirReader_Impl::Read()
+{
+ if (!pDosDir)
+ {
+ pDosDir = opendir( (char*) ByteString(aPath, osl_getThreadTextEncoding()).GetBuffer() );
+ }
+
+ if (!pDosDir)
+ {
+ bReady = TRUE;
+ return 0;
+ }
+
+ // Directories und Files auflisten?
+ if ( ( pDir->eAttrMask & FSYS_KIND_DIR || pDir->eAttrMask & FSYS_KIND_FILE ) &&
+ ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) )
+ {
+ String aD_Name(pDosEntry->d_name, osl_getThreadTextEncoding());
+ if ( pDir->aNameMask.Matches( aD_Name ) )
+ {
+ DirEntryFlag eFlag =
+ 0 == strcmp( pDosEntry->d_name, "." ) ? FSYS_FLAG_CURRENT
+ : 0 == strcmp( pDosEntry->d_name, ".." ) ? FSYS_FLAG_PARENT
+ : FSYS_FLAG_NORMAL;
+ DirEntry *pTemp = new DirEntry( ByteString(pDosEntry->d_name), eFlag, FSYS_STYLE_UNX );
+ if ( pParent )
+ pTemp->ImpChangeParent( new DirEntry( *pParent ), FALSE);
+ FileStat aStat( *pTemp );
+ if ( ( ( ( pDir->eAttrMask & FSYS_KIND_DIR ) &&
+ ( aStat.IsKind( FSYS_KIND_DIR ) ) ) ||
+ ( ( pDir->eAttrMask & FSYS_KIND_FILE ) &&
+ !( aStat.IsKind( FSYS_KIND_DIR ) ) ) ) &&
+ !( pDir->eAttrMask & FSYS_KIND_VISIBLE &&
+ pDosEntry->d_name[0] == '.' ) )
+ {
+ if ( pDir->pStatLst ) //Status fuer Sort gewuenscht?
+ pDir->ImpSortedInsert( pTemp, new FileStat( aStat ) );
+ else
+ pDir->ImpSortedInsert( pTemp, NULL );;
+ return 1;
+ }
+ else
+ delete pTemp;
+ }
+ }
+ else
+ bReady = TRUE;
+ return 0;
+}
+
+/*************************************************************************
+|*
+|* FileStat::FileStat()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MA 05.11.91
+|* Letzte Aenderung MA 07.11.91
+|*
+*************************************************************************/
+
+FileStat::FileStat( const void *, const void * ):
+ aDateCreated(0),
+ aTimeCreated(0),
+ aDateModified(0),
+ aTimeModified(0),
+ aDateAccessed(0),
+ aTimeAccessed(0)
+{
+}
+
+/*************************************************************************
+|*
+|* FileStat::Update()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 11.06.91
+|* Letzte Aenderung MA 07.11.91
+|*
+*************************************************************************/
+BOOL FileStat::Update( const DirEntry& rDirEntry, BOOL )
+{
+
+ nSize = 0;
+ nKindFlags = 0;
+ aCreator.Erase();
+ aType.Erase();
+ aDateCreated = Date(0);
+ aTimeCreated = Time(0);
+ aDateModified = Date(0);
+ aTimeModified = Time(0);
+ aDateAccessed = Date(0);
+ aTimeAccessed = Time(0);
+
+ if ( !rDirEntry.IsValid() )
+ {
+ nError = FSYS_ERR_NOTEXISTS;
+ return FALSE;
+ }
+
+ // Sonderbehandlung falls es sich um eine Root handelt
+ if ( rDirEntry.eFlag == FSYS_FLAG_ABSROOT )
+ {
+ nKindFlags = FSYS_KIND_DIR;
+ nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ struct stat aStat;
+ ByteString aPath( rDirEntry.GetFull(), osl_getThreadTextEncoding() );
+ if ( stat( (char*) aPath.GetBuffer(), &aStat ) )
+ {
+ // pl: #67851#
+ // do this here, because an existing filename containing "wildcards"
+ // should be handled as a file, not a wildcard
+ // note that this is not a solution, since filenames containing special characters
+ // are handled badly across the whole Office
+
+ // Sonderbehandlung falls es sich um eine Wildcard handelt
+ ByteString aTempName( rDirEntry.GetName(), osl_getThreadTextEncoding() );
+ if ( strchr( (char*) aTempName.GetBuffer(), '?' ) ||
+ strchr( (char*) aTempName.GetBuffer(), '*' ) ||
+ strchr( (char*) aTempName.GetBuffer(), ';' ) )
+ {
+ nKindFlags = FSYS_KIND_WILD;
+ nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ nError = FSYS_ERR_NOTEXISTS;
+ return FALSE;
+ }
+
+ nError = FSYS_ERR_OK;
+ nSize = aStat.st_size;
+
+ nKindFlags = FSYS_KIND_UNKNOWN;
+ if ( ( aStat.st_mode & S_IFDIR ) == S_IFDIR )
+ nKindFlags = nKindFlags | FSYS_KIND_DIR;
+ if ( ( aStat.st_mode & S_IFREG ) == S_IFREG )
+ nKindFlags = nKindFlags | FSYS_KIND_FILE;
+ if ( ( aStat.st_mode & S_IFCHR ) == S_IFCHR )
+ nKindFlags = nKindFlags | FSYS_KIND_DEV | FSYS_KIND_CHAR;
+ if ( ( aStat.st_mode & S_IFBLK ) == S_IFBLK )
+ nKindFlags = nKindFlags | FSYS_KIND_DEV | FSYS_KIND_BLOCK;
+ if ( nKindFlags == FSYS_KIND_UNKNOWN )
+ nKindFlags = nKindFlags | FSYS_KIND_FILE;
+
+ Unx2DateAndTime( aStat.st_ctime, aTimeCreated, aDateCreated );
+ Unx2DateAndTime( aStat.st_mtime, aTimeModified, aDateModified );
+ Unx2DateAndTime( aStat.st_atime, aTimeAccessed, aDateAccessed );
+
+ return TRUE;
+}
+
+//====================================================================
+
+const char *TempDirImpl( char *pBuf )
+{
+#ifdef MACOSX
+ // P_tmpdir is /var/tmp on Mac OS X, and it is not cleaned up on system
+ // startup
+ strcpy( pBuf, "/tmp" );
+#else
+ const char *pValue = getenv( "TEMP" );
+ if ( !pValue )
+ pValue = getenv( "TMP" );
+ if ( pValue )
+ strcpy( pBuf, pValue );
+ else
+ // auf Solaris und Linux ist P_tmpdir vorgesehen
+ strcpy( pBuf, P_tmpdir );
+ // hart auf "/tmp" sollte wohl nur im Notfall verwendet werden
+ //strcpy( pBuf, "/tmp" );
+#endif /* MACOSX */
+
+ return pBuf;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetPathStyle() const
+|*
+|* Beschreibung
+|* Ersterstellung MI 11.05.95
+|* Letzte Aenderung MI 11.05.95
+|*
+*************************************************************************/
+
+FSysPathStyle DirEntry::GetPathStyle( const String & )
+{
+ return FSYS_STYLE_UNX;
+}
+
+/*************************************************************************
+|*
+|* FileStat::SetDateTime
+|*
+|* Ersterstellung PB 27.06.97
+|* Letzte Aenderung
+|*
+*************************************************************************/
+
+void FileStat::SetDateTime( const String& rFileName,
+ const DateTime& rNewDateTime )
+{
+ tm times;
+
+ times.tm_year = rNewDateTime.GetYear() - 1900; // 1997 -> 97
+ times.tm_mon = rNewDateTime.GetMonth() - 1; // 0 == Januar!
+ times.tm_mday = rNewDateTime.GetDay();
+
+ times.tm_hour = rNewDateTime.GetHour();
+ times.tm_min = rNewDateTime.GetMin();
+ times.tm_sec = rNewDateTime.GetSec();
+
+ times.tm_wday = 0;
+ times.tm_yday = 0;
+#ifdef SOLARIS
+ times.tm_isdst = -1;
+#else
+ times.tm_isdst = 0;
+#endif
+
+ time_t time = mktime (&times);
+
+ if (time != (time_t) -1)
+ {
+ struct utimbuf u_time;
+ u_time.actime = time;
+ u_time.modtime = time;
+ utime (ByteString(rFileName, osl_getThreadTextEncoding()).GetBuffer(), &u_time);
+ }
+}
+
+//=========================================================================
+
+ErrCode FileStat::QueryDiskSpace( const String &, BigInt &, BigInt & )
+{
+ return ERRCODE_IO_NOTSUPPORTED;
+}
+
+//=========================================================================
+
+void FSysEnableSysErrorBox( BOOL )
+{
+}
+
diff --git a/tools/source/fsys/unx.hxx b/tools/source/fsys/unx.hxx
new file mode 100644
index 000000000000..b6723e8709a3
--- /dev/null
+++ b/tools/source/fsys/unx.hxx
@@ -0,0 +1,95 @@
+/*************************************************************************
+ *
+ * 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 _unx_hxx
+#define _unx_hxx
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <unistd.h>
+/* #include <sysent.h> */
+
+#define FSYS_UNIX TRUE
+#define DRIVE_EXISTS(c) ( TRUE )
+
+#define _mkdir(p) mkdir(p, 0777)
+#define _rmdir rmdir
+#define _chdir chdir
+#define _unlink unlink
+#define _getcwd getcwd
+#define _access access
+
+#ifdef SYSV3
+#define DEFSTYLE FSYS_STYLE_SYSV
+#else
+#define DEFSTYLE FSYS_STYLE_BSD
+#endif
+
+#define CMP_LOWER(s) (s)
+#define TEMPNAME() tmpnam(0)
+#define LOWER(aString) (aString.Lower())
+
+#include <time.h>
+#include <tools/datetime.hxx>
+
+inline Time Unx2Time( time_t nTime )
+{
+ tm atm;
+ tm *pTime;
+ pTime = localtime_r( &nTime, &atm );
+ return Time( pTime->tm_hour,
+ pTime->tm_min,
+ pTime->tm_sec );
+}
+
+inline Date Unx2Date( time_t nDate )
+{
+ tm atm;
+ tm *pTime;
+ pTime = localtime_r( &nDate, &atm );
+ return Date( pTime->tm_mday,
+ pTime->tm_mon + 1,
+ pTime->tm_year + 1900 );
+}
+
+inline void Unx2DateAndTime( time_t nDate, Time& rTime, Date& rDate )
+{
+ tm atm;
+ tm *pTime;
+ pTime = localtime_r( &nDate, &atm );
+ rTime = Time( pTime->tm_hour, pTime->tm_min, pTime->tm_sec );
+ rDate = Date( pTime->tm_mday, pTime->tm_mon + 1, pTime->tm_year + 1900 );
+}
+
+const char* TempDirImpl( char *pBuf );
+
+#define FSysFailOnErrorImpl()
+
+#endif
diff --git a/tools/source/fsys/urlobj.cxx b/tools/source/fsys/urlobj.cxx
new file mode 100644
index 000000000000..b9c4941aa155
--- /dev/null
+++ b/tools/source/fsys/urlobj.cxx
@@ -0,0 +1,5572 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <tools/inetmime.hxx>
+#include "com/sun/star/uno/Reference.hxx"
+#include "com/sun/star/util/XStringWidth.hpp"
+#include "osl/diagnose.h"
+#include "osl/file.hxx"
+#include "rtl/string.h"
+#include "rtl/textenc.h"
+#include "rtl/ustring.hxx"
+#include "sal/types.h"
+
+#ifndef INCLUDED_ALGORITHM
+#include <algorithm>
+#define INCLUDED_ALGORITHM
+#endif
+#ifndef INCLUDED_LIMITS
+#include <limits>
+#define INCLUDED_LIMITS
+#endif
+
+#include <string.h>
+
+namespace unnamed_tools_urlobj {} using namespace unnamed_tools_urlobj;
+ // unnamed namespaces don't work well yet...
+
+using namespace com::sun;
+
+//============================================================================
+//
+// INetURLObject
+//
+//============================================================================
+
+/* The URI grammar (using RFC 2234 conventions).
+
+ Constructs of the form
+ {reference <rule1> using rule2}
+ stand for a rule matching the given rule1 specified in the given reference,
+ encoded to URI syntax using rule2 (as specified in this URI grammar).
+
+
+ ; RFC 1738, RFC 2396, RFC 2732, private
+ login = [user [":" password] "@"] hostport
+ user = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~")
+ password = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~")
+ hostport = host [":" port]
+ host = incomplete-hostname / hostname / IPv4address / IPv6reference
+ incomplete-hostname = *(domainlabel ".") domainlabel
+ hostname = *(domainlabel ".") toplabel ["."]
+ domainlabel = alphanum [*(alphanum / "-") alphanum]
+ toplabel = ALPHA [*(alphanum / "-") alphanum]
+ IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
+ IPv6reference = "[" hexpart [":" IPv4address] "]"
+ hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
+ hexseq = hex4 *(":" hex4)
+ hex4 = 1*4HEXDIG
+ port = *DIGIT
+ escaped = "%" HEXDIG HEXDIG
+ reserved = "$" / "&" / "+" / "," / "/" / ":" / ";" / "=" / "?" / "@" / "[" / "]"
+ mark = "!" / "'" / "(" / ")" / "*" / "-" / "." / "_" / "~"
+ alphanum = ALPHA / DIGIT
+ unreserved = alphanum / mark
+ uric = escaped / reserved / unreserved
+ pchar = escaped / unreserved / "$" / "&" / "+" / "," / ":" / "=" / "@"
+
+
+ ; RFC 1738, RFC 2396
+ ftp-url = "FTP://" login ["/" segment *("/" segment) [";TYPE=" ("A" / "D" / "I")]]
+ segment = *pchar
+
+
+ ; RFC 1738, RFC 2396
+ http-url = "HTTP://" hostport ["/" segment *("/" segment) ["?" *uric]]
+ segment = *(pchar / ";")
+
+
+ ; RFC 1738, RFC 2396, <http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q188997&>
+ file-url = "FILE://" [host / "LOCALHOST" / netbios-name] ["/" segment *("/" segment)]
+ segment = *pchar
+ netbios-name = 1*{<alphanum / "!" / "#" / "$" / "%" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "^" / "_" / "{" / "}" / "~"> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "_" / "~")}
+
+
+ ; RFC 2368, RFC 2396
+ mailto-url = "MAILTO:" [to] [headers]
+ to = {RFC 822 <#mailbox> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
+ headers = "?" header *("&" header)
+ header = hname "=" hvalue
+ hname = {RFC 822 <field-name> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} / "BODY"
+ hvalue = {RFC 822 <field-body> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
+
+
+ ; private (see RFC 1738, RFC 2396)
+ vnd-sun-star-webdav-url = "VND.SUN.STAR.WEBDAV://" hostport ["/" segment *("/" segment) ["?" *uric]]
+ segment = *(pchar / ";")
+
+
+ ; RFC 1738, RFC 2396, RFC 2732
+ news-url = "NEWS:" grouppart
+ grouppart = "*" / group / article
+ group = alpha *(alphanum / "+" / "-" / "." / "_")
+ article = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "?" / "_" / "~") "@" host
+
+
+ ; private
+ private-url = "PRIVATE:" path ["?" *uric]
+ path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
+
+
+ ; private
+ vnd-sun-star-help-url = "VND.SUN.STAR.HELP://" name *("/" segment) ["?" *uric]
+ name = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
+ segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
+
+
+ ; private
+ https-url = "HTTPS://" hostport ["/" segment *("/" segment) ["?" *uric]]
+ segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
+
+
+ ; private
+ slot-url = "SLOT:" path ["?" *uric]
+ path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
+
+
+ ; private
+ macro-url = "MACRO:" path ["?" *uric]
+ path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
+
+
+ ; private
+ javascript-url = "JAVASCRIPT:" *uric
+
+
+ ; private (see RFC 2192)
+ imap-url = "IMAP://" user [";AUTH=" auth] "@" hostport "/" segment *("/" segment) ["/;UID=" nz_number]
+ user = 1*{RFC 2060 <CHAR8> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "=" / "_" / "~")}
+ auth = {RFC 2060 <atom> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "+" / "," / "-" / "." / "=" / "_" / "~")}
+ segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / "=" / "@" / "_" / "~")
+ nz_number = {RFC 2060 <nz_number> using *DIGIT}
+
+
+ ; private
+ pop3-url = "POP3://" login ["/" ["<" *uric ">"]]
+
+
+ ; RFC 2397
+ data-url = "DATA:" [mediatype] [";BASE64"] "," *uric
+ mediatype = [type "/" subtype] *(";" attribute "=" value)
+ type = {RFC 2045 <type> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
+ subtype = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
+ attribute = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
+ value = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
+
+
+ ; RFC 2392, RFC 2396
+ cid-url = "CID:" {RFC 822 <addr-spec> using *uric}
+
+
+ ; private
+ out-url = "OUT:///~" name ["/" *uric]
+ name = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "?" / "@" / "_" / "~"
+
+
+ ; private
+ vnd-sun-star-hier-url = "VND.SUN.STAR.HIER:" ["//"reg_name] *("/" *pchar)
+ reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
+
+ ; private
+ vim-url = "VIM://" +vimc [":" *vimc] ["/" [("INBOX" message) / ("NEWSGROUPS" ["/" [+vimc message]])]]
+ message = ["/" [+vimc [":" +DIGIT "." +DIGIT "." +DIGIT]]]
+ vimc = ("=" HEXDIG HEXDIG) / alphanum
+
+
+ ; private
+ uno-url = ".UNO:" path ["?" *uric]
+ path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
+
+
+ ; private
+ component-url = ".COMPONENT:" path ["?" *uric]
+ path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
+
+
+ ; private
+ vnd-sun-star-pkg-url = "VND.SUN.STAR.PKG://" reg_name *("/" *pchar) ["?" *uric]
+ reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
+
+
+ ; RFC 2255
+ ldap-url = "LDAP://" [hostport] ["/" [dn ["?" [attrdesct *("," attrdesc)] ["?" ["base" / "one" / "sub"] ["?" [filter] ["?" extension *("," extension)]]]]]]
+ dn = {RFC 2253 <distinguishedName> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
+ attrdesc = {RFC 2251 <AttributeDescription> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
+ filter = {RFC 2254 <filter> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
+ extension = ["!"] ["X-"] extoken ["=" exvalue]
+ extoken = {RFC 2252 <oid> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
+ exvalue = {RFC 2251 <LDAPString> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
+
+
+ ; private
+ db-url = "DB:" *uric
+
+
+ ; private
+ vnd-sun-star-cmd-url = "VND.SUN.STAR.CMD:" opaque_part
+ opaque_part = uric_no_slash *uric
+ uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
+
+
+ ; private
+ vnd-sun-star-url = "VND.SUN.STAR.ODMA:" ["/" *uric_no_slash]
+ uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
+
+
+ ; RFC 1738
+ telnet-url = "TELNET://" login ["/"]
+
+
+ ; private
+ vnd-sun-star-expand-url = "VND.SUN.STAR.EXPAND:" opaque_part
+ opaque_part = uric_no_slash *uric
+ uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
+
+
+ ; private
+ vnd-sun-star-tdoc-url = "VND.SUN.STAR.TDOC:/" segment *("/" segment)
+ segment = *pchar
+
+
+ ; private
+ unknown-url = scheme ":" 1*uric
+ scheme = ALPHA *(alphanum / "+" / "-" / ".")
+
+
+ ; private (http://ubiqx.org/cifs/Appendix-D.html):
+ smb-url = "SMB://" login ["/" segment *("/" segment) ["?" *uric]]
+ segment = *(pchar / ";")
+ */
+
+//============================================================================
+inline sal_Int32 INetURLObject::SubString::clear()
+{
+ sal_Int32 nDelta = -m_nLength;
+ m_nBegin = -1;
+ m_nLength = 0;
+ return nDelta;
+}
+
+inline sal_Int32 INetURLObject::SubString::set(rtl::OUStringBuffer & rString,
+ rtl::OUString const & rSubString)
+{
+ rtl::OUString sTemp(rString.makeStringAndClear());
+ sal_Int32 nDelta = set(sTemp, rSubString);
+ rString.append(sTemp);
+ return nDelta;
+}
+
+inline sal_Int32 INetURLObject::SubString::set(rtl::OUString & rString,
+ rtl::OUString const & rSubString)
+{
+ sal_Int32 nDelta = rSubString.getLength() - m_nLength;
+
+ rString = rString.replaceAt(m_nBegin, m_nLength, rSubString);
+
+ m_nLength = rSubString.getLength();
+ return nDelta;
+}
+
+inline sal_Int32 INetURLObject::SubString::set(rtl::OUStringBuffer & rString,
+ rtl::OUString const & rSubString,
+ sal_Int32 nTheBegin)
+{
+ m_nBegin = nTheBegin;
+ return set(rString, rSubString);
+}
+
+//============================================================================
+inline void INetURLObject::SubString::operator +=(sal_Int32 nDelta)
+{
+ if (isPresent())
+ m_nBegin = m_nBegin + nDelta;
+}
+
+//============================================================================
+int INetURLObject::SubString::compare(SubString const & rOther,
+ rtl::OUStringBuffer const & rThisString,
+ rtl::OUStringBuffer const & rOtherString) const
+{
+ sal_Int32 len = std::min(m_nLength, rOther.m_nLength);
+ sal_Unicode const * p1 = rThisString.getStr() + m_nBegin;
+ sal_Unicode const * end = p1 + len;
+ sal_Unicode const * p2 = rOtherString.getStr() + rOther.m_nBegin;
+ while (p1 != end) {
+ if (*p1 < *p2) {
+ return -1;
+ } else if (*p1 > *p2) {
+ return 1;
+ }
+ ++p1;
+ ++p2;
+ }
+ return m_nLength < rOther.m_nLength ? -1
+ : m_nLength > rOther.m_nLength ? 1
+ : 0;
+}
+
+//============================================================================
+struct INetURLObject::SchemeInfo
+{
+ sal_Char const * m_pScheme;
+ sal_Char const * m_pPrefix;
+ sal_uInt16 m_nDefaultPort;
+ bool m_bAuthority;
+ bool m_bUser;
+ bool m_bAuth;
+ bool m_bPassword;
+ bool m_bHost;
+ bool m_bPort;
+ bool m_bHierarchical;
+ bool m_bQuery;
+};
+
+//============================================================================
+struct INetURLObject::PrefixInfo
+{
+ enum Kind { OFFICIAL, INTERNAL, EXTERNAL, ALIAS }; // order is important!
+
+ sal_Char const * m_pPrefix;
+ sal_Char const * m_pTranslatedPrefix;
+ INetProtocol m_eScheme;
+ Kind m_eKind;
+};
+
+//============================================================================
+static INetURLObject::SchemeInfo const aSchemeInfoMap[INET_PROT_END]
+ = { { "", "", 0, false, false, false, false, false, false, false,
+ false },
+ { "ftp", "ftp://", 21, true, true, false, true, true, true, true,
+ false },
+ { "http", "http://", 80, true, false, false, false, true, true,
+ true, true },
+ { "file", "file://", 0, true, false, false, false, true, false,
+ true, false },
+ { "mailto", "mailto:", 0, false, false, false, false, false,
+ false, false, true },
+ { "vnd.sun.star.webdav", "vnd.sun.star.webdav://", 80, true, false,
+ false, false, true, true, true, true },
+ { "news", "news:", 0, false, false, false, false, false, false, false,
+ false },
+ { "private", "private:", 0, false, false, false, false, false,
+ false, false, true },
+ { "vnd.sun.star.help", "vnd.sun.star.help://", 0, true, false, false,
+ false, false, false, true, true },
+ { "https", "https://", 443, true, false, false, false, true, true,
+ true, true },
+ { "slot", "slot:", 0, false, false, false, false, false, false,
+ false, true },
+ { "macro", "macro:", 0, false, false, false, false, false, false,
+ false, true },
+ { "javascript", "javascript:", 0, false, false, false, false,
+ false, false, false, false },
+ { "imap", "imap://", 143, true, true, true, false, true, true,
+ true, false },
+ { "pop3", "pop3://", 110, true, true, false, true, true, true,
+ false, false },
+ { "data", "data:", 0, false, false, false, false, false, false,
+ false, false },
+ { "cid", "cid:", 0, false, false, false, false, false, false,
+ false, false },
+ { "out", "out://", 0, true, false, false, false, false, false,
+ false, false },
+ { "vnd.sun.star.hier", "vnd.sun.star.hier:", 0, true, false, false,
+ false, false, false, true, false },
+ { "vim", "vim://", 0, true, true, false, true, false, false, true,
+ false },
+ { ".uno", ".uno:", 0, false, false, false, false, false, false,
+ false, true },
+ { ".component", ".component:", 0, false, false, false, false,
+ false, false, false, true },
+ { "vnd.sun.star.pkg", "vnd.sun.star.pkg://", 0, true, false, false,
+ false, false, false, true, true },
+ { "ldap", "ldap://", 389, true, false, false, false, true, true,
+ false, true },
+ { "db", "db:", 0, false, false, false, false, false, false, false,
+ false },
+ { "vnd.sun.star.cmd", "vnd.sun.star.cmd:", 0, false, false, false,
+ false, false, false, false, false },
+ { "vnd.sun.star.odma", "vnd.sun.star.odma:", 0, false, false, false,
+ false, false, false, true, false },
+ { "telnet", "telnet://", 23, true, true, false, true, true, true, true,
+ false },
+ { "vnd.sun.star.expand", "vnd.sun.star.expand:", 0, false, false, false,
+ false, false, false, false, false },
+ { "vnd.sun.star.tdoc", "vnd.sun.star.tdoc:", 0, false, false, false,
+ false, false, false, true, false },
+ { "", "", 0, false, false, false, false, true, true, true, false },
+ { "smb", "smb://", 139, true, true, false, true, true, true, true,
+ true } };
+
+// static
+inline INetURLObject::SchemeInfo const &
+INetURLObject::getSchemeInfo(INetProtocol eTheScheme)
+{
+ return aSchemeInfoMap[eTheScheme];
+};
+
+//============================================================================
+inline INetURLObject::SchemeInfo const & INetURLObject::getSchemeInfo() const
+{
+ return getSchemeInfo(m_eScheme);
+}
+
+//============================================================================
+// static
+inline void INetURLObject::appendEscape(rtl::OUStringBuffer & rTheText,
+ sal_Char cEscapePrefix,
+ sal_uInt32 nOctet)
+{
+ rTheText.append(sal_Unicode(cEscapePrefix));
+ rTheText.append(sal_Unicode(INetMIME::getHexDigit(int(nOctet >> 4))));
+ rTheText.append(sal_Unicode(INetMIME::getHexDigit(int(nOctet & 15))));
+}
+
+//============================================================================
+namespace unnamed_tools_urlobj {
+
+enum
+{
+ PA = INetURLObject::PART_OBSOLETE_NORMAL,
+ PB = INetURLObject::PART_OBSOLETE_FILE,
+ PC = INetURLObject::PART_OBSOLETE_PARAM,
+ PD = INetURLObject::PART_USER_PASSWORD,
+ PE = INetURLObject::PART_IMAP_ACHAR,
+ PF = INetURLObject::PART_VIM,
+ PG = INetURLObject::PART_HOST_EXTRA,
+ PH = INetURLObject::PART_FPATH,
+ PI = INetURLObject::PART_AUTHORITY,
+ PJ = INetURLObject::PART_PATH_SEGMENTS_EXTRA,
+ PK = INetURLObject::PART_REL_SEGMENT_EXTRA,
+ PL = INetURLObject::PART_URIC,
+ PM = INetURLObject::PART_HTTP_PATH,
+ PN = INetURLObject::PART_FILE_SEGMENT_EXTRA,
+ PO = INetURLObject::PART_MESSAGE_ID,
+ PP = INetURLObject::PART_MESSAGE_ID_PATH,
+ PQ = INetURLObject::PART_MAILTO,
+ PR = INetURLObject::PART_PATH_BEFORE_QUERY,
+ PS = INetURLObject::PART_PCHAR,
+ PT = INetURLObject::PART_FRAGMENT,
+ PU = INetURLObject::PART_VISIBLE,
+ PV = INetURLObject::PART_VISIBLE_NONSPECIAL,
+ PW = INetURLObject::PART_CREATEFRAGMENT,
+ PX = INetURLObject::PART_UNO_PARAM_VALUE,
+ PY = INetURLObject::PART_UNAMBIGUOUS,
+ PZ = INetURLObject::PART_URIC_NO_SLASH,
+ P1 = INetURLObject::PART_HTTP_QUERY,
+ P2 = INetURLObject::PART_NEWS_ARTICLE_LOCALPART
+};
+
+static sal_uInt32 const aMustEncodeMap[128]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* */ PY,
+/* ! */ PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* " */ PU+PV +PY,
+/* # */ PU,
+/* $ */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* % */ PU,
+/* & */ PA+PB+PC+PD+PE +PH+PI+PJ+PK+PL+PM+PN+PO+PP +PR+PS+PT+PU+PV+PW+PX +PZ+P1+P2,
+/* ' */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* ( */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* ) */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* * */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* + */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX +PZ+P1+P2,
+/* , */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW +PZ+P1+P2,
+/* - */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* . */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* / */ PA+PB+PC +PH +PJ +PL+PM +PP+PQ+PR +PT+PU+PV +PX +P2,
+/* 0 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 1 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 2 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 3 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 4 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 5 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 6 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 7 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 8 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* 9 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* : */ PB+PC +PH+PI+PJ +PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX +PZ+P1+P2,
+/* ; */ PC+PD +PI+PJ+PK+PL+PM +PO+PP+PQ+PR +PT+PU +PW +PZ+P1+P2,
+/* < */ PC +PO+PP +PU+PV +PY,
+/* = */ PA+PB+PC+PD+PE +PH+PI+PJ+PK+PL+PM+PN +PR+PS+PT+PU+PV+PW +PZ+P1+P2,
+/* > */ PC +PO+PP +PU+PV +PY,
+/* ? */ PC +PL +PT+PU +PW+PX +PZ +P2,
+/* @ */ PC +PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1,
+/* A */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* B */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* C */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* D */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* E */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* F */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* G */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* H */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* I */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* J */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* K */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* L */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* M */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* N */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* O */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* P */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* Q */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* R */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* S */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* T */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* U */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* V */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* W */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* X */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* Y */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* Z */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* [ */ PL +PU+PV +PX,
+/* \ */ PB +PU+PV +PY,
+/* ] */ PL +PU+PV +PX,
+/* ^ */ PU+PV +PY,
+/* _ */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* ` */ PU+PV +PY,
+/* a */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* b */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* c */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* d */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* e */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* f */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* g */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* h */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* i */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* j */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* k */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* l */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* m */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* n */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* o */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* p */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* q */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* r */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* s */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* t */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* u */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* v */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* w */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* x */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* y */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* z */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
+/* { */ PU+PV +PY,
+/* | */ PB+PC +PN +PT+PU+PV +PY,
+/* } */ PU+PV +PY,
+/* ~ */ PA+PB+PC+PD+PE +PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ +P2,
+ 0 };
+
+inline bool mustEncode(sal_uInt32 nUTF32, INetURLObject::Part ePart)
+{
+ return !INetMIME::isUSASCII(nUTF32) || !(aMustEncodeMap[nUTF32] & ePart);
+}
+
+}
+
+//============================================================================
+void INetURLObject::setInvalid()
+{
+ m_aAbsURIRef.setLength(0);
+ m_eScheme = INET_PROT_NOT_VALID;
+ m_aScheme.clear();
+ m_aUser.clear();
+ m_aAuth.clear();
+ m_aHost.clear();
+ m_aPort.clear();
+ m_aPath.clear();
+ m_aQuery.clear();
+ m_aFragment.clear();
+}
+
+//============================================================================
+
+namespace unnamed_tools_urlobj {
+
+INetURLObject::FSysStyle
+guessFSysStyleByCounting(sal_Unicode const * pBegin,
+ sal_Unicode const * pEnd,
+ INetURLObject::FSysStyle eStyle)
+{
+ DBG_ASSERT(eStyle
+ & (INetURLObject::FSYS_UNX
+ | INetURLObject::FSYS_DOS
+ | INetURLObject::FSYS_MAC),
+ "guessFSysStyleByCounting(): Bad style");
+ DBG_ASSERT(std::numeric_limits< sal_Int32 >::min() < pBegin - pEnd
+ && pEnd - pBegin <= std::numeric_limits< sal_Int32 >::max(),
+ "guessFSysStyleByCounting(): Too big");
+ sal_Int32 nSlashCount
+ = eStyle & INetURLObject::FSYS_UNX ?
+ 0 : std::numeric_limits< sal_Int32 >::min();
+ sal_Int32 nBackslashCount
+ = eStyle & INetURLObject::FSYS_DOS ?
+ 0 : std::numeric_limits< sal_Int32 >::min();
+ sal_Int32 nColonCount
+ = eStyle & INetURLObject::FSYS_MAC ?
+ 0 : std::numeric_limits< sal_Int32 >::min();
+ while (pBegin != pEnd)
+ switch (*pBegin++)
+ {
+ case '/':
+ ++nSlashCount;
+ break;
+
+ case '\\':
+ ++nBackslashCount;
+ break;
+
+ case ':':
+ ++nColonCount;
+ break;
+ }
+ return nSlashCount >= nBackslashCount ?
+ nSlashCount >= nColonCount ?
+ INetURLObject::FSYS_UNX : INetURLObject::FSYS_MAC :
+ nBackslashCount >= nColonCount ?
+ INetURLObject::FSYS_DOS : INetURLObject::FSYS_MAC;
+}
+
+rtl::OUString parseScheme(
+ sal_Unicode const ** begin, sal_Unicode const * end,
+ sal_uInt32 fragmentDelimiter)
+{
+ sal_Unicode const * p = *begin;
+ if (p != end && INetMIME::isAlpha(*p)) {
+ do {
+ ++p;
+ } while (p != end
+ && (INetMIME::isAlphanumeric(*p) || *p == '+' || *p == '-'
+ || *p == '.'));
+ // #i34835# To avoid problems with Windows file paths like "C:\foo",
+ // do not accept generic schemes that are only one character long:
+ if (end - p > 1 && p[0] == ':' && p[1] != fragmentDelimiter
+ && p - *begin >= 2)
+ {
+ rtl::OUString scheme(
+ rtl::OUString(*begin, p - *begin).toAsciiLowerCase());
+ *begin = p + 1;
+ return scheme;
+ }
+ }
+ return rtl::OUString();
+}
+
+}
+
+bool INetURLObject::setAbsURIRef(rtl::OUString const & rTheAbsURIRef,
+ bool bOctets,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset,
+ bool bSmart,
+ FSysStyle eStyle)
+{
+ sal_Unicode const * pPos = rTheAbsURIRef.getStr();
+ sal_Unicode const * pEnd = pPos + rTheAbsURIRef.getLength();
+
+ setInvalid();
+
+ sal_uInt32 nFragmentDelimiter = '#';
+
+ rtl::OUStringBuffer aSynAbsURIRef;
+
+ // Parse <scheme>:
+ sal_Unicode const * p = pPos;
+ PrefixInfo const * pPrefix = getPrefix(p, pEnd);
+ if (pPrefix)
+ {
+ pPos = p;
+ m_eScheme = pPrefix->m_eScheme;
+
+ rtl::OUString sTemp(rtl::OUString::createFromAscii(pPrefix->m_eKind
+ >= PrefixInfo::EXTERNAL ?
+ pPrefix->m_pTranslatedPrefix :
+ pPrefix->m_pPrefix));
+ aSynAbsURIRef.append(sTemp);
+ m_aScheme = SubString( 0, sTemp.indexOf(static_cast< sal_Unicode >(':')) );
+ }
+ else
+ {
+ if (bSmart)
+ {
+ // For scheme detection, the first (if any) of the following
+ // productions that matches the input string (and for which the
+ // appropriate style bit is set in eStyle, if applicable)
+ // determines the scheme. The productions use the auxiliary rules
+ //
+ // domain = label *("." label)
+ // label = alphanum [*(alphanum / "-") alphanum]
+ // alphanum = ALPHA / DIGIT
+ // IPv6reference = "[" IPv6address "]"
+ // IPv6address = hexpart [":" IPv4address]
+ // IPv4address = 1*3DIGIT 3("." 1*3DIGIT)
+ // hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
+ // hexseq = hex4 *(":" hex4)
+ // hex4 = 1*4HEXDIG
+ // UCS4 = <any UCS4 character>
+ //
+ // 1st Production (known scheme):
+ // <one of the known schemes, ignoring case> ":" *UCS4
+ //
+ // 2nd Production (mailto):
+ // domain "@" domain
+ //
+ // 3rd Production (ftp):
+ // "FTP" 2*("." label) ["/" *UCS4]
+ //
+ // 4th Production (http):
+ // label 2*("." label) ["/" *UCS4]
+ //
+ // 5th Production (file):
+ // "//" (domain / IPv6reference) ["/" *UCS4]
+ //
+ // 6th Production (Unix file):
+ // "/" *UCS4
+ //
+ // 7th Production (UNC file; FSYS_DOS only):
+ // "\\" domain ["\" *UCS4]
+ //
+ // 8th Production (Unix-like DOS file; FSYS_DOS only):
+ // ALPHA ":" ["/" *UCS4]
+ //
+ // 9th Production (DOS file; FSYS_DOS only):
+ // ALPHA ":" ["\" *UCS4]
+ //
+ // For the 'non URL' file productions 6--9, the interpretation of
+ // the input as a (degenerate) URI is turned off, i.e., escape
+ // sequences and fragments are never detected as such, but are
+ // taken as literal characters.
+
+ sal_Unicode const * p1 = pPos;
+ if (eStyle & FSYS_DOS
+ && pEnd - p1 >= 2
+ && INetMIME::isAlpha(p1[0])
+ && p1[1] == ':'
+ && (pEnd - p1 == 2 || p1[2] == '/' || p1[2] == '\\'))
+ {
+ m_eScheme = INET_PROT_FILE; // 8th, 9th
+ eMechanism = ENCODE_ALL;
+ nFragmentDelimiter = 0x80000000;
+ }
+ else if (pEnd - p1 >= 2 && p1[0] == '/' && p1[1] == '/')
+ {
+ p1 += 2;
+ if ((scanDomain(p1, pEnd) > 0 || scanIPv6reference(p1, pEnd))
+ && (p1 == pEnd || *p1 == '/'))
+ m_eScheme = INET_PROT_FILE; // 5th
+ }
+ else if (p1 != pEnd && *p1 == '/')
+ {
+ m_eScheme = INET_PROT_FILE; // 6th
+ eMechanism = ENCODE_ALL;
+ nFragmentDelimiter = 0x80000000;
+ }
+ else if (eStyle & FSYS_DOS
+ && pEnd - p1 >= 2
+ && p1[0] == '\\'
+ && p1[1] == '\\')
+ {
+ p1 += 2;
+ sal_Int32 n = rtl_ustr_indexOfChar_WithLength(
+ p1, pEnd - p1, '\\');
+ sal_Unicode const * pe = n == -1 ? pEnd : p1 + n;
+ if (
+ parseHostOrNetBiosName(
+ p1, pe, bOctets, ENCODE_ALL, RTL_TEXTENCODING_DONTKNOW,
+ true, NULL) ||
+ (scanDomain(p1, pe) > 0 && p1 == pe)
+ )
+ {
+ m_eScheme = INET_PROT_FILE; // 7th
+ eMechanism = ENCODE_ALL;
+ nFragmentDelimiter = 0x80000000;
+ }
+ }
+ else
+ {
+ sal_Unicode const * pDomainEnd = p1;
+ sal_uInt32 nLabels = scanDomain(pDomainEnd, pEnd);
+ if (nLabels > 0 && pDomainEnd != pEnd && *pDomainEnd == '@')
+ {
+ ++pDomainEnd;
+ if (scanDomain(pDomainEnd, pEnd) > 0
+ && pDomainEnd == pEnd)
+ m_eScheme = INET_PROT_MAILTO; // 2nd
+ }
+ else if (nLabels >= 3
+ && (pDomainEnd == pEnd || *pDomainEnd == '/'))
+ m_eScheme
+ = pDomainEnd - p1 >= 4
+ && (p1[0] == 'f' || p1[0] == 'F')
+ && (p1[1] == 't' || p1[1] == 'T')
+ && (p1[2] == 'p' || p1[2] == 'P')
+ && p1[3] == '.' ?
+ INET_PROT_FTP : INET_PROT_HTTP; // 3rd, 4th
+ }
+ }
+
+ rtl::OUString aSynScheme;
+ if (m_eScheme == INET_PROT_NOT_VALID) {
+ sal_Unicode const * p1 = pPos;
+ aSynScheme = parseScheme(&p1, pEnd, nFragmentDelimiter);
+ if (aSynScheme.getLength() > 0)
+ {
+ m_eScheme = INET_PROT_GENERIC;
+ pPos = p1;
+ }
+ }
+
+ if (bSmart && m_eScheme == INET_PROT_NOT_VALID && pPos != pEnd
+ && *pPos != nFragmentDelimiter)
+ {
+ m_eScheme = m_eSmartScheme;
+ }
+
+ if (m_eScheme == INET_PROT_NOT_VALID)
+ {
+ setInvalid();
+ return false;
+ }
+
+ if (m_eScheme != INET_PROT_GENERIC) {
+ aSynScheme = rtl::OUString::createFromAscii(getSchemeInfo().m_pScheme);
+ }
+ m_aScheme.set(aSynAbsURIRef, aSynScheme, aSynAbsURIRef.getLength());
+ aSynAbsURIRef.append(sal_Unicode(':'));
+ }
+
+ sal_Char cEscapePrefix = getEscapePrefix();
+ sal_uInt32 nSegmentDelimiter = '/';
+ sal_uInt32 nAltSegmentDelimiter = 0x80000000;
+ bool bSkippedInitialSlash = false;
+
+ // Parse //<user>;AUTH=<auth>@<host>:<port> or
+ // //<user>:<password>@<host>:<port> or
+ // //<reg_name>
+ if (getSchemeInfo().m_bAuthority)
+ {
+ sal_Unicode const * pUserInfoBegin = 0;
+ sal_Unicode const * pUserInfoEnd = 0;
+ sal_Unicode const * pHostPortBegin = 0;
+ sal_Unicode const * pHostPortEnd = 0;
+
+ switch (m_eScheme)
+ {
+ case INET_PROT_VND_SUN_STAR_HELP:
+ {
+ if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/')
+ {
+ setInvalid();
+ return false;
+ }
+ aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ rtl::OUStringBuffer aSynAuthority;
+ while (pPos < pEnd
+ && *pPos != '/' && *pPos != '?'
+ && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ cEscapePrefix, eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aSynAuthority, nUTF32, eEscapeType, bOctets,
+ PART_AUTHORITY, cEscapePrefix, eCharset,
+ false);
+ }
+ m_aHost.set(aSynAbsURIRef,
+ aSynAuthority.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ // misusing m_aHost to store the authority
+ break;
+ }
+
+ case INET_PROT_VND_SUN_STAR_HIER:
+ {
+ if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
+ {
+ pPos += 2;
+ aSynAbsURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ rtl::OUStringBuffer aSynAuthority;
+ while (pPos < pEnd
+ && *pPos != '/' && *pPos != '?'
+ && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos,
+ pEnd,
+ bOctets,
+ cEscapePrefix,
+ eMechanism,
+ eCharset,
+ eEscapeType);
+ appendUCS4(aSynAuthority,
+ nUTF32,
+ eEscapeType,
+ bOctets,
+ PART_AUTHORITY,
+ cEscapePrefix,
+ eCharset,
+ false);
+ }
+ if (aSynAuthority.getLength() == 0)
+ {
+ setInvalid();
+ return false;
+ }
+ m_aHost.set(aSynAbsURIRef,
+ aSynAuthority.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ // misusing m_aHost to store the authority
+ }
+ break;
+ }
+
+ case INET_PROT_VND_SUN_STAR_PKG:
+ {
+ if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/')
+ {
+ setInvalid();
+ return false;
+ }
+ aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ rtl::OUStringBuffer aSynAuthority;
+ while (pPos < pEnd
+ && *pPos != '/' && *pPos != '?'
+ && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ cEscapePrefix, eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aSynAuthority, nUTF32, eEscapeType, bOctets,
+ PART_AUTHORITY, cEscapePrefix, eCharset,
+ false);
+ }
+ if (aSynAuthority.getLength() == 0)
+ {
+ setInvalid();
+ return false;
+ }
+ m_aHost.set(aSynAbsURIRef,
+ aSynAuthority.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ // misusing m_aHost to store the authority
+ break;
+ }
+
+ case INET_PROT_FILE:
+ if (bSmart)
+ {
+ // The first of the following seven productions that
+ // matches the rest of the input string (and for which the
+ // appropriate style bit is set in eStyle, if applicable)
+ // determines the used notation. The productions use the
+ // auxiliary rules
+ //
+ // domain = label *("." label)
+ // label = alphanum [*(alphanum / "-") alphanum]
+ // alphanum = ALPHA / DIGIT
+ // IPv6reference = "[" IPv6address "]"
+ // IPv6address = hexpart [":" IPv4address]
+ // IPv4address = 1*3DIGIT 3("." 1*3DIGIT)
+ // hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
+ // hexseq = hex4 *(":" hex4)
+ // hex4 = 1*4HEXDIG
+ // path = <any UCS4 character except "#">
+ // UCS4 = <any UCS4 character>
+
+ // 1st Production (URL):
+ // "//" [domain / IPv6reference] ["/" *path]
+ // ["#" *UCS4]
+ // becomes
+ // "file://" domain "/" *path ["#" *UCS4]
+ if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
+ {
+ sal_Unicode const * p1 = pPos + 2;
+ while (p1 != pEnd && *p1 != '/' &&
+ *p1 != nFragmentDelimiter)
+ {
+ ++p1;
+ }
+ if (parseHostOrNetBiosName(
+ pPos + 2, p1, bOctets, ENCODE_ALL,
+ RTL_TEXTENCODING_DONTKNOW, true, NULL))
+ {
+ aSynAbsURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ pHostPortBegin = pPos + 2;
+ pHostPortEnd = p1;
+ pPos = p1;
+ break;
+ }
+ }
+
+ // 2nd Production (MS IE generated 1; FSYS_DOS only):
+ // "//" ALPHA ":" ["/" *path] ["#" *UCS4]
+ // becomes
+ // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
+ // replacing "\" by "/" within <*path>
+ //
+ // 3rd Production (MS IE generated 2; FSYS_DOS only):
+ // "//" ALPHA ":" ["\" *path] ["#" *UCS4]
+ // becomes
+ // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
+ // replacing "\" by "/" within <*path>
+ //
+ // 4th Production (misscounted slashes):
+ // "//" *path ["#" *UCS4]
+ // becomes
+ // "file:///" *path ["#" *UCS4]
+ if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
+ {
+ aSynAbsURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ pPos += 2;
+ bSkippedInitialSlash = true;
+ if ((eStyle & FSYS_DOS) != 0
+ && pEnd - pPos >= 2
+ && INetMIME::isAlpha(pPos[0])
+ && pPos[1] == ':'
+ && (pEnd - pPos == 2
+ || pPos[2] == '/' || pPos[2] == '\\'))
+ nAltSegmentDelimiter = '\\';
+ break;
+ }
+
+ // 5th Production (Unix):
+ // "/" *path ["#" *UCS4]
+ // becomes
+ // "file:///" *path ["#" *UCS4]
+ if (pPos < pEnd && *pPos == '/')
+ {
+ aSynAbsURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ break;
+ }
+
+ // 6th Production (UNC; FSYS_DOS only):
+ // "\\" domain ["\" *path] ["#" *UCS4]
+ // becomes
+ // "file://" domain "/" *path ["#" *UCS4]
+ // replacing "\" by "/" within <*path>
+ if (eStyle & FSYS_DOS
+ && pEnd - pPos >= 2
+ && pPos[0] == '\\'
+ && pPos[1] == '\\')
+ {
+ sal_Unicode const * p1 = pPos + 2;
+ sal_Unicode const * pe = p1;
+ while (pe < pEnd && *pe != '\\' &&
+ *pe != nFragmentDelimiter)
+ {
+ ++pe;
+ }
+ if (
+ parseHostOrNetBiosName(
+ p1, pe, bOctets, ENCODE_ALL,
+ RTL_TEXTENCODING_DONTKNOW, true, NULL) ||
+ (scanDomain(p1, pe) > 0 && p1 == pe)
+ )
+ {
+ aSynAbsURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ pHostPortBegin = pPos + 2;
+ pHostPortEnd = pe;
+ pPos = pe;
+ nSegmentDelimiter = '\\';
+ break;
+ }
+ }
+
+ // 7th Production (Unix-like DOS; FSYS_DOS only):
+ // ALPHA ":" ["/" *path] ["#" *UCS4]
+ // becomes
+ // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
+ // replacing "\" by "/" within <*path>
+ //
+ // 8th Production (DOS; FSYS_DOS only):
+ // ALPHA ":" ["\" *path] ["#" *UCS4]
+ // becomes
+ // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
+ // replacing "\" by "/" within <*path>
+ if (eStyle & FSYS_DOS
+ && pEnd - pPos >= 2
+ && INetMIME::isAlpha(pPos[0])
+ && pPos[1] == ':'
+ && (pEnd - pPos == 2
+ || pPos[2] == '/'
+ || pPos[2] == '\\'))
+ {
+ aSynAbsURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ nAltSegmentDelimiter = '\\';
+ bSkippedInitialSlash = true;
+ break;
+ }
+
+ // 9th Production (any):
+ // *path ["#" *UCS4]
+ // becomes
+ // "file:///" *path ["#" *UCS4]
+ // replacing the delimiter by "/" within <*path>. The
+ // delimiter is that character from the set { "/", "\",
+ // ":" } which appears most often in <*path> (if FSYS_UNX
+ // is not among the style bits, "/" is removed from the
+ // set; if FSYS_DOS is not among the style bits, "\" is
+ // removed from the set; if FSYS_MAC is not among the
+ // style bits, ":" is removed from the set). If two or
+ // more characters appear the same number of times, the
+ // character mentioned first in that set is chosen. If
+ // the first character of <*path> is the delimiter, that
+ // character is not copied.
+ if (eStyle & (FSYS_UNX | FSYS_DOS | FSYS_MAC))
+ {
+ aSynAbsURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ switch (guessFSysStyleByCounting(pPos, pEnd, eStyle))
+ {
+ case FSYS_UNX:
+ nSegmentDelimiter = '/';
+ break;
+
+ case FSYS_DOS:
+ nSegmentDelimiter = '\\';
+ break;
+
+ case FSYS_MAC:
+ nSegmentDelimiter = ':';
+ break;
+
+ default:
+ DBG_ERROR(
+ "INetURLObject::setAbsURIRef():"
+ " Bad guessFSysStyleByCounting");
+ break;
+ }
+ bSkippedInitialSlash
+ = pPos != pEnd && *pPos != nSegmentDelimiter;
+ break;
+ }
+ }
+ default:
+ {
+ // For INET_PROT_FILE, allow an empty authority ("//") to be
+ // missing if the following path starts with an explicit "/"
+ // (Java is notorious in generating such file URLs, so be
+ // liberal here):
+ if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
+ pPos += 2;
+ else if (!bSmart
+ && !(m_eScheme == INET_PROT_FILE
+ && pPos != pEnd && *pPos == '/'))
+ {
+ setInvalid();
+ return false;
+ }
+ aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+
+ sal_Unicode const * pAuthority = pPos;
+ sal_uInt32 c = getSchemeInfo().m_bQuery ? '?' : 0x80000000;
+ while (pPos < pEnd && *pPos != '/' && *pPos != c
+ && *pPos != nFragmentDelimiter)
+ ++pPos;
+ if (getSchemeInfo().m_bUser)
+ if (getSchemeInfo().m_bHost)
+ {
+ sal_Unicode const * p1 = pAuthority;
+ while (p1 < pPos && *p1 != '@')
+ ++p1;
+ if (p1 == pPos)
+ {
+ pHostPortBegin = pAuthority;
+ pHostPortEnd = pPos;
+ }
+ else
+ {
+ pUserInfoBegin = pAuthority;
+ pUserInfoEnd = p1;
+ pHostPortBegin = p1 + 1;
+ pHostPortEnd = pPos;
+ }
+ }
+ else
+ {
+ pUserInfoBegin = pAuthority;
+ pUserInfoEnd = pPos;
+ }
+ else if (getSchemeInfo().m_bHost)
+ {
+ pHostPortBegin = pAuthority;
+ pHostPortEnd = pPos;
+ }
+ else if (pPos != pAuthority)
+ {
+ setInvalid();
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (pUserInfoBegin)
+ {
+ Part ePart = m_eScheme == INET_PROT_IMAP ?
+ PART_IMAP_ACHAR :
+ m_eScheme == INET_PROT_VIM ?
+ PART_VIM :
+ PART_USER_PASSWORD;
+ bool bSupportsPassword = getSchemeInfo().m_bPassword;
+ bool bSupportsAuth
+ = !bSupportsPassword && getSchemeInfo().m_bAuth;
+ bool bHasAuth = false;
+ rtl::OUStringBuffer aSynUser;
+ sal_Unicode const * p1 = pUserInfoBegin;
+ while (p1 < pUserInfoEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets,
+ cEscapePrefix, eMechanism,
+ eCharset, eEscapeType);
+ if (eEscapeType == ESCAPE_NO)
+ {
+ if (nUTF32 == ':' && bSupportsPassword)
+ {
+ bHasAuth = true;
+ break;
+ }
+ else if (nUTF32 == ';' && bSupportsAuth
+ && pUserInfoEnd - p1
+ > RTL_CONSTASCII_LENGTH("auth=")
+ && INetMIME::equalIgnoreCase(
+ p1,
+ p1 + RTL_CONSTASCII_LENGTH("auth="),
+ "auth="))
+ {
+ p1 += RTL_CONSTASCII_LENGTH("auth=");
+ bHasAuth = true;
+ break;
+ }
+ }
+ appendUCS4(aSynUser, nUTF32, eEscapeType, bOctets, ePart,
+ cEscapePrefix, eCharset, false);
+ }
+ m_aUser.set(aSynAbsURIRef, aSynUser.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ if (bHasAuth)
+ {
+ if (bSupportsPassword)
+ {
+ aSynAbsURIRef.append(sal_Unicode(':'));
+ rtl::OUStringBuffer aSynAuth;
+ while (p1 < pUserInfoEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets,
+ cEscapePrefix,
+ eMechanism, eCharset,
+ eEscapeType);
+ appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets,
+ ePart, cEscapePrefix, eCharset, false);
+ }
+ m_aAuth.set(aSynAbsURIRef, aSynAuth.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ }
+ else
+ {
+ aSynAbsURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM(";AUTH="));
+ rtl::OUStringBuffer aSynAuth;
+ while (p1 < pUserInfoEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets,
+ cEscapePrefix,
+ eMechanism, eCharset,
+ eEscapeType);
+ if (!INetMIME::isIMAPAtomChar(nUTF32))
+ {
+ setInvalid();
+ return false;
+ }
+ appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets,
+ ePart, cEscapePrefix, eCharset, false);
+ }
+ m_aAuth.set(aSynAbsURIRef, aSynAuth.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ }
+ }
+ if (pHostPortBegin)
+ aSynAbsURIRef.append(sal_Unicode('@'));
+ }
+
+ if (pHostPortBegin)
+ {
+ sal_Unicode const * pPort = pHostPortEnd;
+ if ( getSchemeInfo().m_bPort && pHostPortBegin < pHostPortEnd )
+ {
+ sal_Unicode const * p1 = pHostPortEnd - 1;
+ while (p1 > pHostPortBegin && INetMIME::isDigit(*p1))
+ --p1;
+ if (*p1 == ':')
+ pPort = p1;
+ }
+ bool bNetBiosName = false;
+ switch (m_eScheme)
+ {
+ case INET_PROT_FILE:
+ // If the host equals "LOCALHOST" (unencoded and ignoring
+ // case), turn it into an empty host:
+ if (INetMIME::equalIgnoreCase(pHostPortBegin, pPort,
+ "localhost"))
+ pHostPortBegin = pPort;
+ bNetBiosName = true;
+ break;
+
+ case INET_PROT_LDAP:
+ case INET_PROT_SMB:
+ if (pHostPortBegin == pPort && pPort != pHostPortEnd)
+ {
+ setInvalid();
+ return false;
+ }
+ break;
+ default:
+ if (pHostPortBegin == pPort)
+ {
+ setInvalid();
+ return false;
+ }
+ break;
+ }
+ rtl::OUStringBuffer aSynHost;
+ if (!parseHostOrNetBiosName(
+ pHostPortBegin, pPort, bOctets, eMechanism, eCharset,
+ bNetBiosName, &aSynHost))
+ {
+ setInvalid();
+ return false;
+ }
+ m_aHost.set(aSynAbsURIRef, aSynHost.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ if (pPort != pHostPortEnd)
+ {
+ aSynAbsURIRef.append(sal_Unicode(':'));
+ m_aPort.set(aSynAbsURIRef,
+ rtl::OUString(pPort + 1, pHostPortEnd - (pPort + 1)),
+ aSynAbsURIRef.getLength());
+ }
+ }
+ }
+
+ // Parse <path>
+ rtl::OUStringBuffer aSynPath;
+ if (!parsePath(m_eScheme, &pPos, pEnd, bOctets, eMechanism, eCharset,
+ bSkippedInitialSlash, nSegmentDelimiter,
+ nAltSegmentDelimiter,
+ getSchemeInfo().m_bQuery ? '?' : 0x80000000,
+ nFragmentDelimiter, aSynPath))
+ {
+ setInvalid();
+ return false;
+ }
+ m_aPath.set(aSynAbsURIRef, aSynPath.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+
+ // Parse ?<query>
+ if (getSchemeInfo().m_bQuery && pPos < pEnd && *pPos == '?')
+ {
+ aSynAbsURIRef.append(sal_Unicode('?'));
+ rtl::OUStringBuffer aSynQuery;
+ for (++pPos; pPos < pEnd && *pPos != nFragmentDelimiter;)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, cEscapePrefix,
+ eMechanism, eCharset, eEscapeType);
+ appendUCS4(aSynQuery, nUTF32, eEscapeType, bOctets,
+ PART_URIC, cEscapePrefix, eCharset, true);
+ }
+ m_aQuery.set(aSynAbsURIRef, aSynQuery.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ }
+
+ // Parse #<fragment>
+ if (pPos < pEnd && *pPos == nFragmentDelimiter)
+ {
+ aSynAbsURIRef.append(sal_Unicode(nFragmentDelimiter));
+ rtl::OUStringBuffer aSynFragment;
+ for (++pPos; pPos < pEnd;)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, cEscapePrefix,
+ eMechanism, eCharset, eEscapeType);
+ appendUCS4(aSynFragment, nUTF32, eEscapeType, bOctets, PART_URIC,
+ cEscapePrefix, eCharset, true);
+ }
+ m_aFragment.set(aSynAbsURIRef, aSynFragment.makeStringAndClear(),
+ aSynAbsURIRef.getLength());
+ }
+
+ if (pPos != pEnd)
+ {
+ setInvalid();
+ return false;
+ }
+
+ m_aAbsURIRef = aSynAbsURIRef;
+
+ return true;
+}
+
+//============================================================================
+bool INetURLObject::convertRelToAbs(rtl::OUString const & rTheRelURIRef,
+ bool bOctets,
+ INetURLObject & rTheAbsURIRef,
+ bool & rWasAbsolute,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset,
+ bool bIgnoreFragment, bool bSmart,
+ bool bRelativeNonURIs, FSysStyle eStyle)
+ const
+{
+ sal_Unicode const * p = rTheRelURIRef.getStr();
+ sal_Unicode const * pEnd = p + rTheRelURIRef.getLength();
+
+ sal_Unicode const * pPrefixBegin = p;
+ PrefixInfo const * pPrefix = getPrefix(pPrefixBegin, pEnd);
+ bool hasScheme = pPrefix != 0;
+ if (!hasScheme) {
+ pPrefixBegin = p;
+ hasScheme = parseScheme(&pPrefixBegin, pEnd, '#').getLength() > 0;
+ }
+
+ sal_uInt32 nSegmentDelimiter = '/';
+ sal_uInt32 nQueryDelimiter
+ = !bSmart || getSchemeInfo().m_bQuery ? '?' : 0x80000000;
+ sal_uInt32 nFragmentDelimiter = '#';
+ Part ePart = PART_VISIBLE;
+
+ if (!hasScheme && bSmart)
+ {
+ // If the input matches any of the following productions (for which
+ // the appropriate style bit is set in eStyle), it is assumed to be an
+ // absolute file system path, rather than a relative URI reference.
+ // (This is only a subset of the productions used for scheme detection
+ // in INetURLObject::setAbsURIRef(), because most of those productions
+ // interfere with the syntax of relative URI references.) The
+ // productions use the auxiliary rules
+ //
+ // domain = label *("." label)
+ // label = alphanum [*(alphanum / "-") alphanum]
+ // alphanum = ALPHA / DIGIT
+ // UCS4 = <any UCS4 character>
+ //
+ // 1st Production (UNC file; FSYS_DOS only):
+ // "\\" domain ["\" *UCS4]
+ //
+ // 2nd Production (Unix-like DOS file; FSYS_DOS only):
+ // ALPHA ":" ["/" *UCS4]
+ //
+ // 3rd Production (DOS file; FSYS_DOS only):
+ // ALPHA ":" ["\" *UCS4]
+ if (eStyle & FSYS_DOS)
+ {
+ bool bFSys = false;
+ sal_Unicode const * q = p;
+ if (pEnd - q >= 2
+ && INetMIME::isAlpha(q[0])
+ && q[1] == ':'
+ && (pEnd - q == 2 || q[2] == '/' || q[2] == '\\'))
+ bFSys = true; // 2nd, 3rd
+ else if (pEnd - q >= 2 && q[0] == '\\' && q[1] == '\\')
+ {
+ q += 2;
+ sal_Int32 n = rtl_ustr_indexOfChar_WithLength(
+ q, pEnd - q, '\\');
+ sal_Unicode const * qe = n == -1 ? pEnd : q + n;
+ if (parseHostOrNetBiosName(
+ q, qe, bOctets, ENCODE_ALL, RTL_TEXTENCODING_DONTKNOW,
+ true, NULL))
+ {
+ bFSys = true; // 1st
+ }
+ }
+ if (bFSys)
+ {
+ INetURLObject aNewURI;
+ aNewURI.setAbsURIRef(rTheRelURIRef, bOctets, eMechanism,
+ eCharset, true, eStyle);
+ if (!aNewURI.HasError())
+ {
+ rTheAbsURIRef = aNewURI;
+ rWasAbsolute = true;
+ return true;
+ }
+ }
+ }
+
+ // When the base URL is a file URL, accept relative file system paths
+ // using "\" or ":" as delimiter (and ignoring URI conventions for "%"
+ // and "#"), as well as relative URIs using "/" as delimiter:
+ if (m_eScheme == INET_PROT_FILE)
+ switch (guessFSysStyleByCounting(p, pEnd, eStyle))
+ {
+ case FSYS_UNX:
+ nSegmentDelimiter = '/';
+ break;
+
+ case FSYS_DOS:
+ nSegmentDelimiter = '\\';
+ bRelativeNonURIs = true;
+ break;
+
+ case FSYS_MAC:
+ nSegmentDelimiter = ':';
+ bRelativeNonURIs = true;
+ break;
+
+ default:
+ DBG_ERROR("INetURLObject::convertRelToAbs():"
+ " Bad guessFSysStyleByCounting");
+ break;
+ }
+
+ if (bRelativeNonURIs)
+ {
+ eMechanism = ENCODE_ALL;
+ nQueryDelimiter = 0x80000000;
+ nFragmentDelimiter = 0x80000000;
+ ePart = PART_VISIBLE_NONSPECIAL;
+ }
+ }
+
+ // If the relative URI has the same scheme as the base URI, and that
+ // scheme is hierarchical, then ignore its presence in the relative
+ // URI in order to be backward compatible (cf. RFC 2396 section 5.2
+ // step 3):
+ if (pPrefix && pPrefix->m_eScheme == m_eScheme
+ && getSchemeInfo().m_bHierarchical)
+ {
+ hasScheme = false;
+ while (p != pEnd && *p++ != ':') ;
+ }
+ rWasAbsolute = hasScheme;
+
+ // Fast solution for non-relative URIs:
+ if (hasScheme)
+ {
+ INetURLObject aNewURI(rTheRelURIRef, eMechanism, eCharset);
+ if (aNewURI.HasError())
+ {
+ rWasAbsolute = false;
+ return false;
+ }
+
+ if (bIgnoreFragment)
+ aNewURI.clearFragment();
+ rTheAbsURIRef = aNewURI;
+ return true;
+ }
+
+ enum State { STATE_AUTH, STATE_ABS_PATH, STATE_REL_PATH, STATE_FRAGMENT,
+ STATE_DONE };
+
+ rtl::OUStringBuffer aSynAbsURIRef;
+ // make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme
+ // is empty ("") in that case, so take the scheme from m_aAbsURIRef
+ if (m_eScheme != INET_PROT_GENERIC)
+ {
+ aSynAbsURIRef.appendAscii(getSchemeInfo().m_pScheme);
+ }
+ else
+ {
+ sal_Unicode const * pSchemeBegin
+ = m_aAbsURIRef.getStr();
+ sal_Unicode const * pSchemeEnd = pSchemeBegin;
+ while (pSchemeEnd[0] != ':')
+ {
+ ++pSchemeEnd;
+ }
+ aSynAbsURIRef.append(pSchemeBegin, pSchemeEnd - pSchemeBegin);
+ }
+ aSynAbsURIRef.append(sal_Unicode(':'));
+
+ sal_Char cEscapePrefix = getEscapePrefix();
+
+ State eState = STATE_AUTH;
+ bool bSameDoc = true;
+
+ if (getSchemeInfo().m_bAuthority)
+ {
+ if (pEnd - p >= 2 && p[0] == '/' && p[1] == '/')
+ {
+ aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ p += 2;
+ eState = STATE_ABS_PATH;
+ bSameDoc = false;
+ while (p != pEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32
+ = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
+ eCharset, eEscapeType);
+ if (eEscapeType == ESCAPE_NO)
+ {
+ if (nUTF32 == nSegmentDelimiter)
+ break;
+ else if (nUTF32 == nFragmentDelimiter)
+ {
+ eState = STATE_FRAGMENT;
+ break;
+ }
+ }
+ appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets,
+ PART_VISIBLE, cEscapePrefix, eCharset, true);
+ }
+ }
+ else
+ {
+ SubString aAuthority(getAuthority());
+ aSynAbsURIRef.append(m_aAbsURIRef.getStr()
+ + aAuthority.getBegin(),
+ aAuthority.getLength());
+ }
+ }
+
+ if (eState == STATE_AUTH)
+ {
+ if (p == pEnd)
+ eState = STATE_DONE;
+ else if (*p == nFragmentDelimiter)
+ {
+ ++p;
+ eState = STATE_FRAGMENT;
+ }
+ else if (*p == nSegmentDelimiter)
+ {
+ ++p;
+ eState = STATE_ABS_PATH;
+ bSameDoc = false;
+ }
+ else
+ {
+ eState = STATE_REL_PATH;
+ bSameDoc = false;
+ }
+ }
+
+ if (eState == STATE_ABS_PATH)
+ {
+ aSynAbsURIRef.append(sal_Unicode('/'));
+ eState = STATE_DONE;
+ while (p != pEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32
+ = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
+ eCharset, eEscapeType);
+ if (eEscapeType == ESCAPE_NO)
+ {
+ if (nUTF32 == nFragmentDelimiter)
+ {
+ eState = STATE_FRAGMENT;
+ break;
+ }
+ else if (nUTF32 == nSegmentDelimiter)
+ nUTF32 = '/';
+ }
+ appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart,
+ cEscapePrefix, eCharset, true);
+ }
+ }
+ else if (eState == STATE_REL_PATH)
+ {
+ if (!getSchemeInfo().m_bHierarchical)
+ {
+ // Detect cases where a relative input could not be made absolute
+ // because the given base URL is broken (most probably because it is
+ // empty):
+ OSL_ASSERT(!HasError());
+ rWasAbsolute = false;
+ return false;
+ }
+
+ sal_Unicode const * pBasePathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pBasePathEnd
+ = pBasePathBegin + m_aPath.getLength();
+ while (pBasePathEnd != pBasePathBegin)
+ if (*(--pBasePathEnd) == '/')
+ {
+ ++pBasePathEnd;
+ break;
+ }
+
+ sal_Int32 nPathBegin = aSynAbsURIRef.getLength();
+ aSynAbsURIRef.append(pBasePathBegin, pBasePathEnd - pBasePathBegin);
+ DBG_ASSERT(aSynAbsURIRef.getLength() > nPathBegin
+ && aSynAbsURIRef.charAt(aSynAbsURIRef.getLength() - 1) == '/',
+ "INetURLObject::convertRelToAbs(): Bad base path");
+
+ while (p != pEnd && *p != nQueryDelimiter && *p != nFragmentDelimiter)
+ {
+ if (*p == '.')
+ {
+ if (pEnd - p == 1
+ || p[1] == nSegmentDelimiter
+ || p[1] == nQueryDelimiter
+ || p[1] == nFragmentDelimiter)
+ {
+ ++p;
+ if (p != pEnd && *p == nSegmentDelimiter)
+ ++p;
+ continue;
+ }
+ else if (pEnd - p >= 2
+ && p[1] == '.'
+ && (pEnd - p == 2
+ || p[2] == nSegmentDelimiter
+ || p[2] == nQueryDelimiter
+ || p[2] == nFragmentDelimiter)
+ && aSynAbsURIRef.getLength() - nPathBegin > 1)
+ {
+ p += 2;
+ if (p != pEnd && *p == nSegmentDelimiter)
+ ++p;
+
+ sal_Int32 i = aSynAbsURIRef.getLength() - 2;
+ while (i > nPathBegin && aSynAbsURIRef.charAt(i) != '/')
+ --i;
+ aSynAbsURIRef.setLength(i + 1);
+ DBG_ASSERT(
+ aSynAbsURIRef.getLength() > nPathBegin
+ && aSynAbsURIRef.charAt(aSynAbsURIRef.getLength() - 1)
+ == '/',
+ "INetURLObject::convertRelToAbs(): Bad base path");
+ continue;
+ }
+ }
+
+ while (p != pEnd
+ && *p != nSegmentDelimiter
+ && *p != nQueryDelimiter
+ && *p != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32
+ = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart,
+ cEscapePrefix, eCharset, true);
+ }
+ if (p != pEnd && *p == nSegmentDelimiter)
+ {
+ aSynAbsURIRef.append(sal_Unicode('/'));
+ ++p;
+ }
+ }
+
+ while (p != pEnd && *p != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32
+ = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart,
+ cEscapePrefix, eCharset, true);
+ }
+
+ if (p == pEnd)
+ eState = STATE_DONE;
+ else
+ {
+ ++p;
+ eState = STATE_FRAGMENT;
+ }
+ }
+ else if (bSameDoc)
+ {
+ aSynAbsURIRef.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(),
+ m_aPath.getLength());
+ if (m_aQuery.isPresent())
+ aSynAbsURIRef.append(m_aAbsURIRef.getStr()
+ + m_aQuery.getBegin() - 1,
+ m_aQuery.getLength() + 1);
+ }
+
+ if (eState == STATE_FRAGMENT && !bIgnoreFragment)
+ {
+ aSynAbsURIRef.append(sal_Unicode('#'));
+ while (p != pEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32
+ = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets,
+ PART_VISIBLE, cEscapePrefix, eCharset, true);
+ }
+ }
+
+ INetURLObject aNewURI(aSynAbsURIRef.makeStringAndClear());
+ if (aNewURI.HasError())
+ {
+ // Detect cases where a relative input could not be made absolute
+ // because the given base URL is broken (most probably because it is
+ // empty):
+ OSL_ASSERT(!HasError());
+ rWasAbsolute = false;
+ return false;
+ }
+
+ rTheAbsURIRef = aNewURI;
+ return true;
+}
+
+//============================================================================
+bool INetURLObject::convertAbsToRel(rtl::OUString const & rTheAbsURIRef,
+ bool bOctets, rtl::OUString & rTheRelURIRef,
+ EncodeMechanism eEncodeMechanism,
+ DecodeMechanism eDecodeMechanism,
+ rtl_TextEncoding eCharset,
+ FSysStyle eStyle) const
+{
+ // Check for hierarchical base URL:
+ if (!getSchemeInfo().m_bHierarchical)
+ {
+ rTheRelURIRef
+ = decode(rTheAbsURIRef,
+ getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)),
+ eDecodeMechanism, eCharset);
+ return false;
+ }
+
+ // Convert the input (absolute or relative URI ref) to an absolute URI
+ // ref:
+ INetURLObject aSubject;
+ bool bWasAbsolute;
+ if (!convertRelToAbs(rTheAbsURIRef, bOctets, aSubject, bWasAbsolute,
+ eEncodeMechanism, eCharset, false, false, false,
+ eStyle))
+ {
+ rTheRelURIRef
+ = decode(rTheAbsURIRef,
+ getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)),
+ eDecodeMechanism, eCharset);
+ return false;
+ }
+
+ // Check for differing scheme or authority parts:
+ if ((m_aScheme.compare(
+ aSubject.m_aScheme, m_aAbsURIRef, aSubject.m_aAbsURIRef)
+ != 0)
+ || (m_aUser.compare(
+ aSubject.m_aUser, m_aAbsURIRef, aSubject.m_aAbsURIRef)
+ != 0)
+ || (m_aAuth.compare(
+ aSubject.m_aAuth, m_aAbsURIRef, aSubject.m_aAbsURIRef)
+ != 0)
+ || (m_aHost.compare(
+ aSubject.m_aHost, m_aAbsURIRef, aSubject.m_aAbsURIRef)
+ != 0)
+ || (m_aPort.compare(
+ aSubject.m_aPort, m_aAbsURIRef, aSubject.m_aAbsURIRef)
+ != 0))
+ {
+ rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
+ return false;
+ }
+
+ sal_Unicode const * pBasePathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pBasePathEnd = pBasePathBegin + m_aPath.getLength();
+ sal_Unicode const * pSubjectPathBegin
+ = aSubject.m_aAbsURIRef.getStr() + aSubject.m_aPath.getBegin();
+ sal_Unicode const * pSubjectPathEnd
+ = pSubjectPathBegin + aSubject.m_aPath.getLength();
+
+ // Make nMatch point past the last matching slash, or past the end of the
+ // paths, in case they are equal:
+ sal_Unicode const * pSlash = 0;
+ sal_Unicode const * p1 = pBasePathBegin;
+ sal_Unicode const * p2 = pSubjectPathBegin;
+ for (;;)
+ {
+ if (p1 == pBasePathEnd || p2 == pSubjectPathEnd)
+ {
+ if (p1 == pBasePathEnd && p2 == pSubjectPathEnd)
+ pSlash = p1;
+ break;
+ }
+
+ sal_Unicode c = *p1++;
+ if (c != *p2++)
+ break;
+ if (c == '/')
+ pSlash = p1;
+ }
+ if (!pSlash)
+ {
+ // One of the paths does not start with '/':
+ rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
+ return false;
+ }
+ sal_Int32 nMatch = pSlash - pBasePathBegin;
+
+ // If the two URLs are DOS file URLs starting with different volumes
+ // (e.g., file:///a:/... and file:///b:/...), the subject is not made
+ // relative (it could be, but some people do not like that):
+ if (m_eScheme == INET_PROT_FILE
+ && nMatch <= 1
+ && hasDosVolume(eStyle)
+ && aSubject.hasDosVolume(eStyle)) //TODO! ok to use eStyle for these?
+ {
+ rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
+ return false;
+ }
+
+ // For every slash in the base path after nMatch, a prefix of "../" is
+ // added to the new relative URL (if the common prefix of the two paths is
+ // only "/"---but see handling of file URLs above---, the complete subject
+ // path could go into the new relative URL instead, but some people don't
+ // like that):
+ rtl::OUStringBuffer aSynRelURIRef;
+// if (nMatch <= 1) nMatch = 0; else // see comment above
+ for (sal_Unicode const * p = pBasePathBegin + nMatch; p != pBasePathEnd;
+ ++p)
+ {
+ if (*p == '/')
+ aSynRelURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("../"));
+ }
+
+ // If the new relative URL would start with "//" (i.e., it would be
+ // mistaken for a relative URL starting with an authority part), or if the
+ // new relative URL would neither be empty nor start with <"/"> nor start
+ // with <1*rseg> (i.e., it could be mistaken for an absolute URL starting
+ // with a scheme part), then the new relative URL is prefixed with "./":
+ if (aSynRelURIRef.getLength() == 0)
+ {
+ if (pSubjectPathEnd - pSubjectPathBegin >= nMatch + 2
+ && pSubjectPathBegin[nMatch] == '/'
+ && pSubjectPathBegin[nMatch + 1] == '/')
+ {
+ aSynRelURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("./"));
+ }
+ else
+ {
+ for (sal_Unicode const * p = pSubjectPathBegin + nMatch;
+ p != pSubjectPathEnd && *p != '/'; ++p)
+ {
+ if (mustEncode(*p, PART_REL_SEGMENT_EXTRA))
+ {
+ aSynRelURIRef.
+ appendAscii(RTL_CONSTASCII_STRINGPARAM("./"));
+ break;
+ }
+ }
+ }
+ }
+
+ // The remainder of the subject path, starting at nMatch, is appended to
+ // the new relative URL:
+ sal_Char cEscapePrefix = getEscapePrefix();
+ aSynRelURIRef.append(decode(pSubjectPathBegin + nMatch, pSubjectPathEnd,
+ cEscapePrefix, eDecodeMechanism, eCharset));
+
+ // If the subject has defined query or fragment parts, they are appended
+ // to the new relative URL:
+ if (aSubject.m_aQuery.isPresent())
+ {
+ aSynRelURIRef.append(sal_Unicode('?'));
+ aSynRelURIRef.append(aSubject.decode(aSubject.m_aQuery, cEscapePrefix,
+ eDecodeMechanism, eCharset));
+ }
+ if (aSubject.m_aFragment.isPresent())
+ {
+ aSynRelURIRef.append(sal_Unicode('#'));
+ aSynRelURIRef.append(aSubject.decode(aSubject.m_aFragment,
+ cEscapePrefix, eDecodeMechanism, eCharset));
+ }
+
+ rTheRelURIRef = aSynRelURIRef.makeStringAndClear();
+ return true;
+}
+
+//============================================================================
+// static
+bool INetURLObject::convertIntToExt(rtl::OUString const & rTheIntURIRef,
+ bool bOctets, rtl::OUString & rTheExtURIRef,
+ DecodeMechanism eDecodeMechanism,
+ rtl_TextEncoding eCharset)
+{
+ sal_Char cEscapePrefix
+ = getEscapePrefix(CompareProtocolScheme(rTheIntURIRef));
+ rtl::OUString aSynExtURIRef(encodeText(rTheIntURIRef, bOctets, PART_VISIBLE,
+ cEscapePrefix, NOT_CANONIC, eCharset,
+ true));
+ sal_Unicode const * pBegin = aSynExtURIRef.getStr();
+ sal_Unicode const * pEnd = pBegin + aSynExtURIRef.getLength();
+ sal_Unicode const * p = pBegin;
+ PrefixInfo const * pPrefix = getPrefix(p, pEnd);
+ bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::INTERNAL;
+ if (bConvert)
+ {
+ aSynExtURIRef =
+ aSynExtURIRef.replaceAt(0, p - pBegin,
+ rtl::OUString::createFromAscii(pPrefix->m_pTranslatedPrefix));
+ }
+ rTheExtURIRef = decode(aSynExtURIRef, cEscapePrefix, eDecodeMechanism,
+ eCharset);
+ return bConvert;
+}
+
+//============================================================================
+// static
+bool INetURLObject::convertExtToInt(rtl::OUString const & rTheExtURIRef,
+ bool bOctets, rtl::OUString & rTheIntURIRef,
+ DecodeMechanism eDecodeMechanism,
+ rtl_TextEncoding eCharset)
+{
+ sal_Char cEscapePrefix
+ = getEscapePrefix(CompareProtocolScheme(rTheExtURIRef));
+ rtl::OUString aSynIntURIRef(encodeText(rTheExtURIRef, bOctets, PART_VISIBLE,
+ cEscapePrefix, NOT_CANONIC, eCharset,
+ true));
+ sal_Unicode const * pBegin = aSynIntURIRef.getStr();
+ sal_Unicode const * pEnd = pBegin + aSynIntURIRef.getLength();
+ sal_Unicode const * p = pBegin;
+ PrefixInfo const * pPrefix = getPrefix(p, pEnd);
+ bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::EXTERNAL;
+ if (bConvert)
+ {
+ aSynIntURIRef =
+ aSynIntURIRef.replaceAt(0, p - pBegin,
+ rtl::OUString::createFromAscii(pPrefix->m_pTranslatedPrefix));
+ }
+ rTheIntURIRef = decode(aSynIntURIRef, cEscapePrefix, eDecodeMechanism,
+ eCharset);
+ return bConvert;
+}
+
+//============================================================================
+// static
+INetURLObject::PrefixInfo const *
+INetURLObject::getPrefix(sal_Unicode const *& rBegin,
+ sal_Unicode const * pEnd)
+{
+ static PrefixInfo const aMap[]
+ = { // dummy entry at front needed, because pLast may point here:
+ { 0, 0, INET_PROT_NOT_VALID, PrefixInfo::INTERNAL },
+ { ".component:", "staroffice.component:", INET_PROT_COMPONENT,
+ PrefixInfo::INTERNAL },
+ { ".uno:", "staroffice.uno:", INET_PROT_UNO,
+ PrefixInfo::INTERNAL },
+ { "cid:", 0, INET_PROT_CID, PrefixInfo::OFFICIAL },
+ { "data:", 0, INET_PROT_DATA, PrefixInfo::OFFICIAL },
+ { "db:", "staroffice.db:", INET_PROT_DB, PrefixInfo::INTERNAL },
+ { "file:", 0, INET_PROT_FILE, PrefixInfo::OFFICIAL },
+ { "ftp:", 0, INET_PROT_FTP, PrefixInfo::OFFICIAL },
+ { "http:", 0, INET_PROT_HTTP, PrefixInfo::OFFICIAL },
+ { "https:", 0, INET_PROT_HTTPS, PrefixInfo::OFFICIAL },
+ { "imap:", 0, INET_PROT_IMAP, PrefixInfo::OFFICIAL },
+ { "javascript:", 0, INET_PROT_JAVASCRIPT, PrefixInfo::OFFICIAL },
+ { "ldap:", 0, INET_PROT_LDAP, PrefixInfo::OFFICIAL },
+ { "macro:", "staroffice.macro:", INET_PROT_MACRO,
+ PrefixInfo::INTERNAL },
+ { "mailto:", 0, INET_PROT_MAILTO, PrefixInfo::OFFICIAL },
+ { "news:", 0, INET_PROT_NEWS, PrefixInfo::OFFICIAL },
+ { "out:", "staroffice.out:", INET_PROT_OUT,
+ PrefixInfo::INTERNAL },
+ { "pop3:", "staroffice.pop3:", INET_PROT_POP3,
+ PrefixInfo::INTERNAL },
+ { "private:", "staroffice.private:", INET_PROT_PRIV_SOFFICE,
+ PrefixInfo::INTERNAL },
+ { "private:factory/", "staroffice.factory:",
+ INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL },
+ { "private:helpid/", "staroffice.helpid:", INET_PROT_PRIV_SOFFICE,
+ PrefixInfo::INTERNAL },
+ { "private:java/", "staroffice.java:", INET_PROT_PRIV_SOFFICE,
+ PrefixInfo::INTERNAL },
+ { "private:searchfolder:", "staroffice.searchfolder:",
+ INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL },
+ { "private:trashcan:", "staroffice.trashcan:",
+ INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL },
+ { "slot:", "staroffice.slot:", INET_PROT_SLOT,
+ PrefixInfo::INTERNAL },
+ { "smb:", 0, INET_PROT_SMB, PrefixInfo::OFFICIAL },
+ { "staroffice.component:", ".component:", INET_PROT_COMPONENT,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.db:", "db:", INET_PROT_DB, PrefixInfo::EXTERNAL },
+ { "staroffice.factory:", "private:factory/",
+ INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL },
+ { "staroffice.helpid:", "private:helpid/", INET_PROT_PRIV_SOFFICE,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.java:", "private:java/", INET_PROT_PRIV_SOFFICE,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.macro:", "macro:", INET_PROT_MACRO,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.out:", "out:", INET_PROT_OUT,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.pop3:", "pop3:", INET_PROT_POP3,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.private:", "private:", INET_PROT_PRIV_SOFFICE,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.searchfolder:", "private:searchfolder:",
+ INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL },
+ { "staroffice.slot:", "slot:", INET_PROT_SLOT,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.trashcan:", "private:trashcan:",
+ INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL },
+ { "staroffice.uno:", ".uno:", INET_PROT_UNO,
+ PrefixInfo::EXTERNAL },
+ { "staroffice.vim:", "vim:", INET_PROT_VIM,
+ PrefixInfo::EXTERNAL },
+ { "staroffice:", "private:", INET_PROT_PRIV_SOFFICE,
+ PrefixInfo::EXTERNAL },
+ { "telnet:", 0, INET_PROT_TELNET, PrefixInfo::OFFICIAL },
+ { "vim:", "staroffice.vim:", INET_PROT_VIM,
+ PrefixInfo::INTERNAL },
+ { "vnd.sun.star.cmd:", 0, INET_PROT_VND_SUN_STAR_CMD,
+ PrefixInfo::OFFICIAL },
+ { "vnd.sun.star.expand:", 0, INET_PROT_VND_SUN_STAR_EXPAND,
+ PrefixInfo::OFFICIAL },
+ { "vnd.sun.star.help:", 0, INET_PROT_VND_SUN_STAR_HELP,
+ PrefixInfo::OFFICIAL },
+ { "vnd.sun.star.hier:", 0, INET_PROT_VND_SUN_STAR_HIER,
+ PrefixInfo::OFFICIAL },
+ { "vnd.sun.star.odma:", 0, INET_PROT_VND_SUN_STAR_ODMA,
+ PrefixInfo::OFFICIAL },
+ { "vnd.sun.star.pkg:", 0, INET_PROT_VND_SUN_STAR_PKG,
+ PrefixInfo::OFFICIAL },
+ { "vnd.sun.star.tdoc:", 0, INET_PROT_VND_SUN_STAR_TDOC,
+ PrefixInfo::OFFICIAL },
+ { "vnd.sun.star.webdav:", 0, INET_PROT_VND_SUN_STAR_WEBDAV,
+ PrefixInfo::OFFICIAL } };
+ PrefixInfo const * pFirst = aMap + 1;
+ PrefixInfo const * pLast = aMap + sizeof aMap / sizeof (PrefixInfo) - 1;
+ PrefixInfo const * pMatch = 0;
+ sal_Unicode const * pMatched = rBegin;
+ sal_Unicode const * p = rBegin;
+ sal_Int32 i = 0;
+ for (; pFirst < pLast; ++i)
+ {
+ if (pFirst->m_pPrefix[i] == '\0')
+ {
+ pMatch = pFirst++;
+ pMatched = p;
+ }
+ if (p >= pEnd)
+ break;
+ sal_uInt32 nChar = INetMIME::toLowerCase(*p++);
+ while (pFirst <= pLast && sal_uChar(pFirst->m_pPrefix[i]) < nChar)
+ ++pFirst;
+ while (pFirst <= pLast && sal_uChar(pLast->m_pPrefix[i]) > nChar)
+ --pLast;
+ }
+ if (pFirst == pLast)
+ {
+ sal_Char const * q = pFirst->m_pPrefix + i;
+ while (p < pEnd && *q != '\0'
+ && INetMIME::toLowerCase(*p) == sal_uChar(*q))
+ {
+ ++p;
+ ++q;
+ }
+ if (*q == '\0')
+ {
+ rBegin = p;
+ return pFirst;
+ }
+ }
+ rBegin = pMatched;
+ return pMatch;
+}
+
+//============================================================================
+sal_Int32 INetURLObject::getAuthorityBegin() const
+{
+ DBG_ASSERT(getSchemeInfo().m_bAuthority,
+ "INetURLObject::getAuthority(): Bad scheme");
+ sal_Int32 nBegin;
+ if (m_aUser.isPresent())
+ nBegin = m_aUser.getBegin();
+ else if (m_aHost.isPresent())
+ nBegin = m_aHost.getBegin();
+ else
+ nBegin = m_aPath.getBegin();
+ nBegin -= RTL_CONSTASCII_LENGTH("//");
+ DBG_ASSERT(m_aAbsURIRef.charAt(nBegin) == '/'
+ && m_aAbsURIRef.charAt(nBegin + 1) == '/',
+ "INetURLObject::getAuthority(): Bad authority");
+ return nBegin;
+}
+
+//============================================================================
+INetURLObject::SubString INetURLObject::getAuthority() const
+{
+ sal_Int32 nBegin = getAuthorityBegin();
+ sal_Int32 nEnd = m_aPort.isPresent() ? m_aPort.getEnd() :
+ m_aHost.isPresent() ? m_aHost.getEnd() :
+ m_aAuth.isPresent() ? m_aAuth.getEnd() :
+ m_aUser.isPresent() ? m_aUser.getEnd() :
+ nBegin + RTL_CONSTASCII_LENGTH("//");
+ return SubString(nBegin, nEnd - nBegin);
+}
+
+//============================================================================
+bool INetURLObject::setUser(rtl::OUString const & rTheUser,
+ bool bOctets, EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ if (
+ !getSchemeInfo().m_bUser ||
+ (m_eScheme == INET_PROT_IMAP && rTheUser.getLength() == 0)
+ )
+ {
+ return false;
+ }
+
+ rtl::OUString aNewUser(encodeText(rTheUser, bOctets,
+ m_eScheme == INET_PROT_IMAP ?
+ PART_IMAP_ACHAR :
+ m_eScheme == INET_PROT_VIM ?
+ PART_VIM :
+ PART_USER_PASSWORD,
+ getEscapePrefix(), eMechanism, eCharset,
+ false));
+ sal_Int32 nDelta;
+ if (m_aUser.isPresent())
+ nDelta = m_aUser.set(m_aAbsURIRef, aNewUser);
+ else if (m_aHost.isPresent())
+ {
+ m_aAbsURIRef.insert(m_aHost.getBegin(), sal_Unicode('@'));
+ nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aHost.getBegin()) + 1;
+ }
+ else if (getSchemeInfo().m_bHost)
+ return false;
+ else
+ nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aPath.getBegin());
+ m_aAuth += nDelta;
+ m_aHost += nDelta;
+ m_aPort += nDelta;
+ m_aPath += nDelta;
+ m_aQuery += nDelta;
+ m_aFragment += nDelta;
+ return true;
+}
+
+namespace
+{
+ void lcl_Erase(rtl::OUStringBuffer &rBuf, sal_Int32 index, sal_Int32 count)
+ {
+ rtl::OUString sTemp(rBuf.makeStringAndClear());
+ rBuf.append(sTemp.replaceAt(index, count, rtl::OUString()));
+ }
+}
+
+//============================================================================
+bool INetURLObject::clearPassword()
+{
+ if (!getSchemeInfo().m_bPassword)
+ return false;
+ if (m_aAuth.isPresent())
+ {
+ lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin() - 1,
+ m_aAuth.getLength() + 1);
+ sal_Int32 nDelta = m_aAuth.clear() - 1;
+ m_aHost += nDelta;
+ m_aPort += nDelta;
+ m_aPath += nDelta;
+ m_aQuery += nDelta;
+ m_aFragment += nDelta;
+ }
+ return true;
+}
+
+//============================================================================
+bool INetURLObject::setPassword(rtl::OUString const & rThePassword,
+ bool bOctets, EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ if (!getSchemeInfo().m_bPassword)
+ return false;
+ rtl::OUString aNewAuth(encodeText(rThePassword, bOctets,
+ m_eScheme == INET_PROT_VIM ?
+ PART_VIM : PART_USER_PASSWORD,
+ getEscapePrefix(), eMechanism, eCharset,
+ false));
+ sal_Int32 nDelta;
+ if (m_aAuth.isPresent())
+ nDelta = m_aAuth.set(m_aAbsURIRef, aNewAuth);
+ else if (m_aUser.isPresent())
+ {
+ m_aAbsURIRef.insert(m_aUser.getEnd(), sal_Unicode(':'));
+ nDelta
+ = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aUser.getEnd() + 1) + 1;
+ }
+ else if (m_aHost.isPresent())
+ {
+ m_aAbsURIRef.insert(m_aHost.getBegin(),
+ rtl::OUString::createFromAscii(":@"));
+ m_aUser.set(m_aAbsURIRef, rtl::OUString(), m_aHost.getBegin());
+ nDelta
+ = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aHost.getBegin() + 1) + 2;
+ }
+ else if (getSchemeInfo().m_bHost)
+ return false;
+ else
+ {
+ m_aAbsURIRef.insert(m_aPath.getBegin(), sal_Unicode(':'));
+ m_aUser.set(m_aAbsURIRef, rtl::OUString(), m_aPath.getBegin());
+ nDelta
+ = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aPath.getBegin() + 1) + 1;
+ }
+ m_aHost += nDelta;
+ m_aPort += nDelta;
+ m_aPath += nDelta;
+ m_aQuery += nDelta;
+ m_aFragment += nDelta;
+ return true;
+}
+
+//============================================================================
+// static
+bool INetURLObject::parseHost(
+ sal_Unicode const *& rBegin, sal_Unicode const * pEnd,
+ rtl::OUString & rCanonic)
+{
+ // RFC 2373 is inconsistent about how to write an IPv6 address in which an
+ // IPv4 address directly follows the abbreviating "::". The ABNF in
+ // Appendix B suggests ":::13.1.68.3", while an example in 2.2/3 explicitly
+ // mentions "::13:1.68.3". This algorithm accepts both variants:
+ enum State { STATE_INITIAL, STATE_LABEL, STATE_LABEL_HYPHEN,
+ STATE_LABEL_DOT, STATE_TOPLABEL, STATE_TOPLABEL_HYPHEN,
+ STATE_TOPLABEL_DOT, STATE_IP4, STATE_IP4_DOT, STATE_IP6,
+ STATE_IP6_COLON, STATE_IP6_2COLON, STATE_IP6_3COLON,
+ STATE_IP6_HEXSEQ1, STATE_IP6_HEXSEQ1_COLON,
+ STATE_IP6_HEXSEQ1_MAYBE_IP4, STATE_IP6_HEXSEQ2,
+ STATE_IP6_HEXSEQ2_COLON, STATE_IP6_HEXSEQ2_MAYBE_IP4,
+ STATE_IP6_IP4, STATE_IP6_IP4_DOT, STATE_IP6_DONE };
+ rtl::OUStringBuffer aTheCanonic;
+ sal_uInt32 nNumber = 0;
+ int nDigits = 0;
+ int nOctets = 0;
+ State eState = STATE_INITIAL;
+ sal_Unicode const * p = rBegin;
+ for (; p != pEnd; ++p)
+ switch (eState)
+ {
+ case STATE_INITIAL:
+ if (*p == '[')
+ {
+ aTheCanonic.append(sal_Unicode('['));
+ eState = STATE_IP6;
+ }
+ else if (INetMIME::isAlpha(*p) || *p == '_')
+ eState = STATE_TOPLABEL;
+ else if (INetMIME::isDigit(*p))
+ {
+ nNumber = INetMIME::getWeight(*p);
+ nDigits = 1;
+ nOctets = 1;
+ eState = STATE_IP4;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_LABEL:
+ if (*p == '.')
+ eState = STATE_LABEL_DOT;
+ else if (*p == '-')
+ eState = STATE_LABEL_HYPHEN;
+ else if (!INetMIME::isAlphanumeric(*p) && *p != '_')
+ goto done;
+ break;
+
+ case STATE_LABEL_HYPHEN:
+ if (INetMIME::isAlphanumeric(*p) || *p == '_')
+ eState = STATE_LABEL;
+ else if (*p != '-')
+ goto done;
+ break;
+
+ case STATE_LABEL_DOT:
+ if (INetMIME::isAlpha(*p) || *p == '_')
+ eState = STATE_TOPLABEL;
+ else if (INetMIME::isDigit(*p))
+ eState = STATE_LABEL;
+ else
+ goto done;
+ break;
+
+ case STATE_TOPLABEL:
+ if (*p == '.')
+ eState = STATE_TOPLABEL_DOT;
+ else if (*p == '-')
+ eState = STATE_TOPLABEL_HYPHEN;
+ else if (!INetMIME::isAlphanumeric(*p) && *p != '_')
+ goto done;
+ break;
+
+ case STATE_TOPLABEL_HYPHEN:
+ if (INetMIME::isAlphanumeric(*p) || *p == '_')
+ eState = STATE_TOPLABEL;
+ else if (*p != '-')
+ goto done;
+ break;
+
+ case STATE_TOPLABEL_DOT:
+ if (INetMIME::isAlpha(*p) || *p == '_')
+ eState = STATE_TOPLABEL;
+ else if (INetMIME::isDigit(*p))
+ eState = STATE_LABEL;
+ else
+ goto done;
+ break;
+
+ case STATE_IP4:
+ if (*p == '.')
+ if (nOctets < 4)
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber)));
+ aTheCanonic.append(sal_Unicode('.'));
+ ++nOctets;
+ eState = STATE_IP4_DOT;
+ }
+ else
+ eState = STATE_LABEL_DOT;
+ else if (*p == '-')
+ eState = STATE_LABEL_HYPHEN;
+ else if (INetMIME::isAlpha(*p) || *p == '_')
+ eState = STATE_LABEL;
+ else if (INetMIME::isDigit(*p))
+ if (nDigits < 3)
+ {
+ nNumber = 10 * nNumber + INetMIME::getWeight(*p);
+ ++nDigits;
+ }
+ else
+ eState = STATE_LABEL;
+ else
+ goto done;
+ break;
+
+ case STATE_IP4_DOT:
+ if (INetMIME::isAlpha(*p) || *p == '_')
+ eState = STATE_TOPLABEL;
+ else if (INetMIME::isDigit(*p))
+ {
+ nNumber = INetMIME::getWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP4;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6:
+ if (*p == ':')
+ eState = STATE_IP6_COLON;
+ else if (INetMIME::isHexDigit(*p))
+ {
+ nNumber = INetMIME::getHexWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP6_HEXSEQ1;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_COLON:
+ if (*p == ':')
+ {
+ aTheCanonic.appendAscii(RTL_CONSTASCII_STRINGPARAM("::"));
+ eState = STATE_IP6_2COLON;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_2COLON:
+ if (*p == ']')
+ eState = STATE_IP6_DONE;
+ else if (*p == ':')
+ {
+ aTheCanonic.append(sal_Unicode(':'));
+ eState = STATE_IP6_3COLON;
+ }
+ else if (INetMIME::isDigit(*p))
+ {
+ nNumber = INetMIME::getWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP6_HEXSEQ2_MAYBE_IP4;
+ }
+ else if (INetMIME::isHexDigit(*p))
+ {
+ nNumber = INetMIME::getHexWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP6_HEXSEQ2;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_3COLON:
+ if (INetMIME::isDigit(*p))
+ {
+ nNumber = INetMIME::getWeight(*p);
+ nDigits = 1;
+ nOctets = 1;
+ eState = STATE_IP6_IP4;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_HEXSEQ1:
+ if (*p == ']')
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber), 16));
+ eState = STATE_IP6_DONE;
+ }
+ else if (*p == ':')
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber), 16));
+ aTheCanonic.append(sal_Unicode(':'));
+ eState = STATE_IP6_HEXSEQ1_COLON;
+ }
+ else if (INetMIME::isHexDigit(*p) && nDigits < 4)
+ {
+ nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
+ ++nDigits;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_HEXSEQ1_COLON:
+ if (*p == ':')
+ {
+ aTheCanonic.append(sal_Unicode(':'));
+ eState = STATE_IP6_2COLON;
+ }
+ else if (INetMIME::isDigit(*p))
+ {
+ nNumber = INetMIME::getWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP6_HEXSEQ1_MAYBE_IP4;
+ }
+ else if (INetMIME::isHexDigit(*p))
+ {
+ nNumber = INetMIME::getHexWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP6_HEXSEQ1;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_HEXSEQ1_MAYBE_IP4:
+ if (*p == ']')
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber), 16));
+ eState = STATE_IP6_DONE;
+ }
+ else if (*p == ':')
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber), 16));
+ aTheCanonic.append(sal_Unicode(':'));
+ eState = STATE_IP6_HEXSEQ1_COLON;
+ }
+ else if (*p == '.')
+ {
+ nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15)
+ + (nNumber & 15);
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber)));
+ aTheCanonic.append(sal_Unicode('.'));
+ nOctets = 2;
+ eState = STATE_IP6_IP4_DOT;
+ }
+ else if (INetMIME::isDigit(*p) && nDigits < 3)
+ {
+ nNumber = 16 * nNumber + INetMIME::getWeight(*p);
+ ++nDigits;
+ }
+ else if (INetMIME::isHexDigit(*p) && nDigits < 4)
+ {
+ nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
+ ++nDigits;
+ eState = STATE_IP6_HEXSEQ1;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_HEXSEQ2:
+ if (*p == ']')
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber), 16));
+ eState = STATE_IP6_DONE;
+ }
+ else if (*p == ':')
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber), 16));
+ aTheCanonic.append(sal_Unicode(':'));
+ eState = STATE_IP6_HEXSEQ2_COLON;
+ }
+ else if (INetMIME::isHexDigit(*p) && nDigits < 4)
+ {
+ nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
+ ++nDigits;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_HEXSEQ2_COLON:
+ if (INetMIME::isDigit(*p))
+ {
+ nNumber = INetMIME::getWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP6_HEXSEQ2_MAYBE_IP4;
+ }
+ else if (INetMIME::isHexDigit(*p))
+ {
+ nNumber = INetMIME::getHexWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP6_HEXSEQ2;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_HEXSEQ2_MAYBE_IP4:
+ if (*p == ']')
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber), 16));
+ eState = STATE_IP6_DONE;
+ }
+ else if (*p == ':')
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber), 16));
+ aTheCanonic.append(sal_Unicode(':'));
+ eState = STATE_IP6_HEXSEQ2_COLON;
+ }
+ else if (*p == '.')
+ {
+ nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15)
+ + (nNumber & 15);
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber)));
+ aTheCanonic.append(sal_Unicode('.'));
+ nOctets = 2;
+ eState = STATE_IP6_IP4_DOT;
+ }
+ else if (INetMIME::isDigit(*p) && nDigits < 3)
+ {
+ nNumber = 16 * nNumber + INetMIME::getWeight(*p);
+ ++nDigits;
+ }
+ else if (INetMIME::isHexDigit(*p) && nDigits < 4)
+ {
+ nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
+ ++nDigits;
+ eState = STATE_IP6_HEXSEQ2;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_IP4:
+ if (*p == ']')
+ if (nOctets == 4)
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber)));
+ eState = STATE_IP6_DONE;
+ }
+ else
+ goto done;
+ else if (*p == '.')
+ if (nOctets < 4)
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber)));
+ aTheCanonic.append(sal_Unicode('.'));
+ ++nOctets;
+ eState = STATE_IP6_IP4_DOT;
+ }
+ else
+ goto done;
+ else if (INetMIME::isDigit(*p) && nDigits < 3)
+ {
+ nNumber = 10 * nNumber + INetMIME::getWeight(*p);
+ ++nDigits;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_IP4_DOT:
+ if (INetMIME::isDigit(*p))
+ {
+ nNumber = INetMIME::getWeight(*p);
+ nDigits = 1;
+ eState = STATE_IP6_IP4;
+ }
+ else
+ goto done;
+ break;
+
+ case STATE_IP6_DONE:
+ goto done;
+ }
+ done:
+ switch (eState)
+ {
+ case STATE_LABEL:
+ case STATE_TOPLABEL:
+ case STATE_TOPLABEL_DOT:
+ aTheCanonic.setLength(0);
+ aTheCanonic.append(rBegin, p - rBegin);
+ rBegin = p;
+ rCanonic = aTheCanonic.makeStringAndClear();
+ return true;
+
+ case STATE_IP4:
+ if (nOctets == 4)
+ {
+ aTheCanonic.append(
+ rtl::OUString::valueOf(sal_Int32(nNumber)));
+ rBegin = p;
+ rCanonic = aTheCanonic.makeStringAndClear();
+ return true;
+ }
+ return false;
+
+ case STATE_IP6_DONE:
+ aTheCanonic.append(sal_Unicode(']'));
+ rBegin = p;
+ rCanonic = aTheCanonic.makeStringAndClear();
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+//============================================================================
+// static
+bool INetURLObject::parseHostOrNetBiosName(
+ sal_Unicode const * pBegin, sal_Unicode const * pEnd, bool bOctets,
+ EncodeMechanism eMechanism, rtl_TextEncoding eCharset, bool bNetBiosName,
+ rtl::OUStringBuffer* pCanonic)
+{
+ rtl::OUString aTheCanonic;
+ if (pBegin < pEnd)
+ {
+ sal_Unicode const * p = pBegin;
+ if (!parseHost(p, pEnd, aTheCanonic) || p != pEnd)
+ {
+ if (bNetBiosName)
+ {
+ rtl::OUStringBuffer buf;
+ while (pBegin < pEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, bOctets, '%',
+ eMechanism, eCharset,
+ eEscapeType);
+ if (!INetMIME::isVisible(nUTF32))
+ return false;
+ if (!INetMIME::isAlphanumeric(nUTF32))
+ switch (nUTF32)
+ {
+ case '"':
+ case '*':
+ case '+':
+ case ',':
+ case '/':
+ case ':':
+ case ';':
+ case '<':
+ case '=':
+ case '>':
+ case '?':
+ case '[':
+ case '\\':
+ case ']':
+ case '`':
+ case '|':
+ return false;;
+ }
+ if (pCanonic != NULL) {
+ appendUCS4(
+ buf, nUTF32, eEscapeType, bOctets, PART_URIC, '%',
+ eCharset, true);
+ }
+ }
+ aTheCanonic = buf.makeStringAndClear();
+ }
+ else
+ return false;
+ }
+ }
+ if (pCanonic != NULL) {
+ *pCanonic = aTheCanonic;
+ }
+ return true;
+}
+
+//============================================================================
+// static
+rtl::OUString INetURLObject::encodeHostPort(rtl::OUString const & rTheHostPort,
+ bool bOctets,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ sal_Int32 nPort = rTheHostPort.getLength();
+ if (nPort != 0)
+ {
+ sal_Int32 i = nPort - 1;
+ while (i != 0 && INetMIME::isDigit(rTheHostPort.getStr()[i]))
+ --i;
+ if (rTheHostPort.getStr()[i] == ':')
+ nPort = i;
+ }
+ rtl::OUString aResult(encodeText(rTheHostPort.copy(0, nPort), bOctets,
+ PART_HOST_EXTRA, '%', eMechanism, eCharset,
+ true));
+ aResult += rTheHostPort.copy(nPort);
+ return aResult;
+}
+
+//============================================================================
+bool INetURLObject::setHost(rtl::OUString const & rTheHost, bool bOctets,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ if (!getSchemeInfo().m_bHost)
+ return false;
+ rtl::OUStringBuffer aSynHost(rTheHost);
+ bool bNetBiosName = false;
+ switch (m_eScheme)
+ {
+ case INET_PROT_FILE:
+ {
+ rtl::OUString sTemp(aSynHost);
+ if (sTemp.equalsIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("localhost")))
+ {
+ aSynHost.setLength(0);
+ }
+ bNetBiosName = true;
+ }
+ break;
+ case INET_PROT_LDAP:
+ if (aSynHost.getLength() == 0 && m_aPort.isPresent())
+ return false;
+ break;
+
+ default:
+ if (aSynHost.getLength() == 0)
+ return false;
+ break;
+ }
+ if (!parseHostOrNetBiosName(
+ aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(),
+ bOctets, eMechanism, eCharset, bNetBiosName, &aSynHost))
+ return false;
+ sal_Int32 nDelta = m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear());
+ m_aPort += nDelta;
+ m_aPath += nDelta;
+ m_aQuery += nDelta;
+ m_aFragment += nDelta;
+ return true;
+}
+
+//============================================================================
+// static
+bool INetURLObject::parsePath(INetProtocol eScheme,
+ sal_Unicode const ** pBegin,
+ sal_Unicode const * pEnd,
+ bool bOctets,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset,
+ bool bSkippedInitialSlash,
+ sal_uInt32 nSegmentDelimiter,
+ sal_uInt32 nAltSegmentDelimiter,
+ sal_uInt32 nQueryDelimiter,
+ sal_uInt32 nFragmentDelimiter,
+ rtl::OUStringBuffer &rSynPath)
+{
+ DBG_ASSERT(pBegin, "INetURLObject::parsePath(): Null output param");
+
+ sal_Unicode const * pPos = *pBegin;
+ rtl::OUStringBuffer aTheSynPath;
+
+ switch (eScheme)
+ {
+ case INET_PROT_NOT_VALID:
+ return false;
+
+ case INET_PROT_FTP:
+ case INET_PROT_IMAP:
+ if (pPos < pEnd && *pPos != '/')
+ return false;
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_HTTP_PATH, '%', eCharset, true);
+ }
+ if (aTheSynPath.getLength() == 0)
+ aTheSynPath.append(sal_Unicode('/'));
+ break;
+
+ case INET_PROT_HTTP:
+ case INET_PROT_VND_SUN_STAR_WEBDAV:
+ case INET_PROT_HTTPS:
+ case INET_PROT_SMB:
+ if (pPos < pEnd && *pPos != '/')
+ return false;
+ while (pPos < pEnd && *pPos != nQueryDelimiter
+ && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_HTTP_PATH, '%', eCharset, true);
+ }
+ if (aTheSynPath.getLength() == 0)
+ aTheSynPath.append(sal_Unicode('/'));
+ break;
+
+ case INET_PROT_FILE:
+ {
+ if (bSkippedInitialSlash)
+ aTheSynPath.append(sal_Unicode('/'));
+ else if (pPos < pEnd
+ && *pPos != nSegmentDelimiter
+ && *pPos != nAltSegmentDelimiter)
+ return false;
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ if (eEscapeType == ESCAPE_NO)
+ {
+ if (nUTF32 == nSegmentDelimiter
+ || nUTF32 == nAltSegmentDelimiter)
+ {
+ aTheSynPath.append(sal_Unicode('/'));
+ continue;
+ }
+ else if (nUTF32 == '|'
+ && (pPos == pEnd
+ || *pPos == nFragmentDelimiter
+ || *pPos == nSegmentDelimiter
+ || *pPos == nAltSegmentDelimiter)
+ && aTheSynPath.getLength() == 2
+ && INetMIME::isAlpha(aTheSynPath.charAt(1)))
+ {
+ // A first segment of <ALPHA "|"> is translated to
+ // <ALPHA ":">:
+ aTheSynPath.append(sal_Unicode(':'));
+ continue;
+ }
+ }
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_PCHAR, '%', eCharset, true);
+ }
+ if (aTheSynPath.getLength() == 0)
+ aTheSynPath.append(sal_Unicode('/'));
+ break;
+ }
+
+ case INET_PROT_MAILTO:
+ while (pPos < pEnd && *pPos != nQueryDelimiter
+ && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_MAILTO, '%', eCharset, true);
+ }
+ break;
+
+ case INET_PROT_NEWS:
+ if (pPos == pEnd || *pPos == nQueryDelimiter
+ || *pPos == nFragmentDelimiter)
+ return false;
+
+ // Match <"*">:
+ if (*pPos == '*'
+ && (pEnd - pPos == 1 || pPos[1] == nQueryDelimiter
+ || pPos[1] == nFragmentDelimiter))
+ {
+ ++pPos;
+ aTheSynPath.append(sal_Unicode('*'));
+ break;
+ }
+
+ // Match <group>:
+ if (INetMIME::isAlpha(*pPos))
+ for (sal_Unicode const * p = pPos + 1;; ++p)
+ if (p == pEnd || *p == nQueryDelimiter
+ || *p == nFragmentDelimiter)
+ {
+ aTheSynPath.setLength(0);
+ aTheSynPath.append(pPos, p - pPos);
+ pPos = p;
+ goto done;
+ }
+ else if (!INetMIME::isAlphanumeric(*p) && *p != '+'
+ && *p != '-' && *p != '.' && *p != '_')
+ break;
+
+ // Match <article>:
+ for (;;)
+ {
+ if (pPos == pEnd || *pPos == nQueryDelimiter
+ || *pPos == nFragmentDelimiter)
+ return false;
+ if (*pPos == '@')
+ break;
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, '%',
+ eMechanism, eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_NEWS_ARTICLE_LOCALPART, '%', eCharset, true);
+ }
+ if (aTheSynPath.getLength() == 0)
+ return false;
+ ++pPos;
+ aTheSynPath.append(sal_Unicode('@'));
+ {
+ sal_Unicode const * p = pPos;
+ while (p < pEnd && *pPos != nQueryDelimiter
+ && *pPos != nFragmentDelimiter)
+ ++p;
+ rtl::OUString aCanonic;
+ if (!parseHost(pPos, p, aCanonic))
+ return false;
+ aTheSynPath.append(aCanonic);
+ }
+
+ done:
+ break;
+
+ case INET_PROT_POP3:
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_MESSAGE_ID_PATH, '%', eCharset,
+ true);
+ }
+ break;
+
+ case INET_PROT_PRIV_SOFFICE:
+ case INET_PROT_SLOT:
+ case INET_PROT_MACRO:
+ case INET_PROT_UNO:
+ case INET_PROT_COMPONENT:
+ case INET_PROT_LDAP:
+ while (pPos < pEnd && *pPos != nQueryDelimiter
+ && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_PATH_BEFORE_QUERY, '%', eCharset,
+ true);
+ }
+ break;
+
+ case INET_PROT_VND_SUN_STAR_HELP:
+ if (pPos == pEnd
+ || *pPos == nQueryDelimiter
+ || *pPos == nFragmentDelimiter)
+ aTheSynPath.append(sal_Unicode('/'));
+ else
+ {
+ if (*pPos != '/')
+ return false;
+ while (pPos < pEnd && *pPos != nQueryDelimiter
+ && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_HTTP_PATH, '%', eCharset, true);
+ }
+ }
+ break;
+
+ case INET_PROT_JAVASCRIPT:
+ case INET_PROT_DATA:
+ case INET_PROT_CID:
+ case INET_PROT_DB:
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_URIC, '%', eCharset, true);
+ }
+ break;
+
+ case INET_PROT_OUT:
+ if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '~')
+ return false;
+ aTheSynPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("/~"));
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_URIC, '%', eCharset, true);
+ }
+ break;
+
+ case INET_PROT_VND_SUN_STAR_HIER:
+ case INET_PROT_VND_SUN_STAR_PKG:
+ if (pPos < pEnd && *pPos != '/'
+ && *pPos != nQueryDelimiter && *pPos != nFragmentDelimiter)
+ return false;
+ while (pPos < pEnd && *pPos != nQueryDelimiter
+ && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ if (eEscapeType == ESCAPE_NO && nUTF32 == '/')
+ aTheSynPath.append(sal_Unicode('/'));
+ else
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_PCHAR, '%', eCharset, false);
+ }
+ if (aTheSynPath.getLength() == 0)
+ aTheSynPath.append(sal_Unicode('/'));
+ break;
+
+ case INET_PROT_VIM:
+ {
+/* test had to be taken out to make parsePath static; ok since INET_PROT_VIM is
+ obsolete, anyway
+ if (m_aUser.isEmpty())
+ return false;
+*/
+ sal_Unicode const * pPathEnd = pPos;
+ while (pPathEnd < pEnd && *pPathEnd != nFragmentDelimiter)
+ ++pPathEnd;
+ aTheSynPath.append(sal_Unicode('/'));
+ if (pPos == pPathEnd)
+ break;
+ else if (*pPos++ != '/')
+ return false;
+ if (pPos == pPathEnd)
+ break;
+ while (pPos < pPathEnd && *pPos != '/')
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets,
+ '=', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath,
+ eEscapeType == ESCAPE_NO ?
+ INetMIME::toLowerCase(nUTF32) : nUTF32,
+ eEscapeType, bOctets, PART_VIM, '=',
+ eCharset, false);
+ }
+ bool bInbox;
+ rtl::OUString sCompare(aTheSynPath);
+ if (sCompare.equalsAscii("/inbox"))
+ bInbox = true;
+ else if (sCompare.equalsAscii("/newsgroups"))
+ bInbox = false;
+ else
+ return false;
+ aTheSynPath.append(sal_Unicode('/'));
+ if (pPos == pPathEnd)
+ break;
+ else if (*pPos++ != '/')
+ return false;
+ if (!bInbox)
+ {
+ bool bEmpty = true;
+ while (pPos < pPathEnd && *pPos != '/')
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets,
+ '=', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_VIM, '=', eCharset, false);
+ bEmpty = false;
+ }
+ if (bEmpty)
+ return false;
+ aTheSynPath.append(sal_Unicode('/'));
+ if (pPos == pPathEnd)
+ break;
+ else if (*pPos++ != '/')
+ return false;
+ }
+ bool bEmpty = true;
+ while (pPos < pPathEnd && *pPos != ':')
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets,
+ '=', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_VIM, '=', eCharset, false);
+ bEmpty = false;
+ }
+ if (bEmpty)
+ return false;
+ if (pPos == pPathEnd)
+ break;
+ else if (*pPos++ != ':')
+ return false;
+ aTheSynPath.append(sal_Unicode(':'));
+ for (int i = 0; i < 3; ++i)
+ {
+ if (i != 0)
+ {
+ if (pPos == pPathEnd || *pPos++ != '.')
+ return false;
+ aTheSynPath.append(sal_Unicode('.'));
+ }
+ bEmpty = true;
+ while (pPos < pPathEnd && *pPos != '.')
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets,
+ '=', eMechanism,
+ eCharset, eEscapeType);
+ if (!INetMIME::isDigit(nUTF32))
+ return false;
+ aTheSynPath.append(sal_Unicode(nUTF32));
+ bEmpty = false;
+ }
+ if (bEmpty)
+ return false;
+ }
+ if (pPos != pPathEnd)
+ return false;
+ break;
+ }
+
+ case INET_PROT_VND_SUN_STAR_CMD:
+ case INET_PROT_VND_SUN_STAR_EXPAND:
+ {
+ if (pPos == pEnd || *pPos == nFragmentDelimiter)
+ return false;
+ Part ePart = PART_URIC_NO_SLASH;
+ while (pPos != pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, ePart,
+ '%', eCharset, true);
+ ePart = PART_URIC;
+ }
+ break;
+ }
+
+ case INET_PROT_VND_SUN_STAR_ODMA:
+ if (pPos < pEnd)
+ {
+ if (*pPos == '/')
+ ++pPos;
+ else
+ return false;
+ }
+ aTheSynPath.append(sal_Unicode('/'));
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_URIC_NO_SLASH, '%', eCharset, true);
+ }
+ break;
+
+ case INET_PROT_TELNET:
+ if (pPos < pEnd)
+ {
+ if (*pPos != '/' || pEnd - pPos > 1)
+ return false;
+ ++pPos;
+ }
+ aTheSynPath.append(sal_Unicode('/'));
+ break;
+
+ case INET_PROT_VND_SUN_STAR_TDOC:
+ if (pPos == pEnd || *pPos != '/')
+ return false;
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ if (eEscapeType == ESCAPE_NO && nUTF32 == '/')
+ aTheSynPath.append(sal_Unicode('/'));
+ else
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_PCHAR, '%', eCharset, false);
+ }
+ break;
+
+ case INET_PROT_GENERIC:
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
+ '%', eMechanism,
+ eCharset, eEscapeType);
+ appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
+ PART_URIC, '%', eCharset, true);
+ }
+ if (aTheSynPath.getLength() == 0)
+ return false;
+ break;
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+
+ *pBegin = pPos;
+ rSynPath = aTheSynPath;
+ return true;
+}
+
+//============================================================================
+bool INetURLObject::setPath(rtl::OUString const & rThePath, bool bOctets,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ rtl::OUStringBuffer aSynPath;
+ sal_Unicode const * p = rThePath.getStr();
+ sal_Unicode const * pEnd = p + rThePath.getLength();
+ if (!parsePath(m_eScheme, &p, pEnd, bOctets, eMechanism, eCharset, false,
+ '/', 0x80000000, 0x80000000, 0x80000000, aSynPath)
+ || p != pEnd)
+ return false;
+ sal_Int32 nDelta = m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear());
+ m_aQuery += nDelta;
+ m_aFragment += nDelta;
+ return true;
+}
+
+//============================================================================
+bool INetURLObject::checkHierarchical() const {
+ if (m_eScheme == INET_PROT_VND_SUN_STAR_EXPAND) {
+ OSL_ENSURE(
+ false, "INetURLObject::checkHierarchical vnd.sun.star.expand");
+ return true;
+ } else {
+ return getSchemeInfo().m_bHierarchical;
+ }
+}
+
+//============================================================================
+bool INetURLObject::appendSegment(rtl::OUString const & rTheSegment,
+ bool bOctets, EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ return insertName(rTheSegment, bOctets, false, LAST_SEGMENT, true,
+ eMechanism, eCharset);
+}
+
+//============================================================================
+INetURLObject::SubString INetURLObject::getSegment(sal_Int32 nIndex,
+ bool bIgnoreFinalSlash)
+ const
+{
+ DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT,
+ "INetURLObject::getSegment(): Bad index");
+
+ if (!checkHierarchical())
+ return SubString();
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ sal_Unicode const * pSegBegin;
+ sal_Unicode const * pSegEnd;
+ if (nIndex == LAST_SEGMENT)
+ {
+ pSegEnd = pPathEnd;
+ if (bIgnoreFinalSlash && pSegEnd > pPathBegin && pSegEnd[-1] == '/')
+ --pSegEnd;
+ if (pSegEnd <= pPathBegin)
+ return SubString();
+ pSegBegin = pSegEnd - 1;
+ while (pSegBegin > pPathBegin && *pSegBegin != '/')
+ --pSegBegin;
+ }
+ else
+ {
+ pSegBegin = pPathBegin;
+ while (nIndex-- > 0)
+ do
+ {
+ ++pSegBegin;
+ if (pSegBegin >= pPathEnd)
+ return SubString();
+ }
+ while (*pSegBegin != '/');
+ pSegEnd = pSegBegin + 1;
+ while (pSegEnd < pPathEnd && *pSegEnd != '/')
+ ++pSegEnd;
+ }
+
+ return SubString(pSegBegin - m_aAbsURIRef.getStr(),
+ pSegEnd - pSegBegin);
+}
+
+//============================================================================
+bool INetURLObject::insertName(rtl::OUString const & rTheName, bool bOctets,
+ bool bAppendFinalSlash, sal_Int32 nIndex,
+ bool bIgnoreFinalSlash,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT,
+ "INetURLObject::insertName(): Bad index");
+
+ if (!checkHierarchical())
+ return false;
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ sal_Unicode const * pPrefixEnd;
+ bool bInsertSlash;
+ sal_Unicode const * pSuffixBegin;
+ if (nIndex == LAST_SEGMENT)
+ {
+ pPrefixEnd = pPathEnd;
+ if (bIgnoreFinalSlash && pPrefixEnd > pPathBegin &&
+ pPrefixEnd[-1] == '/')
+ {
+ --pPrefixEnd;
+ }
+ bInsertSlash = bAppendFinalSlash;
+ pSuffixBegin = pPathEnd;
+ }
+ else if (nIndex == 0)
+ {
+ pPrefixEnd = pPathBegin;
+ bInsertSlash =
+ (pPathBegin < pPathEnd && *pPathBegin != '/') ||
+ (pPathBegin == pPathEnd && bAppendFinalSlash);
+ pSuffixBegin =
+ (pPathEnd - pPathBegin == 1 && *pPathBegin == '/' &&
+ !bAppendFinalSlash && bIgnoreFinalSlash)
+ ? pPathEnd : pPathBegin;
+ }
+ else
+ {
+ pPrefixEnd = pPathBegin;
+ sal_Unicode const * pEnd = pPathEnd;
+ if (bIgnoreFinalSlash && pEnd > pPathBegin && pEnd[-1] == '/')
+ --pEnd;
+ bool bSkip = pPrefixEnd < pEnd && *pPrefixEnd == '/';
+ bInsertSlash = false;
+ pSuffixBegin = pPathEnd;
+ while (nIndex-- > 0)
+ for (;;)
+ {
+ if (bSkip)
+ ++pPrefixEnd;
+ bSkip = true;
+ if (pPrefixEnd >= pEnd)
+ {
+ if (nIndex == 0)
+ {
+ bInsertSlash = bAppendFinalSlash;
+ break;
+ }
+ else
+ return false;
+ }
+ if (*pPrefixEnd == '/')
+ {
+ pSuffixBegin = pPrefixEnd;
+ break;
+ }
+ }
+ }
+
+ rtl::OUStringBuffer aNewPath;
+ aNewPath.append(pPathBegin, pPrefixEnd - pPathBegin);
+ aNewPath.append(sal_Unicode('/'));
+ aNewPath.append(encodeText(rTheName, bOctets, PART_PCHAR, getEscapePrefix(),
+ eMechanism, eCharset, true));
+ if (bInsertSlash) {
+ aNewPath.append(sal_Unicode('/'));
+ }
+ aNewPath.append(pSuffixBegin, pPathEnd - pSuffixBegin);
+
+ return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
+ RTL_TEXTENCODING_UTF8);
+}
+
+//============================================================================
+bool INetURLObject::clearQuery()
+{
+ if (HasError())
+ return false;
+ if (m_aQuery.isPresent())
+ {
+ lcl_Erase(m_aAbsURIRef, m_aQuery.getBegin() - 1,
+ m_aQuery.getLength() + 1);
+ m_aFragment += m_aQuery.clear() - 1;
+ }
+ return false;
+}
+
+//============================================================================
+bool INetURLObject::setQuery(rtl::OUString const & rTheQuery, bool bOctets,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ if (!getSchemeInfo().m_bQuery)
+ return false;
+ rtl::OUString aNewQuery(encodeText(rTheQuery, bOctets, PART_URIC,
+ getEscapePrefix(), eMechanism, eCharset,
+ true));
+ sal_Int32 nDelta;
+ if (m_aQuery.isPresent())
+ nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery);
+ else
+ {
+ m_aAbsURIRef.insert(m_aPath.getEnd(), sal_Unicode('?'));
+ nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery, m_aPath.getEnd() + 1)
+ + 1;
+ }
+ m_aFragment += nDelta;
+ return true;
+}
+
+//============================================================================
+bool INetURLObject::clearFragment()
+{
+ if (HasError())
+ return false;
+ if (m_aFragment.isPresent())
+ {
+ m_aAbsURIRef.setLength(m_aFragment.getBegin() - 1);
+ m_aFragment.clear();
+ }
+ return true;
+}
+
+//============================================================================
+bool INetURLObject::setFragment(rtl::OUString const & rTheFragment,
+ bool bOctets, EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ if (HasError())
+ return false;
+ rtl::OUString aNewFragment(encodeText(rTheFragment, bOctets, PART_URIC,
+ getEscapePrefix(), eMechanism,
+ eCharset, true));
+ if (m_aFragment.isPresent())
+ m_aFragment.set(m_aAbsURIRef, aNewFragment);
+ else
+ {
+ m_aAbsURIRef.append(sal_Unicode('#'));
+ m_aFragment.set(m_aAbsURIRef, aNewFragment, m_aAbsURIRef.getLength());
+ }
+ return true;
+}
+
+//============================================================================
+INetURLObject::FTPType INetURLObject::getFTPType() const
+{
+ if (m_eScheme == INET_PROT_FTP
+ && m_aPath.getLength() >= RTL_CONSTASCII_LENGTH(";type=") + 1
+ && rtl::OUString(m_aAbsURIRef).copy(
+ m_aPath.getEnd() - (RTL_CONSTASCII_LENGTH(";type=") + 1),
+ RTL_CONSTASCII_LENGTH(";type=")).equalsIgnoreAsciiCaseAscii(";type="))
+ switch (m_aAbsURIRef.charAt(m_aPath.getEnd()))
+ {
+ case 'A':
+ case 'a':
+ return FTP_TYPE_A;
+
+ case 'D':
+ case 'd':
+ return FTP_TYPE_D;
+
+ case 'I':
+ case 'i':
+ return FTP_TYPE_I;
+ }
+ return FTP_TYPE_NONE;
+}
+
+//============================================================================
+bool INetURLObject::hasDosVolume(FSysStyle eStyle) const
+{
+ sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ return (eStyle & FSYS_DOS) != 0
+ && m_aPath.getLength() >= 3
+ && p[0] == '/'
+ && INetMIME::isAlpha(p[1])
+ && p[2] == ':'
+ && (m_aPath.getLength() == 3 || p[3] == '/');
+}
+
+//============================================================================
+sal_uInt32 INetURLObject::getIMAPUID() const
+{
+ if (m_eScheme == INET_PROT_IMAP
+ && m_aPath.getLength() >= RTL_CONSTASCII_LENGTH("/;uid=") + 1)
+ {
+ sal_Unicode const * pBegin = m_aAbsURIRef.getStr()
+ + m_aPath.getBegin()
+ + RTL_CONSTASCII_LENGTH("/;uid=");
+ sal_Unicode const * pEnd = pBegin + m_aPath.getLength();
+ sal_Unicode const * p = pEnd;
+ while (p > pBegin && INetMIME::isDigit(p[-1]))
+ --p;
+ if (p < pEnd && *--p != '0'
+ && rtl::OUString(m_aAbsURIRef).copy(
+ p - RTL_CONSTASCII_LENGTH("/;uid=") - m_aAbsURIRef.getStr(),
+ RTL_CONSTASCII_LENGTH("/;uid=")).equalsIgnoreAsciiCaseAscii("/;uid=")
+ )
+ {
+ sal_uInt32 nUID;
+ if (INetMIME::scanUnsigned(p, pEnd, false, nUID))
+ return nUID;
+ }
+ }
+ return 0;
+}
+
+//============================================================================
+// static
+rtl::OUString INetURLObject::encodeText(sal_Unicode const * pBegin,
+ sal_Unicode const * pEnd, bool bOctets,
+ Part ePart, sal_Char cEscapePrefix,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset,
+ bool bKeepVisibleEscapes)
+{
+ rtl::OUStringBuffer aResult;
+ while (pBegin < pEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, bOctets, cEscapePrefix,
+ eMechanism, eCharset, eEscapeType);
+ appendUCS4(aResult, nUTF32, eEscapeType, bOctets, ePart,
+ cEscapePrefix, eCharset, bKeepVisibleEscapes);
+ }
+ return aResult.makeStringAndClear();
+}
+
+//============================================================================
+// static
+rtl::OUString INetURLObject::decode(sal_Unicode const * pBegin,
+ sal_Unicode const * pEnd,
+ sal_Char cEscapePrefix,
+ DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ switch (eMechanism)
+ {
+ case NO_DECODE:
+ return rtl::OUString(pBegin, pEnd - pBegin);
+
+ case DECODE_TO_IURI:
+ eCharset = RTL_TEXTENCODING_UTF8;
+ break;
+
+ default:
+ break;
+ }
+ rtl::OUStringBuffer aResult;
+ while (pBegin < pEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, false, cEscapePrefix,
+ WAS_ENCODED, eCharset, eEscapeType);
+ switch (eEscapeType)
+ {
+ case ESCAPE_NO:
+ aResult.append(sal_Unicode(nUTF32));
+ break;
+
+ case ESCAPE_OCTET:
+ appendEscape(aResult, cEscapePrefix, nUTF32);
+ break;
+
+ case ESCAPE_UTF32:
+ if (
+ INetMIME::isUSASCII(nUTF32) &&
+ (
+ eMechanism == DECODE_TO_IURI ||
+ (
+ eMechanism == DECODE_UNAMBIGUOUS &&
+ mustEncode(nUTF32, PART_UNAMBIGUOUS)
+ )
+ )
+ )
+ {
+ appendEscape(aResult, cEscapePrefix, nUTF32);
+ }
+ else
+ aResult.append(sal_Unicode(nUTF32));
+ break;
+ }
+ }
+ return aResult.makeStringAndClear();
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetURLNoPass(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ INetURLObject aTemp(*this);
+ aTemp.clearPassword();
+ return aTemp.GetMainURL(eMechanism, eCharset);
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetURLNoMark(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ INetURLObject aTemp(*this);
+ aTemp.clearFragment();
+ return aTemp.GetMainURL(eMechanism, eCharset);
+}
+
+//============================================================================
+rtl::OUString
+INetURLObject::getAbbreviated(
+ star::uno::Reference< star::util::XStringWidth > const & rStringWidth,
+ sal_Int32 nWidth,
+ DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+ const
+{
+ OSL_ENSURE(rStringWidth.is(), "specification violation");
+ sal_Char cEscapePrefix = getEscapePrefix();
+ rtl::OUStringBuffer aBuffer;
+ // make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme
+ // is empty ("") in that case, so take the scheme from m_aAbsURIRef
+ if (m_eScheme != INET_PROT_GENERIC)
+ {
+ aBuffer.appendAscii(getSchemeInfo().m_pScheme);
+ }
+ else
+ {
+ if (m_aAbsURIRef)
+ {
+ sal_Unicode const * pSchemeBegin
+ = m_aAbsURIRef.getStr();
+ sal_Unicode const * pSchemeEnd = pSchemeBegin;
+
+ while (pSchemeEnd[0] != ':')
+ {
+ ++pSchemeEnd;
+ }
+ aBuffer.append(pSchemeBegin, pSchemeEnd - pSchemeBegin);
+ }
+ }
+ aBuffer.append(static_cast< sal_Unicode >(':'));
+ bool bAuthority = getSchemeInfo().m_bAuthority;
+ sal_Unicode const * pCoreBegin
+ = m_aAbsURIRef.getStr() + (bAuthority ? getAuthorityBegin() :
+ m_aPath.getBegin());
+ sal_Unicode const * pCoreEnd
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin() + m_aPath.getLength();
+ bool bSegment = false;
+ if (getSchemeInfo().m_bHierarchical)
+ {
+ rtl::OUString aRest;
+ if (m_aQuery.isPresent())
+ aRest = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("?..."));
+ else if (m_aFragment.isPresent())
+ aRest = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("#..."));
+ rtl::OUStringBuffer aTrailer;
+ sal_Unicode const * pBegin = pCoreBegin;
+ sal_Unicode const * pEnd = pCoreEnd;
+ sal_Unicode const * pPrefixBegin = pBegin;
+ sal_Unicode const * pSuffixEnd = pEnd;
+ bool bPrefix = true;
+ bool bSuffix = true;
+ do
+ {
+ if (bSuffix)
+ {
+ sal_Unicode const * p = pSuffixEnd - 1;
+ if (pSuffixEnd == pCoreEnd && *p == '/')
+ --p;
+ while (*p != '/')
+ --p;
+ if (bAuthority && p == pCoreBegin + 1)
+ --p;
+ rtl::OUString
+ aSegment(decode(p + (p == pBegin && pBegin != pCoreBegin ?
+ 1 : 0),
+ pSuffixEnd,
+ cEscapePrefix,
+ eMechanism,
+ eCharset));
+ pSuffixEnd = p;
+ rtl::OUStringBuffer aResult(aBuffer);
+ if (pSuffixEnd != pBegin)
+ aResult.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
+ aResult.append(aSegment);
+ aResult.append(aTrailer);
+ aResult.append(aRest);
+ if (rStringWidth->
+ queryStringWidth(aResult.makeStringAndClear())
+ <= nWidth)
+ {
+ aTrailer.insert(0, aSegment);
+ bSegment = true;
+ pEnd = pSuffixEnd;
+ }
+ else
+ bSuffix = false;
+ if (pPrefixBegin > pSuffixEnd)
+ pPrefixBegin = pSuffixEnd;
+ if (pBegin == pEnd)
+ break;
+ }
+ if (bPrefix)
+ {
+ sal_Unicode const * p
+ = pPrefixBegin
+ + (bAuthority && pPrefixBegin == pCoreBegin ? 2 :
+ 1);
+ OSL_ASSERT(p <= pEnd);
+ while (p < pEnd && *p != '/')
+ ++p;
+ if (p == pCoreEnd - 1 && *p == '/')
+ ++p;
+ rtl::OUString
+ aSegment(decode(pPrefixBegin
+ + (pPrefixBegin == pCoreBegin ? 0 :
+ 1),
+ p == pEnd ? p : p + 1,
+ cEscapePrefix,
+ eMechanism,
+ eCharset));
+ pPrefixBegin = p;
+ rtl::OUStringBuffer aResult(aBuffer);
+ aResult.append(aSegment);
+ if (pPrefixBegin != pEnd)
+ aResult.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
+ aResult.append(aTrailer);
+ aResult.append(aRest);
+ if (rStringWidth->
+ queryStringWidth(aResult.makeStringAndClear())
+ <= nWidth)
+ {
+ aBuffer.append(aSegment);
+ bSegment = true;
+ pBegin = pPrefixBegin;
+ }
+ else
+ bPrefix = false;
+ if (pPrefixBegin > pSuffixEnd)
+ pSuffixEnd = pPrefixBegin;
+ if (pBegin == pEnd)
+ break;
+ }
+ }
+ while (bPrefix || bSuffix);
+ if (bSegment)
+ {
+ if (pPrefixBegin != pBegin || pSuffixEnd != pEnd)
+ aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
+ aBuffer.append(aTrailer);
+ }
+ }
+ if (!bSegment)
+ aBuffer.append(decode(pCoreBegin,
+ pCoreEnd,
+ cEscapePrefix,
+ eMechanism,
+ eCharset));
+ if (m_aQuery.isPresent())
+ {
+ aBuffer.append(static_cast< sal_Unicode >('?'));
+ aBuffer.append(decode(m_aQuery, cEscapePrefix, eMechanism, eCharset));
+ }
+ if (m_aFragment.isPresent())
+ {
+ aBuffer.append(static_cast< sal_Unicode >('#'));
+ aBuffer.
+ append(decode(m_aFragment, cEscapePrefix, eMechanism, eCharset));
+ }
+ if (aBuffer.getLength() != 0)
+ {
+ rtl::OUStringBuffer aResult(aBuffer);
+ if (rStringWidth->queryStringWidth(aResult.makeStringAndClear())
+ > nWidth)
+ for (sal_Int32 i = aBuffer.getLength();;)
+ {
+ if (i == 0)
+ {
+ aBuffer.setLength(aBuffer.getLength() - 1);
+ if (aBuffer.getLength() == 0)
+ break;
+ }
+ else
+ {
+ aBuffer.setLength(--i);
+ aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
+ }
+ aResult = aBuffer;
+ if (rStringWidth->
+ queryStringWidth(aResult.makeStringAndClear())
+ <= nWidth)
+ break;
+ }
+ }
+ return aBuffer.makeStringAndClear();
+}
+
+//============================================================================
+bool INetURLObject::operator ==(INetURLObject const & rObject) const
+{
+ if (m_eScheme != rObject.m_eScheme)
+ return false;
+ if (m_eScheme == INET_PROT_NOT_VALID)
+ return (m_aAbsURIRef == rObject.m_aAbsURIRef) != false;
+ if ((m_aScheme.compare(
+ rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef)
+ != 0)
+ || GetUser(NO_DECODE) != rObject.GetUser(NO_DECODE)
+ || GetPass(NO_DECODE) != rObject.GetPass(NO_DECODE)
+ || !GetHost(NO_DECODE).equalsIgnoreAsciiCase(
+ rObject.GetHost(NO_DECODE))
+ || GetPort() != rObject.GetPort()
+ || HasParam() != rObject.HasParam()
+ || GetParam(NO_DECODE) != rObject.GetParam(NO_DECODE)
+ || GetMsgId(NO_DECODE) != rObject.GetMsgId(NO_DECODE))
+ return false;
+ rtl::OUString aPath1(GetURLPath(NO_DECODE));
+ rtl::OUString aPath2(rObject.GetURLPath(NO_DECODE));
+ switch (m_eScheme)
+ {
+ case INET_PROT_FILE:
+ {
+ // If the URL paths of two file URLs only differ in that one has a
+ // final '/' and the other has not, take the two paths as
+ // equivalent (this could be usefull for other schemes, too):
+ sal_Int32 nLength = aPath1.getLength();
+ switch (nLength - aPath2.getLength())
+ {
+ case -1:
+ if (aPath2.getStr()[nLength] != '/')
+ return false;
+ break;
+
+ case 0:
+ break;
+
+ case 1:
+ if (aPath1.getStr()[--nLength] != '/')
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+ return aPath1.compareTo(aPath2, nLength) == 0;
+ }
+
+ default:
+ return (aPath1 == aPath2) != false;
+ }
+}
+
+//============================================================================
+bool INetURLObject::operator <(INetURLObject const & rObject) const
+{
+ sal_Int32 nCompare = m_aScheme.compare(
+ rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef);
+ if (nCompare < 0) {
+ return true;
+ } else if (nCompare > 0) {
+ return false;
+ }
+ sal_uInt32 nPort1 = GetPort();
+ sal_uInt32 nPort2 = rObject.GetPort();
+ if (nPort1 < nPort2)
+ return true;
+ else if (nPort1 > nPort2)
+ return false;
+ nCompare = GetUser(NO_DECODE).compareTo(rObject.GetUser(NO_DECODE));
+ if (nCompare < 0)
+ return true;
+ else if (nCompare > 0)
+ return false;
+ nCompare = GetPass(NO_DECODE).compareTo(rObject.GetPass(NO_DECODE));
+ if (nCompare < 0)
+ return true;
+ else if (nCompare > 0)
+ return false;
+ nCompare = GetHost(NO_DECODE).compareTo(rObject.GetHost(NO_DECODE));
+ if (nCompare < 0)
+ return true;
+ else if (nCompare > 0)
+ return false;
+ const rtl::OUString &rPath1(GetURLPath(NO_DECODE));
+ const rtl::OUString &rPath2(rObject.GetURLPath(NO_DECODE));
+ nCompare = rPath1.compareTo(rPath2);
+ if (nCompare < 0)
+ return true;
+ else if (nCompare > 0)
+ return false;
+ nCompare = GetParam(NO_DECODE).compareTo(rObject.GetParam(NO_DECODE));
+ if (nCompare < 0)
+ return true;
+ else if (nCompare > 0)
+ return false;
+ return GetMsgId(NO_DECODE).compareTo(rObject.GetMsgId(NO_DECODE)) < 0;
+}
+
+//============================================================================
+bool INetURLObject::ConcatData(INetProtocol eTheScheme,
+ rtl::OUString const & rTheUser,
+ rtl::OUString const & rThePassword,
+ rtl::OUString const & rTheHost,
+ sal_uInt32 nThePort,
+ rtl::OUString const & rThePath,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ setInvalid();
+ m_eScheme = eTheScheme;
+ if (HasError() || m_eScheme == INET_PROT_GENERIC)
+ return false;
+ m_aAbsURIRef.setLength(0);
+ m_aAbsURIRef.appendAscii(getSchemeInfo().m_pScheme);
+ m_aAbsURIRef.append(sal_Unicode(':'));
+ if (getSchemeInfo().m_bAuthority)
+ {
+ m_aAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ bool bUserInfo = false;
+ if (getSchemeInfo().m_bUser)
+ {
+ if (m_eScheme == INET_PROT_IMAP && rTheUser.getLength() == 0)
+ {
+ setInvalid();
+ return false;
+ }
+ if (rTheUser.getLength() != 0)
+ {
+ m_aUser.set(m_aAbsURIRef,
+ encodeText(rTheUser, false,
+ m_eScheme == INET_PROT_IMAP ?
+ PART_IMAP_ACHAR :
+ m_eScheme == INET_PROT_VIM ?
+ PART_VIM :
+ PART_USER_PASSWORD,
+ getEscapePrefix(), eMechanism,
+ eCharset, false),
+ m_aAbsURIRef.getLength());
+ bUserInfo = true;
+ }
+ }
+ else if (rTheUser.getLength() != 0)
+ {
+ setInvalid();
+ return false;
+ }
+ if (rThePassword.getLength() != 0)
+ {
+ if (getSchemeInfo().m_bPassword)
+ {
+ m_aAbsURIRef.append(sal_Unicode(':'));
+ m_aAuth.set(m_aAbsURIRef,
+ encodeText(rThePassword, false,
+ m_eScheme == INET_PROT_VIM ?
+ PART_VIM : PART_USER_PASSWORD,
+ getEscapePrefix(), eMechanism,
+ eCharset, false),
+ m_aAbsURIRef.getLength());
+ bUserInfo = true;
+ }
+ else
+ {
+ setInvalid();
+ return false;
+ }
+ }
+ if (bUserInfo && getSchemeInfo().m_bHost)
+ m_aAbsURIRef.append(sal_Unicode('@'));
+ if (getSchemeInfo().m_bHost)
+ {
+ rtl::OUStringBuffer aSynHost(rTheHost);
+ bool bNetBiosName = false;
+ switch (m_eScheme)
+ {
+ case INET_PROT_FILE:
+ {
+ rtl::OUString sTemp(aSynHost);
+ if (sTemp.equalsIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("localhost")))
+ {
+ aSynHost.setLength(0);
+ }
+ bNetBiosName = true;
+ }
+ break;
+
+ case INET_PROT_LDAP:
+ if (aSynHost.getLength() == 0 && nThePort != 0)
+ {
+ setInvalid();
+ return false;
+ }
+ break;
+
+ default:
+ if (aSynHost.getLength() == 0)
+ {
+ setInvalid();
+ return false;
+ }
+ break;
+ }
+ if (!parseHostOrNetBiosName(
+ aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(),
+ false, eMechanism, eCharset, bNetBiosName, &aSynHost))
+ {
+ setInvalid();
+ return false;
+ }
+ m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear(),
+ m_aAbsURIRef.getLength());
+ if (nThePort != 0)
+ {
+ if (getSchemeInfo().m_bPort)
+ {
+ m_aAbsURIRef.append(sal_Unicode(':'));
+ m_aPort.set(m_aAbsURIRef,
+ rtl::OUString::valueOf(sal_Int64(nThePort)),
+ m_aAbsURIRef.getLength());
+ }
+ else
+ {
+ setInvalid();
+ return false;
+ }
+ }
+ }
+ else if (rTheHost.getLength() != 0 || nThePort != 0)
+ {
+ setInvalid();
+ return false;
+ }
+ }
+ rtl::OUStringBuffer aSynPath;
+ sal_Unicode const * p = rThePath.getStr();
+ sal_Unicode const * pEnd = p + rThePath.getLength();
+ if (!parsePath(m_eScheme, &p, pEnd, false, eMechanism, eCharset, false, '/',
+ 0x80000000, 0x80000000, 0x80000000, aSynPath)
+ || p != pEnd)
+ {
+ setInvalid();
+ return false;
+ }
+ m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear(),
+ m_aAbsURIRef.getLength());
+ return true;
+}
+
+//============================================================================
+// static
+rtl::OUString INetURLObject::GetAbsURL(rtl::OUString const & rTheBaseURIRef,
+ rtl::OUString const & rTheRelURIRef,
+ bool bIgnoreFragment,
+ EncodeMechanism eEncodeMechanism,
+ DecodeMechanism eDecodeMechanism,
+ rtl_TextEncoding eCharset,
+ FSysStyle eStyle)
+{
+ // Backwards compatibility:
+ if (rTheRelURIRef.getLength() == 0 || rTheRelURIRef[0] == '#')
+ return rTheRelURIRef;
+
+ INetURLObject aTheAbsURIRef;
+ bool bWasAbsolute;
+ return INetURLObject(rTheBaseURIRef, eEncodeMechanism, eCharset).
+ convertRelToAbs(rTheRelURIRef, false, aTheAbsURIRef,
+ bWasAbsolute, eEncodeMechanism,
+ eCharset, bIgnoreFragment, false,
+ false, eStyle)
+ || eEncodeMechanism != WAS_ENCODED
+ || eDecodeMechanism != DECODE_TO_IURI
+ || eCharset != RTL_TEXTENCODING_UTF8 ?
+ aTheAbsURIRef.GetMainURL(eDecodeMechanism, eCharset) :
+ rTheRelURIRef;
+}
+
+//============================================================================
+rtl::OUString INetURLObject::getExternalURL(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ rtl::OUString aTheExtURIRef;
+ translateToExternal(
+ rtl::OUString(m_aAbsURIRef), aTheExtURIRef, eMechanism, eCharset);
+ return aTheExtURIRef;
+}
+
+//============================================================================
+// static
+rtl::OUString INetURLObject::GetScheme(INetProtocol eTheScheme)
+{
+ return rtl::OUString::createFromAscii(getSchemeInfo(eTheScheme).m_pPrefix);
+}
+
+//============================================================================
+// static
+INetProtocol INetURLObject::CompareProtocolScheme(rtl::OUString const &
+ rTheAbsURIRef)
+{
+ sal_Unicode const * p = rTheAbsURIRef.getStr();
+ PrefixInfo const * pPrefix = getPrefix(p, p + rTheAbsURIRef.getLength());
+ return pPrefix ? pPrefix->m_eScheme : INET_PROT_NOT_VALID;
+}
+
+//============================================================================
+bool INetURLObject::hasPassword() const
+{
+ return m_aAuth.isPresent() && getSchemeInfo().m_bPassword;
+}
+
+//============================================================================
+void INetURLObject::makeAuthCanonic()
+{
+ if (m_eScheme == INET_PROT_IMAP && m_aAuth.getLength() == 1
+ && m_aAbsURIRef.charAt(m_aAuth.getBegin()) == '*')
+ {
+ lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin()
+ - RTL_CONSTASCII_LENGTH(";AUTH="),
+ RTL_CONSTASCII_LENGTH(";AUTH=*"));
+ sal_Int32 nDelta = m_aAuth.clear() - RTL_CONSTASCII_LENGTH(";AUTH=");
+ m_aPath += nDelta;
+ m_aQuery += nDelta;
+ m_aFragment += nDelta;
+ }
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetHostPort(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ // Check because PROT_VND_SUN_STAR_HELP, PROT_VND_SUN_STAR_HIER, and
+ // PROT_VND_SUN_STAR_PKG misuse m_aHost:
+ if (!getSchemeInfo().m_bHost)
+ return rtl::OUString();
+ rtl::OUStringBuffer aHostPort(decode(m_aHost, getEscapePrefix(),
+ eMechanism, eCharset));
+ if (m_aPort.isPresent())
+ {
+ aHostPort.append(sal_Unicode(':'));
+ aHostPort.append(decode(m_aPort, getEscapePrefix(),
+ eMechanism, eCharset));
+ }
+ return aHostPort.makeStringAndClear();
+}
+
+//============================================================================
+sal_uInt32 INetURLObject::GetPort() const
+{
+ if (m_aPort.isPresent())
+ {
+ sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin();
+ sal_Unicode const * pEnd = p + m_aPort.getLength();
+ sal_uInt32 nThePort;
+ if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd)
+ return nThePort;
+ }
+ return 0;
+}
+
+//============================================================================
+bool INetURLObject::SetPort(sal_uInt32 nThePort)
+{
+ if (getSchemeInfo().m_bPort && m_aHost.isPresent())
+ {
+ rtl::OUString aNewPort(rtl::OUString::valueOf(sal_Int64(nThePort)));
+ sal_Int32 nDelta;
+ if (m_aPort.isPresent())
+ nDelta = m_aPort.set(m_aAbsURIRef, aNewPort);
+ else
+ {
+ m_aAbsURIRef.insert(m_aHost.getEnd(), sal_Unicode(':'));
+ nDelta = m_aPort.set(m_aAbsURIRef, aNewPort, m_aHost.getEnd() + 1)
+ + 1;
+ }
+ m_aPath += nDelta;
+ m_aQuery += nDelta;
+ m_aFragment += nDelta;
+ return true;
+ }
+ return false;
+}
+
+//============================================================================
+void INetURLObject::makePortCanonic()
+{
+ if (m_aPort.isPresent())
+ {
+ sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin();
+ sal_Unicode const * pEnd = p + m_aPort.getLength();
+ sal_uInt32 nThePort;
+ if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd)
+ {
+ sal_Int32 nDelta;
+ if (nThePort != 0 && nThePort == getSchemeInfo().m_nDefaultPort)
+ {
+ lcl_Erase(m_aAbsURIRef, m_aPort.getBegin() - 1,
+ m_aPort.getLength() + 1);
+ nDelta = m_aPort.clear() - 1;
+ }
+ else
+ nDelta = m_aPort.set(m_aAbsURIRef,
+ rtl::OUString::valueOf(sal_Int64(nThePort)));
+ m_aPath += nDelta;
+ m_aQuery += nDelta;
+ m_aFragment += nDelta;
+ }
+ }
+}
+
+//============================================================================
+sal_Int32 INetURLObject::getSegmentCount(bool bIgnoreFinalSlash) const
+{
+ if (!checkHierarchical())
+ return 0;
+
+ sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pEnd = p + m_aPath.getLength();
+ if (bIgnoreFinalSlash && pEnd > p && pEnd[-1] == '/')
+ --pEnd;
+ sal_Int32 n = p == pEnd || *p == '/' ? 0 : 1;
+ while (p != pEnd)
+ if (*p++ == '/')
+ ++n;
+ return n;
+}
+
+//============================================================================
+bool INetURLObject::removeSegment(sal_Int32 nIndex, bool bIgnoreFinalSlash)
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return false;
+
+ rtl::OUStringBuffer aNewPath;
+ aNewPath.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(),
+ aSegment.getBegin() - m_aPath.getBegin());
+ if (bIgnoreFinalSlash && aSegment.getEnd() == m_aPath.getEnd())
+ aNewPath.append(sal_Unicode('/'));
+ else
+ aNewPath.append(m_aAbsURIRef.getStr() + aSegment.getEnd(),
+ m_aPath.getEnd() - aSegment.getEnd());
+ if (aNewPath.getLength() == 0 && !aSegment.isEmpty() &&
+ m_aAbsURIRef[aSegment.getBegin()] == '/')
+ {
+ aNewPath.append(sal_Unicode('/'));
+ }
+
+ return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
+ RTL_TEXTENCODING_UTF8);
+}
+
+//============================================================================
+rtl::OUString INetURLObject::getName(sal_Int32 nIndex, bool bIgnoreFinalSlash,
+ DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return rtl::OUString();
+
+ sal_Unicode const * pSegBegin
+ = m_aAbsURIRef.getStr() + aSegment.getBegin();
+ sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
+
+ if (pSegBegin < pSegEnd && *pSegBegin == '/')
+ ++pSegBegin;
+ sal_Unicode const * p = pSegBegin;
+ while (p != pSegEnd && *p != ';')
+ ++p;
+
+ return decode(pSegBegin, p, getEscapePrefix(), eMechanism, eCharset);
+}
+
+//============================================================================
+bool INetURLObject::setName(rtl::OUString const & rTheName, sal_Int32 nIndex,
+ bool bIgnoreFinalSlash,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return false;
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ sal_Unicode const * pSegBegin
+ = m_aAbsURIRef.getStr() + aSegment.getBegin();
+ sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
+
+ if (pSegBegin < pSegEnd && *pSegBegin == '/')
+ ++pSegBegin;
+ sal_Unicode const * p = pSegBegin;
+ while (p != pSegEnd && *p != ';')
+ ++p;
+
+ rtl::OUStringBuffer aNewPath;
+ aNewPath.append(pPathBegin, pSegBegin - pPathBegin);
+ aNewPath.append(encodeText(rTheName, false, PART_PCHAR, getEscapePrefix(),
+ eMechanism, eCharset, true));
+ aNewPath.append(p, pPathEnd - p);
+
+ return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
+ RTL_TEXTENCODING_UTF8);
+}
+
+//============================================================================
+bool INetURLObject::hasExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash)
+ const
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return false;
+
+ sal_Unicode const * pSegBegin
+ = m_aAbsURIRef.getStr() + aSegment.getBegin();
+ sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
+
+ if (pSegBegin < pSegEnd && *pSegBegin == '/')
+ ++pSegBegin;
+ for (sal_Unicode const * p = pSegBegin; p != pSegEnd && *p != ';'; ++p)
+ if (*p == '.' && p != pSegBegin)
+ return true;
+ return false;
+}
+
+//============================================================================
+rtl::OUString INetURLObject::getBase(sal_Int32 nIndex, bool bIgnoreFinalSlash,
+ DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return rtl::OUString();
+
+ sal_Unicode const * pSegBegin
+ = m_aAbsURIRef.getStr() + aSegment.getBegin();
+ sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
+
+ if (pSegBegin < pSegEnd && *pSegBegin == '/')
+ ++pSegBegin;
+ sal_Unicode const * pExtension = 0;
+ sal_Unicode const * p = pSegBegin;
+ for (; p != pSegEnd && *p != ';'; ++p)
+ if (*p == '.' && p != pSegBegin)
+ pExtension = p;
+ if (!pExtension)
+ pExtension = p;
+
+ return decode(pSegBegin, pExtension, getEscapePrefix(), eMechanism,
+ eCharset);
+}
+
+//============================================================================
+bool INetURLObject::setBase(rtl::OUString const & rTheBase, sal_Int32 nIndex,
+ bool bIgnoreFinalSlash,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return false;
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ sal_Unicode const * pSegBegin
+ = m_aAbsURIRef.getStr() + aSegment.getBegin();
+ sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
+
+ if (pSegBegin < pSegEnd && *pSegBegin == '/')
+ ++pSegBegin;
+ sal_Unicode const * pExtension = 0;
+ sal_Unicode const * p = pSegBegin;
+ for (; p != pSegEnd && *p != ';'; ++p)
+ if (*p == '.' && p != pSegBegin)
+ pExtension = p;
+ if (!pExtension)
+ pExtension = p;
+
+ rtl::OUStringBuffer aNewPath;
+ aNewPath.append(pPathBegin, pSegBegin - pPathBegin);
+ aNewPath.append(encodeText(rTheBase, false, PART_PCHAR, getEscapePrefix(),
+ eMechanism, eCharset, true));
+ aNewPath.append(pExtension, pPathEnd - pExtension);
+
+ return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
+ RTL_TEXTENCODING_UTF8);
+}
+
+//============================================================================
+rtl::OUString INetURLObject::getExtension(sal_Int32 nIndex,
+ bool bIgnoreFinalSlash,
+ DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return rtl::OUString();
+
+ sal_Unicode const * pSegBegin
+ = m_aAbsURIRef.getStr() + aSegment.getBegin();
+ sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
+
+ if (pSegBegin < pSegEnd && *pSegBegin == '/')
+ ++pSegBegin;
+ sal_Unicode const * pExtension = 0;
+ sal_Unicode const * p = pSegBegin;
+ for (; p != pSegEnd && *p != ';'; ++p)
+ if (*p == '.' && p != pSegBegin)
+ pExtension = p;
+
+ if (!pExtension)
+ return rtl::OUString();
+
+ return decode(pExtension + 1, p, getEscapePrefix(), eMechanism, eCharset);
+}
+
+//============================================================================
+bool INetURLObject::setExtension(rtl::OUString const & rTheExtension,
+ sal_Int32 nIndex, bool bIgnoreFinalSlash,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return false;
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ sal_Unicode const * pSegBegin
+ = m_aAbsURIRef.getStr() + aSegment.getBegin();
+ sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
+
+ if (pSegBegin < pSegEnd && *pSegBegin == '/')
+ ++pSegBegin;
+ sal_Unicode const * pExtension = 0;
+ sal_Unicode const * p = pSegBegin;
+ for (; p != pSegEnd && *p != ';'; ++p)
+ if (*p == '.' && p != pSegBegin)
+ pExtension = p;
+ if (!pExtension)
+ pExtension = p;
+
+ rtl::OUStringBuffer aNewPath;
+ aNewPath.append(pPathBegin, pExtension - pPathBegin);
+ aNewPath.append(sal_Unicode('.'));
+ aNewPath.append(encodeText(rTheExtension, false, PART_PCHAR,
+ getEscapePrefix(), eMechanism, eCharset, true));
+ aNewPath.append(p, pPathEnd - p);
+
+ return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
+ RTL_TEXTENCODING_UTF8);
+}
+
+//============================================================================
+bool INetURLObject::removeExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash)
+{
+ SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
+ if (!aSegment.isPresent())
+ return false;
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ sal_Unicode const * pSegBegin
+ = m_aAbsURIRef.getStr() + aSegment.getBegin();
+ sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
+
+ if (pSegBegin < pSegEnd && *pSegBegin == '/')
+ ++pSegBegin;
+ sal_Unicode const * pExtension = 0;
+ sal_Unicode const * p = pSegBegin;
+ for (; p != pSegEnd && *p != ';'; ++p)
+ if (*p == '.' && p != pSegBegin)
+ pExtension = p;
+ if (!pExtension)
+ return true;
+
+ rtl::OUStringBuffer aNewPath;
+ aNewPath.append(pPathBegin, pExtension - pPathBegin);
+ aNewPath.append(p, pPathEnd - p);
+
+ return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
+ RTL_TEXTENCODING_UTF8);
+}
+
+//============================================================================
+bool INetURLObject::hasFinalSlash() const
+{
+ if (!checkHierarchical())
+ return false;
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ return pPathEnd > pPathBegin && pPathEnd[-1] == '/';
+}
+
+//============================================================================
+bool INetURLObject::setFinalSlash()
+{
+ if (!checkHierarchical())
+ return false;
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ if (pPathEnd > pPathBegin && pPathEnd[-1] == '/')
+ return true;
+
+ rtl::OUStringBuffer aNewPath;
+ aNewPath.append(pPathBegin, pPathEnd - pPathBegin);
+ aNewPath.append(sal_Unicode('/'));
+
+ return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
+ RTL_TEXTENCODING_UTF8);
+}
+
+//============================================================================
+bool INetURLObject::removeFinalSlash()
+{
+ if (!checkHierarchical())
+ return false;
+
+ sal_Unicode const * pPathBegin
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
+ if (pPathEnd <= pPathBegin || pPathEnd[-1] != '/')
+ return true;
+
+ --pPathEnd;
+ if (pPathEnd == pPathBegin && *pPathBegin == '/')
+ return false;
+ rtl::OUString aNewPath(pPathBegin, pPathEnd - pPathBegin);
+
+ return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8);
+}
+
+//============================================================================
+// static
+rtl::OUString INetURLObject::createFragment(rtl::OUString const & rText)
+{
+ rtl::OUString aFragment(rText);
+ for (sal_Int32 i = 0; i < aFragment.getLength();)
+ {
+ sal_Unicode c = aFragment.getStr()[i];
+ if (mustEncode(c, PART_CREATEFRAGMENT))
+ aFragment = aFragment.replaceAt(i, 1, rtl::OUString());
+ else
+ ++i;
+ }
+ return aFragment;
+}
+
+//============================================================================
+bool INetURLObject::setFSysPath(rtl::OUString const & rFSysPath,
+ FSysStyle eStyle)
+{
+ sal_Unicode const * pFSysBegin = rFSysPath.getStr();
+ sal_Unicode const * pFSysEnd = pFSysBegin + rFSysPath.getLength();
+
+ switch ((eStyle & FSYS_VOS ? 1 : 0)
+ + (eStyle & FSYS_UNX ? 1 : 0)
+ + (eStyle & FSYS_DOS ? 1 : 0)
+ + (eStyle & FSYS_MAC ? 1 : 0))
+ {
+ case 0:
+ return false;
+
+ case 1:
+ break;
+
+ default:
+ if (eStyle & FSYS_VOS
+ && pFSysEnd - pFSysBegin >= 2
+ && pFSysBegin[0] == '/'
+ && pFSysBegin[1] == '/')
+ {
+ if (pFSysEnd - pFSysBegin >= 3
+ && pFSysBegin[2] == '.'
+ && (pFSysEnd - pFSysBegin == 3 || pFSysBegin[3] == '/'))
+ {
+ eStyle = FSYS_VOS; // Production T1
+ break;
+ }
+
+ sal_Unicode const * p = pFSysBegin + 2;
+ rtl::OUString aHost;
+ if (parseHost(p, pFSysEnd, aHost)
+ && (p == pFSysEnd || *p == '/'))
+ {
+ eStyle = FSYS_VOS; // Production T2
+ break;
+ }
+ }
+
+ if (eStyle & FSYS_DOS
+ && pFSysEnd - pFSysBegin >= 2
+ && pFSysBegin[0] == '\\'
+ && pFSysBegin[1] == '\\')
+ {
+ sal_Unicode const * p = pFSysBegin + 2;
+ rtl::OUString aHost;
+ if (parseHost(p, pFSysEnd, aHost)
+ && (p == pFSysEnd || *p == '\\'))
+ {
+ eStyle = FSYS_DOS; // Production T3
+ break;
+ }
+ }
+
+ if (eStyle & FSYS_DOS
+ && pFSysEnd - pFSysBegin >= 2
+ && INetMIME::isAlpha(pFSysBegin[0])
+ && pFSysBegin[1] == ':'
+ && (pFSysEnd - pFSysBegin == 2
+ || pFSysBegin[2] == '/'
+ || pFSysBegin[2] == '\\'))
+ {
+ eStyle = FSYS_DOS; // Productions T4, T5
+ break;
+ }
+
+ if (!(eStyle & (FSYS_UNX | FSYS_DOS | FSYS_MAC)))
+ return false;
+
+ eStyle = guessFSysStyleByCounting(pFSysBegin, pFSysEnd, eStyle);
+ // Production T6
+ break;
+ }
+
+ rtl::OUStringBuffer aSynAbsURIRef(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("file://")));
+
+ switch (eStyle)
+ {
+ case FSYS_VOS:
+ {
+ sal_Unicode const * p = pFSysBegin;
+ if (pFSysEnd - p < 2 || *p++ != '/' || *p++ != '/')
+ return false;
+ if (p != pFSysEnd && *p == '.'
+ && (pFSysEnd - p == 1 || p[1] == '/'))
+ ++p;
+ for (; p != pFSysEnd; ++p)
+ switch (*p)
+ {
+ case '#':
+ case '%':
+ appendEscape(aSynAbsURIRef, '%', *p);
+ break;
+
+ default:
+ aSynAbsURIRef.append(*p);
+ break;
+ }
+ break;
+ }
+
+ case FSYS_UNX:
+ {
+ sal_Unicode const * p = pFSysBegin;
+ if (p != pFSysEnd && *p != '/')
+ return false;
+ for (; p != pFSysEnd; ++p)
+ switch (*p)
+ {
+ case '|':
+ case '#':
+ case '%':
+ appendEscape(aSynAbsURIRef, '%', *p);
+ break;
+
+ default:
+ aSynAbsURIRef.append(*p);
+ break;
+ }
+ break;
+ }
+
+ case FSYS_DOS:
+ {
+ sal_uInt32 nAltDelimiter = 0x80000000;
+ sal_Unicode const * p = pFSysBegin;
+ if (pFSysEnd - p >= 3 && p[0] == '\\' && p[1] == '\\')
+ p += 2;
+ else
+ {
+ aSynAbsURIRef.append(sal_Unicode('/'));
+ if (pFSysEnd - p >= 2
+ && INetMIME::isAlpha(p[0])
+ && p[1] == ':'
+ && (pFSysEnd - p == 2 || p[2] == '\\' || p[2] == '/'))
+ nAltDelimiter = '/';
+ }
+ for (; p != pFSysEnd; ++p)
+ if (*p == '\\' || *p == nAltDelimiter)
+ aSynAbsURIRef.append(sal_Unicode('/'));
+ else
+ switch (*p)
+ {
+ case '/':
+ case '#':
+ case '%':
+ appendEscape(aSynAbsURIRef, '%', *p);
+ break;
+
+ default:
+ aSynAbsURIRef.append(*p);
+ break;
+ }
+ break;
+ }
+
+ case FSYS_MAC:
+ aSynAbsURIRef.append(sal_Unicode('/'));
+ {for (sal_Unicode const * p = pFSysBegin; p != pFSysEnd; ++p)
+ switch (*p)
+ {
+ case ':':
+ aSynAbsURIRef.append(sal_Unicode('/'));
+ break;
+
+ case '/':
+ case '|':
+ case '#':
+ case '%':
+ appendEscape(aSynAbsURIRef, '%', *p);
+ break;
+
+ default:
+ aSynAbsURIRef.append(*p);
+ break;
+ }
+ }
+ break;
+
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+
+ INetURLObject aTemp(aSynAbsURIRef.makeStringAndClear(), WAS_ENCODED,
+ RTL_TEXTENCODING_UTF8);
+ if (aTemp.HasError())
+ return false;
+
+ *this = aTemp;
+ return true;
+}
+
+//============================================================================
+rtl::OUString INetURLObject::getFSysPath(FSysStyle eStyle,
+ sal_Unicode * pDelimiter) const
+{
+ if (m_eScheme != INET_PROT_FILE)
+ return rtl::OUString();
+
+ if ((eStyle & FSYS_VOS ? 1 : 0)
+ + (eStyle & FSYS_UNX ? 1 : 0)
+ + (eStyle & FSYS_DOS ? 1 : 0)
+ + (eStyle & FSYS_MAC ? 1 : 0)
+ > 1)
+ {
+ eStyle = eStyle & FSYS_VOS
+ && m_aHost.isPresent()
+ && m_aHost.getLength() > 0 ?
+ FSYS_VOS :
+ hasDosVolume(eStyle)
+ || ((eStyle & FSYS_DOS) != 0
+ && m_aHost.isPresent()
+ && m_aHost.getLength() > 0) ?
+ FSYS_DOS :
+ eStyle & FSYS_UNX
+ && (!m_aHost.isPresent() || m_aHost.getLength() == 0) ?
+ FSYS_UNX :
+ FSysStyle(0);
+ }
+
+ switch (eStyle)
+ {
+ case FSYS_VOS:
+ {
+ if (pDelimiter)
+ *pDelimiter = '/';
+
+ rtl::OUStringBuffer aSynFSysPath;
+ aSynFSysPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
+ if (m_aHost.isPresent() && m_aHost.getLength() > 0)
+ aSynFSysPath.append(decode(m_aHost, '%', DECODE_WITH_CHARSET,
+ RTL_TEXTENCODING_UTF8));
+ else
+ aSynFSysPath.append(sal_Unicode('.'));
+ aSynFSysPath.append(decode(m_aPath, '%', DECODE_WITH_CHARSET,
+ RTL_TEXTENCODING_UTF8));
+ return aSynFSysPath.makeStringAndClear();
+ }
+
+ case FSYS_UNX:
+ {
+ if (m_aHost.isPresent() && m_aHost.getLength() > 0)
+ return rtl::OUString();
+
+ if (pDelimiter)
+ *pDelimiter = '/';
+
+ return decode(m_aPath, '%', DECODE_WITH_CHARSET,
+ RTL_TEXTENCODING_UTF8);
+ }
+
+ case FSYS_DOS:
+ {
+ if (pDelimiter)
+ *pDelimiter = '\\';
+
+ rtl::OUStringBuffer aSynFSysPath;
+ if (m_aHost.isPresent() && m_aHost.getLength() > 0)
+ {
+ aSynFSysPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("\\\\"));
+ aSynFSysPath.append(decode(m_aHost, '%', DECODE_WITH_CHARSET,
+ RTL_TEXTENCODING_UTF8));
+ aSynFSysPath.append(sal_Unicode('\\'));
+ }
+ sal_Unicode const * p
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pEnd = p + m_aPath.getLength();
+ DBG_ASSERT(p < pEnd && *p == '/',
+ "INetURLObject::getFSysPath(): Bad path");
+ ++p;
+ while (p < pEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(p, pEnd, false, '%', WAS_ENCODED,
+ RTL_TEXTENCODING_UTF8,
+ eEscapeType);
+ if (eEscapeType == ESCAPE_NO && nUTF32 == '/')
+ aSynFSysPath.append(sal_Unicode('\\'));
+ else
+ aSynFSysPath.appendUtf32(nUTF32);
+ }
+ return aSynFSysPath.makeStringAndClear();
+ }
+
+ case FSYS_MAC:
+ {
+ if (m_aHost.isPresent() && m_aHost.getLength() > 0)
+ return rtl::OUString();
+
+ if (pDelimiter)
+ *pDelimiter = ':';
+
+ rtl::OUStringBuffer aSynFSysPath;
+ sal_Unicode const * p
+ = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pEnd = p + m_aPath.getLength();
+ DBG_ASSERT(p < pEnd && *p == '/',
+ "INetURLObject::getFSysPath(): Bad path");
+ ++p;
+ while (p < pEnd)
+ {
+ EscapeType eEscapeType;
+ sal_uInt32 nUTF32 = getUTF32(p, pEnd, false, '%', WAS_ENCODED,
+ RTL_TEXTENCODING_UTF8,
+ eEscapeType);
+ if (eEscapeType == ESCAPE_NO && nUTF32 == '/')
+ aSynFSysPath.append(sal_Unicode(':'));
+ else
+ aSynFSysPath.appendUtf32(nUTF32);
+ }
+ return aSynFSysPath.makeStringAndClear();
+ }
+
+ default:
+ return rtl::OUString();
+ }
+}
+
+//============================================================================
+bool INetURLObject::HasMsgId() const
+{
+ if (m_eScheme != INET_PROT_POP3)
+ return false;
+ sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pEnd = p + m_aPath.getLength();
+ for (; p < pEnd; ++p)
+ if (*p == '<')
+ return true;
+ return false;
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetMsgId(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ if (m_eScheme != INET_PROT_POP3)
+ return rtl::OUString();
+ sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
+ sal_Unicode const * pEnd = p + m_aPath.getLength();
+ for (; p < pEnd; ++p)
+ if (*p == '<')
+ return decode(p, pEnd, getEscapePrefix(), eMechanism, eCharset);
+ return rtl::OUString();
+}
+
+//============================================================================
+// static
+void INetURLObject::appendUCS4Escape(rtl::OUStringBuffer & rTheText,
+ sal_Char cEscapePrefix, sal_uInt32 nUCS4)
+{
+ DBG_ASSERT(nUCS4 < 0x80000000,
+ "INetURLObject::appendUCS4Escape(): Bad char");
+ if (nUCS4 < 0x80)
+ appendEscape(rTheText, cEscapePrefix, nUCS4);
+ else if (nUCS4 < 0x800)
+ {
+ appendEscape(rTheText, cEscapePrefix, nUCS4 >> 6 | 0xC0);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
+ }
+ else if (nUCS4 < 0x10000)
+ {
+ appendEscape(rTheText, cEscapePrefix, nUCS4 >> 12 | 0xE0);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
+ }
+ else if (nUCS4 < 0x200000)
+ {
+ appendEscape(rTheText, cEscapePrefix, nUCS4 >> 18 | 0xF0);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
+ }
+ else if (nUCS4 < 0x4000000)
+ {
+ appendEscape(rTheText, cEscapePrefix, nUCS4 >> 24 | 0xF8);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 18 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
+ }
+ else
+ {
+ appendEscape(rTheText, cEscapePrefix, nUCS4 >> 30 | 0xFC);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 24 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 18 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80);
+ appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
+ }
+}
+
+//============================================================================
+// static
+void INetURLObject::appendUCS4(rtl::OUStringBuffer& rTheText, sal_uInt32 nUCS4,
+ EscapeType eEscapeType, bool bOctets,
+ Part ePart, sal_Char cEscapePrefix,
+ rtl_TextEncoding eCharset,
+ bool bKeepVisibleEscapes)
+{
+ bool bEscape;
+ rtl_TextEncoding eTargetCharset = RTL_TEXTENCODING_DONTKNOW;
+ switch (eEscapeType)
+ {
+ case ESCAPE_NO:
+ if (mustEncode(nUCS4, ePart))
+ {
+ bEscape = true;
+ eTargetCharset = bOctets ? RTL_TEXTENCODING_ISO_8859_1 :
+ RTL_TEXTENCODING_UTF8;
+ }
+ else
+ bEscape = false;
+ break;
+
+ case ESCAPE_OCTET:
+ bEscape = true;
+ eTargetCharset = RTL_TEXTENCODING_ISO_8859_1;
+ break;
+
+ case ESCAPE_UTF32:
+ if (mustEncode(nUCS4, ePart))
+ {
+ bEscape = true;
+ eTargetCharset = eCharset;
+ }
+ else if (bKeepVisibleEscapes && INetMIME::isVisible(nUCS4))
+ {
+ bEscape = true;
+ eTargetCharset = RTL_TEXTENCODING_ASCII_US;
+ }
+ else
+ bEscape = false;
+ break;
+ default:
+ bEscape = false;
+ }
+
+ if (bEscape)
+ {
+ switch (eTargetCharset)
+ {
+ default:
+ DBG_ERROR("INetURLObject::appendUCS4(): Unsupported charset");
+ case RTL_TEXTENCODING_ASCII_US:
+ case RTL_TEXTENCODING_ISO_8859_1:
+ appendEscape(rTheText, cEscapePrefix, nUCS4);
+ break;
+
+ case RTL_TEXTENCODING_UTF8:
+ appendUCS4Escape(rTheText, cEscapePrefix, nUCS4);
+ break;
+ }
+ }
+ else
+ rTheText.append(sal_Unicode(nUCS4));
+}
+
+//============================================================================
+// static
+sal_uInt32 INetURLObject::getUTF32(sal_Unicode const *& rBegin,
+ sal_Unicode const * pEnd, bool bOctets,
+ sal_Char cEscapePrefix,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset,
+ EscapeType & rEscapeType)
+{
+ DBG_ASSERT(rBegin < pEnd, "INetURLObject::getUTF32(): Bad sequence");
+ sal_uInt32 nUTF32 = bOctets ? *rBegin++ :
+ INetMIME::getUTF32Character(rBegin, pEnd);
+ switch (eMechanism)
+ {
+ case ENCODE_ALL:
+ rEscapeType = ESCAPE_NO;
+ break;
+
+ case WAS_ENCODED:
+ {
+ int nWeight1;
+ int nWeight2;
+ if (nUTF32 == sal_uChar(cEscapePrefix) && rBegin + 1 < pEnd
+ && (nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0
+ && (nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0)
+ {
+ rBegin += 2;
+ nUTF32 = nWeight1 << 4 | nWeight2;
+ switch (eCharset)
+ {
+ default:
+ DBG_ERROR(
+ "INetURLObject::getUTF32(): Unsupported charset");
+ case RTL_TEXTENCODING_ASCII_US:
+ rEscapeType = INetMIME::isUSASCII(nUTF32) ?
+ ESCAPE_UTF32 : ESCAPE_OCTET;
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_1:
+ rEscapeType = ESCAPE_UTF32;
+ break;
+
+ case RTL_TEXTENCODING_UTF8:
+ if (INetMIME::isUSASCII(nUTF32))
+ rEscapeType = ESCAPE_UTF32;
+ else
+ {
+ if (nUTF32 >= 0xC0 && nUTF32 <= 0xF4)
+ {
+ sal_uInt32 nEncoded;
+ int nShift;
+ sal_uInt32 nMin;
+ if (nUTF32 <= 0xDF)
+ {
+ nEncoded = (nUTF32 & 0x1F) << 6;
+ nShift = 0;
+ nMin = 0x80;
+ }
+ else if (nUTF32 <= 0xEF)
+ {
+ nEncoded = (nUTF32 & 0x0F) << 12;
+ nShift = 6;
+ nMin = 0x800;
+ }
+ else
+ {
+ nEncoded = (nUTF32 & 0x07) << 18;
+ nShift = 12;
+ nMin = 0x10000;
+ }
+ sal_Unicode const * p = rBegin;
+ bool bUTF8 = true;
+ for (;;)
+ {
+ if (pEnd - p < 3
+ || p[0] != cEscapePrefix
+ || (nWeight1
+ = INetMIME::getHexWeight(p[1]))
+ < 8
+ || nWeight1 > 11
+ || (nWeight2
+ = INetMIME::getHexWeight(p[2]))
+ < 0)
+ {
+ bUTF8 = false;
+ break;
+ }
+ p += 3;
+ nEncoded
+ |= ((nWeight1 & 3) << 4 | nWeight2)
+ << nShift;
+ if (nShift == 0)
+ break;
+ nShift -= 6;
+ }
+ if (bUTF8 && nEncoded >= nMin
+ && !INetMIME::isHighSurrogate(nEncoded)
+ && !INetMIME::isLowSurrogate(nEncoded)
+ && nEncoded <= 0x10FFFF)
+ {
+ rBegin = p;
+ nUTF32 = nEncoded;
+ rEscapeType = ESCAPE_UTF32;
+ break;
+ }
+ }
+ rEscapeType = ESCAPE_OCTET;
+ }
+ break;
+ }
+ }
+ else
+ rEscapeType = ESCAPE_NO;
+ break;
+ }
+
+ case NOT_CANONIC:
+ {
+ int nWeight1;
+ int nWeight2;
+ if (nUTF32 == sal_uChar(cEscapePrefix) && rBegin + 1 < pEnd
+ && ((nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0)
+ && ((nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0))
+ {
+ rBegin += 2;
+ nUTF32 = nWeight1 << 4 | nWeight2;
+ rEscapeType = ESCAPE_OCTET;
+ }
+ else
+ rEscapeType = ESCAPE_NO;
+ break;
+ }
+ }
+ return nUTF32;
+}
+
+//============================================================================
+// static
+sal_uInt32 INetURLObject::scanDomain(sal_Unicode const *& rBegin,
+ sal_Unicode const * pEnd,
+ bool bEager)
+{
+ enum State { STATE_DOT, STATE_LABEL, STATE_HYPHEN };
+ State eState = STATE_DOT;
+ sal_Int32 nLabels = 0;
+ sal_Unicode const * pLastAlphanumeric = 0;
+ for (sal_Unicode const * p = rBegin;; ++p)
+ switch (eState)
+ {
+ case STATE_DOT:
+ if (p != pEnd && (INetMIME::isAlphanumeric(*p) || *p == '_'))
+ {
+ ++nLabels;
+ eState = STATE_LABEL;
+ break;
+ }
+ if (bEager || nLabels == 0)
+ return 0;
+ rBegin = p - 1;
+ return nLabels;
+
+ case STATE_LABEL:
+ if (p != pEnd)
+ {
+ if (INetMIME::isAlphanumeric(*p) || *p == '_')
+ break;
+ else if (*p == '.')
+ {
+ eState = STATE_DOT;
+ break;
+ }
+ else if (*p == '-')
+ {
+ pLastAlphanumeric = p;
+ eState = STATE_HYPHEN;
+ break;
+ }
+ }
+ rBegin = p;
+ return nLabels;
+
+ case STATE_HYPHEN:
+ if (p != pEnd)
+ {
+ if (INetMIME::isAlphanumeric(*p) || *p == '_')
+ {
+ eState = STATE_LABEL;
+ break;
+ }
+ else if (*p == '-')
+ break;
+ }
+ if (bEager)
+ return 0;
+ rBegin = pLastAlphanumeric;
+ return nLabels;
+ }
+}
+
+//============================================================================
+// static
+bool INetURLObject::scanIPv6reference(sal_Unicode const *& rBegin,
+ sal_Unicode const * pEnd)
+{
+ if (rBegin != pEnd && *rBegin == '[') {
+ sal_Unicode const * p = rBegin + 1;
+ //TODO: check for valid IPv6address (RFC 2373):
+ while (p != pEnd && (INetMIME::isHexDigit(*p) || *p == ':' || *p == '.'))
+ {
+ ++p;
+ }
+ if (p != pEnd && *p == ']') {
+ rBegin = p + 1;
+ return true;
+ }
+ }
+ return false;
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetPartBeforeLastName(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+ const
+{
+ if (!checkHierarchical())
+ return rtl::OUString();
+ INetURLObject aTemp(*this);
+ aTemp.clearFragment();
+ aTemp.clearQuery();
+ aTemp.removeSegment(LAST_SEGMENT, false);
+ aTemp.setFinalSlash();
+ return aTemp.GetMainURL(eMechanism, eCharset);
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetLastName(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ return getName(LAST_SEGMENT, true, eMechanism, eCharset);
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetFileExtension(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset) const
+{
+ return getExtension(LAST_SEGMENT, false, eMechanism, eCharset);
+}
+
+//============================================================================
+bool INetURLObject::CutLastName()
+{
+ INetURLObject aTemp(*this);
+ aTemp.clearFragment();
+ aTemp.clearQuery();
+ if (!aTemp.removeSegment(LAST_SEGMENT, false))
+ return false;
+ *this = aTemp;
+ return true;
+}
+
+//============================================================================
+rtl::OUString INetURLObject::PathToFileName() const
+{
+ if (m_eScheme != INET_PROT_FILE)
+ return rtl::OUString();
+ rtl::OUString aSystemPath;
+ if (osl::FileBase::getSystemPathFromFileURL(
+ decode(m_aAbsURIRef.getStr(),
+ m_aAbsURIRef.getStr() + m_aPath.getEnd(),
+ getEscapePrefix(), NO_DECODE, RTL_TEXTENCODING_UTF8),
+ aSystemPath)
+ != osl::FileBase::E_None)
+ return rtl::OUString();
+ return aSystemPath;
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetFull() const
+{
+ INetURLObject aTemp(*this);
+ aTemp.removeFinalSlash();
+ return aTemp.PathToFileName();
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetPath() const
+{
+ INetURLObject aTemp(*this);
+ aTemp.removeSegment(LAST_SEGMENT, true);
+ aTemp.removeFinalSlash();
+ return aTemp.PathToFileName();
+}
+
+//============================================================================
+void INetURLObject::SetBase(rtl::OUString const & rTheBase)
+{
+ setBase(rTheBase, LAST_SEGMENT, true, ENCODE_ALL);
+}
+
+//============================================================================
+rtl::OUString INetURLObject::GetBase() const
+{
+ return getBase(LAST_SEGMENT, true, DECODE_WITH_CHARSET);
+}
+
+//============================================================================
+void INetURLObject::SetName(rtl::OUString const & rTheName,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ INetURLObject aTemp(*this);
+ if (aTemp.removeSegment(LAST_SEGMENT, true)
+ && aTemp.insertName(rTheName, false, LAST_SEGMENT, true, eMechanism,
+ eCharset))
+ *this = aTemp;
+}
+
+//============================================================================
+rtl::OUString INetURLObject::CutName(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ rtl::OUString aTheName(getName(LAST_SEGMENT, true, eMechanism, eCharset));
+ return removeSegment(LAST_SEGMENT, true) ? aTheName : rtl::OUString();
+}
+
+//============================================================================
+void INetURLObject::SetExtension(rtl::OUString const & rTheExtension,
+ EncodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ setExtension(rTheExtension, LAST_SEGMENT, false, eMechanism, eCharset);
+}
+
+//============================================================================
+rtl::OUString INetURLObject::CutExtension(DecodeMechanism eMechanism,
+ rtl_TextEncoding eCharset)
+{
+ rtl::OUString aTheExtension(getExtension(LAST_SEGMENT, false, eMechanism,
+ eCharset));
+ return removeExtension(LAST_SEGMENT, false)
+ ? aTheExtension : rtl::OUString();
+}
+
+//============================================================================
+bool INetURLObject::IsCaseSensitive() const
+{
+ return true;
+}
diff --git a/tools/source/fsys/wldcrd.cxx b/tools/source/fsys/wldcrd.cxx
new file mode 100644
index 000000000000..293d16877498
--- /dev/null
+++ b/tools/source/fsys/wldcrd.cxx
@@ -0,0 +1,143 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <tools/wldcrd.hxx>
+
+/*************************************************************************
+|*
+|* WildCard::Match()
+|*
+|* Beschreibung WLDCRD.SDW
+|* Ersterstellung MA 19.06.91
+|* Letzte Aenderung MA 03.07.91
+|*
+*************************************************************************/
+
+/* Diese Methode ueberprueft, ob die Wilde Karte in pWild mit dem String
+ * in pStr matscht.
+ * Vertragen sich die beiden, so wird 1 zurueckgegeben, sonst 0.
+ *
+ * ein '*' in pWild bedeutet n beliebige Zeichen, mit n>=0
+ * ein '?' in pWild bedeutet genau ein beliebiges Zeichen
+ *
+ */
+
+USHORT WildCard::ImpMatch( const char *pWild, const char *pStr ) const
+{
+ int pos=0;
+ int flag=0;
+
+ while ( *pWild || flag )
+ {
+ switch (*pWild)
+ {
+ case '?':
+ if ( *pStr == '\0' )
+ return 0;
+ break;
+
+ default:
+ if ( (*pWild == '\\') && ((*(pWild+1)=='?') || (*(pWild+1) == '*')) )
+ pWild++;
+ if ( *pWild != *pStr )
+ if ( !pos )
+ return 0;
+ else
+ pWild += pos;
+ else
+ break; // ACHTUNG laeuft unter bestimmten
+ // Umstaenden in den nachsten case rein!!
+ case '*':
+ while ( *pWild == '*' )
+ pWild++;
+ if ( *pWild == '\0' )
+ return 1;
+ flag = 1;
+ pos = 0;
+ if ( *pStr == '\0' )
+ return ( *pWild == '\0' );
+ while ( *pStr && *pStr != *pWild )
+ {
+ if ( *pWild == '?' ) {
+ pWild++;
+ while ( *pWild == '*' )
+ pWild++;
+ }
+ pStr++;
+ if ( *pStr == '\0' )
+ return ( *pWild == '\0' );
+ }
+ break;
+ }
+ if ( *pWild != '\0' )
+ pWild++;
+ if ( *pStr != '\0' )
+ pStr++;
+ else
+ flag = 0;
+ if ( flag )
+ pos--;
+ }
+ return ( *pStr == '\0' ) && ( *pWild == '\0' );
+}
+
+/*************************************************************************
+|*
+|* WildCard::Matches()
+|*
+|* Beschreibung WLDCRD.SDW
+|* Ersterstellung MA 19.06.91
+|* Letzte Aenderung TH 02.02.96
+|*
+*************************************************************************/
+
+BOOL WildCard::Matches( const String& rString ) const
+{
+ ByteString aTmpWild = aWildString;
+ ByteString aString(rString, osl_getThreadTextEncoding());
+
+ USHORT nSepPos;
+
+ if ( cSepSymbol != '\0' )
+ {
+ while ( (nSepPos = aTmpWild.Search( cSepSymbol )) != STRING_NOTFOUND )
+ {
+ // alle getrennten WildCard's pruefen
+ if ( ImpMatch( aTmpWild.Copy( 0, nSepPos ).GetBuffer(), aString.GetBuffer() ) )
+ return TRUE;
+ aTmpWild.Erase( 0, nSepPos + 1 ); // Trennsymbol entfernen
+ }
+ // und noch den hinter dem letzen Trennsymbol bzw. den einzigen
+ }
+
+ if ( ImpMatch( aTmpWild.GetBuffer(), aString.GetBuffer() ) )
+ return TRUE;
+ else
+ return FALSE;
+}
diff --git a/tools/source/fsys/wntmsc.cxx b/tools/source/fsys/wntmsc.cxx
new file mode 100644
index 000000000000..a8cf1c1eecec
--- /dev/null
+++ b/tools/source/fsys/wntmsc.cxx
@@ -0,0 +1,1081 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#ifdef _MSC_VER
+#pragma warning (push,1)
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#include <limits.h>
+#ifdef _MSC_VER
+#pragma warning (pop)
+#endif
+
+#include "wntmsc.hxx"
+#include <tools/errinf.hxx>
+#include <tools/debug.hxx>
+#include <tools/list.hxx>
+#include <tools/wldcrd.hxx>
+#include <tools/fsys.hxx>
+#include <tools/bigint.hxx>
+
+DECLARE_LIST( DirEntryList, DirEntry* );
+DECLARE_LIST( FSysSortList, FSysSort* );
+DECLARE_LIST( FileStatList, FileStat* );
+
+int Sys2SolarError_Impl( int nSysErr );
+
+static BOOL bLastCaseSensitive = FALSE;
+
+//--------------------------------------------------------------------
+
+ByteString Upper_Impl( const ByteString &rStr )
+{
+ ByteString aRet( rStr.GetBuffer() ); // es muss ein neuer String entstehen!
+ CharUpperBuff( (char*) aRet.GetBuffer(), aRet.Len() );
+ return aRet;
+}
+
+//--------------------------------------------------------------------
+
+DIR *opendir( const char* pPfad )
+{
+ DIR *pDir = new DIR;
+ if ( pDir )
+ pDir->p = (char*) pPfad;
+ return pDir;
+}
+
+struct dirent *readdir( DIR *pDir )
+{
+ bool bOk = false;
+ if ( pDir->p )
+ {
+ char *pBuf = new char[ strlen( pDir->p ) + 5 ];
+ if ( pBuf )
+ {
+ // *.* dahinter, ggf mit "\\" abtrennen (falls nicht schon da)
+ strcpy( pBuf, pDir->p );
+ strcat( pBuf, "\\*.*" + ( *(pBuf + strlen( pBuf ) - 1 ) == '\\' ) );
+ CharUpperBuff( pBuf, strlen(pBuf) );
+ pDir->h = FindFirstFile( pBuf, &pDir->aDirEnt );
+ bOk = pDir->h != INVALID_HANDLE_VALUE;
+ pDir->p = NULL;
+ delete [] pBuf;
+ }
+ else
+ pDir->h = INVALID_HANDLE_VALUE;
+ }
+ else
+ {
+ bOk = FindNextFile( pDir->h, &pDir->aDirEnt );
+ }
+
+ return bOk ? &pDir->aDirEnt : NULL;
+}
+
+int closedir( DIR *pDir )
+{
+ BOOL bOk = FALSE;
+ if ( pDir )
+ {
+ bOk = 0 != pDir->p || FindClose( pDir->h );
+ delete pDir;
+ }
+ return bOk;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::GetPathStyle() const
+|*
+|* Beschreibung
+|* Ersterstellung MI 11.05.95
+|* Letzte Aenderung MI 11.05.95
+|*
+*************************************************************************/
+
+ErrCode GetPathStyle_Impl( const String &rDevice, FSysPathStyle &rStyle )
+{
+ ByteString aRootDir(rDevice, osl_getThreadTextEncoding());
+ if ( aRootDir.Len() && aRootDir.GetBuffer()[aRootDir.Len()-1] != '\\' )
+ aRootDir += '\\';
+
+ char sVolumeName[256];
+ char sFileSysName[16];
+ DWORD nSerial[2];
+ DWORD nMaxCompLen[2];
+ DWORD nFlags[2];
+
+ // Windows95 hat VFAT, WindowsNT nicht
+ DWORD nVer = GetVersion();
+ BOOL bW95 = ( nVer & 0xFF ) >= 4;
+
+ FSysFailOnErrorImpl();
+ rStyle = FSYS_STYLE_UNKNOWN;
+ if ( GetVolumeInformation(
+ (char*) aRootDir.GetBuffer(),
+ sVolumeName, 256, (LPDWORD) &nSerial, (LPDWORD) &nMaxCompLen,
+ (LPDWORD) &nFlags, sFileSysName, 16 ) )
+ {
+ // FAT/VFAT?
+ if ( 0 == strcmp( "FAT", sFileSysName ) )
+ rStyle = bW95 ? FSYS_STYLE_VFAT : FSYS_STYLE_FAT;
+
+ // NTFS?
+ else if ( 0 == strcmp( "NTFS", sFileSysName ) )
+ rStyle = FSYS_STYLE_NTFS;
+
+ // HPFS?
+ else if ( 0 == strcmp( "HPFS", sFileSysName ) )
+ rStyle = FSYS_STYLE_HPFS;
+
+ // NWCOMPA/NWFS?
+ else if ( 0 == strncmp( "NW", sFileSysName, 2 ) )
+ rStyle = FSYS_STYLE_NWFS;
+
+ return ERRCODE_NONE;
+ }
+
+ return ERRCODE_IO_INVALIDDEVICE;
+}
+
+FSysPathStyle DirEntry::GetPathStyle( const String &rDevice )
+{
+
+ FSysPathStyle eStyle;
+ GetPathStyle_Impl( rDevice, eStyle );
+ return eStyle;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::IsCaseSensitive()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 10.06.93
+|* Letzte Aenderung TPF 26.02.1999
+|*
+*************************************************************************/
+
+BOOL DirEntry::IsCaseSensitive( FSysPathStyle eFormatter ) const
+{
+
+ if (eFormatter==FSYS_STYLE_HOST)
+ {
+/*
+ DirEntry aRoot(*this);
+ aRoot.ToAbs();
+ aRoot = aRoot[Level()-1];
+ String aRootDir = aRoot.GetFull(FSYS_STYLE_HOST, TRUE);
+
+ char sVolumeName[256];
+ DWORD nVolumeSerial;
+ DWORD nMaxCompLen;
+ DWORD nFlags;
+ char sFileSysName[16];
+
+ if ( GetVolumeInformation( (char*) aRootDir.GetStr(),
+ sVolumeName,
+ 256,
+ (LPDWORD) &nVolumeSerial,
+ (LPDWORD) &nMaxCompLen,
+ (LPDWORD) &nFlags,
+ sFileSysName,
+ 16 ))
+ {
+ return (nFlags & FS_CASE_SENSITIVE) ? TRUE : FALSE;
+ }
+ else
+ {
+ return FALSE;
+ }
+*/
+ //
+ // guter versuch, aber FS_CASE_SENSITIVE ist D?nnsinn in T?ten:
+ //
+ // sFileSysName FS_CASE_SENSITIVE
+ // FAT FALSE
+ // NTFS TRUE !!!
+ // NWCompat FALSE
+ // Samba FALSE
+ //
+ // NT spricht auch NTFS lediglich case preserving an, also ist unter NT alles case insensitiv
+ //
+
+ return FALSE;
+ }
+ else
+ {
+ BOOL isCaseSensitive = FALSE; // ich bin unter win32, also ist der default case insensitiv
+ switch ( eFormatter )
+ {
+ case FSYS_STYLE_MAC:
+ case FSYS_STYLE_FAT:
+ case FSYS_STYLE_VFAT:
+ case FSYS_STYLE_NTFS:
+ case FSYS_STYLE_NWFS:
+ case FSYS_STYLE_HPFS:
+ case FSYS_STYLE_DETECT:
+ {
+ isCaseSensitive = FALSE;
+ break;
+ }
+ case FSYS_STYLE_SYSV:
+ case FSYS_STYLE_BSD:
+ {
+ isCaseSensitive = TRUE;
+ break;
+ }
+ default:
+ {
+ isCaseSensitive = FALSE; // ich bin unter win32, also ist der default case insensitiv
+ break;
+ }
+ }
+ return isCaseSensitive;
+ }
+}
+
+/*************************************************************************
+|*
+|* DirEntry::ToAbs()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MA 02.12.91
+|*
+*************************************************************************/
+
+BOOL DirEntry::ToAbs()
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ if ( FSYS_FLAG_VOLUME == eFlag )
+ {
+ eFlag = FSYS_FLAG_ABSROOT;
+ return TRUE;
+ }
+
+ if ( IsAbs() )
+ {
+ return TRUE;
+ }
+
+
+ char sBuf[256];
+ char *pOld;
+ ByteString aFullName( GetFull(), osl_getThreadTextEncoding() );
+ FSysFailOnErrorImpl();
+ if ( GetFullPathName((char*)aFullName.GetBuffer(),256,sBuf,&pOld) > 511 )
+ return FALSE;
+
+ *this = DirEntry( String(sBuf, osl_getThreadTextEncoding() ));
+ return TRUE;
+}
+
+
+/*************************************************************************
+|*
+|* DirEntry::GetVolume()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 27.08.92
+|* Letzte Aenderung MI 28.08.92
+|*
+*************************************************************************/
+
+String DirEntry::GetVolume() const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ String aRet;
+ const DirEntry *pTop = ImpGetTopPtr();
+ ByteString aName = ByteString( pTop->aName ).ToLowerAscii();
+
+ if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT ||
+ pTop->eFlag == FSYS_FLAG_RELROOT ||
+ pTop->eFlag == FSYS_FLAG_VOLUME )
+ && aName != "a:" && aName != "b:" && Exists() )
+ {
+ char sFileSysName[256];
+ char sVolumeName[256];
+ DWORD nVolumeNameLen = 256;
+ DWORD nSerial[2];
+ DWORD nMaxCompLen[2];
+ DWORD nFlags[2];
+ ByteString aRootDir = pTop->aName;
+ FSysFailOnErrorImpl();
+
+ // Network-Device zuerst probieren wegen langsamer Samba-Drives
+ if ( !WNetGetConnection( (char*) aRootDir.GetBuffer(),
+ sVolumeName, &nVolumeNameLen ) )
+ aRet = String( sVolumeName, osl_getThreadTextEncoding());
+
+ // dann den VolumeNamen fuer lokale Drives
+ if ( aRet.Len() == 0 )
+ {
+ aRootDir += "\\";
+ if ( GetVolumeInformation( (char*) aRootDir.GetBuffer(),
+ sVolumeName, 256,
+ (LPDWORD) &nSerial, (LPDWORD) &nMaxCompLen,
+ (LPDWORD) &nFlags, sFileSysName, 256 ) )
+ aRet = String( sVolumeName, osl_getThreadTextEncoding());
+ }
+ }
+
+ return aRet;
+}
+
+/*************************************************************************
+|*
+|* DirEntry::SetCWD()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 26.04.91
+|* Letzte Aenderung MI 21.05.92
+|*
+*************************************************************************/
+
+BOOL DirEntry::SetCWD( BOOL bSloppy ) const
+{
+ DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
+
+ FSysFailOnErrorImpl();
+
+ if ( eFlag == FSYS_FLAG_CURRENT && !aName.Len() )
+ return TRUE;
+
+ if ( SetCurrentDirectory(ByteString(GetFull(), osl_getThreadTextEncoding()).GetBuffer()) )
+ {
+ return TRUE;
+ }
+
+ if ( bSloppy && pParent &&
+ SetCurrentDirectory(ByteString(pParent->GetFull(), osl_getThreadTextEncoding()).GetBuffer()) )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-------------------------------------------------------------------------
+
+USHORT DirReader_Impl::Init()
+{
+ // Block-Devices auflisten?
+ if ( pDir->eAttrMask & FSYS_KIND_BLOCK )
+ {
+ // CWD merken
+ DirEntry aCurrentDir;
+ aCurrentDir.ToAbs();
+
+ // einzeln auf Existenz und Masken-konformit"at pr"ufen
+ USHORT nRead = 0;
+ char sDrive[3] = { '?', ':', 0 };
+ char sRoot[4] = { '?', ':', '\\', 0 };
+ for ( char c = 'a'; c <= 'z'; c++ )
+ {
+ sDrive[0] = c;
+ sRoot[0] = c;
+ DirEntry* pDrive = new DirEntry( sDrive, FSYS_FLAG_VOLUME, FSYS_STYLE_HOST );
+ if ( pDir->aNameMask.Matches( String( ByteString(sDrive), osl_getThreadTextEncoding())) && GetDriveType( sRoot ) != 1 )
+ {
+ if ( pDir->pStatLst ) //Status fuer Sort gewuenscht?
+ {
+ FileStat *pNewStat = new FileStat( *pDrive );
+ pDir->ImpSortedInsert( pDrive, pNewStat );
+ }
+ else
+ pDir->ImpSortedInsert( pDrive, NULL );
+ ++nRead;
+ }
+ else
+ delete pDrive;
+ }
+
+ // CWD restaurieren
+ aCurrentDir.SetCWD();
+ return nRead;
+ }
+
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+
+USHORT DirReader_Impl::Read()
+{
+ // Directories und Files auflisten?
+ if ( ( pDir->eAttrMask & FSYS_KIND_DIR ||
+ pDir->eAttrMask & FSYS_KIND_FILE ) &&
+ ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) )
+ {
+ // Gross/Kleinschreibung nicht beruecksichtigen
+ ByteString aLowerName = pDosEntry->d_name;
+ CharLowerBuff( (char*) aLowerName.GetBuffer(), aLowerName.Len() );
+
+ // Flags pruefen
+ BOOL bIsDirAndWantsDir =
+ ( ( pDir->eAttrMask & FSYS_KIND_DIR ) &&
+#ifdef ICC
+ ( pDosEntry->d_type & ( strcmp(pDosEntry->d_name,".") ||
+ strcmp(pDosEntry->d_name,"..")) ) );
+#else
+ ( pDosEntry->d_type & DOS_DIRECT ) );
+#endif
+ BOOL bIsFileAndWantsFile =
+ ( ( pDir->eAttrMask & FSYS_KIND_FILE ) &&
+#ifdef ICC
+ !( pDosEntry->d_type & ( strcmp(pDosEntry->d_name,".") ||
+ strcmp(pDosEntry->d_name,"..")) ) &&
+#else
+ !( pDosEntry->d_type & DOS_DIRECT ) &&
+#endif
+ !( pDosEntry->d_type & DOS_VOLUMEID ) );
+ BOOL bIsHidden = (pDosEntry->d_type & _A_HIDDEN) != 0;
+ BOOL bWantsHidden = 0 == ( pDir->eAttrMask & FSYS_KIND_VISIBLE );
+ if ( ( bIsDirAndWantsDir || bIsFileAndWantsFile ) &&
+ ( bWantsHidden || !bIsHidden ) &&
+ pDir->aNameMask.Matches( String(aLowerName, osl_getThreadTextEncoding()) ) )
+ {
+#ifdef DBG_UTIL
+ DbgOutf( "%s %s flags:%x found",
+ pDosEntry->d_name,
+ bIsFileAndWantsFile ? "file" : "dir",
+ pDosEntry->d_type );
+#endif
+ DirEntryFlag eFlag =
+ 0 == strcmp( pDosEntry->d_name, "." ) ? FSYS_FLAG_CURRENT
+ : 0 == strcmp( pDosEntry->d_name, ".." ) ? FSYS_FLAG_PARENT
+ : FSYS_FLAG_NORMAL;
+ DirEntry *pTemp = new DirEntry( ByteString(pDosEntry->d_name),
+ eFlag, FSYS_STYLE_NTFS );
+#ifdef FEAT_FSYS_DOUBLESPEED
+ pTemp->ImpSetStat( new FileStat( (void*) pDosDir, (void*) 0 ) );
+#endif
+ if ( pParent )
+ pTemp->ImpChangeParent( new DirEntry( *pParent ), FALSE );
+ if ( pDir->pStatLst ) //Status fuer Sort gewuenscht?
+ {
+ FileStat *pNewStat = new FileStat( (void*) pDosDir, (void*) 0 );
+ pDir->ImpSortedInsert( pTemp, pNewStat );
+ }
+ else
+ pDir->ImpSortedInsert( pTemp, NULL );
+ return 1;
+ }
+#ifdef DBG_UTIL
+ else
+ DbgOutf( "%s flags:%x skipped",
+ pDosEntry->d_name,
+ pDosEntry->d_type );
+#endif
+
+ }
+ else
+ bReady = TRUE;
+ return 0;
+}
+
+/*************************************************************************
+|*
+|* InitFileStat()
+|*
+|* Beschreibung gemeinsamer Teil der Ctoren fuer FileStat
+|* Ersterstellung MI 28.08.92
+|* Letzte Aenderung MI 28.08.92
+|*
+*************************************************************************/
+
+void FileStat::ImpInit( void* p )
+{
+ _WIN32_FIND_DATAA *pDirEnt = (_WIN32_FIND_DATAA*) p;
+
+ nError = FSYS_ERR_OK;
+ nSize = pDirEnt->nFileSizeLow;
+
+ SYSTEMTIME aSysTime;
+ FILETIME aLocTime;
+
+ // use the last write date / time when the creation date / time isn't set
+ if ( ( pDirEnt->ftCreationTime.dwLowDateTime == 0 ) &&
+ ( pDirEnt->ftCreationTime.dwHighDateTime == 0 ) )
+ {
+ pDirEnt->ftCreationTime.dwLowDateTime = pDirEnt->ftLastWriteTime.dwLowDateTime;
+ pDirEnt->ftCreationTime.dwHighDateTime = pDirEnt->ftLastWriteTime.dwHighDateTime;
+ }
+
+ // use the last write date / time when the last accessed date / time isn't set
+ if ( ( pDirEnt->ftLastAccessTime.dwLowDateTime == 0 ) &&
+ ( pDirEnt->ftLastAccessTime.dwHighDateTime == 0 ) )
+ {
+ pDirEnt->ftLastAccessTime.dwLowDateTime = pDirEnt->ftLastWriteTime.dwLowDateTime;
+ pDirEnt->ftLastAccessTime.dwHighDateTime = pDirEnt->ftLastWriteTime.dwHighDateTime;
+ }
+
+ FileTimeToLocalFileTime( &pDirEnt->ftCreationTime, &aLocTime );
+ FileTimeToSystemTime( &aLocTime, &aSysTime );
+ aDateCreated = Date( aSysTime.wDay, aSysTime.wMonth, aSysTime.wYear );
+ aTimeCreated = Time( aSysTime.wHour, aSysTime.wMinute,
+ aSysTime.wSecond, 0 );
+
+ FileTimeToLocalFileTime( &pDirEnt->ftLastWriteTime, &aLocTime );
+ FileTimeToSystemTime( &aLocTime, &aSysTime );
+ aDateModified = Date( aSysTime.wDay, aSysTime.wMonth, aSysTime.wYear );
+ aTimeModified = Time( aSysTime.wHour, aSysTime.wMinute,
+ aSysTime.wSecond, 0 );
+
+ FileTimeToLocalFileTime( &pDirEnt->ftLastAccessTime, &aLocTime );
+ FileTimeToSystemTime( &aLocTime, &aSysTime );
+ aDateAccessed = Date( aSysTime.wDay, aSysTime.wMonth, aSysTime.wYear );
+ aTimeAccessed = Time( aSysTime.wHour, aSysTime.wMinute,
+ aSysTime.wSecond, 0 );
+
+ nKindFlags = FSYS_KIND_FILE;
+ if ( pDirEnt->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ nKindFlags = FSYS_KIND_DIR;
+}
+
+/*************************************************************************
+|*
+|* FileStat::FileStat()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 27.08.92
+|* Letzte Aenderung MI 28.08.92
+|*
+*************************************************************************/
+
+FileStat::FileStat( const void *pInfo, // struct dirent
+ const void * ): // dummy
+ aDateCreated(0),
+ aTimeCreated(0),
+ aDateModified(0),
+ aTimeModified(0),
+ aDateAccessed(0),
+ aTimeAccessed(0)
+{
+ ImpInit( ( (dirent*) pInfo ) );
+}
+
+/*************************************************************************
+|*
+|* FileStat::Update()
+|*
+|* Beschreibung FSYS.SDW
+|* Ersterstellung MI 27.08.92
+|* Letzte Aenderung MI 28.08.92
+|*
+*************************************************************************/
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#pragma warning(disable: 4917)
+#endif
+#include <shlobj.h>
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#ifdef UNICODE
+#define lstrchr wcschr
+#define lstrncmp wcsncmp
+#else
+#define lstrchr strchr
+#define lstrncmp strncmp
+#endif
+
+//---------------------------------------------------------------------------
+
+void SHFreeMem( void *p )
+{
+ LPMALLOC pMalloc = NULL;
+
+ if ( SUCCEEDED(SHGetMalloc(&pMalloc)) )
+ {
+ pMalloc->Free( p );
+ pMalloc->Release();
+ }
+}
+
+//---------------------------------------------------------------------------
+
+HRESULT SHGetIDListFromPath( HWND hwndOwner, LPCTSTR pszPath, LPITEMIDLIST *ppidl )
+{
+ if ( IsBadWritePtr(ppidl, sizeof(LPITEMIDLIST)) )
+ return E_INVALIDARG;
+
+ LPSHELLFOLDER pDesktopFolder = NULL;
+
+ HRESULT hResult = SHGetDesktopFolder( &pDesktopFolder );
+ if ( FAILED(hResult) )
+ return hResult;
+
+ ULONG chEaten = lstrlen( pszPath );
+ DWORD dwAttributes = FILE_ATTRIBUTE_DIRECTORY;
+
+#ifdef UNICODE
+ LPOLESTR wszPath = pszPath;
+#else
+ WCHAR wszPath[MAX_PATH];
+ MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszPath, -1, wszPath, MAX_PATH );
+#endif
+
+ hResult = pDesktopFolder->ParseDisplayName( hwndOwner, (LPBC)NULL, wszPath, &chEaten, ppidl, &dwAttributes );
+ pDesktopFolder->Release();
+
+ return hResult;
+}
+
+//---------------------------------------------------------------------------
+
+HRESULT SHGetFolderFromIDList( LPCITEMIDLIST pidl, LPSHELLFOLDER *ppFolder )
+{
+ if ( IsBadWritePtr(ppFolder, sizeof(LPSHELLFOLDER)) )
+ return E_INVALIDARG;
+
+ *ppFolder = NULL;
+
+ LPSHELLFOLDER pDesktopFolder = NULL;
+
+ HRESULT hResult = SHGetDesktopFolder( &pDesktopFolder );
+ if ( FAILED(hResult) )
+ return hResult;
+
+ hResult = pDesktopFolder->BindToObject( pidl, (LPBC)NULL, IID_IShellFolder, (LPVOID *)ppFolder );
+ pDesktopFolder->Release();
+
+ return hResult;
+}
+
+//---------------------------------------------------------------------------
+
+HRESULT SHResolvePath( HWND hwndOwner, LPCTSTR pszPath, LPITEMIDLIST *ppidl )
+{
+ // If hwndOwner is NULL, use the desktop window, because dialogs need a parent
+
+#ifdef BOOTSTRAP
+ return NO_ERROR;
+#else
+ if ( !hwndOwner )
+ hwndOwner = GetDesktopWindow();
+
+ HRESULT hResult = NOERROR;
+ LPTSTR pszPathCopy;
+ LPTSTR pszTrailingPath;
+ TCHAR cBackup = 0;
+
+ // First make a copy of the path
+
+ pszPathCopy = new TCHAR[lstrlen(pszPath) + 1];
+ if ( pszPathCopy )
+ lstrcpy( pszPathCopy, pszPath );
+ else
+ return E_OUTOFMEMORY;
+
+ // Determine the first token
+
+ if ( !lstrncmp( pszPathCopy, "\\\\", 2 ) )
+ pszTrailingPath = lstrchr( pszPathCopy + 2, '\\' );
+ else
+ pszTrailingPath = lstrchr( pszPathCopy, '\\' );
+
+ // Now scan the path tokens
+
+ while ( SUCCEEDED(hResult) )
+ {
+ if ( pszTrailingPath )
+ {
+ cBackup = *(++pszTrailingPath);
+ *pszTrailingPath = 0;
+ }
+
+ LPITEMIDLIST pidl = NULL;
+
+ // Make item ID list from leading path
+
+ hResult = SHGetIDListFromPath( hwndOwner, pszPathCopy, &pidl );
+
+ // if path exists try to open it as folder
+
+ if ( SUCCEEDED(hResult) )
+ {
+ // Only open the folder if it was not the last token
+
+ if ( pszTrailingPath )
+ {
+ LPSHELLFOLDER pFolder;
+
+ // Create a folder instance
+ hResult = SHGetFolderFromIDList( pidl, &pFolder);
+
+ // Is it a folder ?
+ if ( SUCCEEDED(hResult) )
+ {
+ // No try to instantiate an enumerator.
+ // This should popup a login dialog if any
+
+ LPENUMIDLIST pEnum = NULL;
+
+ hResult = pFolder->EnumObjects( hwndOwner,
+ SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN,
+ &pEnum );
+
+ // Release the enumerator interface
+ if ( SUCCEEDED(hResult) )
+ pEnum->Release();
+
+ // Release the folder interface
+ pFolder->Release();
+ }
+
+ SHFreeMem( pidl );
+ }
+ else // It was the last token
+ {
+ if ( ppidl )
+ *ppidl = pidl;
+ else
+ SHFreeMem( pidl );
+ }
+ }
+
+
+ // Forward to next token
+
+ if ( pszTrailingPath )
+ {
+ *pszTrailingPath = cBackup;
+ pszTrailingPath = lstrchr( pszTrailingPath, '\\' );
+ }
+ else
+ break;
+ }
+
+ // Free the working copy of the path
+ delete pszPathCopy;
+
+ // NOERROR or OLE error code
+ return hResult;
+#endif
+}
+
+//---------------------------------------------------------------------------
+// The Wrapper
+//---------------------------------------------------------------------------
+
+BOOL Exists_Impl( const ByteString & crPath )
+{
+ // We do not know if OLE was initialized for this thread
+
+ CoInitialize( NULL );
+
+ BOOL bSuccess = SUCCEEDED( SHResolvePath(NULL, crPath.GetBuffer(), NULL) );
+
+ CoUninitialize();
+
+ return bSuccess;
+}
+
+//---------------------------------------------------------------------------
+
+BOOL FileStat::Update( const DirEntry& rDirEntry, BOOL bForceAccess )
+{
+ nSize = 0;
+ nKindFlags = 0;
+ aCreator.Erase();
+ aType.Erase();
+ aDateCreated = Date(0);
+ aTimeCreated = Time(0);
+ aDateModified = Date(0);
+ aTimeModified = Time(0);
+ aDateAccessed = Date(0);
+ aTimeAccessed = Time(0);
+
+ if ( !rDirEntry.IsValid() )
+ {
+ nError = FSYS_ERR_UNKNOWN;
+ nKindFlags = 0;
+ return FALSE;
+ }
+
+ // Sonderbehandlung falls es sich um eine Root ohne Laufwerk handelt
+
+ if ( !rDirEntry.aName.Len() && rDirEntry.eFlag == FSYS_FLAG_ABSROOT )
+ {
+ nKindFlags = FSYS_KIND_DIR;
+ nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ // keine Error-Boxen anzeigen
+ FSysFailOnErrorImpl();
+
+ // Redirect
+ String aPath( rDirEntry.GetFull() );
+#ifndef BOOTSTRAP
+ FSysRedirector::DoRedirect( aPath );
+#endif
+ DirEntry aDirEntry( aPath );
+
+ // ist ein Medium im Laufwerk?
+ HACK("wie?")
+ BOOL bAccess = TRUE;
+ const DirEntry *pTop = aDirEntry.ImpGetTopPtr();
+ ByteString aName = ByteString(pTop->aName).ToLowerAscii();
+ if ( !bForceAccess &&
+ ( pTop->eFlag == FSYS_FLAG_ABSROOT ||
+ pTop->eFlag == FSYS_FLAG_RELROOT ||
+ pTop->eFlag == FSYS_FLAG_VOLUME ) )
+ if ( aName == "a:" || aName == "b:" )
+ bAccess = FALSE;
+ else
+ DBG_TRACE( "FSys: will access removable device!" );
+ if ( bAccess && ( aName == "a:" || aName == "b:" ) ) {
+ DBG_WARNING( "floppy will clatter" );
+ }
+
+ // Sonderbehandlung, falls es sich um ein Volume handelt
+ if ( aDirEntry.eFlag == FSYS_FLAG_VOLUME ||
+ aDirEntry.eFlag == FSYS_FLAG_ABSROOT )
+ {
+ if ( aDirEntry.eFlag == FSYS_FLAG_VOLUME )
+ nKindFlags = FSYS_KIND_DEV | ( aDirEntry.aName.Len() == 2
+ ? FSYS_KIND_BLOCK
+ : FSYS_KIND_CHAR );
+ else
+ nKindFlags = FSYS_KIND_DIR;
+
+ if ( !bAccess )
+ {
+ if ( aDirEntry.eFlag == FSYS_FLAG_VOLUME )
+ nKindFlags |= FSYS_KIND_REMOVEABLE;
+ nError = FSYS_ERR_NOTEXISTS;
+ nKindFlags = 0;
+ return FALSE;
+ }
+
+ ByteString aRootDir = aDirEntry.aName;
+ aRootDir += ByteString( "\\" );
+ UINT nType = GetDriveType( (char *) aRootDir.GetBuffer() ); //TPF: 2i
+ if ( nType == 1 || nType == 0 )
+ {
+ nError = FSYS_ERR_NOTEXISTS;
+ nKindFlags = 0;
+ return FALSE;
+ }
+
+ if ( aDirEntry.eFlag == FSYS_FLAG_VOLUME )
+ nKindFlags = nKindFlags |
+ ( ( nType == DRIVE_REMOVABLE ) ? FSYS_KIND_REMOVEABLE : 0 ) |
+ ( ( nType == DRIVE_FIXED ) ? FSYS_KIND_FIXED : 0 ) |
+ ( ( nType == DRIVE_REMOTE ) ? FSYS_KIND_REMOTE : 0 ) |
+ ( ( nType == DRIVE_RAMDISK ) ? FSYS_KIND_RAM : 0 ) |
+ ( ( nType == DRIVE_CDROM ) ? FSYS_KIND_CDROM : 0 ) |
+ ( ( nType == 0 ) ? FSYS_KIND_UNKNOWN : 0 );
+
+ nError = ERRCODE_NONE;
+
+ return TRUE;
+ }
+
+ // Statusinformation vom Betriebssystem holen
+ HANDLE h; //()
+ _WIN32_FIND_DATAA aEntry = {};
+ DirEntry aAbsEntry( aDirEntry );
+ if ( bAccess && aAbsEntry.ToAbs() )
+ {
+ // im Namen k"onnen auch ';*?' als normale Zeichen vorkommen
+ ByteString aFilePath( aAbsEntry.GetFull(), osl_getThreadTextEncoding() );
+
+ // MI: dann gehen Umlaute auf Novell-Servern nicht / wozu ueberhaupt
+ // CharUpperBuff( (char*) aFilePath.GetStr(), aFilePath.Len() );
+ DBG_TRACE1( "FileStat: %s", aFilePath.GetBuffer() );
+ h = aFilePath.Len() < 230
+ // die Win32-API ist hier sehr schwammig
+ ? FindFirstFile( (char *) aFilePath.GetBuffer(), &aEntry )//TPF: 2i
+ : INVALID_HANDLE_VALUE;
+
+ if ( INVALID_HANDLE_VALUE != h )
+ {
+ if ( !( aEntry.dwFileAttributes & 0x40 ) ) // com1: etc. e.g. not encrypted (means normal)
+ {
+ ByteString aUpperName = Upper_Impl(ByteString(aAbsEntry.GetName(), osl_getThreadTextEncoding()));
+
+ // HRO: #74051# Compare also with short alternate filename
+ if ( aUpperName != Upper_Impl( aEntry.cFileName ) && aUpperName != Upper_Impl( aEntry.cAlternateFileName ) )
+ h = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if ( INVALID_HANDLE_VALUE == h )
+ {
+ DWORD dwError = GetLastError();
+
+ if ( ERROR_BAD_NET_NAME == dwError )
+ {
+ nKindFlags = FSYS_KIND_UNKNOWN;
+ nError = FSYS_ERR_NOTEXISTS;
+ return FALSE;
+ }
+
+ // UNC-Volume?
+ DirEntry *pTop = aAbsEntry.ImpGetTopPtr();
+ if ( pTop->GetFlag() == FSYS_FLAG_ABSROOT &&
+ ( pTop->aName.Len() > 1 && (pTop->aName.GetBuffer()[1] != ':' )) )
+ {
+ if ( bForceAccess )
+ {
+ if ( Exists_Impl( aFilePath ) )
+ {
+ nKindFlags = FSYS_KIND_DIR|FSYS_KIND_REMOTE;
+ nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+ else
+ {
+ nKindFlags = FSYS_KIND_UNKNOWN;
+ nError = FSYS_ERR_NOTEXISTS;
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+ else
+ h = INVALID_HANDLE_VALUE;
+
+ if ( h == INVALID_HANDLE_VALUE )
+ {
+ // Sonderbehandlung falls es sich um eine Wildcard handelt
+ ByteString aTempName( aDirEntry.GetName(), osl_getThreadTextEncoding() );
+ if ( strchr( aTempName.GetBuffer(), '?' ) ||
+ strchr( aTempName.GetBuffer(), '*' ) ||
+ strchr( aTempName.GetBuffer(), ';' ) )
+ {
+ nKindFlags = FSYS_KIND_WILD;
+ nError = FSYS_ERR_OK;
+ return TRUE;
+ }
+
+ if ( bAccess )
+ {
+ nError = FSYS_ERR_NOTEXISTS;
+ nKindFlags = FSYS_KIND_UNKNOWN;
+ }
+ else
+ nKindFlags = FSYS_KIND_REMOVEABLE;
+ }
+ else
+ {
+ ImpInit( &aEntry );
+ FindClose( h );
+ }
+
+ if ( 0 != nError )
+ nKindFlags = 0;
+
+ return 0 == nError;
+
+}
+
+BOOL IsRedirectable_Impl( const ByteString &rPath )
+{
+ if ( rPath.Len() >= 3 && ':' == rPath.GetBuffer()[1] )
+ {
+ ByteString aVolume = rPath.Copy( 0, 3 );
+ UINT nType = GetDriveType( (char *) aVolume.GetBuffer() );
+ SetLastError( ERROR_SUCCESS );
+ return DRIVE_FIXED != nType;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* TempDirImpl()
+|*
+|* Beschreibung liefert den Namens des Directories fuer temporaere
+|* Dateien
+|* Ersterstellung MI 16.03.94
+|* Letzte Aenderung MI 16.03.94
+|*
+*************************************************************************/
+
+const char* TempDirImpl( char *pBuf )
+{
+ if ( !GetTempPath( MAX_PATH, pBuf ) &&
+ !GetWindowsDirectory( pBuf, MAX_PATH ) &&
+ !GetEnvironmentVariable( "HOMEPATH", pBuf, MAX_PATH ) )
+ return 0;
+
+ return pBuf;
+}
+
+//=======================================================================
+
+ErrCode FileStat::QueryDiskSpace( const String &rPath,
+ BigInt &rFreeBytes, BigInt &rTotalBytes )
+{
+ DWORD nSectorsPerCluster; /* address of sectors per cluster */
+ DWORD nBytesPerSector; /* address of bytes per sector */
+ DWORD nFreeClusters; /* address of number of free clusters */
+ DWORD nClusters; /* address of total number of clusters */
+
+ ByteString aVol( DirEntry(rPath).ImpGetTopPtr()->GetName(), osl_getThreadTextEncoding());
+ bool bOK = GetDiskFreeSpace( aVol.GetBuffer(),
+ &nSectorsPerCluster, &nBytesPerSector,
+ &nFreeClusters, &nClusters );
+ if ( !bOK )
+ return Sys2SolarError_Impl( GetLastError() );
+
+ BigInt aBytesPerCluster( BigInt(nSectorsPerCluster) *
+ BigInt(nBytesPerSector) );
+ rFreeBytes = aBytesPerCluster * BigInt(nFreeClusters);
+ rTotalBytes = aBytesPerCluster * BigInt(nClusters);
+ return 0;
+}
+
+//=========================================================================
+
+void FSysEnableSysErrorBox( BOOL bEnable )
+{ // Preserve other Bits!!
+ sal_uInt32 nErrorMode = SetErrorMode( bEnable ? 0 : SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX );
+ if ( bEnable )
+ nErrorMode &= ~(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+ else
+ nErrorMode |= (SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+ SetErrorMode( nErrorMode );
+}
+
+
+
diff --git a/tools/source/fsys/wntmsc.hxx b/tools/source/fsys/wntmsc.hxx
new file mode 100644
index 000000000000..a6202cc71cc6
--- /dev/null
+++ b/tools/source/fsys/wntmsc.hxx
@@ -0,0 +1,102 @@
+/*************************************************************************
+ *
+ * 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 _dosmsc_hxx
+#define _dosmsc_hxx
+
+#include <string.h>
+
+#ifndef ICC
+#include <io.h>
+#endif
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <direct.h>
+
+#include <tools/svwin.h>
+#ifdef _MSC_VER
+#pragma warning (push,1)
+#endif
+#include <winbase.h>
+#ifdef _MSC_VER
+#pragma warning (pop)
+#endif
+#include <tools/solar.h>
+
+#include <tools/string.hxx>
+
+//--------------------------------------------------------------------
+
+#define FSYS_UNIX FALSE
+
+#define DOS_DIRECT _A_SUBDIR
+#define DOS_VOLUMEID 0x08
+#ifndef S_IFBLK
+#define S_IFBLK 0x6000
+#endif
+#define setdrive(n,a) _chdrive(n)
+#define GETDRIVE(n) (n = _getdrive())
+
+#define dirent _WIN32_FIND_DATAA
+#define d_name cFileName
+#define d_type dwFileAttributes
+
+#if defined (TCPP) || defined (tcpp)
+#define _mkdir mkdir
+#define _rmdir rmdir
+#define _chdir chdir
+#define _unlink unlink
+#define _getcwd getcwd
+#define _access access
+#endif
+
+typedef struct
+{
+ _WIN32_FIND_DATAA aDirEnt;
+ HANDLE h;
+ const char *p;
+} DIR;
+
+#define PATHDELIMITER ";"
+#define DEFSTYLE FSYS_STYLE_NTFS
+#define MKDIR( p ) mkdir( p )
+#define CMP_LOWER(s) ( ByteString(s).ToLowerAscii() )
+
+#define START_DRV 'a'
+
+inline BOOL DRIVE_EXISTS(char c)
+{
+ ByteString aDriveRoot( c );
+ aDriveRoot += ":\\";
+ return GetDriveType( aDriveRoot.GetBuffer() ) > 1;
+}
+
+const char* TempDirImpl( char *pBuf );
+
+#define FSysFailOnErrorImpl()
+
+#endif
diff --git a/tools/source/generic/b3dtrans.cxx b/tools/source/generic/b3dtrans.cxx
new file mode 100644
index 000000000000..9ed887457035
--- /dev/null
+++ b/tools/source/generic/b3dtrans.cxx
@@ -0,0 +1,1014 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <tools/b3dtrans.hxx>
+#include <tools/debug.hxx>
+
+/*************************************************************************
+|*
+|* Transformationen fuer alle 3D Ausgaben
+|*
+\************************************************************************/
+
+B3dTransformationSet::B3dTransformationSet()
+{
+ Reset();
+}
+
+B3dTransformationSet::~B3dTransformationSet()
+{
+}
+
+void B3dTransformationSet::Orientation(basegfx::B3DHomMatrix& rTarget, basegfx::B3DPoint aVRP, basegfx::B3DVector aVPN, basegfx::B3DVector aVUP)
+{
+ rTarget.translate( -aVRP.getX(), -aVRP.getY(), -aVRP.getZ());
+ aVUP.normalize();
+ aVPN.normalize();
+ basegfx::B3DVector aRx(aVUP);
+ basegfx::B3DVector aRy(aVPN);
+ aRx = aRx.getPerpendicular(aRy);
+ aRx.normalize();
+ aRy = aRy.getPerpendicular(aRx);
+ aRy.normalize();
+ basegfx::B3DHomMatrix aTemp;
+ aTemp.set(0, 0, aRx.getX());
+ aTemp.set(0, 1, aRx.getY());
+ aTemp.set(0, 2, aRx.getZ());
+ aTemp.set(1, 0, aRy.getX());
+ aTemp.set(1, 1, aRy.getY());
+ aTemp.set(1, 2, aRy.getZ());
+ aTemp.set(2, 0, aVPN.getX());
+ aTemp.set(2, 1, aVPN.getY());
+ aTemp.set(2, 2, aVPN.getZ());
+ rTarget *= aTemp;
+}
+
+void B3dTransformationSet::Frustum(basegfx::B3DHomMatrix& rTarget, double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
+{
+ if(!(fNear > 0.0))
+ {
+ fNear = 0.001;
+ }
+ if(!(fFar > 0.0))
+ {
+ fFar = 1.0;
+ }
+ if(fNear == fFar)
+ {
+ fFar = fNear + 1.0;
+ }
+ if(fLeft == fRight)
+ {
+ fLeft -= 1.0;
+ fRight += 1.0;
+ }
+ if(fTop == fBottom)
+ {
+ fBottom -= 1.0;
+ fTop += 1.0;
+ }
+ basegfx::B3DHomMatrix aTemp;
+
+ aTemp.set(0, 0, 2.0 * fNear / (fRight - fLeft));
+ aTemp.set(1, 1, 2.0 * fNear / (fTop - fBottom));
+ aTemp.set(0, 2, (fRight + fLeft) / (fRight - fLeft));
+ aTemp.set(1, 2, (fTop + fBottom) / (fTop - fBottom));
+ aTemp.set(2, 2, -1.0 * ((fFar + fNear) / (fFar - fNear)));
+ aTemp.set(3, 2, -1.0);
+ aTemp.set(2, 3, -1.0 * ((2.0 * fFar * fNear) / (fFar - fNear)));
+ aTemp.set(3, 3, 0.0);
+
+ rTarget *= aTemp;
+}
+
+void B3dTransformationSet::Ortho(basegfx::B3DHomMatrix& rTarget, double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
+{
+ if(fNear == fFar)
+ {
+ DBG_ERROR("Near and far clipping plane in Ortho definition are identical");
+ fFar = fNear + 1.0;
+ }
+ if(fLeft == fRight)
+ {
+ DBG_ERROR("Left and right in Ortho definition are identical");
+ fLeft -= 1.0;
+ fRight += 1.0;
+ }
+ if(fTop == fBottom)
+ {
+ DBG_ERROR("Top and bottom in Ortho definition are identical");
+ fBottom -= 1.0;
+ fTop += 1.0;
+ }
+ basegfx::B3DHomMatrix aTemp;
+
+ aTemp.set(0, 0, 2.0 / (fRight - fLeft));
+ aTemp.set(1, 1, 2.0 / (fTop - fBottom));
+ aTemp.set(2, 2, -1.0 * (2.0 / (fFar - fNear)));
+ aTemp.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft)));
+ aTemp.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom)));
+ aTemp.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear)));
+
+ rTarget *= aTemp;
+}
+
+/*************************************************************************
+|*
+|* Reset der Werte
+|*
+\************************************************************************/
+
+void B3dTransformationSet::Reset()
+{
+ // Matritzen auf Einheitsmatritzen
+ maObjectTrans.identity();
+ PostSetObjectTrans();
+
+ Orientation(maOrientation);
+ PostSetOrientation();
+
+ maTexture.identity();
+
+ mfLeftBound = mfBottomBound = -1.0;
+ mfRightBound = mfTopBound = 1.0;
+ mfNearBound = 0.001;
+ mfFarBound = 1.001;
+
+ meRatio = Base3DRatioGrow;
+ mfRatio = 0.0;
+
+ maViewportRectangle = Rectangle(-1, -1, 2, 2);
+ maVisibleRectangle = maViewportRectangle;
+
+ mbPerspective = sal_True;
+
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+
+ CalcViewport();
+}
+
+/*************************************************************************
+|*
+|* Objekttransformation
+|*
+\************************************************************************/
+
+void B3dTransformationSet::SetObjectTrans(const basegfx::B3DHomMatrix& rObj)
+{
+ maObjectTrans = rObj;
+
+ mbObjectToDeviceValid = sal_False;
+ mbInvTransObjectToEyeValid = sal_False;
+
+ PostSetObjectTrans();
+}
+
+void B3dTransformationSet::PostSetObjectTrans()
+{
+ // Zuweisen und Inverse bestimmen
+ maInvObjectTrans = maObjectTrans;
+ maInvObjectTrans.invert();
+}
+
+/*************************************************************************
+|*
+|* Orientierungstransformation
+|*
+\************************************************************************/
+
+void B3dTransformationSet::SetOrientation( basegfx::B3DPoint aVRP, basegfx::B3DVector aVPN, basegfx::B3DVector aVUP)
+{
+ maOrientation.identity();
+ Orientation(maOrientation, aVRP, aVPN, aVUP);
+
+ mbInvTransObjectToEyeValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+
+ PostSetOrientation();
+}
+
+void B3dTransformationSet::SetOrientation(basegfx::B3DHomMatrix& mOrient)
+{
+ maOrientation = mOrient;
+
+ mbInvTransObjectToEyeValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+
+ PostSetOrientation();
+}
+
+void B3dTransformationSet::PostSetOrientation()
+{
+ // Zuweisen und Inverse bestimmen
+ maInvOrientation = maOrientation;
+ maInvOrientation.invert();
+}
+
+/*************************************************************************
+|*
+|* Projektionstransformation
+|*
+\************************************************************************/
+
+void B3dTransformationSet::SetProjection(const basegfx::B3DHomMatrix& mProject)
+{
+ maProjection = mProject;
+ PostSetProjection();
+}
+
+const basegfx::B3DHomMatrix& B3dTransformationSet::GetProjection()
+{
+ if(!mbProjectionValid)
+ CalcViewport();
+ return maProjection;
+}
+
+const basegfx::B3DHomMatrix& B3dTransformationSet::GetInvProjection()
+{
+ if(!mbProjectionValid)
+ CalcViewport();
+ return maInvProjection;
+}
+
+void B3dTransformationSet::PostSetProjection()
+{
+ // Zuweisen und Inverse bestimmen
+ maInvProjection = GetProjection();
+ maInvProjection.invert();
+
+ // Abhaengige Matritzen invalidieren
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+}
+
+/*************************************************************************
+|*
+|* Texturtransformation
+|*
+\************************************************************************/
+
+void B3dTransformationSet::SetTexture(const basegfx::B2DHomMatrix& rTxt)
+{
+ maTexture = rTxt;
+ PostSetTexture();
+}
+
+void B3dTransformationSet::PostSetTexture()
+{
+}
+
+/*************************************************************************
+|*
+|* Viewport-Transformation
+|*
+\************************************************************************/
+
+void B3dTransformationSet::CalcViewport()
+{
+ // Faktoren fuer die Projektion
+ double fLeft(mfLeftBound);
+ double fRight(mfRightBound);
+ double fBottom(mfBottomBound);
+ double fTop(mfTopBound);
+
+ // Soll das Seitenverhaeltnis Beachtung finden?
+ // Falls ja, Bereich der Projektion an Seitenverhaeltnis anpassen
+ if(GetRatio() != 0.0)
+ {
+ // Berechne aktuelles Seitenverhaeltnis der Bounds
+ double fBoundWidth = (double)(maViewportRectangle.GetWidth() + 1);
+ double fBoundHeight = (double)(maViewportRectangle.GetHeight() + 1);
+ double fActRatio = 1;
+ double fFactor;
+
+ if(fBoundWidth != 0.0)
+ fActRatio = fBoundHeight / fBoundWidth;
+ // FIXME else in this case has a lot of problems, should this return.
+
+ switch(meRatio)
+ {
+ case Base3DRatioShrink :
+ {
+ // Kleineren Teil vergroessern
+ if(fActRatio > mfRatio)
+ {
+ // X vergroessern
+ fFactor = 1.0 / fActRatio;
+ fRight *= fFactor;
+ fLeft *= fFactor;
+ }
+ else
+ {
+ // Y vergroessern
+ fFactor = fActRatio;
+ fTop *= fFactor;
+ fBottom *= fFactor;
+ }
+ break;
+ }
+ case Base3DRatioGrow :
+ {
+ // GroesserenTeil verkleinern
+ if(fActRatio > mfRatio)
+ {
+ // Y verkleinern
+ fFactor = fActRatio;
+ fTop *= fFactor;
+ fBottom *= fFactor;
+ }
+ else
+ {
+ // X verkleinern
+ fFactor = 1.0 / fActRatio;
+ fRight *= fFactor;
+ fLeft *= fFactor;
+ }
+ break;
+ }
+ case Base3DRatioMiddle :
+ {
+ // Mitteln
+ fFactor = ((1.0 / fActRatio) + 1.0) / 2.0;
+ fRight *= fFactor;
+ fLeft *= fFactor;
+ fFactor = (fActRatio + 1.0) / 2.0;
+ fTop *= fFactor;
+ fBottom *= fFactor;
+ break;
+ }
+ }
+ }
+
+ // Ueberschneiden sich Darstellungsflaeche und Objektflaeche?
+ maSetBound = maViewportRectangle;
+
+ // Mit den neuen Werten Projektion und ViewPort setzen
+ basegfx::B3DHomMatrix aNewProjection;
+
+ // #i36281#
+ // OpenGL needs a little more rough additional size to not let
+ // the front face vanish. Changed from SMALL_DVALUE to 0.000001,
+ // which is 1/10000th, comared with 1/tenth of a million from SMALL_DVALUE.
+ const double fDistPart((mfFarBound - mfNearBound) * 0.0001);
+
+ // Near, Far etwas grosszuegiger setzen, um falsches,
+ // zu kritisches clippen zu verhindern
+ if(mbPerspective)
+ {
+ Frustum(aNewProjection, fLeft, fRight, fBottom, fTop, mfNearBound - fDistPart, mfFarBound + fDistPart);
+ }
+ else
+ {
+ Ortho(aNewProjection, fLeft, fRight, fBottom, fTop, mfNearBound - fDistPart, mfFarBound + fDistPart);
+ }
+
+ // jetzt schon auf gueltig setzen um Endlosschleife zu vermeiden
+ mbProjectionValid = sal_True;
+
+ // Neue Projektion setzen
+ SetProjection(aNewProjection);
+
+ // fill parameters for ViewportTransformation
+ // Translation
+ maTranslate.setX((double)maSetBound.Left() + ((maSetBound.GetWidth() - 1L) / 2.0));
+ maTranslate.setY((double)maSetBound.Top() + ((maSetBound.GetHeight() - 1L) / 2.0));
+ maTranslate.setZ(ZBUFFER_DEPTH_RANGE / 2.0);
+
+ // Skalierung
+ maScale.setX((maSetBound.GetWidth() - 1L) / 2.0);
+ maScale.setY((maSetBound.GetHeight() - 1L) / -2.0);
+ maScale.setZ(ZBUFFER_DEPTH_RANGE / 2.0);
+
+ // Auf Veraenderung des ViewPorts reagieren
+ PostSetViewport();
+}
+
+void B3dTransformationSet::SetRatio(double fNew)
+{
+ if(mfRatio != fNew)
+ {
+ mfRatio = fNew;
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+ }
+}
+
+void B3dTransformationSet::SetRatioMode(Base3DRatio eNew)
+{
+ if(meRatio != eNew)
+ {
+ meRatio = eNew;
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+ }
+}
+
+void B3dTransformationSet::SetDeviceRectangle(double fL, double fR, double fB, double fT,
+ sal_Bool bBroadCastChange)
+{
+ if(fL != mfLeftBound || fR != mfRightBound || fB != mfBottomBound || fT != mfTopBound)
+ {
+ mfLeftBound = fL;
+ mfRightBound = fR;
+ mfBottomBound = fB;
+ mfTopBound = fT;
+
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+
+ // Aenderung bekanntmachen
+ if(bBroadCastChange)
+ DeviceRectangleChange();
+ }
+}
+
+void B3dTransformationSet::SetDeviceVolume(const basegfx::B3DRange& rVol, sal_Bool bBroadCastChange)
+{
+ SetDeviceRectangle(rVol.getMinX(), rVol.getMaxX(), rVol.getMinY(), rVol.getMaxY(), bBroadCastChange);
+ SetFrontClippingPlane(rVol.getMinZ());
+ SetBackClippingPlane(rVol.getMaxZ());
+}
+
+void B3dTransformationSet::DeviceRectangleChange()
+{
+}
+
+void B3dTransformationSet::GetDeviceRectangle(double &fL, double &fR, double& fB, double& fT)
+{
+ fL = mfLeftBound;
+ fR = mfRightBound;
+ fB = mfBottomBound;
+ fT = mfTopBound;
+
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+}
+
+basegfx::B3DRange B3dTransformationSet::GetDeviceVolume()
+{
+ basegfx::B3DRange aRet;
+
+ aRet.expand(basegfx::B3DTuple(mfLeftBound, mfBottomBound, mfNearBound));
+ aRet.expand(basegfx::B3DTuple(mfRightBound, mfTopBound, mfFarBound));
+
+ return aRet;
+}
+
+void B3dTransformationSet::SetFrontClippingPlane(double fF)
+{
+ if(mfNearBound != fF)
+ {
+ mfNearBound = fF;
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+ }
+}
+
+void B3dTransformationSet::SetBackClippingPlane(double fB)
+{
+ if(mfFarBound != fB)
+ {
+ mfFarBound = fB;
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+ }
+}
+
+void B3dTransformationSet::SetPerspective(sal_Bool bNew)
+{
+ if(mbPerspective != bNew)
+ {
+ mbPerspective = bNew;
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+ }
+}
+
+void B3dTransformationSet::SetViewportRectangle(Rectangle& rRect, Rectangle& rVisible)
+{
+ if(rRect != maViewportRectangle || rVisible != maVisibleRectangle)
+ {
+ maViewportRectangle = rRect;
+ maVisibleRectangle = rVisible;
+
+ mbProjectionValid = sal_False;
+ mbObjectToDeviceValid = sal_False;
+ mbWorldToViewValid = sal_False;
+ }
+}
+
+void B3dTransformationSet::PostSetViewport()
+{
+}
+
+const Rectangle& B3dTransformationSet::GetLogicalViewportBounds()
+{
+ if(!mbProjectionValid)
+ CalcViewport();
+ return maSetBound;
+}
+
+const basegfx::B3DVector& B3dTransformationSet::GetScale()
+{
+ if(!mbProjectionValid)
+ CalcViewport();
+ return maScale;
+}
+
+const basegfx::B3DVector& B3dTransformationSet::GetTranslate()
+{
+ if(!mbProjectionValid)
+ CalcViewport();
+ return maTranslate;
+}
+
+/*************************************************************************
+|*
+|* Hilfsmatrixberechnungsroutinen
+|*
+\************************************************************************/
+
+void B3dTransformationSet::CalcMatObjectToDevice()
+{
+ // ObjectToDevice berechnen (Orientation * Projection * Object)
+ maObjectToDevice = maObjectTrans;
+ maObjectToDevice *= maOrientation;
+ maObjectToDevice *= GetProjection();
+
+ // auf gueltig setzen
+ mbObjectToDeviceValid = sal_True;
+}
+
+const basegfx::B3DHomMatrix& B3dTransformationSet::GetObjectToDevice()
+{
+ if(!mbObjectToDeviceValid)
+ CalcMatObjectToDevice();
+ return maObjectToDevice;
+}
+
+void B3dTransformationSet::CalcMatInvTransObjectToEye()
+{
+ maInvTransObjectToEye = maObjectTrans;
+ maInvTransObjectToEye *= maOrientation;
+ maInvTransObjectToEye.invert();
+ maInvTransObjectToEye.transpose();
+
+ // eventuelle Translationen rausschmeissen, da diese
+ // Matrix nur zur Transformation von Vektoren gedacht ist
+ maInvTransObjectToEye.set(3, 0, 0.0);
+ maInvTransObjectToEye.set(3, 1, 0.0);
+ maInvTransObjectToEye.set(3, 2, 0.0);
+ maInvTransObjectToEye.set(3, 3, 1.0);
+
+ // auf gueltig setzen
+ mbInvTransObjectToEyeValid = sal_True;
+}
+
+const basegfx::B3DHomMatrix& B3dTransformationSet::GetInvTransObjectToEye()
+{
+ if(!mbInvTransObjectToEyeValid)
+ CalcMatInvTransObjectToEye();
+ return maInvTransObjectToEye;
+}
+
+basegfx::B3DHomMatrix B3dTransformationSet::GetMatFromObjectToView()
+{
+ basegfx::B3DHomMatrix aFromObjectToView = GetObjectToDevice();
+
+ const basegfx::B3DVector& rScale(GetScale());
+ aFromObjectToView.scale(rScale.getX(), rScale.getY(), rScale.getZ());
+ const basegfx::B3DVector& rTranslate(GetTranslate());
+ aFromObjectToView.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ());
+
+ return aFromObjectToView;
+}
+
+void B3dTransformationSet::CalcMatFromWorldToView()
+{
+ maMatFromWorldToView = maOrientation;
+ maMatFromWorldToView *= GetProjection();
+ const basegfx::B3DVector& rScale(GetScale());
+ maMatFromWorldToView.scale(rScale.getX(), rScale.getY(), rScale.getZ());
+ const basegfx::B3DVector& rTranslate(GetTranslate());
+ maMatFromWorldToView.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ());
+ maInvMatFromWorldToView = maMatFromWorldToView;
+ maInvMatFromWorldToView.invert();
+
+ // gueltig setzen
+ mbWorldToViewValid = sal_True;
+}
+
+const basegfx::B3DHomMatrix& B3dTransformationSet::GetMatFromWorldToView()
+{
+ if(!mbWorldToViewValid)
+ CalcMatFromWorldToView();
+ return maMatFromWorldToView;
+}
+
+const basegfx::B3DHomMatrix& B3dTransformationSet::GetInvMatFromWorldToView()
+{
+ if(!mbWorldToViewValid)
+ CalcMatFromWorldToView();
+ return maInvMatFromWorldToView;
+}
+
+/*************************************************************************
+|*
+|* Direkter Zugriff auf verschiedene Transformationen
+|*
+\************************************************************************/
+
+const basegfx::B3DPoint B3dTransformationSet::WorldToEyeCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetOrientation();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::EyeToWorldCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetInvOrientation();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::EyeToViewCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetProjection();
+ aVec *= GetScale();
+ aVec += GetTranslate();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::ViewToEyeCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec -= GetTranslate();
+ aVec = aVec / GetScale();
+ aVec *= GetInvProjection();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::WorldToViewCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetMatFromWorldToView();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::ViewToWorldCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetInvMatFromWorldToView();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::DeviceToViewCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetScale();
+ aVec += GetTranslate();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::ViewToDeviceCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec -= GetTranslate();
+ aVec = aVec / GetScale();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::ObjectToWorldCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetObjectTrans();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::WorldToObjectCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetInvObjectTrans();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::ObjectToViewCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetObjectTrans();
+ aVec *= GetMatFromWorldToView();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::ViewToObjectCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetInvMatFromWorldToView();
+ aVec *= GetInvObjectTrans();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::ObjectToEyeCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetObjectTrans();
+ aVec *= GetOrientation();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::EyeToObjectCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetInvOrientation();
+ aVec *= GetInvObjectTrans();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::DeviceToEyeCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetInvProjection();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::EyeToDeviceCoor(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetProjection();
+ return aVec;
+}
+
+const basegfx::B3DPoint B3dTransformationSet::InvTransObjectToEye(const basegfx::B3DPoint& rVec)
+{
+ basegfx::B3DPoint aVec(rVec);
+ aVec *= GetInvTransObjectToEye();
+ return aVec;
+}
+
+const basegfx::B2DPoint B3dTransformationSet::TransTextureCoor(const basegfx::B2DPoint& rVec)
+{
+ basegfx::B2DPoint aVec(rVec);
+ aVec *= GetTexture();
+ return aVec;
+}
+
+/*************************************************************************
+|*
+|* Konstruktor B3dViewport
+|*
+\************************************************************************/
+
+B3dViewport::B3dViewport()
+: B3dTransformationSet(),
+ aVRP(0, 0, 0),
+ aVPN(0, 0, 1),
+ aVUV(0, 1, 0)
+{
+ CalcOrientation();
+}
+
+B3dViewport::~B3dViewport()
+{
+}
+
+void B3dViewport::SetVRP(const basegfx::B3DPoint& rNewVRP)
+{
+ aVRP = rNewVRP;
+ CalcOrientation();
+}
+
+void B3dViewport::SetVPN(const basegfx::B3DVector& rNewVPN)
+{
+ aVPN = rNewVPN;
+ CalcOrientation();
+}
+
+void B3dViewport::SetVUV(const basegfx::B3DVector& rNewVUV)
+{
+ aVUV = rNewVUV;
+ CalcOrientation();
+}
+
+void B3dViewport::SetViewportValues(
+ const basegfx::B3DPoint& rNewVRP,
+ const basegfx::B3DVector& rNewVPN,
+ const basegfx::B3DVector& rNewVUV)
+{
+ aVRP = rNewVRP;
+ aVPN = rNewVPN;
+ aVUV = rNewVUV;
+ CalcOrientation();
+}
+
+void B3dViewport::CalcOrientation()
+{
+ SetOrientation(aVRP, aVPN, aVUV);
+}
+
+/*************************************************************************
+|*
+|* Konstruktor B3dViewport
+|*
+\************************************************************************/
+
+B3dCamera::B3dCamera(
+ const basegfx::B3DPoint& rPos, const basegfx::B3DVector& rLkAt,
+ double fFocLen, double fBnkAng, sal_Bool bUseFocLen)
+: B3dViewport(),
+ aPosition(rPos),
+ aCorrectedPosition(rPos),
+ aLookAt(rLkAt),
+ fFocalLength(fFocLen),
+ fBankAngle(fBnkAng),
+ bUseFocalLength(bUseFocLen)
+{
+ CalcNewViewportValues();
+}
+
+B3dCamera::~B3dCamera()
+{
+}
+
+void B3dCamera::SetPosition(const basegfx::B3DPoint& rNewPos)
+{
+ if(rNewPos != aPosition)
+ {
+ // Zuweisen
+ aCorrectedPosition = aPosition = rNewPos;
+
+ // Neuberechnung
+ CalcNewViewportValues();
+ }
+}
+
+void B3dCamera::SetLookAt(const basegfx::B3DVector& rNewLookAt)
+{
+ if(rNewLookAt != aLookAt)
+ {
+ // Zuweisen
+ aLookAt = rNewLookAt;
+
+ // Neuberechnung
+ CalcNewViewportValues();
+ }
+}
+
+void B3dCamera::SetPositionAndLookAt(const basegfx::B3DPoint& rNewPos, const basegfx::B3DVector& rNewLookAt)
+{
+ if(rNewPos != aPosition || rNewLookAt != aLookAt)
+ {
+ // Zuweisen
+ aPosition = rNewPos;
+ aLookAt = rNewLookAt;
+
+ // Neuberechnung
+ CalcNewViewportValues();
+ }
+}
+
+void B3dCamera::SetFocalLength(double fLen)
+{
+ if(fLen != fFocalLength)
+ {
+ // Zuweisen
+ if(fLen < 5.0)
+ fLen = 5.0;
+ fFocalLength = fLen;
+
+ // Neuberechnung
+ CalcNewViewportValues();
+ }
+}
+
+void B3dCamera::SetBankAngle(double fAngle)
+{
+ if(fAngle != fBankAngle)
+ {
+ // Zuweisen
+ fBankAngle = fAngle;
+
+ // Neuberechnung
+ CalcNewViewportValues();
+ }
+}
+
+void B3dCamera::SetUseFocalLength(sal_Bool bNew)
+{
+ if(bNew != (sal_Bool)bUseFocalLength)
+ {
+ // Zuweisen
+ bUseFocalLength = bNew;
+
+ // Neuberechnung
+ CalcNewViewportValues();
+ }
+}
+
+void B3dCamera::DeviceRectangleChange()
+{
+ // call parent
+ B3dViewport::DeviceRectangleChange();
+
+ // Auf Aenderung reagieren
+ CalcNewViewportValues();
+}
+
+void B3dCamera::CalcNewViewportValues()
+{
+ basegfx::B3DVector aViewVector(aPosition - aLookAt);
+ basegfx::B3DVector aNewVPN(aViewVector);
+
+ basegfx::B3DVector aNewVUV(0.0, 1.0, 0.0);
+ if(aNewVPN.getLength() < aNewVPN.getY())
+ aNewVUV.setX(0.5);
+
+ aNewVUV.normalize();
+ aNewVPN.normalize();
+
+ basegfx::B3DVector aNewToTheRight = aNewVPN;
+ aNewToTheRight = aNewToTheRight.getPerpendicular(aNewVUV);
+ aNewToTheRight.normalize();
+ aNewVUV = aNewToTheRight.getPerpendicular(aNewVPN);
+ aNewVUV.normalize();
+
+ SetViewportValues(aPosition, aNewVPN, aNewVUV);
+ if(CalcFocalLength())
+ SetViewportValues(aCorrectedPosition, aNewVPN, aNewVUV);
+
+ if(fBankAngle != 0.0)
+ {
+ basegfx::B3DHomMatrix aRotMat;
+ aRotMat.rotate(0.0, 0.0, fBankAngle);
+ basegfx::B3DVector aUp(0.0, 1.0, 0.0);
+ aUp *= aRotMat;
+ aUp = EyeToWorldCoor(aUp);
+ aUp.normalize();
+ SetVUV(aUp);
+ }
+}
+
+sal_Bool B3dCamera::CalcFocalLength()
+{
+ double fWidth = GetDeviceRectangleWidth();
+ sal_Bool bRetval = sal_False;
+
+ if(bUseFocalLength)
+ {
+ // Position aufgrund der FocalLength korrigieren
+ aCorrectedPosition = basegfx::B3DPoint(0.0, 0.0, fFocalLength * fWidth / 35.0);
+ aCorrectedPosition = EyeToWorldCoor(aCorrectedPosition);
+ bRetval = sal_True;
+ }
+ else
+ {
+ // FocalLength anhand der Position anpassen
+ basegfx::B3DPoint aOldPosition;
+ aOldPosition = WorldToEyeCoor(aOldPosition);
+ if(fWidth != 0.0)
+ fFocalLength = aOldPosition.getZ() / fWidth * 35.0;
+ if(fFocalLength < 5.0)
+ fFocalLength = 5.0;
+ }
+ return bRetval;
+}
+
+// eof
diff --git a/tools/source/generic/bigint.cxx b/tools/source/generic/bigint.cxx
new file mode 100644
index 000000000000..7b10f31d733f
--- /dev/null
+++ b/tools/source/generic/bigint.cxx
@@ -0,0 +1,1141 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <math.h>
+#include <tools/tools.h>
+
+#include <tools/bigint.hxx>
+#include <tools/string.hxx>
+#include <tools/debug.hxx>
+
+#include <string.h>
+#include <ctype.h>
+
+static const long MY_MAXLONG = 0x3fffffff;
+static const long MY_MINLONG = -MY_MAXLONG;
+static const long MY_MAXSHORT = 0x00007fff;
+static const long MY_MINSHORT = -MY_MAXSHORT;
+
+/* Die ganzen Algorithmen zur Addition, Subtraktion, Multiplikation und
+ * Division von langen Zahlen stammen aus SEMINUMERICAL ALGORITHMS von
+ * DONALD E. KNUTH aus der Reihe The Art of Computer Programming. Zu finden
+ * sind diese Algorithmen im Kapitel 4.3.1. The Classical Algorithms.
+ */
+
+// Muss auf UINT16/INT16/UINT32/INT32 umgestellt werden !!! W.P.
+
+// -----------------------------------------------------------------------
+
+void BigInt::MakeBigInt( const BigInt& rVal )
+{
+ if ( rVal.bIsBig )
+ {
+ memcpy( (void*)this, (const void*)&rVal, sizeof( BigInt ) );
+ while ( nLen > 1 && nNum[nLen-1] == 0 )
+ nLen--;
+ }
+ else
+ {
+ long nTmp = rVal.nVal;
+
+ nVal = rVal.nVal;
+ bIsBig = sal_True;
+ if ( nTmp < 0 )
+ {
+ bIsNeg = sal_True;
+ nTmp = -nTmp;
+ }
+ else
+ bIsNeg = sal_False;
+
+ nNum[0] = (sal_uInt16)(nTmp & 0xffffL);
+ nNum[1] = (sal_uInt16)(nTmp >> 16);
+#ifndef _WIN16
+ if ( nTmp & 0xffff0000L )
+#else
+ long l = 0xffff0000L;
+ if ( nTmp & l )
+#endif
+ nLen = 2;
+ else
+ nLen = 1;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::Normalize()
+{
+ if ( bIsBig )
+ {
+ while ( nLen > 1 && nNum[nLen-1] == 0 )
+ nLen--;
+
+ if ( nLen < 3 )
+ {
+ if ( nLen < 2 )
+ nVal = nNum[0];
+ else if ( nNum[1] & 0x8000 )
+ return;
+ else
+ nVal = ((long)nNum[1] << 16) + nNum[0];
+
+ bIsBig = sal_False;
+
+ if ( bIsNeg )
+ nVal = -nVal;
+ }
+ // else ist nVal undefiniert !!! W.P.
+ }
+ // wozu, nLen ist doch undefiniert ??? W.P.
+ else if ( nVal & 0xFFFF0000L )
+ nLen = 2;
+ else
+ nLen = 1;
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::Mult( const BigInt &rVal, sal_uInt16 nMul )
+{
+ sal_uInt16 nK = 0;
+ for ( int i = 0; i < rVal.nLen; i++ )
+ {
+ sal_uInt32 nTmp = (sal_uInt32)rVal.nNum[i] * (sal_uInt32)nMul + nK;
+ nK = (sal_uInt16)(nTmp >> 16);
+ nNum[i] = (sal_uInt16)nTmp;
+ }
+
+ if ( nK )
+ {
+ nNum[rVal.nLen] = nK;
+ nLen = rVal.nLen + 1;
+ }
+ else
+ nLen = rVal.nLen;
+
+ bIsBig = sal_True;
+ bIsNeg = rVal.bIsNeg;
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::Div( sal_uInt16 nDiv, sal_uInt16& rRem )
+{
+ sal_uInt32 nK = 0;
+ for ( int i = nLen - 1; i >= 0; i-- )
+ {
+ sal_uInt32 nTmp = (sal_uInt32)nNum[i] + (nK << 16);
+ nNum[i] = (sal_uInt16)(nTmp / nDiv);
+ nK = nTmp % nDiv;
+ }
+ rRem = (sal_uInt16)nK;
+
+ if ( nNum[nLen-1] == 0 )
+ nLen -= 1;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool BigInt::IsLess( const BigInt& rVal ) const
+{
+ if ( rVal.nLen < nLen)
+ return sal_True;
+ if ( rVal.nLen > nLen )
+ return sal_False;
+
+ int i;
+ for ( i = nLen - 1; i > 0 && nNum[i] == rVal.nNum[i]; i-- )
+ {
+ }
+ return rVal.nNum[i] < nNum[i];
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::AddLong( BigInt& rB, BigInt& rErg )
+{
+ if ( bIsNeg == rB.bIsNeg )
+ {
+ int i;
+ char len;
+
+ // wenn die Zahlen unterschiedlich lang sind, sollte zunaechst bei
+ // der kleineren Zahl die fehlenden Ziffern mit 0 initialisert werden
+ if (nLen >= rB.nLen)
+ {
+ len = nLen;
+ for (i = rB.nLen; i < len; i++)
+ rB.nNum[i] = 0;
+ }
+ else
+ {
+ len = rB.nLen;
+ for (i = nLen; i < len; i++)
+ nNum[i] = 0;
+ }
+
+ // Die Ziffern werden von hinten nach vorne addiert
+ long k;
+ long nZ = 0;
+ for (i = 0, k = 0; i < len; i++) {
+ nZ = (long)nNum[i] + (long)rB.nNum[i] + k;
+ if (nZ & 0xff0000L)
+ k = 1;
+ else
+ k = 0;
+ rErg.nNum[i] = (sal_uInt16)(nZ & 0xffffL);
+ }
+ // Trat nach der letzten Addition ein Ueberlauf auf, muss dieser
+ // noch ins Ergebis uebernommen werden
+ if (nZ & 0xff0000L) // oder if(k)
+ {
+ rErg.nNum[i] = 1;
+ len++;
+ }
+ // Die Laenge und das Vorzeichen setzen
+ rErg.nLen = len;
+ rErg.bIsNeg = bIsNeg && rB.bIsNeg;
+ rErg.bIsBig = sal_True;
+ }
+ // Wenn nur einer der beiden Operanten negativ ist, wird aus der
+ // Addition eine Subtaktion
+ else if (bIsNeg)
+ {
+ bIsNeg = sal_False;
+ rB.SubLong(*this, rErg);
+ bIsNeg = sal_True;
+ }
+ else
+ {
+ rB.bIsNeg = sal_False;
+ SubLong(rB, rErg);
+ rB.bIsNeg = sal_True;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::SubLong( BigInt& rB, BigInt& rErg )
+{
+ if ( bIsNeg == rB.bIsNeg )
+ {
+ int i;
+ char len;
+ long nZ, k;
+
+ // wenn die Zahlen unterschiedlich lang sind, sollte zunaechst bei
+ // der kleineren Zahl die fehlenden Ziffern mit 0 initialisert werden
+ if (nLen >= rB.nLen)
+ {
+ len = nLen;
+ for (i = rB.nLen; i < len; i++)
+ rB.nNum[i] = 0;
+ }
+ else
+ {
+ len = rB.nLen;
+ for (i = nLen; i < len; i++)
+ nNum[i] = 0;
+ }
+
+ if ( IsLess(rB) )
+ {
+ for (i = 0, k = 0; i < len; i++)
+ {
+ nZ = (long)nNum[i] - (long)rB.nNum[i] + k;
+ if (nZ < 0)
+ k = -1;
+ else
+ k = 0;
+ rErg.nNum[i] = (sal_uInt16)(nZ & 0xffffL);
+ }
+ rErg.bIsNeg = bIsNeg;
+ }
+ else
+ {
+ for (i = 0, k = 0; i < len; i++)
+ {
+ nZ = (long)rB.nNum[i] - (long)nNum[i] + k;
+ if (nZ < 0)
+ k = -1;
+ else
+ k = 0;
+ rErg.nNum[i] = (sal_uInt16)(nZ & 0xffffL);
+ }
+ // wenn a < b, dann Vorzeichen vom Ergebnis umdrehen
+ rErg.bIsNeg = !bIsNeg;
+ }
+ rErg.nLen = len;
+ rErg.bIsBig = sal_True;
+ }
+ // Wenn nur einer der beiden Operanten negativ ist, wird aus der
+ // Subtaktion eine Addition
+ else if (bIsNeg)
+ {
+ bIsNeg = sal_False;
+ AddLong(rB, rErg);
+ bIsNeg = sal_True;
+ rErg.bIsNeg = sal_True;
+ }
+ else
+ {
+ rB.bIsNeg = sal_False;
+ AddLong(rB, rErg);
+ rB.bIsNeg = sal_True;
+ rErg.bIsNeg = sal_False;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::MultLong( const BigInt& rB, BigInt& rErg ) const
+{
+ int i, j;
+ sal_uInt32 nZ, k;
+
+ rErg.bIsNeg = bIsNeg != rB.bIsNeg;
+ rErg.bIsBig = sal_True;
+ rErg.nLen = nLen + rB.nLen;
+
+ for (i = 0; i < rErg.nLen; i++)
+ rErg.nNum[i] = 0;
+
+ for (j = 0; j < rB.nLen; j++)
+ {
+ for (i = 0, k = 0; i < nLen; i++)
+ {
+ nZ = (sal_uInt32)nNum[i] * (sal_uInt32)rB.nNum[j] +
+ (sal_uInt32)rErg.nNum[i + j] + k;
+ rErg.nNum[i + j] = (sal_uInt16)(nZ & 0xffffUL);
+ k = nZ >> 16;
+ }
+ rErg.nNum[i + j] = (sal_uInt16)k;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::DivLong( const BigInt& rB, BigInt& rErg ) const
+{
+ int i, j;
+ long nTmp;
+ sal_uInt16 nK, nQ, nMult;
+ short nLenB = rB.nLen;
+ short nLenB1 = rB.nLen - 1;
+ BigInt aTmpA, aTmpB;
+
+ nMult = (sal_uInt16)(0x10000L / ((long)rB.nNum[nLenB1] + 1));
+
+ aTmpA.Mult( *this, nMult );
+ if ( aTmpA.nLen == nLen )
+ {
+ aTmpA.nNum[aTmpA.nLen] = 0;
+ aTmpA.nLen++;
+ }
+
+ aTmpB.Mult( rB, nMult );
+
+ for (j = aTmpA.nLen - 1; j >= nLenB; j--)
+ { // Raten des Divisors
+ nTmp = ( (long)aTmpA.nNum[j] << 16 ) + aTmpA.nNum[j - 1];
+ if (aTmpA.nNum[j] == aTmpB.nNum[nLenB1])
+ nQ = 0xFFFF;
+ else
+ nQ = (sal_uInt16)(((sal_uInt32)nTmp) / aTmpB.nNum[nLenB1]);
+
+ if ( ((sal_uInt32)aTmpB.nNum[nLenB1 - 1] * nQ) >
+ ((((sal_uInt32)nTmp) - aTmpB.nNum[nLenB1] * nQ) << 16) + aTmpA.nNum[j - 2])
+ nQ--;
+ // Und hier faengt das Teilen an
+ nK = 0;
+ nTmp = 0;
+ for (i = 0; i < nLenB; i++)
+ {
+ nTmp = (long)aTmpA.nNum[j - nLenB + i]
+ - ((long)aTmpB.nNum[i] * nQ)
+ - nK;
+ aTmpA.nNum[j - nLenB + i] = (sal_uInt16)nTmp;
+ nK = (sal_uInt16) (nTmp >> 16);
+ if ( nK )
+ nK = (sal_uInt16)(0x10000UL - nK);
+ }
+ unsigned short& rNum( aTmpA.nNum[j - nLenB + i] );
+ rNum = rNum - nK; // MSVC yields a warning on -= here, so don't use it
+ if (aTmpA.nNum[j - nLenB + i] == 0)
+ rErg.nNum[j - nLenB] = nQ;
+ else
+ {
+ rErg.nNum[j - nLenB] = nQ - 1;
+ nK = 0;
+ for (i = 0; i < nLenB; i++)
+ {
+ nTmp = aTmpA.nNum[j - nLenB + i] + aTmpB.nNum[i] + nK;
+ aTmpA.nNum[j - nLenB + i] = (sal_uInt16)(nTmp & 0xFFFFL);
+ if (nTmp & 0xFFFF0000L)
+ nK = 1;
+ else
+ nK = 0;
+ }
+ }
+ }
+
+ rErg.bIsNeg = bIsNeg != rB.bIsNeg;
+ rErg.bIsBig = sal_True;
+ rErg.nLen = nLen - rB.nLen + 1;
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::ModLong( const BigInt& rB, BigInt& rErg ) const
+{
+ short i, j;
+ long nTmp;
+ sal_uInt16 nK, nQ, nMult;
+ short nLenB = rB.nLen;
+ short nLenB1 = rB.nLen - 1;
+ BigInt aTmpA, aTmpB;
+
+ nMult = (sal_uInt16)(0x10000L / ((long)rB.nNum[nLenB1] + 1));
+
+ aTmpA.Mult( *this, nMult);
+ if ( aTmpA.nLen == nLen )
+ {
+ aTmpA.nNum[aTmpA.nLen] = 0;
+ aTmpA.nLen++;
+ }
+
+ aTmpB.Mult( rB, nMult);
+
+ for (j = aTmpA.nLen - 1; j >= nLenB; j--)
+ { // Raten des Divisors
+ nTmp = ( (long)aTmpA.nNum[j] << 16 ) + aTmpA.nNum[j - 1];
+ if (aTmpA.nNum[j] == aTmpB.nNum[nLenB1])
+ nQ = 0xFFFF;
+ else
+ nQ = (sal_uInt16)(((sal_uInt32)nTmp) / aTmpB.nNum[nLenB1]);
+
+ if ( ((sal_uInt32)aTmpB.nNum[nLenB1 - 1] * nQ) >
+ ((((sal_uInt32)nTmp) - aTmpB.nNum[nLenB1] * nQ) << 16) + aTmpA.nNum[j - 2])
+ nQ--;
+ // Und hier faengt das Teilen an
+ nK = 0;
+ nTmp = 0;
+ for (i = 0; i < nLenB; i++)
+ {
+ nTmp = (long)aTmpA.nNum[j - nLenB + i]
+ - ((long)aTmpB.nNum[i] * nQ)
+ - nK;
+ aTmpA.nNum[j - nLenB + i] = (sal_uInt16)nTmp;
+ nK = (sal_uInt16) (nTmp >> 16);
+ if ( nK )
+ nK = (sal_uInt16)(0x10000UL - nK);
+ }
+ unsigned short& rNum( aTmpA.nNum[j - nLenB + i] );
+ rNum = rNum - nK;
+ if (aTmpA.nNum[j - nLenB + i] == 0)
+ rErg.nNum[j - nLenB] = nQ;
+ else
+ {
+ rErg.nNum[j - nLenB] = nQ - 1;
+ nK = 0;
+ for (i = 0; i < nLenB; i++) {
+ nTmp = aTmpA.nNum[j - nLenB + i] + aTmpB.nNum[i] + nK;
+ aTmpA.nNum[j - nLenB + i] = (sal_uInt16)(nTmp & 0xFFFFL);
+ if (nTmp & 0xFFFF0000L)
+ nK = 1;
+ else
+ nK = 0;
+ }
+ }
+ }
+
+ rErg = aTmpA;
+ rErg.Div( nMult, nQ );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool BigInt::ABS_IsLess( const BigInt& rB ) const
+{
+ if (bIsBig || rB.bIsBig)
+ {
+ BigInt nA, nB;
+ nA.MakeBigInt( *this );
+ nB.MakeBigInt( rB );
+ if (nA.nLen == nB.nLen)
+ {
+ int i;
+ for (i = nA.nLen - 1; i > 0 && nA.nNum[i] == nB.nNum[i]; i--)
+ {
+ }
+ return nA.nNum[i] < nB.nNum[i];
+ }
+ else
+ return nA.nLen < nB.nLen;
+ }
+ if ( nVal < 0 )
+ if ( rB.nVal < 0 )
+ return nVal > rB.nVal;
+ else
+ return nVal > -rB.nVal;
+ else
+ if ( rB.nVal < 0 )
+ return nVal < -rB.nVal;
+ else
+ return nVal < rB.nVal;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt::BigInt( const BigInt& rBigInt )
+{
+ if ( rBigInt.bIsBig )
+ memcpy( (void*)this, (const void*)&rBigInt, sizeof( BigInt ) );
+ else
+ {
+ bIsSet = rBigInt.bIsSet;
+ bIsBig = sal_False;
+ nVal = rBigInt.nVal;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BigInt::BigInt( const ByteString& rString )
+{
+ bIsSet = sal_True;
+ bIsNeg = sal_False;
+ bIsBig = sal_False;
+ nVal = 0;
+
+ sal_Bool bNeg = sal_False;
+ const sal_Char* p = rString.GetBuffer();
+ if ( *p == '-' )
+ {
+ bNeg = sal_True;
+ p++;
+ }
+ while( *p >= '0' && *p <= '9' )
+ {
+ *this *= 10;
+ *this += *p - '0';
+ p++;
+ }
+ if ( bIsBig )
+ bIsNeg = bNeg;
+ else if( bNeg )
+ nVal = -nVal;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt::BigInt( const UniString& rString )
+{
+ bIsSet = sal_True;
+ bIsNeg = sal_False;
+ bIsBig = sal_False;
+ nVal = 0;
+
+ sal_Bool bNeg = sal_False;
+ const sal_Unicode* p = rString.GetBuffer();
+ if ( *p == '-' )
+ {
+ bNeg = sal_True;
+ p++;
+ }
+ while( *p >= '0' && *p <= '9' )
+ {
+ *this *= 10;
+ *this += *p - '0';
+ p++;
+ }
+ if ( bIsBig )
+ bIsNeg = bNeg;
+ else if( bNeg )
+ nVal = -nVal;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt::BigInt( double nValue )
+{
+ bIsSet = sal_True;
+
+ if ( nValue < 0 )
+ {
+ nValue *= -1;
+ bIsNeg = sal_True;
+ }
+ else
+ {
+ bIsNeg = sal_False;
+ }
+
+ if ( nValue < 1 )
+ {
+ bIsBig = sal_False;
+ nVal = 0;
+ }
+ else
+ {
+ bIsBig = sal_True;
+
+ int i=0;
+
+ while ( ( nValue > 65536.0 ) && ( i < MAX_DIGITS ) )
+ {
+ nNum[i] = (sal_uInt16) fmod( nValue, 65536.0 );
+ nValue -= nNum[i];
+ nValue /= 65536.0;
+ i++;
+ }
+ if ( i < MAX_DIGITS )
+ nNum[i++] = (sal_uInt16) nValue;
+
+ nLen = i;
+
+ if ( i < 3 )
+ Normalize();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BigInt::BigInt( sal_uInt32 nValue )
+{
+ bIsSet = sal_True;
+ if ( nValue & 0x80000000UL )
+ {
+ bIsBig = sal_True;
+ bIsNeg = sal_False;
+ nNum[0] = (sal_uInt16)(nValue & 0xffffUL);
+ nNum[1] = (sal_uInt16)(nValue >> 16);
+ nLen = 2;
+ }
+ else
+ {
+ bIsBig = sal_False;
+ nVal = nValue;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BigInt::operator ULONG() const
+{
+ if ( !bIsBig )
+ return (sal_uInt32)nVal;
+ else if ( nLen == 2 )
+ {
+ sal_uInt32 nRet;
+ nRet = ((sal_uInt32)nNum[1]) << 16;
+ nRet += nNum[0];
+ return nRet;
+ }
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt::operator double() const
+{
+ if ( !bIsBig )
+ return (double) nVal;
+ else
+ {
+ int i = nLen-1;
+ double nRet = (double) ((sal_uInt32)nNum[i]);
+
+ while ( i )
+ {
+ nRet *= 65536.0;
+ i--;
+ nRet += (double) ((sal_uInt32)nNum[i]);
+ }
+
+ if ( bIsNeg )
+ nRet *= -1;
+
+ return nRet;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ByteString BigInt::GetByteString() const
+{
+ ByteString aString;
+
+ if ( !bIsBig )
+ aString = ByteString::CreateFromInt32( nVal );
+ else
+ {
+ BigInt aTmp( *this );
+ BigInt a1000000000( 1000000000L );
+ aTmp.Abs();
+
+ do
+ {
+ BigInt a = aTmp;
+ a %= a1000000000;
+ aTmp /= a1000000000;
+
+ ByteString aStr = aString;
+ if ( a.nVal < 100000000L )
+ { // leading 0s
+ aString = ByteString::CreateFromInt32( a.nVal + 1000000000L );
+ aString.Erase( 0, 1 );
+ }
+ else
+ aString = ByteString::CreateFromInt32( a.nVal );
+ aString += aStr;
+ }
+ while( aTmp.bIsBig );
+
+ ByteString aStr = aString;
+ if ( bIsNeg )
+ aString = ByteString::CreateFromInt32( -aTmp.nVal );
+ else
+ aString = ByteString::CreateFromInt32( aTmp.nVal );
+ aString += aStr;
+ }
+
+ return aString;
+}
+
+// -----------------------------------------------------------------------
+
+UniString BigInt::GetString() const
+{
+ UniString aString;
+
+ if ( !bIsBig )
+ aString = UniString::CreateFromInt32( nVal );
+ else
+ {
+ BigInt aTmp( *this );
+ BigInt a1000000000( 1000000000L );
+ aTmp.Abs();
+
+ do
+ {
+ BigInt a = aTmp;
+ a %= a1000000000;
+ aTmp /= a1000000000;
+
+ UniString aStr = aString;
+ if ( a.nVal < 100000000L )
+ { // leading 0s
+ aString = UniString::CreateFromInt32( a.nVal + 1000000000L );
+ aString.Erase(0,1);
+ }
+ else
+ aString = UniString::CreateFromInt32( a.nVal );
+ aString += aStr;
+ }
+ while( aTmp.bIsBig );
+
+ UniString aStr = aString;
+ if ( bIsNeg )
+ aString = UniString::CreateFromInt32( -aTmp.nVal );
+ else
+ aString = UniString::CreateFromInt32( aTmp.nVal );
+ aString += aStr;
+ }
+
+ return aString;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt& BigInt::operator=( const BigInt& rBigInt )
+{
+ if ( rBigInt.bIsBig )
+ memcpy( (void*)this, (const void*)&rBigInt, sizeof( BigInt ) );
+ else
+ {
+ bIsSet = rBigInt.bIsSet;
+ bIsBig = sal_False;
+ nVal = rBigInt.nVal;
+ }
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt& BigInt::operator+=( const BigInt& rVal )
+{
+ if ( !bIsBig && !rVal.bIsBig )
+ {
+ if( nVal <= MY_MAXLONG && rVal.nVal <= MY_MAXLONG
+ && nVal >= MY_MINLONG && rVal.nVal >= MY_MINLONG )
+ { // wir bewegen uns im ungefaehrlichem Bereich
+ nVal += rVal.nVal;
+ return *this;
+ }
+
+ if( (nVal < 0) != (rVal.nVal < 0) )
+ { // wir bewegen uns im ungefaehrlichem Bereich
+ nVal += rVal.nVal;
+ return *this;
+ }
+ }
+
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.AddLong( aTmp2, *this );
+ Normalize();
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt& BigInt::operator-=( const BigInt& rVal )
+{
+ if ( !bIsBig && !rVal.bIsBig )
+ {
+ if ( nVal <= MY_MAXLONG && rVal.nVal <= MY_MAXLONG &&
+ nVal >= MY_MINLONG && rVal.nVal >= MY_MINLONG )
+ { // wir bewegen uns im ungefaehrlichem Bereich
+ nVal -= rVal.nVal;
+ return *this;
+ }
+
+ if ( (nVal < 0) == (rVal.nVal < 0) )
+ { // wir bewegen uns im ungefaehrlichem Bereich
+ nVal -= rVal.nVal;
+ return *this;
+ }
+ }
+
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.SubLong( aTmp2, *this );
+ Normalize();
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt& BigInt::operator*=( const BigInt& rVal )
+{
+ if ( !bIsBig && !rVal.bIsBig
+ && nVal <= MY_MAXSHORT && rVal.nVal <= MY_MAXSHORT
+ && nVal >= MY_MINSHORT && rVal.nVal >= MY_MINSHORT )
+ // nicht optimal !!! W.P.
+ { // wir bewegen uns im ungefaehrlichem Bereich
+ nVal *= rVal.nVal;
+ }
+ else
+ {
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( rVal );
+ aTmp2.MakeBigInt( *this );
+ aTmp1.MultLong(aTmp2, *this);
+ Normalize();
+ }
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BigInt& BigInt::operator/=( const BigInt& rVal )
+{
+ if ( !rVal.bIsBig )
+ {
+ if ( rVal.nVal == 0 )
+ {
+ DBG_ERROR( "BigInt::operator/ --> divide by zero" );
+ return *this;
+ }
+
+ if ( !bIsBig )
+ {
+ // wir bewegen uns im ungefaehrlichem Bereich
+ nVal /= rVal.nVal;
+ return *this;
+ }
+
+ if ( rVal.nVal == 1 )
+ return *this;
+
+ if ( rVal.nVal == -1 )
+ {
+ bIsNeg = !bIsNeg;
+ return *this;
+ }
+
+ if ( rVal.nVal <= (long)0xFFFF && rVal.nVal >= -(long)0xFFFF )
+ {
+ // ein BigInt durch ein sal_uInt16 teilen
+ sal_uInt16 nTmp;
+ if ( rVal.nVal < 0 )
+ {
+ nTmp = (sal_uInt16) -rVal.nVal;
+ bIsNeg = !bIsNeg;
+ }
+ else
+ nTmp = (sal_uInt16) rVal.nVal;
+
+ Div( nTmp, nTmp );
+ Normalize();
+ return *this;
+ }
+ }
+
+ if ( ABS_IsLess( rVal ) )
+ {
+ *this = BigInt( (long)0 );
+ return *this;
+ }
+
+ // BigInt durch BigInt teilen
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.DivLong(aTmp2, *this);
+ Normalize();
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void BigInt::DivMod( const BigInt& rVal, BigInt& rMod )
+{
+ if ( !rVal.bIsBig )
+ {
+ if ( rVal.nVal == 0 )
+ {
+ DBG_ERROR( "BigInt::operator/ --> divide by zero" );
+ return;
+ }
+
+ if ( !bIsBig )
+ {
+ // wir bewegen uns im ungefaehrlichem Bereich
+ rMod = BigInt( nVal % rVal.nVal );
+ nVal /= rVal.nVal;
+ return;
+ }
+
+ if ( rVal.nVal == 1 )
+ {
+ rMod = BigInt( (long)0 );
+ return;
+ }
+
+ if ( rVal.nVal == -1 )
+ {
+ rMod = BigInt( (long)0 );
+ bIsNeg = !bIsNeg;
+ return;
+ }
+
+ if ( rVal.nVal <= (long)0xFFFF && rVal.nVal >= -(long)0xFFFF )
+ {
+ // ein BigInt durch ein sal_uInt16 teilen
+ sal_uInt16 nTmp;
+ if ( rVal.nVal < 0 )
+ {
+ nTmp = (sal_uInt16) -rVal.nVal;
+ bIsNeg = !bIsNeg;
+ }
+ else
+ nTmp = (sal_uInt16) rVal.nVal;
+
+ Div( nTmp, nTmp );
+ rMod = BigInt( (long)nTmp );
+ Normalize();
+ return;
+ }
+ }
+
+ if ( ABS_IsLess( rVal ) )
+ {
+ rMod = *this;
+ *this = BigInt( (long)0 );
+ return;
+ }
+
+ // BigInt durch BigInt teilen
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.DivLong(aTmp2, *this);
+ Normalize();
+ aTmp1.ModLong(aTmp2, rMod); // nicht optimal
+ rMod.Normalize();
+}
+
+// -----------------------------------------------------------------------
+
+BigInt& BigInt::operator%=( const BigInt& rVal )
+{
+ if ( !rVal.bIsBig )
+ {
+ if ( rVal.nVal == 0 )
+ {
+ DBG_ERROR( "BigInt::operator/ --> divide by zero" );
+ return *this;
+ }
+
+ if ( !bIsBig )
+ {
+ // wir bewegen uns im ungefaehrlichem Bereich
+ nVal %= rVal.nVal;
+ return *this;
+ }
+
+ if ( rVal.nVal <= (long)0xFFFF && rVal.nVal >= -(long)0xFFFF )
+ {
+ // ein BigInt durch ein short teilen
+ sal_uInt16 nTmp;
+ if ( rVal.nVal < 0 )
+ {
+ nTmp = (sal_uInt16) -rVal.nVal;
+ bIsNeg = !bIsNeg;
+ }
+ else
+ nTmp = (sal_uInt16) rVal.nVal;
+
+ Div( nTmp, nTmp );
+ *this = BigInt( (long)nTmp );
+ return *this;
+ }
+ }
+
+ if ( ABS_IsLess( rVal ) )
+ return *this;
+
+ // BigInt durch BigInt teilen
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.ModLong(aTmp2, *this);
+ Normalize();
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool operator==( const BigInt& rVal1, const BigInt& rVal2 )
+{
+ if ( rVal1.bIsBig || rVal2.bIsBig )
+ {
+ BigInt nA, nB;
+ nA.MakeBigInt( rVal1 );
+ nB.MakeBigInt( rVal2 );
+ if ( nA.bIsNeg == nB.bIsNeg )
+ {
+ if ( nA.nLen == nB.nLen )
+ {
+ int i;
+ for ( i = nA.nLen - 1; i > 0 && nA.nNum[i] == nB.nNum[i]; i-- )
+ {
+ }
+
+ return nA.nNum[i] == nB.nNum[i];
+ }
+ return sal_False;
+ }
+ return sal_False;
+ }
+ return rVal1.nVal == rVal2.nVal;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool operator<( const BigInt& rVal1, const BigInt& rVal2 )
+{
+ if ( rVal1.bIsBig || rVal2.bIsBig )
+ {
+ BigInt nA, nB;
+ nA.MakeBigInt( rVal1 );
+ nB.MakeBigInt( rVal2 );
+ if ( nA.bIsNeg == nB.bIsNeg )
+ {
+ if ( nA.nLen == nB.nLen )
+ {
+ int i;
+ for ( i = nA.nLen - 1; i > 0 && nA.nNum[i] == nB.nNum[i]; i-- )
+ {
+ }
+
+ if ( nA.bIsNeg )
+ return nA.nNum[i] > nB.nNum[i];
+ else
+ return nA.nNum[i] < nB.nNum[i];
+ }
+ if ( nA.bIsNeg )
+ return nA.nLen > nB.nLen;
+ else
+ return nA.nLen < nB.nLen;
+ }
+ return !nB.bIsNeg;
+ }
+ return rVal1.nVal < rVal2.nVal;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool operator >(const BigInt& rVal1, const BigInt& rVal2 )
+{
+ if ( rVal1.bIsBig || rVal2.bIsBig )
+ {
+ BigInt nA, nB;
+ nA.MakeBigInt( rVal1 );
+ nB.MakeBigInt( rVal2 );
+ if ( nA.bIsNeg == nB.bIsNeg )
+ {
+ if ( nA.nLen == nB.nLen )
+ {
+ int i;
+ for ( i = nA.nLen - 1; i > 0 && nA.nNum[i] == nB.nNum[i]; i-- )
+ {
+ }
+
+ if ( nA.bIsNeg )
+ return nA.nNum[i] < nB.nNum[i];
+ else
+ return nA.nNum[i] > nB.nNum[i];
+ }
+ if ( nA.bIsNeg )
+ return nA.nLen < nB.nLen;
+ else
+ return nA.nLen > nB.nLen;
+ }
+ return !nA.bIsNeg;
+ }
+
+ return rVal1.nVal > rVal2.nVal;
+}
diff --git a/tools/source/generic/color.cxx b/tools/source/generic/color.cxx
new file mode 100644
index 000000000000..37e9dedf9259
--- /dev/null
+++ b/tools/source/generic/color.cxx
@@ -0,0 +1,510 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <stdlib.h>
+#include <vos/macros.hxx>
+#include <tools/color.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <tools/rc.hxx>
+#include <tools/rcid.h>
+#include <tools/resid.hxx>
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+
+// -----------
+// - Inlines -
+// -----------
+
+static inline long _FRound( double fVal )
+{
+ return( fVal > 0.0 ? (long) ( fVal + 0.5 ) : -(long) ( -fVal + 0.5 ) );
+}
+
+// ---------
+// - Color -
+// ---------
+
+Color::Color( const ResId& rResId )
+{
+ rResId.SetRT( RSC_COLOR );
+ ResMgr* pResMgr = rResId.GetResMgr();
+ if ( pResMgr && pResMgr->GetResource( rResId ) )
+ {
+ // Header ueberspringen
+ pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
+
+ // Daten laden
+ USHORT nRed = pResMgr->ReadShort();
+ USHORT nGreen = pResMgr->ReadShort();
+ USHORT nBlue = pResMgr->ReadShort();
+ // one more historical ULONG
+ pResMgr->ReadLong();
+
+ // RGB-Farbe
+ mnColor = RGB_COLORDATA( nRed>>8, nGreen>>8, nBlue>>8 );
+ }
+ else
+ {
+ mnColor = RGB_COLORDATA( 0, 0, 0 );
+ }
+}
+UINT8 Color::GetColorError( const Color& rCompareColor ) const
+{
+ const long nErrAbs = labs( (long) rCompareColor.GetRed() - GetRed() ) +
+ labs( (long) rCompareColor.GetGreen() - GetGreen() ) +
+ labs( (long) rCompareColor.GetBlue() - GetBlue() );
+
+ return (UINT8) _FRound( nErrAbs * 0.3333333333 );
+}
+
+// -----------------------------------------------------------------------
+
+void Color::IncreaseLuminance( UINT8 cLumInc )
+{
+ SetRed( (UINT8) VOS_BOUND( (long) COLORDATA_RED( mnColor ) + cLumInc, 0L, 255L ) );
+ SetGreen( (UINT8) VOS_BOUND( (long) COLORDATA_GREEN( mnColor ) + cLumInc, 0L, 255L ) );
+ SetBlue( (UINT8) VOS_BOUND( (long) COLORDATA_BLUE( mnColor ) + cLumInc, 0L, 255L ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Color::DecreaseLuminance( UINT8 cLumDec )
+{
+ SetRed( (UINT8) VOS_BOUND( (long) COLORDATA_RED( mnColor ) - cLumDec, 0L, 255L ) );
+ SetGreen( (UINT8) VOS_BOUND( (long) COLORDATA_GREEN( mnColor ) - cLumDec, 0L, 255L ) );
+ SetBlue( (UINT8) VOS_BOUND( (long) COLORDATA_BLUE( mnColor ) - cLumDec, 0L, 255L ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Color::IncreaseContrast( UINT8 cContInc )
+{
+ if( cContInc)
+ {
+ const double fM = 128.0 / ( 128.0 - 0.4985 * cContInc );
+ const double fOff = 128.0 - fM * 128.0;
+
+ SetRed( (UINT8) VOS_BOUND( _FRound( COLORDATA_RED( mnColor ) * fM + fOff ), 0L, 255L ) );
+ SetGreen( (UINT8) VOS_BOUND( _FRound( COLORDATA_GREEN( mnColor ) * fM + fOff ), 0L, 255L ) );
+ SetBlue( (UINT8) VOS_BOUND( _FRound( COLORDATA_BLUE( mnColor ) * fM + fOff ), 0L, 255L ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Color::DecreaseContrast( UINT8 cContDec )
+{
+ if( cContDec )
+ {
+ const double fM = ( 128.0 - 0.4985 * cContDec ) / 128.0;
+ const double fOff = 128.0 - fM * 128.0;
+
+ SetRed( (UINT8) VOS_BOUND( _FRound( COLORDATA_RED( mnColor ) * fM + fOff ), 0L, 255L ) );
+ SetGreen( (UINT8) VOS_BOUND( _FRound( COLORDATA_GREEN( mnColor ) * fM + fOff ), 0L, 255L ) );
+ SetBlue( (UINT8) VOS_BOUND( _FRound( COLORDATA_BLUE( mnColor ) * fM + fOff ), 0L, 255L ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Color::Invert()
+{
+ SetRed( ~COLORDATA_RED( mnColor ) );
+ SetGreen( ~COLORDATA_GREEN( mnColor ) );
+ SetBlue( ~COLORDATA_BLUE( mnColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Color::IsDark() const
+{
+ return GetLuminance() <= 38;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Color::IsBright() const
+{
+ return GetLuminance() >= 245;
+}
+
+// -----------------------------------------------------------------------
+// color space conversion
+// -----------------------------------------------------------------------
+
+void Color::RGBtoHSB( USHORT& nHue, USHORT& nSat, USHORT& nBri ) const
+{
+ UINT8 c[3];
+ UINT8 cMax, cMin;
+
+ c[0] = GetRed();
+ c[1] = GetGreen();
+ c[2] = GetBlue();
+
+ cMax = c[0];
+ if( c[1] > cMax )
+ cMax = c[1];
+ if( c[2] > cMax )
+ cMax = c[2];
+
+ // Brightness = max(R, G, B);
+ nBri = cMax * 100 / 255;
+
+ cMin = c[0];
+ if( c[1] < cMin )
+ cMin = c[1];
+ if( c[2] < cMin )
+ cMin = c[2];
+
+ UINT8 cDelta = cMax - cMin;
+
+ // Saturation = max - min / max
+ if( nBri > 0 )
+ nSat = cDelta * 100 / cMax;
+ else
+ nSat = 0;
+
+ if( nSat == 0 )
+ nHue = 0; // Default = undefined
+ else
+ {
+ double dHue = 0.0;
+
+ if( c[0] == cMax )
+ {
+ dHue = (double)( c[1] - c[2] ) / (double)cDelta;
+ }
+ else if( c[1] == cMax )
+ {
+ dHue = 2.0 + (double)( c[2] - c[0] ) / (double)cDelta;
+ }
+ else if ( c[2] == cMax )
+ {
+ dHue = 4.0 + (double)( c[0] - c[1] ) / (double)cDelta;
+ }
+ dHue *= 60.0;
+
+ if( dHue < 0.0 )
+ dHue += 360.0;
+
+ nHue = (UINT16) dHue;
+ }
+}
+
+ColorData Color::HSBtoRGB( USHORT nHue, USHORT nSat, USHORT nBri )
+{
+ UINT8 cR=0,cG=0,cB=0;
+ UINT8 nB = (UINT8) ( nBri * 255 / 100 );
+
+ if( nSat == 0 )
+ {
+ cR = nB;
+ cG = nB;
+ cB = nB;
+ }
+ else
+ {
+ double dH = nHue;
+ double f;
+ UINT16 n;
+ if( dH == 360.0 )
+ dH = 0.0;
+
+ dH /= 60.0;
+ n = (UINT16) dH;
+ f = dH - n;
+
+ UINT8 a = (UINT8) ( nB * ( 100 - nSat ) / 100 );
+ UINT8 b = (UINT8) ( nB * ( 100 - ( (double)nSat * f + 0.5 ) ) / 100 );
+ UINT8 c = (UINT8) ( nB * ( 100 - ( (double)nSat * ( 1.0 - f ) + 0.5 ) ) / 100 );
+
+ switch( n )
+ {
+ case 0: cR = nB; cG = c; cB = a; break;
+ case 1: cR = b; cG = nB; cB = a; break;
+ case 2: cR = a; cG = nB; cB = c; break;
+ case 3: cR = a; cG = b; cB = nB; break;
+ case 4: cR = c; cG = a; cB = nB; break;
+ case 5: cR = nB; cG = a; cB = b; break;
+ }
+ }
+
+ return RGB_COLORDATA( cR, cG, cB );
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& Color::Read( SvStream& rIStm, BOOL bNewFormat )
+{
+ if ( bNewFormat )
+ rIStm >> mnColor;
+ else
+ rIStm >> *this;
+
+ return rIStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& Color::Write( SvStream& rOStm, BOOL bNewFormat )
+{
+ if ( bNewFormat )
+ rOStm << mnColor;
+ else
+ rOStm << *this;
+
+ return rOStm;
+}
+
+// -----------------------------------------------------------------------
+
+#define COL_NAME_USER ((USHORT)0x8000)
+#define COL_RED_1B ((USHORT)0x0001)
+#define COL_RED_2B ((USHORT)0x0002)
+#define COL_GREEN_1B ((USHORT)0x0010)
+#define COL_GREEN_2B ((USHORT)0x0020)
+#define COL_BLUE_1B ((USHORT)0x0100)
+#define COL_BLUE_2B ((USHORT)0x0200)
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStream, Color& rColor )
+{
+ DBG_ASSERTWARNING( rIStream.GetVersion(), "Color::>> - Solar-Version not set on rIStream" );
+
+ USHORT nColorName;
+ USHORT nRed;
+ USHORT nGreen;
+ USHORT nBlue;
+
+ rIStream >> nColorName;
+
+ if ( nColorName & COL_NAME_USER )
+ {
+ if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
+ {
+ unsigned char cAry[6];
+ USHORT i = 0;
+
+ nRed = 0;
+ nGreen = 0;
+ nBlue = 0;
+
+ if ( nColorName & COL_RED_2B )
+ i += 2;
+ else if ( nColorName & COL_RED_1B )
+ i++;
+ if ( nColorName & COL_GREEN_2B )
+ i += 2;
+ else if ( nColorName & COL_GREEN_1B )
+ i++;
+ if ( nColorName & COL_BLUE_2B )
+ i += 2;
+ else if ( nColorName & COL_BLUE_1B )
+ i++;
+
+ rIStream.Read( cAry, i );
+ i = 0;
+
+ if ( nColorName & COL_RED_2B )
+ {
+ nRed = cAry[i];
+ nRed <<= 8;
+ i++;
+ nRed |= cAry[i];
+ i++;
+ }
+ else if ( nColorName & COL_RED_1B )
+ {
+ nRed = cAry[i];
+ nRed <<= 8;
+ i++;
+ }
+ if ( nColorName & COL_GREEN_2B )
+ {
+ nGreen = cAry[i];
+ nGreen <<= 8;
+ i++;
+ nGreen |= cAry[i];
+ i++;
+ }
+ else if ( nColorName & COL_GREEN_1B )
+ {
+ nGreen = cAry[i];
+ nGreen <<= 8;
+ i++;
+ }
+ if ( nColorName & COL_BLUE_2B )
+ {
+ nBlue = cAry[i];
+ nBlue <<= 8;
+ i++;
+ nBlue |= cAry[i];
+ i++;
+ }
+ else if ( nColorName & COL_BLUE_1B )
+ {
+ nBlue = cAry[i];
+ nBlue <<= 8;
+ i++;
+ }
+ }
+ else
+ {
+ rIStream >> nRed;
+ rIStream >> nGreen;
+ rIStream >> nBlue;
+ }
+
+ rColor.mnColor = RGB_COLORDATA( nRed>>8, nGreen>>8, nBlue>>8 );
+ }
+ else
+ {
+ static ColorData aColAry[] =
+ {
+ COL_BLACK, // COL_BLACK
+ COL_BLUE, // COL_BLUE
+ COL_GREEN, // COL_GREEN
+ COL_CYAN, // COL_CYAN
+ COL_RED, // COL_RED
+ COL_MAGENTA, // COL_MAGENTA
+ COL_BROWN, // COL_BROWN
+ COL_GRAY, // COL_GRAY
+ COL_LIGHTGRAY, // COL_LIGHTGRAY
+ COL_LIGHTBLUE, // COL_LIGHTBLUE
+ COL_LIGHTGREEN, // COL_LIGHTGREEN
+ COL_LIGHTCYAN, // COL_LIGHTCYAN
+ COL_LIGHTRED, // COL_LIGHTRED
+ COL_LIGHTMAGENTA, // COL_LIGHTMAGENTA
+ COL_YELLOW, // COL_YELLOW
+ COL_WHITE, // COL_WHITE
+ COL_WHITE, // COL_MENUBAR
+ COL_BLACK, // COL_MENUBARTEXT
+ COL_WHITE, // COL_POPUPMENU
+ COL_BLACK, // COL_POPUPMENUTEXT
+ COL_BLACK, // COL_WINDOWTEXT
+ COL_WHITE, // COL_WINDOWWORKSPACE
+ COL_BLACK, // COL_HIGHLIGHT
+ COL_WHITE, // COL_HIGHLIGHTTEXT
+ COL_BLACK, // COL_3DTEXT
+ COL_LIGHTGRAY, // COL_3DFACE
+ COL_WHITE, // COL_3DLIGHT
+ COL_GRAY, // COL_3DSHADOW
+ COL_LIGHTGRAY, // COL_SCROLLBAR
+ COL_WHITE, // COL_FIELD
+ COL_BLACK // COL_FIELDTEXT
+ };
+
+ if ( nColorName < (sizeof( aColAry )/sizeof(ColorData)) )
+ rColor.mnColor = aColAry[nColorName];
+ else
+ rColor.mnColor = COL_BLACK;
+ }
+
+ return rIStream;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const Color& rColor )
+{
+ DBG_ASSERTWARNING( rOStream.GetVersion(), "Color::<< - Solar-Version not set on rOStream" );
+
+ USHORT nColorName = COL_NAME_USER;
+ USHORT nRed = rColor.GetRed();
+ USHORT nGreen = rColor.GetGreen();
+ USHORT nBlue = rColor.GetBlue();
+ nRed = (nRed<<8) + nRed;
+ nGreen = (nGreen<<8) + nGreen;
+ nBlue = (nBlue<<8) + nBlue;
+
+ if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
+ {
+ unsigned char cAry[6];
+ USHORT i = 0;
+
+ if ( nRed & 0x00FF )
+ {
+ nColorName |= COL_RED_2B;
+ cAry[i] = (unsigned char)(nRed & 0xFF);
+ i++;
+ cAry[i] = (unsigned char)((nRed >> 8) & 0xFF);
+ i++;
+ }
+ else if ( nRed & 0xFF00 )
+ {
+ nColorName |= COL_RED_1B;
+ cAry[i] = (unsigned char)((nRed >> 8) & 0xFF);
+ i++;
+ }
+ if ( nGreen & 0x00FF )
+ {
+ nColorName |= COL_GREEN_2B;
+ cAry[i] = (unsigned char)(nGreen & 0xFF);
+ i++;
+ cAry[i] = (unsigned char)((nGreen >> 8) & 0xFF);
+ i++;
+ }
+ else if ( nGreen & 0xFF00 )
+ {
+ nColorName |= COL_GREEN_1B;
+ cAry[i] = (unsigned char)((nGreen >> 8) & 0xFF);
+ i++;
+ }
+ if ( nBlue & 0x00FF )
+ {
+ nColorName |= COL_BLUE_2B;
+ cAry[i] = (unsigned char)(nBlue & 0xFF);
+ i++;
+ cAry[i] = (unsigned char)((nBlue >> 8) & 0xFF);
+ i++;
+ }
+ else if ( nBlue & 0xFF00 )
+ {
+ nColorName |= COL_BLUE_1B;
+ cAry[i] = (unsigned char)((nBlue >> 8) & 0xFF);
+ i++;
+ }
+
+ rOStream << nColorName;
+ rOStream.Write( cAry, i );
+ }
+ else
+ {
+ rOStream << nColorName;
+ rOStream << nRed;
+ rOStream << nGreen;
+ rOStream << nBlue;
+ }
+
+ return rOStream;
+}
diff --git a/tools/source/generic/config.cxx b/tools/source/generic/config.cxx
new file mode 100644
index 000000000000..1a94c2b11198
--- /dev/null
+++ b/tools/source/generic/config.cxx
@@ -0,0 +1,1304 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _CONFIG_CXX
+
+#include <cstddef>
+#include <cstdlib>
+#include <limits>
+#include <new>
+#include <string.h>
+
+#ifdef WNT
+#include "stdlib.h"
+#endif
+#include <osl/file.hxx>
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+#include <tools/config.hxx>
+#include <osl/security.h>
+
+#define MAXBUFLEN 1024 // Fuer Buffer bei VOS-Funktionen
+
+// -----------------
+// - ImplConfigData -
+// -----------------
+
+struct ImplKeyData
+{
+ ImplKeyData* mpNext;
+ ByteString maKey;
+ ByteString maValue;
+ BOOL mbIsComment;
+};
+
+struct ImplGroupData
+{
+ ImplGroupData* mpNext;
+ ImplKeyData* mpFirstKey;
+ ByteString maGroupName;
+ USHORT mnEmptyLines;
+};
+
+struct ImplConfigData
+{
+ ImplGroupData* mpFirstGroup;
+ XubString maFileName;
+ ULONG mnDataUpdateId;
+ ULONG mnTimeStamp;
+ LineEnd meLineEnd;
+ USHORT mnRefCount;
+ BOOL mbModified;
+ BOOL mbRead;
+ BOOL mbIsUTF8BOM;
+};
+
+// =======================================================================
+
+static ByteString& getEmptyByteString()
+{
+ static ByteString aEmpty;
+ return aEmpty;
+}
+
+// =======================================================================
+
+static String toUncPath( const String& rPath )
+{
+ ::rtl::OUString aFileURL;
+
+ // check if rFileName is already a URL; if not make it so
+ if( rPath.CompareToAscii( "file://", 7 ) == COMPARE_EQUAL )
+ aFileURL = rPath;
+ else if( ::osl::FileBase::getFileURLFromSystemPath( rPath, aFileURL ) != ::osl::FileBase::E_None )
+ aFileURL = rPath;
+
+ return aFileURL;
+}
+
+static ULONG ImplSysGetConfigTimeStamp( const XubString& rFileName )
+{
+ ULONG nTimeStamp = 0;
+ ::osl::DirectoryItem aItem;
+ ::osl::FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
+
+ int nError = 0;
+ if( ( nError = ::osl::DirectoryItem::get( rFileName, aItem ) ) == ::osl::FileBase::E_None &&
+ aItem.getFileStatus( aStatus ) == ::osl::FileBase::E_None )
+ {
+ nTimeStamp = aStatus.getModifyTime().Seconds;
+ }
+
+ return nTimeStamp;
+}
+
+// -----------------------------------------------------------------------
+
+static BYTE* ImplSysReadConfig( const XubString& rFileName,
+ sal_uInt64& rRead, BOOL& rbRead, BOOL& rbIsUTF8BOM, ULONG& rTimeStamp )
+{
+ BYTE* pBuf = NULL;
+ ::osl::File aFile( rFileName );
+
+ if( aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None )
+ {
+ sal_uInt64 nPos = 0, nRead = 0;
+ if( aFile.getSize( nPos ) == ::osl::FileBase::E_None )
+ {
+ if (nPos > std::numeric_limits< std::size_t >::max()) {
+ aFile.close();
+ return 0;
+ }
+ pBuf = new BYTE[static_cast< std::size_t >(nPos)];
+ if( aFile.read( pBuf, nPos, nRead ) == ::osl::FileBase::E_None && nRead == nPos )
+ {
+ //skip the byte-order-mark 0xEF 0xBB 0xBF, if it was UTF8 files
+ unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
+ if (nRead > 2 && memcmp(pBuf, BOM, 3) == 0)
+ {
+ nRead -= 3;
+ rtl_moveMemory(pBuf, pBuf + 3, sal::static_int_cast<sal_Size>(nRead * sizeof(BYTE)) );
+ rbIsUTF8BOM = TRUE;
+ }
+
+ rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
+ rbRead = TRUE;
+ rRead = nRead;
+ }
+ else
+ {
+ delete[] pBuf;
+ pBuf = NULL;
+ }
+ }
+ aFile.close();
+ }
+
+ return pBuf;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplSysWriteConfig( const XubString& rFileName,
+ const BYTE* pBuf, ULONG nBufLen, BOOL rbIsUTF8BOM, ULONG& rTimeStamp )
+{
+ BOOL bSuccess = FALSE;
+ BOOL bUTF8BOMSuccess = FALSE;
+
+ ::osl::File aFile( rFileName );
+ ::osl::FileBase::RC eError = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
+ if( eError != ::osl::FileBase::E_None )
+ eError = aFile.open( osl_File_OpenFlag_Write );
+ if( eError == ::osl::FileBase::E_None )
+ {
+ // truncate
+ aFile.setSize( 0 );
+ sal_uInt64 nWritten;
+
+ //write the the byte-order-mark 0xEF 0xBB 0xBF first , if it was UTF8 files
+ if ( rbIsUTF8BOM )
+ {
+ unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
+ sal_uInt64 nUTF8BOMWritten;
+ if( aFile.write( BOM, 3, nUTF8BOMWritten ) == ::osl::FileBase::E_None && 3 == nUTF8BOMWritten )
+ {
+ bUTF8BOMSuccess = TRUE;
+ }
+ }
+
+ if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen )
+ {
+ bSuccess = TRUE;
+ }
+ if ( rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess )
+ {
+ rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
+ }
+ }
+
+ return rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+static String ImplMakeConfigName( const XubString* pFileName,
+ const XubString* pPathName )
+{
+ ::rtl::OUString aFileName;
+ ::rtl::OUString aPathName;
+ if ( pFileName )
+ {
+#ifdef UNX
+ aFileName = ::rtl::OUString::createFromAscii( "." );
+ aFileName += *pFileName;
+ aFileName += ::rtl::OUString::createFromAscii( "rc" );
+#else
+ aFileName = *pFileName;
+ aFileName += ::rtl::OUString::createFromAscii( ".ini" );
+#endif
+ }
+ else
+ {
+#ifdef UNX
+ aFileName = ::rtl::OUString::createFromAscii( ".sversionrc" );
+#else
+ aFileName = ::rtl::OUString::createFromAscii( "sversion.ini" );
+#endif
+ }
+
+ // #88208# in case pPathName is set but empty and pFileName is set
+ // and not empty just return the filename; on the default case
+ // prepend default path as usual
+ if ( pPathName && pPathName->Len() )
+ aPathName = toUncPath( *pPathName );
+ else if( pPathName && pFileName && pFileName->Len() )
+ return aFileName;
+ else
+ {
+ oslSecurity aSec = osl_getCurrentSecurity();
+ osl_getConfigDir( aSec, &aPathName.pData );
+ osl_freeSecurityHandle( aSec );
+ }
+
+ ::rtl::OUString aName( aPathName );
+ aName += ::rtl::OUString::createFromAscii( "/" );
+ aName += aFileName;
+
+ return aName;
+}
+
+// -----------------------------------------------------------------------
+
+namespace {
+
+ByteString makeByteString(BYTE const * p, sal_uInt64 n) {
+ if (n > STRING_MAXLEN) {
+ #ifdef WNT
+ abort();
+ #else
+ ::std::abort(); //TODO: handle this gracefully
+ #endif
+ }
+ return ByteString(
+ reinterpret_cast< char const * >(p),
+ sal::static_int_cast< xub_StrLen >(n));
+}
+
+}
+
+static void ImplMakeConfigList( ImplConfigData* pData,
+ const BYTE* pBuf, sal_uInt64 nLen )
+{
+ // kein Buffer, keine Daten
+ if ( !nLen )
+ return;
+
+ // Buffer parsen und Liste zusammenbauen
+ sal_uInt64 nStart;
+ sal_uInt64 nLineLen;
+ xub_StrLen nNameLen;
+ xub_StrLen nKeyLen;
+ sal_uInt64 i;
+ const BYTE* pLine;
+ ImplKeyData* pPrevKey = NULL;
+ ImplKeyData* pKey;
+ ImplGroupData* pPrevGroup = NULL;
+ ImplGroupData* pGroup = NULL;
+ i = 0;
+ while ( i < nLen )
+ {
+ // Ctrl+Z
+ if ( pBuf[i] == 0x1A )
+ break;
+
+ // Spaces und Tabs entfernen
+ while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') )
+ i++;
+
+ // Zeilenanfang merken
+ nStart = i;
+ pLine = pBuf+i;
+
+ // Zeilenende suchen
+ while ( (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') &&
+ (pBuf[i] != 0x1A) )
+ i++;
+
+ nLineLen = i-nStart;
+
+ // Wenn Zeilenende (CR/LF), dann noch einen weiterschalten
+ if ( (i+1 < nLen) &&
+ (pBuf[i] != pBuf[i+1]) &&
+ ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) )
+ i++;
+ i++;
+
+ // Zeile auswerten
+ if ( *pLine == '[' )
+ {
+ pGroup = new ImplGroupData;
+ pGroup->mpNext = NULL;
+ pGroup->mpFirstKey = NULL;
+ pGroup->mnEmptyLines = 0;
+ if ( pPrevGroup )
+ pPrevGroup->mpNext = pGroup;
+ else
+ pData->mpFirstGroup = pGroup;
+ pPrevGroup = pGroup;
+ pPrevKey = NULL;
+ pKey = NULL;
+
+ // Gruppennamen rausfiltern
+ pLine++;
+ nLineLen--;
+ // Spaces und Tabs entfernen
+ while ( (*pLine == ' ') || (*pLine == '\t') )
+ {
+ nLineLen--;
+ pLine++;
+ }
+ nNameLen = 0;
+ while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') )
+ nNameLen++;
+ if ( nNameLen )
+ {
+ while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
+ nNameLen--;
+ }
+ pGroup->maGroupName = ByteString( (const sal_Char*)pLine, nNameLen );
+ }
+ else
+ {
+ if ( nLineLen )
+ {
+ // Wenn noch keine Gruppe existiert, dann alle Keys in die
+ // Default-Gruppe
+ if ( !pGroup )
+ {
+ pGroup = new ImplGroupData;
+ pGroup->mpNext = NULL;
+ pGroup->mpFirstKey = NULL;
+ pGroup->mnEmptyLines = 0;
+ if ( pPrevGroup )
+ pPrevGroup->mpNext = pGroup;
+ else
+ pData->mpFirstGroup = pGroup;
+ pPrevGroup = pGroup;
+ pPrevKey = NULL;
+ }
+
+ // Falls Leerzeile vorhanden, dann anhaengen
+ if ( pPrevKey )
+ {
+ while ( pGroup->mnEmptyLines )
+ {
+ pKey = new ImplKeyData;
+ pKey->mbIsComment = TRUE;
+ pPrevKey->mpNext = pKey;
+ pPrevKey = pKey;
+ pGroup->mnEmptyLines--;
+ }
+ }
+
+ // Neuen Key erzeugen
+ pKey = new ImplKeyData;
+ pKey->mpNext = NULL;
+ if ( pPrevKey )
+ pPrevKey->mpNext = pKey;
+ else
+ pGroup->mpFirstKey = pKey;
+ pPrevKey = pKey;
+ if ( pLine[0] == ';' )
+ {
+ pKey->maValue = makeByteString(pLine, nLineLen);
+ pKey->mbIsComment = TRUE;
+ }
+ else
+ {
+ pKey->mbIsComment = FALSE;
+ nNameLen = 0;
+ while ( (nNameLen < nLineLen) && (pLine[nNameLen] != '=') )
+ nNameLen++;
+ nKeyLen = nNameLen;
+ // Spaces und Tabs entfernen
+ if ( nNameLen )
+ {
+ while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
+ nNameLen--;
+ }
+ pKey->maKey = ByteString( (const sal_Char*)pLine, nNameLen );
+ nKeyLen++;
+ if ( nKeyLen < nLineLen )
+ {
+ pLine += nKeyLen;
+ nLineLen -= nKeyLen;
+ // Spaces und Tabs entfernen
+ while ( (*pLine == ' ') || (*pLine == '\t') )
+ {
+ nLineLen--;
+ pLine++;
+ }
+ if ( nLineLen )
+ {
+ while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') )
+ nLineLen--;
+ pKey->maValue = makeByteString(pLine, nLineLen);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Leerzeilen werden nur gezaehlt und beim Erzeugen des
+ // naechsten Keys angehaengt, da wir Leerzeilen am Ende
+ // einer Gruppe auch nach hinzufuegen von neuen Keys nur
+ // am Ende der Gruppe wieder speichern wollen
+ if ( pGroup )
+ pGroup->mnEmptyLines++;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static BYTE* ImplGetConfigBuffer( const ImplConfigData* pData, ULONG& rLen )
+{
+ BYTE* pWriteBuf;
+ BYTE* pBuf;
+ BYTE aLineEndBuf[2] = {0, 0};
+ ImplKeyData* pKey;
+ ImplGroupData* pGroup;
+ unsigned int nBufLen;
+ USHORT nValueLen;
+ USHORT nKeyLen;
+ USHORT nLineEndLen;
+
+ if ( pData->meLineEnd == LINEEND_CR )
+ {
+ aLineEndBuf[0] = _CR;
+ nLineEndLen = 1;
+ }
+ else if ( pData->meLineEnd == LINEEND_LF )
+ {
+ aLineEndBuf[0] = _LF;
+ nLineEndLen = 1;
+ }
+ else
+ {
+ aLineEndBuf[0] = _CR;
+ aLineEndBuf[1] = _LF;
+ nLineEndLen = 2;
+ }
+
+ // Buffergroesse ermitteln
+ nBufLen = 0;
+ pGroup = pData->mpFirstGroup;
+ while ( pGroup )
+ {
+ // Leere Gruppen werden nicht geschrieben
+ if ( pGroup->mpFirstKey )
+ {
+ nBufLen += pGroup->maGroupName.Len() + nLineEndLen + 2;
+ pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ nValueLen = pKey->maValue.Len();
+ if ( pKey->mbIsComment )
+ nBufLen += nValueLen + nLineEndLen;
+ else
+ nBufLen += pKey->maKey.Len() + nValueLen + nLineEndLen + 1;
+
+ pKey = pKey->mpNext;
+ }
+
+ // Leerzeile nach jeder Gruppe auch wieder speichern
+ if ( !pGroup->mnEmptyLines )
+ pGroup->mnEmptyLines = 1;
+ nBufLen += nLineEndLen * pGroup->mnEmptyLines;
+ }
+
+ pGroup = pGroup->mpNext;
+ }
+
+ // Laenge dem Aufrufer mitteilen
+ rLen = nBufLen;
+ if ( !nBufLen )
+ {
+ pWriteBuf = new BYTE[nLineEndLen];
+ if ( pWriteBuf )
+ {
+ pWriteBuf[0] = aLineEndBuf[0];
+ if ( nLineEndLen == 2 )
+ pWriteBuf[1] = aLineEndBuf[1];
+ return pWriteBuf;
+ }
+ else
+ return 0;
+ }
+
+ // Schreibbuffer anlegen (wird vom Aufrufer zerstoert)
+ pWriteBuf = new BYTE[nBufLen];
+ if ( !pWriteBuf )
+ return 0;
+
+ // Buffer fuellen
+ pBuf = pWriteBuf;
+ pGroup = pData->mpFirstGroup;
+ while ( pGroup )
+ {
+ // Leere Gruppen werden nicht geschrieben
+ if ( pGroup->mpFirstKey )
+ {
+ *pBuf = '['; pBuf++;
+ memcpy( pBuf, pGroup->maGroupName.GetBuffer(), pGroup->maGroupName.Len() );
+ pBuf += pGroup->maGroupName.Len();
+ *pBuf = ']'; pBuf++;
+ *pBuf = aLineEndBuf[0]; pBuf++;
+ if ( nLineEndLen == 2 )
+ {
+ *pBuf = aLineEndBuf[1]; pBuf++;
+ }
+ pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ nValueLen = pKey->maValue.Len();
+ if ( pKey->mbIsComment )
+ {
+ if ( nValueLen )
+ {
+ memcpy( pBuf, pKey->maValue.GetBuffer(), nValueLen );
+ pBuf += nValueLen;
+ }
+ *pBuf = aLineEndBuf[0]; pBuf++;
+ if ( nLineEndLen == 2 )
+ {
+ *pBuf = aLineEndBuf[1]; pBuf++;
+ }
+ }
+ else
+ {
+ nKeyLen = pKey->maKey.Len();
+ memcpy( pBuf, pKey->maKey.GetBuffer(), nKeyLen );
+ pBuf += nKeyLen;
+ *pBuf = '='; pBuf++;
+ memcpy( pBuf, pKey->maValue.GetBuffer(), nValueLen );
+ pBuf += nValueLen;
+ *pBuf = aLineEndBuf[0]; pBuf++;
+ if ( nLineEndLen == 2 )
+ {
+ *pBuf = aLineEndBuf[1]; pBuf++;
+ }
+ }
+
+ pKey = pKey->mpNext;
+ }
+
+ // Leerzeile nach jeder Gruppe auch wieder speichern
+ USHORT nEmptyLines = pGroup->mnEmptyLines;
+ while ( nEmptyLines )
+ {
+ *pBuf = aLineEndBuf[0]; pBuf++;
+ if ( nLineEndLen == 2 )
+ {
+ *pBuf = aLineEndBuf[1]; pBuf++;
+ }
+ nEmptyLines--;
+ }
+ }
+
+ pGroup = pGroup->mpNext;
+ }
+
+ return pWriteBuf;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplReadConfig( ImplConfigData* pData )
+{
+ ULONG nTimeStamp = 0;
+ sal_uInt64 nRead = 0;
+ BOOL bRead = FALSE;
+ BOOL bIsUTF8BOM =FALSE;
+ BYTE* pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp );
+
+ // Aus dem Buffer die Config-Verwaltungsliste aufbauen
+ if ( pBuf )
+ {
+ ImplMakeConfigList( pData, pBuf, nRead );
+ delete[] pBuf;
+ }
+ pData->mnTimeStamp = nTimeStamp;
+ pData->mbModified = FALSE;
+ if ( bRead )
+ pData->mbRead = TRUE;
+ if ( bIsUTF8BOM )
+ pData->mbIsUTF8BOM = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplWriteConfig( ImplConfigData* pData )
+{
+#ifdef DBG_UTIL
+ if ( DbgIsAssert() )
+ {
+ if ( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ) )
+ {
+ DBG_ERROR1( "Config overwrites modified configfile:\n %s", ByteString( pData->maFileName, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+ }
+#endif
+
+ // Aus der Config-Liste einen Buffer zusammenbauen
+ ULONG nBufLen;
+ BYTE* pBuf = ImplGetConfigBuffer( pData, nBufLen );
+ if ( pBuf )
+ {
+ if ( ImplSysWriteConfig( pData->maFileName, pBuf, nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
+ pData->mbModified = FALSE;
+ delete[] pBuf;
+ }
+ else
+ pData->mbModified = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDeleteConfigData( ImplConfigData* pData )
+{
+ ImplKeyData* pTempKey;
+ ImplKeyData* pKey;
+ ImplGroupData* pTempGroup;
+ ImplGroupData* pGroup = pData->mpFirstGroup;
+ while ( pGroup )
+ {
+ pTempGroup = pGroup->mpNext;
+
+ // Alle Keys loeschen
+ pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ pTempKey = pKey->mpNext;
+ delete pKey;
+ pKey = pTempKey;
+ }
+
+ // Gruppe loeschen und weiterschalten
+ delete pGroup;
+ pGroup = pTempGroup;
+ }
+
+ pData->mpFirstGroup = NULL;
+}
+
+// =======================================================================
+
+static ImplConfigData* ImplGetConfigData( const XubString& rFileName )
+{
+ ImplConfigData* pData;
+
+ pData = new ImplConfigData;
+ pData->maFileName = rFileName;
+ pData->mpFirstGroup = NULL;
+ pData->mnDataUpdateId = 0;
+ pData->meLineEnd = LINEEND_CRLF;
+ pData->mnRefCount = 0;
+ pData->mbRead = FALSE;
+ pData->mbIsUTF8BOM = FALSE;
+ ImplReadConfig( pData );
+
+ return pData;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplFreeConfigData( ImplConfigData* pDelData )
+{
+ ImplDeleteConfigData( pDelData );
+ delete pDelData;
+}
+
+// =======================================================================
+
+BOOL Config::ImplUpdateConfig() const
+{
+ // Wenn sich TimeStamp unterscheidet, dann Datei neu einlesen
+ if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
+ {
+ ImplDeleteConfigData( mpData );
+ ImplReadConfig( mpData );
+ mpData->mnDataUpdateId++;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplGroupData* Config::ImplGetGroup() const
+{
+ if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) )
+ {
+ ImplGroupData* pPrevGroup = NULL;
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ while ( pGroup )
+ {
+ if ( pGroup->maGroupName.EqualsIgnoreCaseAscii( maGroupName ) )
+ break;
+
+ pPrevGroup = pGroup;
+ pGroup = pGroup->mpNext;
+ }
+
+ // Falls Gruppe noch nicht existiert, dann dazufuegen
+ if ( !pGroup )
+ {
+ pGroup = new ImplGroupData;
+ pGroup->mpNext = NULL;
+ pGroup->mpFirstKey = NULL;
+ pGroup->mnEmptyLines = 1;
+ if ( pPrevGroup )
+ pPrevGroup->mpNext = pGroup;
+ else
+ mpData->mpFirstGroup = pGroup;
+ }
+
+ // Gruppenname immer uebernehmen, da er auch in dieser Form
+ // geschrieben werden soll. Ausserdem die Cache-Members der
+ // Config-Klasse updaten
+ pGroup->maGroupName = maGroupName;
+ ((Config*)this)->mnDataUpdateId = mpData->mnDataUpdateId;
+ ((Config*)this)->mpActGroup = pGroup;
+ }
+
+ return mpActGroup;
+}
+
+// =======================================================================
+
+Config::Config()
+{
+ // Daten initialisieren und einlesen
+ maFileName = ImplMakeConfigName( NULL, NULL );
+ mpData = ImplGetConfigData( maFileName );
+ mpActGroup = NULL;
+ mnDataUpdateId = 0;
+ mnLockCount = 1;
+ mbPersistence = TRUE;
+
+#ifdef DBG_UTIL
+ DBG_TRACE( "Config::Config()" );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+Config::Config( const XubString& rFileName )
+{
+ // Daten initialisieren und einlesen
+ maFileName = toUncPath( rFileName );
+ mpData = ImplGetConfigData( maFileName );
+ mpActGroup = NULL;
+ mnDataUpdateId = 0;
+ mnLockCount = 1;
+ mbPersistence = TRUE;
+
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::Config( " );
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ aTraceStr += " )";
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+Config::~Config()
+{
+#ifdef DBG_UTIL
+ DBG_TRACE( "Config::~Config()" );
+#endif
+
+ Flush();
+ ImplFreeConfigData( mpData );
+}
+
+// -----------------------------------------------------------------------
+
+String Config::GetDefDirectory()
+{
+ ::rtl::OUString aDefConfig;
+ oslSecurity aSec = osl_getCurrentSecurity();
+ osl_getConfigDir( aSec, &aDefConfig.pData );
+ osl_freeSecurityHandle( aSec );
+
+ return aDefConfig;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Config::GetConfigName( const XubString& rPath,
+ const XubString& rBaseName )
+{
+ return ImplMakeConfigName( &rBaseName, &rPath );
+}
+
+// -----------------------------------------------------------------------
+
+void Config::SetGroup( const ByteString& rGroup )
+{
+ // Wenn neue Gruppe gesetzt wird, muss beim naechsten mal die
+ // Gruppe neu ermittelt werden
+ if ( maGroupName != rGroup )
+ {
+ maGroupName = rGroup;
+ mnDataUpdateId = mpData->mnDataUpdateId-1;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Config::DeleteGroup( const ByteString& rGroup )
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount || !mpData->mbRead )
+ {
+ ImplUpdateConfig();
+ mpData->mbRead = TRUE;
+ }
+
+ ImplGroupData* pPrevGroup = NULL;
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ while ( pGroup )
+ {
+ if ( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) )
+ break;
+
+ pPrevGroup = pGroup;
+ pGroup = pGroup->mpNext;
+ }
+
+ if ( pGroup )
+ {
+ // Alle Keys loeschen
+ ImplKeyData* pTempKey;
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ pTempKey = pKey->mpNext;
+ delete pKey;
+ pKey = pTempKey;
+ }
+
+ // Gruppe weiterschalten und loeschen
+ if ( pPrevGroup )
+ pPrevGroup->mpNext = pGroup->mpNext;
+ else
+ mpData->mpFirstGroup = pGroup->mpNext;
+ delete pGroup;
+
+ // Config-Datei neu schreiben
+ if ( !mnLockCount && mbPersistence )
+ ImplWriteConfig( mpData );
+ else
+ {
+ mpData->mbModified = TRUE;
+ }
+
+ // Gruppen auf ungluetig setzen
+ mnDataUpdateId = mpData->mnDataUpdateId;
+ mpData->mnDataUpdateId++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::GetGroupName( USHORT nGroup ) const
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ USHORT nGroupCount = 0;
+ ByteString aGroupName;
+ while ( pGroup )
+ {
+ if ( nGroup == nGroupCount )
+ {
+ aGroupName = pGroup->maGroupName;
+ break;
+ }
+
+ nGroupCount++;
+ pGroup = pGroup->mpNext;
+ }
+
+ return aGroupName;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Config::GetGroupCount() const
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ USHORT nGroupCount = 0;
+ while ( pGroup )
+ {
+ nGroupCount++;
+ pGroup = pGroup->mpNext;
+ }
+
+ return nGroupCount;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Config::HasGroup( const ByteString& rGroup ) const
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ BOOL bRet = FALSE;
+
+ while( pGroup )
+ {
+ if( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) )
+ {
+ bRet = TRUE;
+ break;
+ }
+
+ pGroup = pGroup->mpNext;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::ReadKey( const ByteString& rKey ) const
+{
+ return ReadKey( rKey, getEmptyByteString() );
+}
+
+// -----------------------------------------------------------------------
+
+UniString Config::ReadKey( const ByteString& rKey, rtl_TextEncoding eEncoding ) const
+{
+ if ( mpData->mbIsUTF8BOM )
+ eEncoding = RTL_TEXTENCODING_UTF8;
+ return UniString( ReadKey( rKey ), eEncoding );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::ReadKey( const ByteString& rKey, const ByteString& rDefault ) const
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::ReadKey( " );
+ aTraceStr += rKey;
+ aTraceStr += " ) from ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ // Key suchen und Value zurueckgeben
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
+ return pKey->maValue;
+
+ pKey = pKey->mpNext;
+ }
+ }
+
+ return rDefault;
+}
+
+// -----------------------------------------------------------------------
+
+void Config::WriteKey( const ByteString& rKey, const ByteString& rStr )
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::WriteKey( " );
+ aTraceStr += rKey;
+ aTraceStr += ", ";
+ aTraceStr += rStr;
+ aTraceStr += " ) to ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+ DBG_ASSERTWARNING( rStr != ReadKey( rKey ), "Config::WriteKey() with the same Value" );
+#endif
+
+ // Config-Daten evt. updaten
+ if ( !mnLockCount || !mpData->mbRead )
+ {
+ ImplUpdateConfig();
+ mpData->mbRead = TRUE;
+ }
+
+ // Key suchen und Value setzen
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pPrevKey = NULL;
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
+ break;
+
+ pPrevKey = pKey;
+ pKey = pKey->mpNext;
+ }
+
+ BOOL bNewValue;
+ if ( !pKey )
+ {
+ pKey = new ImplKeyData;
+ pKey->mpNext = NULL;
+ pKey->maKey = rKey;
+ pKey->mbIsComment = FALSE;
+ if ( pPrevKey )
+ pPrevKey->mpNext = pKey;
+ else
+ pGroup->mpFirstKey = pKey;
+ bNewValue = TRUE;
+ }
+ else
+ bNewValue = pKey->maValue != rStr;
+
+ if ( bNewValue )
+ {
+ pKey->maValue = rStr;
+
+ if ( !mnLockCount && mbPersistence )
+ ImplWriteConfig( mpData );
+ else
+ {
+ mpData->mbModified = TRUE;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Config::WriteKey( const ByteString& rKey, const UniString& rValue, rtl_TextEncoding eEncoding )
+{
+ if ( mpData->mbIsUTF8BOM )
+ eEncoding = RTL_TEXTENCODING_UTF8;
+ WriteKey( rKey, ByteString( rValue, eEncoding ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Config::DeleteKey( const ByteString& rKey )
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount || !mpData->mbRead )
+ {
+ ImplUpdateConfig();
+ mpData->mbRead = TRUE;
+ }
+
+ // Key suchen und Value setzen
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pPrevKey = NULL;
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
+ break;
+
+ pPrevKey = pKey;
+ pKey = pKey->mpNext;
+ }
+
+ if ( pKey )
+ {
+ // Gruppe weiterschalten und loeschen
+ if ( pPrevKey )
+ pPrevKey->mpNext = pKey->mpNext;
+ else
+ pGroup->mpFirstKey = pKey->mpNext;
+ delete pKey;
+
+ // Config-Datei neu schreiben
+ if ( !mnLockCount && mbPersistence )
+ ImplWriteConfig( mpData );
+ else
+ {
+ mpData->mbModified = TRUE;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Config::GetKeyCount() const
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::GetKeyCount()" );
+ aTraceStr += " from ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ // Key suchen und Value zurueckgeben
+ USHORT nCount = 0;
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment )
+ nCount++;
+
+ pKey = pKey->mpNext;
+ }
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::GetKeyName( USHORT nKey ) const
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::GetKeyName( " );
+ aTraceStr += ByteString::CreateFromInt32(nKey);
+ aTraceStr += " ) from ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ // Key suchen und Name zurueckgeben
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment )
+ {
+ if ( !nKey )
+ return pKey->maKey;
+ nKey--;
+ }
+
+ pKey = pKey->mpNext;
+ }
+ }
+
+ return getEmptyByteString();
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::ReadKey( USHORT nKey ) const
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::ReadKey( " );
+ aTraceStr += ByteString::CreateFromInt32( nKey );
+ aTraceStr += " ) from ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ // Key suchen und Value zurueckgeben
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment )
+ {
+ if ( !nKey )
+ return pKey->maValue;
+ nKey--;
+ }
+
+ pKey = pKey->mpNext;
+ }
+ }
+
+ return getEmptyByteString();
+}
+
+// -----------------------------------------------------------------------
+
+void Config::EnterLock()
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ mnLockCount++;
+}
+
+// -----------------------------------------------------------------------
+
+void Config::LeaveLock()
+{
+ DBG_ASSERT( mnLockCount, "Config::LeaveLook() without Config::EnterLook()" );
+ mnLockCount--;
+
+ if ( (mnLockCount == 0) && mpData->mbModified && mbPersistence )
+ ImplWriteConfig( mpData );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Config::Update()
+{
+ return ImplUpdateConfig();
+}
+
+// -----------------------------------------------------------------------
+
+void Config::Flush()
+{
+ if ( mpData->mbModified && mbPersistence )
+ ImplWriteConfig( mpData );
+}
+
+// -----------------------------------------------------------------------
+
+void Config::SetLineEnd( LineEnd eLineEnd )
+{
+ mpData->meLineEnd = eLineEnd;
+}
+
+// -----------------------------------------------------------------------
+
+LineEnd Config::GetLineEnd() const
+{
+ return mpData->meLineEnd;
+}
+
diff --git a/tools/source/generic/fract.cxx b/tools/source/generic/fract.cxx
new file mode 100644
index 000000000000..0b8231d620ce
--- /dev/null
+++ b/tools/source/generic/fract.cxx
@@ -0,0 +1,736 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#ifndef _LIMITS_H
+#include <limits.h>
+#endif
+#include <tools/debug.hxx>
+#include <tools/fract.hxx>
+#include <tools/stream.hxx>
+
+#include <tools/bigint.hxx>
+
+/*************************************************************************
+|*
+|* GetGGT()
+|*
+|* Beschreibung Berechnet den groessten gemeinsamen Teiler von
+|* nVal1 und nVal2
+|* Parameter long nVal1, long nVal2
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung DV 21.12.92
+|*
+*************************************************************************/
+
+// Die Funktion GetGGT berechnet den groessten gemeinsamen Teiler der
+// beiden als Parameter uebergebenen Werte nVal1 und nVal2 nach dem
+// Algorithmus von Euklid. Hat einer der beiden Parameter den Wert 0 oder
+// 1, so wird als Ergebnis der Wert 1 zurŸckgegeben. Da der Algorithmus
+// nur mit positiven Zahlen arbeitet, werden die beiden Parameter
+// entsprechend umgewandelt.
+// Zum Algorithmus: die beiden Parameter werden solange ducheinander
+// geteilt, bis sie beide gleich sind oder bis bei der Division
+// kein Rest bleibt. Der kleinere der beiden Werte ist dann der
+// GGT.
+
+static long GetGGT( long nVal1, long nVal2 )
+{
+ nVal1 = Abs( nVal1 );
+ nVal2 = Abs( nVal2 );
+
+ if ( nVal1 <= 1 || nVal2 <= 1 )
+ return 1;
+
+ while ( nVal1 != nVal2 )
+ {
+ if ( nVal1 > nVal2 )
+ {
+ nVal1 %= nVal2;
+ if ( nVal1 == 0 )
+ return nVal2;
+ }
+ else
+ {
+ nVal2 %= nVal1;
+ if ( nVal2 == 0 )
+ return nVal1;
+ }
+ }
+
+ return nVal1;
+}
+
+static void Reduce( BigInt &rVal1, BigInt &rVal2 )
+{
+ BigInt nA( rVal1 );
+ BigInt nB( rVal2 );
+ nA.Abs();
+ nB.Abs();
+
+ if ( nA.IsOne() || nB.IsOne() || nA.IsZero() || nB.IsZero() )
+ return;
+
+ while ( nA != nB )
+ {
+ if ( nA > nB )
+ {
+ nA %= nB;
+ if ( nA.IsZero() )
+ {
+ rVal1 /= nB;
+ rVal2 /= nB;
+ return;
+ }
+ }
+ else
+ {
+ nB %= nA;
+ if ( nB.IsZero() )
+ {
+ rVal1 /= nA;
+ rVal2 /= nA;
+ return;
+ }
+ }
+ }
+
+ rVal1 /= nA;
+ rVal2 /= nB;
+}
+
+/*************************************************************************
+|*
+|* Fraction::Fraction()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung WP 07.03.97
+|* Letzte Aenderung
+|*
+*************************************************************************/
+
+Fraction::Fraction( long nN1, long nN2, long nD1, long nD2 )
+{
+ long n;
+ int i = 1;
+
+ if( nN1 < 0 ) { i = -i; nN1 = -nN1; }
+ if( nN2 < 0 ) { i = -i; nN2 = -nN2; }
+ if( nD1 < 0 ) { i = -i; nD1 = -nD1; }
+ if( nD2 < 0 ) { i = -i; nD2 = -nD2; }
+
+ n = GetGGT( nN1, nD1 ); if( n > 1 ) { nN1 /= n; nD1 /= n; }
+ n = GetGGT( nN1, nD2 ); if( n > 1 ) { nN1 /= n; nD2 /= n; }
+ n = GetGGT( nN2, nD1 ); if( n > 1 ) { nN2 /= n; nD1 /= n; }
+ n = GetGGT( nN2, nD2 ); if( n > 1 ) { nN2 /= n; nD2 /= n; }
+
+ BigInt nN( nN1 );
+ nN *= BigInt( nN2 );
+
+ BigInt nD( nD1 );
+ nD *= BigInt( nD2 );
+
+ while ( nN.bIsBig || nD.bIsBig )
+ {
+ BigInt n1 = 1;
+ BigInt n2 = 2;
+
+ nN += n1;
+ nN /= n2;
+ nD += n1;
+ nD /= n2;
+
+ // Kuerzen ueber Groesste Gemeinsame Teiler
+ Reduce( nN, nD );
+ }
+
+ nNumerator = i * (long)nN;
+ nDenominator = (long)nD;
+}
+
+/*************************************************************************
+|*
+|* Fraction::Fraction()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung DV 21.12.92
+|*
+*************************************************************************/
+
+// Zur Initialisierung eines Bruches wird nNum dem Zaehler und nDen dem
+// Nenner zugewiesen. Da negative Werte des Nenners einen Bruch als
+// ungueltig kennzeichnen, wird bei der Eingabe eines negativen Nenners
+// sowohl das Vorzeichen des Nenners und des Zaehlers invertiert um wieder
+// einen gueltigen Wert fuer den Bruch zu erhalten.
+
+Fraction::Fraction( long nNum, long nDen )
+{
+ nNumerator = nNum;
+ nDenominator = nDen;
+ if ( nDenominator < 0 )
+ {
+ nDenominator = -nDenominator;
+ nNumerator = -nNumerator;
+ }
+
+ // Kuerzen ueber Groesste Gemeinsame Teiler
+ long n = GetGGT( nNumerator, nDenominator );
+ nNumerator /= n;
+ nDenominator /= n;
+}
+
+/*************************************************************************
+|*
+|* Fraction::Fraction()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung DV 21.12.92
+|*
+*************************************************************************/
+
+// Wenn der Wert von dVal groesser ist als LONG_MAX, dann wird der Bruch
+// auf den Wert ungueltig gesetzt, ansonsten werden dVal und der Nenner
+// solange mit 10 multipliziert, bis entweder der Zaehler oder der Nenner
+// groesser als LONG_MAX / 10 ist. Zum Schluss wird der so entstandene Bruch
+// gekuerzt.
+
+Fraction::Fraction( double dVal )
+{
+ long nDen = 1;
+ long nMAX = LONG_MAX / 10;
+
+ if ( dVal > LONG_MAX || dVal < LONG_MIN )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ return;
+ }
+
+ while ( Abs( (long)dVal ) < nMAX && nDen < nMAX )
+ {
+ dVal *= 10;
+ nDen *= 10;
+ }
+ nNumerator = (long)dVal;
+ nDenominator = nDen;
+
+ // Kuerzen ueber Groesste Gemeinsame Teiler
+ long n = GetGGT( nNumerator, nDenominator );
+ nNumerator /= n;
+ nDenominator /= n;
+}
+
+/*************************************************************************
+|*
+|* Fraction::operator double()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung DV 14.05.91
+|*
+*************************************************************************/
+
+Fraction::operator double() const
+{
+ if ( nDenominator > 0 )
+ return (double)nNumerator / (double)nDenominator;
+ else
+ return (double)0;
+}
+
+/*************************************************************************
+|*
+|* Fraction::operator+=()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung DV 21.12.92
+|*
+*************************************************************************/
+
+// Zunaechst werden die beiden Parameter auf ihre Gueltigkeit ueberprueft.
+// Ist einer der Parameter ungueltig, dann ist auch des Ergebnis
+// ungueltig. Zur Addition werden die beiden Brueche erst durch
+// Erweiterung mit den Nenner des jeweils anderen Bruches auf einen
+// gemeinsamen Nenner gebracht. Anschliessend werden die beiden Zaehler
+// addiert und das Ergebnis gekuerzt (durch Division von Zaehler und
+// Nenner mit nGGT). Innerhalb der Funktion wird mit dem Datentyp SLong
+// gerechnet, um einen Moeglichen Ueberlauf erkennen zu koennen. Bei
+// einem Ueberlauf wird das Ergebnis auf den Wert ungueltig gesetzt.
+
+Fraction& Fraction::operator += ( const Fraction& rVal )
+{
+ if ( !rVal.IsValid() )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ }
+ if ( !IsValid() )
+ return *this;
+
+ // (a/b) + (c/d) = ( (a*d) + (c*b) ) / (b*d)
+ BigInt nN( nNumerator );
+ nN *= BigInt( rVal.nDenominator );
+ BigInt nW1Temp( nDenominator );
+ nW1Temp *= BigInt( rVal.nNumerator );
+ nN += nW1Temp;
+
+ BigInt nD( nDenominator );
+ nD *= BigInt( rVal.nDenominator );
+
+ Reduce( nN, nD );
+
+ if ( nN.bIsBig || nD.bIsBig )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ }
+ else
+ {
+ nNumerator = (long)nN,
+ nDenominator = (long)nD;
+ }
+
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Fraction::operator-=()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung DV 21.12.92
+|*
+*************************************************************************/
+
+// Zunaechst werden die beiden Parameter auf ihre Gueltigkeit ueberprueft.
+// Ist einer der Parameter ungueltig, dann ist auch des Ergebnis
+// ungueltig. Zur Subtraktion werden die beiden Brueche erst durch
+// Erweiterung mit den Nenner des jeweils anderen Bruches auf einen
+// gemeinsamen Nenner gebracht. Anschliessend werden die beiden Zaehler
+// subtrahiert und das Ergebnis gekuerzt (durch Division von Zaehler und
+// Nenner mit nGGT). Innerhalb der Funktion wird mit dem Datentyp BigInt
+// gerechnet, um einen Moeglichen Ueberlauf erkennen zu koennen. Bei
+// einem Ueberlauf wird das Ergebnis auf den Wert ungueltig gesetzt.
+
+Fraction& Fraction::operator -= ( const Fraction& rVal )
+{
+ if ( !rVal.IsValid() )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ }
+ if ( !IsValid() )
+ return *this;
+
+ // (a/b) - (c/d) = ( (a*d) - (c*b) ) / (b*d)
+ BigInt nN( nNumerator );
+ nN *= BigInt( rVal.nDenominator );
+ BigInt nW1Temp( nDenominator );
+ nW1Temp *= BigInt( rVal.nNumerator );
+ nN -= nW1Temp;
+
+ BigInt nD( nDenominator );
+ nD *= BigInt( rVal.nDenominator );
+
+ Reduce( nN, nD );
+
+ if ( nN.bIsBig || nD.bIsBig )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ }
+ else
+ {
+ nNumerator = (long)nN,
+ nDenominator = (long)nD;
+ }
+
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Fraction::operator*=()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung TH 19.08.92
+|*
+*************************************************************************/
+
+// Zunaechst werden die beiden Parameter auf ihre Gueltigkeit ueberprueft.
+// Ist einer der Parameter ungueltig, dann ist auch des Ergebnis
+// ungueltig. Zur Multiplikation werden jeweils die beiden Zaehler und
+// Nenner miteinander multipliziert. Um Ueberlaufe zu vermeiden, werden
+// vorher jeweils der GGT zwischen dem Zaehler des einen und dem Nenner
+// des anderen Bruches bestimmt und bei der Multiplikation Zaehler und
+// Nenner durch die entsprechenden Werte geteilt.
+// Innerhalb der Funktion wird mit dem Datentyp BigInt gerechnet, um
+// einen Moeglichen Ueberlauf erkennen zu koennen. Bei einem Ueberlauf
+// wird das Ergebnis auf den Wert ungueltig gesetzt.
+
+Fraction& Fraction::operator *= ( const Fraction& rVal )
+{
+ if ( !rVal.IsValid() )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ }
+ if ( !IsValid() )
+ return *this;
+
+ long nGGT1 = GetGGT( nNumerator, rVal.nDenominator );
+ long nGGT2 = GetGGT( rVal.nNumerator, nDenominator );
+ BigInt nN( nNumerator / nGGT1 );
+ nN *= BigInt( rVal.nNumerator / nGGT2 );
+ BigInt nD( nDenominator / nGGT2 );
+ nD *= BigInt( rVal.nDenominator / nGGT1 );
+
+ if ( nN.bIsBig || nD.bIsBig )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ }
+ else
+ {
+ nNumerator = (long)nN,
+ nDenominator = (long)nD;
+ }
+
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Fraction::operator/=()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung DV 21.12.92
+|*
+*************************************************************************/
+
+// Zunaechst werden die beiden Parameter auf ihre Gueltigkeit ueberprueft.
+// Ist einer der Parameter ungueltig, dann ist auch des Ergebnis
+// ungueltig.
+// Um den Bruch a durch b zu teilen, wird a mit dem Kehrwert von b
+// multipliziert. Analog zu Multiplikation wird jezt jeweils der Zaehler
+// des einen Bruches mit dem Nenner des anderen multipliziert.
+// Um Ueberlaufe zu vermeiden, werden vorher jeweils der GGT zwischen den
+// beiden Zaehlern und den beiden Nennern bestimmt und bei der
+// Multiplikation Zaehler und Nenner durch die entsprechenden Werte
+// geteilt.
+// Innerhalb der Funktion wird mit dem Datentyp BigInt gerechnet, um
+// einen Moeglichen Ueberlauf erkennen zu koennen. Bei einem Ueberlauf
+// wird das Ergebnis auf den Wert ungueltig gesetzt.
+
+Fraction& Fraction::operator /= ( const Fraction& rVal )
+{
+ if ( !rVal.IsValid() )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ }
+ if ( !IsValid() )
+ return *this;
+
+ long nGGT1 = GetGGT( nNumerator, rVal.nNumerator );
+ long nGGT2 = GetGGT( rVal.nDenominator, nDenominator );
+ BigInt nN( nNumerator / nGGT1 );
+ nN *= BigInt( rVal.nDenominator / nGGT2 );
+ BigInt nD( nDenominator / nGGT2 );
+ nD *= BigInt( rVal.nNumerator / nGGT1 );
+
+ if ( nN.bIsBig || nD.bIsBig )
+ {
+ nNumerator = 0;
+ nDenominator = -1;
+ }
+ else
+ {
+ nNumerator = (long)nN,
+ nDenominator = (long)nD;
+ if ( nDenominator < 0 )
+ {
+ nDenominator = -nDenominator;
+ nNumerator = -nNumerator;
+ }
+ }
+
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Fraction::ReduceInaccurate()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung JOE 17.09.95
+|* Letzte Aenderung kendy 2007-06-13
+|*
+*************************************************************************/
+
+
+// Similar to clz_table that can be googled
+const char nbits_table[32] =
+{
+ 32, 1, 23, 2, 29, 24, 14, 3,
+ 30, 27, 25, 18, 20, 15, 10, 4,
+ 31, 22, 28, 13, 26, 17, 19, 9,
+ 21, 12, 16, 8, 11, 7, 6, 5
+};
+
+static int impl_NumberOfBits( unsigned long nNum )
+{
+ // http://en.wikipedia.org/wiki/De_Bruijn_sequence
+ //
+ // background paper: Using de Bruijn Sequences to Index a 1 in a
+ // Computer Word (1998) Charles E. Leiserson,
+ // Harald Prokop, Keith H. Randall
+ // (e.g. http://citeseer.ist.psu.edu/leiserson98using.html)
+ const sal_uInt32 nDeBruijn = 0x7DCD629;
+
+ if ( nNum == 0 )
+ return 0;
+
+ // Get it to form like 0000001111111111b
+ nNum |= ( nNum >> 1 );
+ nNum |= ( nNum >> 2 );
+ nNum |= ( nNum >> 4 );
+ nNum |= ( nNum >> 8 );
+ nNum |= ( nNum >> 16 );
+
+ sal_uInt32 nNumber;
+ int nBonus = 0;
+
+#if SAL_TYPES_SIZEOFLONG == 4
+ nNumber = nNum;
+#elif SAL_TYPES_SIZEOFLONG == 8
+ nNum |= ( nNum >> 32 );
+
+ if ( nNum & 0x80000000 )
+ {
+ nNumber = sal_uInt32( nNum >> 32 );
+ nBonus = 32;
+
+ if ( nNumber == 0 )
+ return 32;
+ }
+ else
+ nNumber = sal_uInt32( nNum & 0xFFFFFFFF );
+#else
+#error "Unknown size of long!"
+#endif
+
+ // De facto shift left of nDeBruijn using multiplication (nNumber
+ // is all ones from topmost bit, thus nDeBruijn + (nDeBruijn *
+ // nNumber) => nDeBruijn * (nNumber+1) clears all those bits to
+ // zero, sets the next bit to one, and thus effectively shift-left
+ // nDeBruijn by lg2(nNumber+1). This generates a distinct 5bit
+ // sequence in the msb for each distinct position of the last
+ // leading 0 bit - that's the property of a de Bruijn number.
+ nNumber = nDeBruijn + ( nDeBruijn * nNumber );
+
+ // 5-bit window indexes the result
+ return ( nbits_table[nNumber >> 27] ) + nBonus;
+}
+
+/** Inaccurate cancellation for a fraction.
+
+ Clip both nominator and denominator to said number of bits. If
+ either of those already have equal or less number of bits used,
+ this method does nothing.
+
+ @param nSignificantBits denotes, how many significant binary
+ digits to maintain, in both nominator and denominator.
+
+ @example ReduceInaccurate(8) has an error <1% [1/2^(8-1)] - the
+ largest error occurs with the following pair of values:
+
+ binary 1000000011111111111111111111111b/1000000000000000000000000000000b
+ = 1082130431/1073741824
+ = approx. 1.007812499
+
+ A ReduceInaccurate(8) yields 1/1.
+*/
+void Fraction::ReduceInaccurate( unsigned nSignificantBits )
+{
+ if ( !nNumerator || !nDenominator )
+ return;
+
+ // Count with unsigned longs only
+ const bool bNeg = ( nNumerator < 0 );
+ unsigned long nMul = (unsigned long)( bNeg? -nNumerator: nNumerator );
+ unsigned long nDiv = (unsigned long)( nDenominator );
+
+ DBG_ASSERT(nSignificantBits<65, "More than 64 bit of significance is overkill!");
+
+ // How much bits can we lose?
+ const int nMulBitsToLose = Max( ( impl_NumberOfBits( nMul ) - int( nSignificantBits ) ), 0 );
+ const int nDivBitsToLose = Max( ( impl_NumberOfBits( nDiv ) - int( nSignificantBits ) ), 0 );
+
+ const int nToLose = Min( nMulBitsToLose, nDivBitsToLose );
+
+ // Remove the bits
+ nMul >>= nToLose;
+ nDiv >>= nToLose;
+
+ if ( !nMul || !nDiv )
+ {
+ // Return without reduction
+ DBG_ERROR( "Oops, we reduced too much..." );
+ return;
+ }
+
+ // Reduce
+ long n1 = GetGGT( nMul, nDiv );
+ if ( n1 != 1 )
+ {
+ nMul /= n1;
+ nDiv /= n1;
+ }
+
+ nNumerator = bNeg? -long( nMul ): long( nMul );
+ nDenominator = nDiv;
+}
+
+/*************************************************************************
+|*
+|* Fraction::operator ==()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung TH 19.08.92
+|*
+*************************************************************************/
+
+BOOL operator == ( const Fraction& rVal1, const Fraction& rVal2 )
+{
+ if ( !rVal1.IsValid() || !rVal2.IsValid() )
+ return FALSE;
+
+ return rVal1.nNumerator == rVal2.nNumerator
+ && rVal1.nDenominator == rVal2.nDenominator;
+}
+
+/*************************************************************************
+|*
+|* Fraction::operator <()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung DV 21.12.92
+|*
+*************************************************************************/
+
+// Beide Operanden werden zunaechst auf ihre Gueltigkeit ueberprueft und
+// anschliessend zur Sicherheit noch einmal gekuerzt. Um die Brueche
+// (a/b) und (c/d) zu vergleichen, werden sie zunaechst auf einen
+// gemeinsamen Nenner gebracht (b*d), um dann die beiden Zaehler (a*d)
+// und (c*b) zu vergleichen. Das Ergebnis dieses Vergleichs wird
+// zurueckgegeben.
+
+BOOL operator < ( const Fraction& rVal1, const Fraction& rVal2 )
+{
+ if ( !rVal1.IsValid() || !rVal2.IsValid() )
+ return FALSE;
+
+ BigInt nN( rVal1.nNumerator );
+ nN *= BigInt( rVal2.nDenominator );
+ BigInt nD( rVal1.nDenominator );
+ nD *= BigInt( rVal2.nNumerator );
+
+ return nN < nD;
+}
+
+/*************************************************************************
+|*
+|* Fraction::operator >()
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung DV 20.09.90
+|* Letzte Aenderung TH 19.08.92
+|*
+*************************************************************************/
+
+// Beide Operanden werden zunaechst auf ihre Gueltigkeit ueberprueft und
+// anschliessend zur Sicherheit noch einmal gekuerzt. Um die Brueche
+// (a/b) und (c/d) zu vergleichen, werden sie zunaechst auf einen
+// gemeinsamen Nenner gebracht (b*d), um dann die beiden Zaehler (a*d)
+// und (c*b) zu vergleichen. Das Ergebnis dieses Vergleichs wird
+// zurueckgegeben.
+
+BOOL operator > ( const Fraction& rVal1, const Fraction& rVal2 )
+{
+ if ( !rVal1.IsValid() || !rVal2.IsValid() )
+ return FALSE;
+
+ BigInt nN( rVal1.nNumerator );
+ nN *= BigInt( rVal2.nDenominator );
+ BigInt nD( rVal1.nDenominator);
+ nD *= BigInt( rVal2.nNumerator );
+
+ return nN > nD;
+}
+
+/*************************************************************************
+|*
+|* SvStream& operator>>( SvStream& rIStream, Fraction& rFract )
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung MM 08.01.96
+|* Letzte Aenderung MM 08.01.96
+|*
+*************************************************************************/
+SvStream& operator >> ( SvStream& rIStream, Fraction& rFract )
+{
+ rIStream >> rFract.nNumerator;
+ rIStream >> rFract.nDenominator;
+ return rIStream;
+}
+
+/*************************************************************************
+|*
+|* SvStream& operator<<( SvStream& rIStream, Fraction& rFract )
+|*
+|* Beschreibung FRACT.SDW
+|* Ersterstellung MM 08.01.96
+|* Letzte Aenderung MM 08.01.96
+|*
+*************************************************************************/
+SvStream& operator << ( SvStream& rOStream, const Fraction& rFract )
+{
+ rOStream << rFract.nNumerator;
+ rOStream << rFract.nDenominator;
+ return rOStream;
+}
diff --git a/tools/source/generic/gen.cxx b/tools/source/generic/gen.cxx
new file mode 100644
index 000000000000..b0eb57f1ab73
--- /dev/null
+++ b/tools/source/generic/gen.cxx
@@ -0,0 +1,661 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <tools/debug.hxx>
+#include <tools/gen.hxx>
+#include <tools/stream.hxx>
+
+// =======================================================================
+
+SvStream& operator>>( SvStream& rIStream, Pair& rPair )
+{
+ DBG_ASSERTWARNING( rIStream.GetVersion(), "Pair::>> - Solar-Version not set on rIStream" );
+
+ if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
+ {
+ unsigned char cId;
+ unsigned char cAry[8];
+ int i;
+ int i1;
+ int i2;
+ UINT32 nNum;
+
+ rIStream >> cId;
+ i1 = (cId & 0x70) >> 4;
+ i2 = cId & 0x07;
+ rIStream.Read( cAry, i1+i2 );
+
+ nNum = 0;
+ i = i1;
+ while ( i )
+ {
+ i--;
+ nNum <<= 8;
+ nNum |= cAry[i];
+ }
+ if ( cId & 0x80 )
+ nNum ^= 0xFFFFFFFF;
+ rPair.nA = (INT32)nNum;
+
+ nNum = 0;
+ i = i1+i2;
+ while ( i > i1 )
+ {
+ i--;
+ nNum <<= 8;
+ nNum |= cAry[i];
+ }
+ if ( cId & 0x08 )
+ nNum ^= 0xFFFFFFFF;
+ rPair.nB = (INT32)nNum;
+ }
+ else
+ {
+ rIStream >> rPair.nA >> rPair.nB;
+ }
+
+ return rIStream;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const Pair& rPair )
+{
+ DBG_ASSERTWARNING( rOStream.GetVersion(), "Pair::<< - Solar-Version not set on rOStream" );
+
+ if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
+ {
+ unsigned char cAry[9];
+ int i = 1;
+ UINT32 nNum;
+
+ cAry[0] = 0;
+
+ nNum = (UINT32)(INT32)rPair.nA;
+ if ( rPair.nA < 0 )
+ {
+ cAry[0] |= 0x80;
+ nNum ^= 0xFFFFFFFF;
+ }
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+ cAry[0] |= 0x40;
+ }
+ else
+ cAry[0] |= 0x30;
+ }
+ else
+ cAry[0] |= 0x20;
+ }
+ else
+ cAry[0] |= 0x10;
+ }
+
+ nNum = (UINT32)(INT32)rPair.nB;
+ if ( rPair.nB < 0 )
+ {
+ cAry[0] |= 0x08;
+ nNum ^= 0xFFFFFFFF;
+ }
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+ cAry[0] |= 0x04;
+ }
+ else
+ cAry[0] |= 0x03;
+ }
+ else
+ cAry[0] |= 0x02;
+ }
+ else
+ cAry[0] |= 0x01;
+ }
+
+ rOStream.Write( cAry, i );
+ }
+ else
+ {
+ rOStream << rPair.nA << rPair.nB;
+ }
+
+ return rOStream;
+}
+
+/*************************************************************************
+|*
+|* Rectangle::SetSize()
+|*
+|* Beschreibung GEN.SDW
+|* Ersterstellung DV 29.10.91
+|* Letzte Aenderung MM 21.04.94
+|*
+*************************************************************************/
+
+void Rectangle::SetSize( const Size& rSize )
+{
+ if ( rSize.Width() < 0 )
+ nRight = nLeft + rSize.Width() +1;
+ else if ( rSize.Width() > 0 )
+ nRight = nLeft + rSize.Width() -1;
+ else
+ nRight = RECT_EMPTY;
+
+ if ( rSize.Height() < 0 )
+ nBottom = nTop + rSize.Height() +1;
+ else if ( rSize.Height() > 0 )
+ nBottom = nTop + rSize.Height() -1;
+ else
+ nBottom = RECT_EMPTY;
+}
+
+/*************************************************************************
+|*
+|* Rectangle::Union()
+|*
+|* Beschreibung GEN.SDW
+|* Ersterstellung TH 20.10.92
+|* Letzte Aenderung MM 21.04.94
+|*
+*************************************************************************/
+
+Rectangle& Rectangle::Union( const Rectangle& rRect )
+{
+ if ( rRect.IsEmpty() )
+ return *this;
+
+ if ( IsEmpty() )
+ *this = rRect;
+ else
+ {
+ nLeft = Min( Min( nLeft, rRect.nLeft ), Min( nRight, rRect.nRight ) );
+ nRight = Max( Max( nLeft, rRect.nLeft ), Max( nRight, rRect.nRight ) );
+ nTop = Min( Min( nTop, rRect.nTop ), Min( nBottom, rRect.nBottom ) );
+ nBottom = Max( Max( nTop, rRect.nTop ), Max( nBottom, rRect.nBottom ) );
+ }
+
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Rectangle::Intersection()
+|*
+|* Beschreibung GEN.SDW
+|* Ersterstellung TH 20.10.92
+|* Letzte Aenderung MM 21.04.94
+|*
+*************************************************************************/
+
+Rectangle& Rectangle::Intersection( const Rectangle& rRect )
+{
+ if ( IsEmpty() )
+ return *this;
+ if ( rRect.IsEmpty() )
+ {
+ *this = Rectangle();
+ return *this;
+ }
+
+ // nicht mit umgedrehten Rechtecken arbeiten
+ Rectangle aTmpRect( rRect );
+ Justify();
+ aTmpRect.Justify();
+
+ // Schnitt bilden
+ nLeft = Max( nLeft, aTmpRect.nLeft );
+ nRight = Min( nRight, aTmpRect.nRight );
+ nTop = Max( nTop, aTmpRect.nTop );
+ nBottom= Min( nBottom, aTmpRect.nBottom );
+
+ // Feststellen ob Schnitt leer
+ if ( nRight < nLeft || nBottom < nTop )
+ *this = Rectangle();
+
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Rectangle::Justify()
+|*
+|* Beschreibung GEN.SDW
+|* Ersterstellung DV 07.03.91
+|* Letzte Aenderung DV 07.03.91
+|*
+*************************************************************************/
+
+void Rectangle::Justify()
+{
+ long nHelp;
+
+ // Abfrage, ob Right kleiner Left
+ if ( (nRight < nLeft) && (nRight != RECT_EMPTY) )
+ {
+ nHelp = nLeft;
+ nLeft = nRight;
+ nRight = nHelp;
+ }
+
+ // Abfrage, ob Bottom kleiner Top
+ if ( (nBottom < nTop) && (nBottom != RECT_EMPTY) )
+ {
+ nHelp = nBottom;
+ nBottom = nTop;
+ nTop = nHelp;
+ }
+}
+
+/*************************************************************************
+|*
+|* Rectangle::IsInside()
+|*
+|* Beschreibung GEN.SDW
+|* Ersterstellung TH 19.03.90
+|* Letzte Aenderung MM 21.04.94
+|*
+*************************************************************************/
+
+BOOL Rectangle::IsInside( const Point& rPoint ) const
+{
+ if ( IsEmpty() )
+ return FALSE;
+
+ BOOL bRet = TRUE;
+ if ( nLeft <= nRight )
+ {
+ if ( (rPoint.X() < nLeft) || (rPoint.X() > nRight) )
+ bRet = FALSE;
+ }
+ else
+ {
+ if ( (rPoint.X() > nLeft) || (rPoint.X() < nRight) )
+ bRet = FALSE;
+ }
+ if ( nTop <= nBottom )
+ {
+ if ( (rPoint.Y() < nTop) || (rPoint.Y() > nBottom) )
+ bRet = FALSE;
+ }
+ else
+ {
+ if ( (rPoint.Y() > nTop) || (rPoint.Y() < nBottom) )
+ bRet = FALSE;
+ }
+ return bRet;
+}
+
+/*************************************************************************
+|*
+|* Rectangle::IsInside()
+|*
+|* Beschreibung GEN.SDW
+|* Ersterstellung TH 19.03.90
+|* Letzte Aenderung MM 21.04.94
+|*
+*************************************************************************/
+
+BOOL Rectangle::IsInside( const Rectangle& rRect ) const
+{
+ if ( IsInside( rRect.TopLeft() ) && IsInside( rRect.BottomRight() ) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* Rectangle::IsOver()
+|*
+|* Beschreibung GEN.SDW
+|* Ersterstellung TH 19.03.90
+|* Letzte Aenderung MM 21.04.94
+|*
+*************************************************************************/
+
+BOOL Rectangle::IsOver( const Rectangle& rRect ) const
+{
+ // Wenn sie sich nicht schneiden, ueberlappen sie auch nicht
+ return !GetIntersection( rRect ).IsEmpty();
+}
+
+// =======================================================================
+
+SvStream& operator>>( SvStream& rIStream, Rectangle& rRect )
+{
+ DBG_ASSERTWARNING( rIStream.GetVersion(), "Rectangle::>> - Solar-Version not set on rIStream" );
+
+ if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
+ {
+ unsigned char cIdAry[2];
+ unsigned char cAry[16];
+ int i;
+ int iLast;
+ int i1;
+ int i2;
+ int i3;
+ int i4;
+ UINT32 nNum;
+
+ rIStream.Read( cIdAry, 2 );
+ i1 = (cIdAry[0] & 0x70) >> 4;
+ i2 = cIdAry[0] & 0x07;
+ i3 = (cIdAry[1] & 0x70) >> 4;
+ i4 = cIdAry[1] & 0x07;
+ rIStream.Read( cAry, i1+i2+i3+i4 );
+
+ nNum = 0;
+ i = i1;
+ iLast = i;
+ while ( i )
+ {
+ i--;
+ nNum <<= 8;
+ nNum |= cAry[i];
+ }
+ iLast = i1;
+ if ( cIdAry[0] & 0x80 )
+ nNum ^= 0xFFFFFFFF;
+ rRect.nLeft = (INT32)nNum;
+
+ nNum = 0;
+ i = iLast+i2;
+ while ( i > iLast )
+ {
+ i--;
+ nNum <<= 8;
+ nNum |= cAry[i];
+ }
+ iLast += i2;
+ if ( cIdAry[0] & 0x08 )
+ nNum ^= 0xFFFFFFFF;
+ rRect.nTop = (INT32)nNum;
+
+ nNum = 0;
+ i = iLast+i3;
+ while ( i > iLast )
+ {
+ i--;
+ nNum <<= 8;
+ nNum |= cAry[i];
+ }
+ iLast += i3;
+ if ( cIdAry[1] & 0x80 )
+ nNum ^= 0xFFFFFFFF;
+ rRect.nRight = (INT32)nNum;
+
+ nNum = 0;
+ i = iLast+i4;
+ while ( i > iLast )
+ {
+ i--;
+ nNum <<= 8;
+ nNum |= cAry[i];
+ }
+ if ( cIdAry[1] & 0x08 )
+ nNum ^= 0xFFFFFFFF;
+ rRect.nBottom = (INT32)nNum;
+ }
+ else
+ {
+ rIStream >> rRect.nLeft >> rRect.nTop >> rRect.nRight >> rRect.nBottom;
+ }
+
+ return rIStream;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const Rectangle& rRect )
+{
+ DBG_ASSERTWARNING( rOStream.GetVersion(), "Rectangle::<< - Solar-Version not set on rOStream" );
+
+ if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
+ {
+ unsigned char cAry[18];
+ int i = 2;
+ UINT32 nNum;
+
+ cAry[0] = 0;
+ cAry[1] = 0;
+
+ nNum = (UINT32)(INT32)rRect.nLeft;
+ if ( rRect.nLeft < 0 )
+ {
+ cAry[0] |= 0x80;
+ nNum ^= 0xFFFFFFFF;
+ }
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+ cAry[0] |= 0x40;
+ }
+ else
+ cAry[0] |= 0x30;
+ }
+ else
+ cAry[0] |= 0x20;
+ }
+ else
+ cAry[0] |= 0x10;
+ }
+
+ nNum = (UINT32)(INT32)rRect.nTop;
+ if ( rRect.nTop < 0 )
+ {
+ cAry[0] |= 0x08;
+ nNum ^= 0xFFFFFFFF;
+ }
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+ cAry[0] |= 0x04;
+ }
+ else
+ cAry[0] |= 0x03;
+ }
+ else
+ cAry[0] |= 0x02;
+ }
+ else
+ cAry[0] |= 0x01;
+ }
+
+ nNum = (UINT32)(INT32)rRect.nRight;
+ if ( rRect.nRight < 0 )
+ {
+ cAry[1] |= 0x80;
+ nNum ^= 0xFFFFFFFF;
+ }
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+ cAry[1] |= 0x40;
+ }
+ else
+ cAry[1] |= 0x30;
+ }
+ else
+ cAry[1] |= 0x20;
+ }
+ else
+ cAry[1] |= 0x10;
+ }
+
+ nNum = (UINT32)(INT32)rRect.nBottom;
+ if ( rRect.nBottom < 0 )
+ {
+ cAry[1] |= 0x08;
+ nNum ^= 0xFFFFFFFF;
+ }
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+
+ if ( nNum )
+ {
+ cAry[i] = (unsigned char)(nNum & 0xFF);
+ nNum >>= 8;
+ i++;
+ cAry[1] |= 0x04;
+ }
+ else
+ cAry[1] |= 0x03;
+ }
+ else
+ cAry[1] |= 0x02;
+ }
+ else
+ cAry[1] |= 0x01;
+ }
+
+ rOStream.Write( cAry, i );
+ }
+ else
+ {
+ rOStream << rRect.nLeft << rRect.nTop << rRect.nRight << rRect.nBottom;
+ }
+
+ return rOStream;
+}
diff --git a/tools/source/generic/line.cxx b/tools/source/generic/line.cxx
new file mode 100644
index 000000000000..0c2de98d843d
--- /dev/null
+++ b/tools/source/generic/line.cxx
@@ -0,0 +1,363 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _LINE_CXX
+#include <tools/link.hxx>
+#include <tools/line.hxx>
+#include <tools/debug.hxx>
+
+#include <cstdlib>
+#include <math.h>
+
+// --------
+// - Line -
+// --------
+
+double Line::GetLength() const
+{
+ return hypot( maStart.X() - maEnd.X(), maStart.Y() - maEnd.Y() );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Line::Intersection( const Line& rLine, Point& rIntersection ) const
+{
+ double fX, fY;
+ BOOL bRet;
+
+ if( Intersection( rLine, fX, fY ) )
+ {
+ rIntersection.X() = FRound( fX );
+ rIntersection.Y() = FRound( fY );
+ bRet = TRUE;
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Line::Intersection( const Line& rLine, double& rIntersectionX, double& rIntersectionY ) const
+{
+ const double fAx = maEnd.X() - maStart.X();
+ const double fAy = maEnd.Y() - maStart.Y();
+ const double fBx = rLine.maStart.X() - rLine.maEnd.X();
+ const double fBy = rLine.maStart.Y() - rLine.maEnd.Y();
+ const double fDen = fAy * fBx - fAx * fBy;
+ BOOL bOk = FALSE;
+
+ if( fDen != 0. )
+ {
+ const double fCx = maStart.X() - rLine.maStart.X();
+ const double fCy = maStart.Y() - rLine.maStart.Y();
+ const double fA = fBy * fCx - fBx * fCy;
+ const BOOL bGreater = ( fDen > 0. );
+
+ bOk = TRUE;
+
+ if ( bGreater )
+ {
+ if ( ( fA < 0. ) || ( fA > fDen ) )
+ bOk = FALSE;
+ }
+ else if ( ( fA > 0. ) || ( fA < fDen ) )
+ bOk = FALSE;
+
+ if ( bOk )
+ {
+ const double fB = fAx * fCy - fAy * fCx;
+
+ if ( bGreater )
+ {
+ if ( ( fB < 0. ) || ( fB > fDen ) )
+ bOk = FALSE;
+ }
+ else if ( ( fB > 0. ) || ( fB < fDen ) )
+ bOk = FALSE;
+
+ if( bOk )
+ {
+ const double fAlpha = fA / fDen;
+
+ rIntersectionX = ( maStart.X() + fAlpha * fAx );
+ rIntersectionY = ( maStart.Y() + fAlpha * fAy );
+ }
+ }
+ }
+
+ return bOk;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Line::Intersection( const Rectangle& rRect, Line& rIntersection ) const
+{
+ const BOOL bStartInside = rRect.IsInside( maStart );
+ const BOOL bEndInside = rRect.IsInside( maEnd );
+ BOOL bRet = TRUE;
+
+ if( bStartInside && bEndInside )
+ {
+ // line completely inside rect
+ rIntersection.maStart = maStart;
+ rIntersection.maEnd = maEnd;
+ }
+ else
+ {
+ // calculate intersections
+ const Point aTL( rRect.TopLeft() ), aTR( rRect.TopRight() );
+ const Point aBR( rRect.BottomRight() ), aBL( rRect.BottomLeft() );
+ Point aIntersect1, aIntersect2;
+ Point* pCurIntersection = &aIntersect1;
+
+ if( Intersection( Line( aTL, aTR ), *pCurIntersection ) )
+ pCurIntersection = &aIntersect2;
+
+ if( Intersection( Line( aTR, aBR ), *pCurIntersection ) )
+ pCurIntersection = ( pCurIntersection == &aIntersect1 ) ? &aIntersect2 : NULL;
+
+ if( pCurIntersection && Intersection( Line( aBR, aBL ), *pCurIntersection ) )
+ pCurIntersection = ( pCurIntersection == &aIntersect1 ) ? &aIntersect2 : NULL;
+
+ if( pCurIntersection && Intersection( Line( aBL, aTL ), *pCurIntersection ) )
+ pCurIntersection = ( pCurIntersection == &aIntersect1 ) ? &aIntersect2 : NULL;
+
+ if( !pCurIntersection )
+ {
+ // two intersections
+ rIntersection.maStart = aIntersect1;
+ rIntersection.maEnd = aIntersect2;
+ }
+ else if( pCurIntersection == &aIntersect2 )
+ {
+ // one intersection
+ rIntersection.maStart = aIntersect1;
+
+ if( ( maStart != aIntersect1 ) && bStartInside )
+ rIntersection.maEnd = maStart;
+ else if( ( maEnd != aIntersect1 ) && bEndInside )
+ rIntersection.maEnd = maEnd;
+ else
+ rIntersection.maEnd = rIntersection.maStart;
+ }
+ else
+ bRet = FALSE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+Point Line::NearestPoint( const Point& rPoint ) const
+{
+ Point aRetPt;
+
+ if ( maStart != maEnd )
+ {
+ const double fDistX = maEnd.X() - maStart.X();
+ const double fDistY = maStart.Y() - maEnd.Y();
+ const double fTau = ( ( maStart.Y() - rPoint.Y() ) * fDistY -
+ ( maStart.X() - rPoint.X() ) * fDistX ) /
+ ( fDistX * fDistX + fDistY * fDistY );
+
+ if( fTau < 0.0 )
+ aRetPt = maStart;
+ else if( fTau <= 1.0 )
+ {
+ aRetPt.X() = FRound( maStart.X() + fTau * fDistX );
+ aRetPt.Y() = FRound( maStart.Y() - fTau * fDistY );
+ }
+ else
+ aRetPt = maEnd;
+ }
+ else
+ aRetPt = maStart;
+
+ return aRetPt;
+}
+
+// ------------------------------------------------------------------------
+
+double Line::GetDistance( const double& rPtX, const double& rPtY ) const
+{
+ double fDist;
+
+ if( maStart != maEnd )
+ {
+ const double fDistX = maEnd.X() - maStart.X();
+ const double fDistY = maEnd.Y() - maStart.Y();
+ const double fACX = maStart.X() - rPtX;
+ const double fACY = maStart.Y() - rPtY;
+ const double fL2 = fDistX * fDistX + fDistY * fDistY;
+ const double fR = ( fACY * -fDistY - fACX * fDistX ) / fL2;
+ const double fS = ( fACY * fDistX - fACX * fDistY ) / fL2;
+
+ if( fR < 0.0 )
+ {
+ fDist = hypot( maStart.X() - rPtX, maStart.Y() - rPtY );
+
+ if( fS < 0.0 )
+ fDist *= -1.0;
+ }
+ else if( fR <= 1.0 )
+ fDist = fS * sqrt( fL2 );
+ else
+ {
+ fDist = hypot( maEnd.X() - rPtX, maEnd.Y() - rPtY );
+
+ if( fS < 0.0 )
+ fDist *= -1.0;
+ }
+ }
+ else
+ fDist = hypot( maStart.X() - rPtX, maStart.Y() - rPtY );
+
+ return fDist;
+}
+
+// ------------------------------------------------------------------------
+
+void Line::Enum( const Link& rEnumLink )
+{
+ DBG_ASSERT( rEnumLink.IsSet(), "This call doesn't make any sense with !rEnumLink.IsSet()" );
+
+ Point aEnum;
+ long nX;
+ long nY;
+
+ if( maStart.X() == maEnd.X() )
+ {
+ const long nEndY = maEnd.Y();
+
+ nX = maStart.X();
+ nY = maStart.Y();
+
+ if( nEndY > nY )
+ {
+ while( nY <= nEndY )
+ {
+ aEnum.X() = nX;
+ aEnum.Y() = nY++;
+ rEnumLink.Call( &aEnum );
+ }
+ }
+ else
+ {
+ while( nY >= nEndY )
+ {
+ aEnum.X() = nX;
+ aEnum.Y() = nY--;
+ rEnumLink.Call( &aEnum );
+ }
+ }
+ }
+ else if( maStart.Y() == maEnd.Y() )
+ {
+ const long nEndX = maEnd.X();
+
+ nX = maStart.X();
+ nY = maStart.Y();
+
+ if( nEndX > nX )
+ {
+ while( nX <= nEndX )
+ {
+ aEnum.X() = nX++;
+ aEnum.Y() = nY;
+ rEnumLink.Call( &aEnum );
+ }
+ }
+ else
+ {
+ while( nX >= nEndX )
+ {
+ aEnum.X() = nX--;
+ aEnum.Y() = nY;
+ rEnumLink.Call( &aEnum );
+ }
+ }
+ }
+ else
+ {
+ const long nDX = labs( maEnd.X() - maStart.X() );
+ const long nDY = labs( maEnd.Y() - maStart.Y() );
+ const long nStartX = maStart.X();
+ const long nStartY = maStart.Y();
+ const long nEndX = maEnd.X();
+ const long nEndY = maEnd.Y();
+ const long nXInc = ( nStartX < nEndX ) ? 1L : -1L;
+ const long nYInc = ( nStartY < nEndY ) ? 1L : -1L;
+
+ if( nDX >= nDY )
+ {
+ const long nDYX = ( nDY - nDX ) << 1;
+ const long nDY2 = nDY << 1;
+ long nD = nDY2 - nDX;
+
+ for( nX = nStartX, nY = nStartY; nX != nEndX; nX += nXInc )
+ {
+ aEnum.X() = nX;
+ aEnum.Y() = nY;
+ rEnumLink.Call( &aEnum );
+
+ if( nD < 0L )
+ nD += nDY2;
+ else
+ nD += nDYX, nY += nYInc;
+ }
+ }
+ else
+ {
+ const long nDYX = ( nDX - nDY ) << 1;
+ const long nDY2 = nDX << 1;
+ long nD = nDY2 - nDY;
+
+ for( nX = nStartX, nY = nStartY; nY != nEndY; nY += nYInc )
+ {
+ aEnum.X() = nX;
+ aEnum.Y() = nY;
+ rEnumLink.Call( &aEnum );
+
+ if( nD < 0L )
+ nD += nDY2;
+ else
+ nD += nDYX, nX += nXInc;
+ }
+ }
+
+ // last point
+ aEnum.X() = nEndX;
+ aEnum.Y() = nEndY;
+ rEnumLink.Call( &aEnum );
+ }
+}
diff --git a/tools/source/generic/link.cxx b/tools/source/generic/link.cxx
new file mode 100644
index 000000000000..928251306901
--- /dev/null
+++ b/tools/source/generic/link.cxx
@@ -0,0 +1,58 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <tools/link.hxx>
+
+/*************************************************************************
+|*
+|* Link::operator==()
+|*
+|* Beschreibung LINK.SDW
+|* Ersterstellung AM 14.02.91
+|* Letzte Aenderung TH 07.11.95
+|*
+*************************************************************************/
+
+BOOL Link::operator==( const Link& rLink ) const
+{
+ if ( pFunc == rLink.pFunc )
+ {
+ if ( pFunc )
+ {
+ if ( pInst == rLink.pInst )
+ return TRUE;
+ else
+ return FALSE;
+ }
+ else
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
diff --git a/tools/source/generic/makefile.mk b/tools/source/generic/makefile.mk
new file mode 100644
index 000000000000..07bab82f32b0
--- /dev/null
+++ b/tools/source/generic/makefile.mk
@@ -0,0 +1,71 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=gen
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+EXCEPTIONSFILES = $(SLO)$/poly.obj $(OBJ)$/poly.obj $(SLO)$/svlibrary.obj
+
+SLOFILES= $(SLO)$/toolsin.obj \
+ $(SLO)$/svlibrary.obj \
+ $(SLO)$/b3dtrans.obj \
+ $(SLO)$/link.obj \
+ $(SLO)$/bigint.obj \
+ $(SLO)$/fract.obj \
+ $(SLO)$/color.obj \
+ $(SLO)$/gen.obj \
+ $(SLO)$/config.obj \
+ $(SLO)$/poly.obj \
+ $(SLO)$/poly2.obj \
+ $(SLO)$/svborder.obj \
+ $(SLO)$/line.obj
+
+OBJFILES= $(OBJ)$/toolsin.obj \
+ $(OBJ)$/b3dtrans.obj \
+ $(OBJ)$/link.obj \
+ $(OBJ)$/bigint.obj \
+ $(OBJ)$/fract.obj \
+ $(OBJ)$/color.obj \
+ $(OBJ)$/gen.obj \
+ $(OBJ)$/config.obj \
+ $(OBJ)$/poly.obj \
+ $(OBJ)$/poly2.obj \
+ $(OBJ)$/svborder.obj \
+ $(OBJ)$/line.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/generic/poly.cxx b/tools/source/generic/poly.cxx
new file mode 100644
index 000000000000..e9f98b07adbd
--- /dev/null
+++ b/tools/source/generic/poly.cxx
@@ -0,0 +1,2380 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _SV_POLY_CXX
+#include <osl/endian.h>
+#include <tools/bigint.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <poly.h>
+#include <tools/line.hxx>
+#ifndef _VECTOR2D_H
+#include <tools/vector2d.hxx>
+#endif
+#ifndef _POLY_HXX
+#include <tools/poly.hxx>
+#endif
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/curve/b2dcubicbezier.hxx>
+
+#include <vector>
+#include <iterator>
+#include <algorithm>
+#include <cstring>
+#include <limits.h>
+#include <cmath>
+
+
+// =======================================================================
+
+DBG_NAME( Polygon )
+
+// -----------------------------------------------------------------------
+
+#define EDGE_LEFT 1
+#define EDGE_TOP 2
+#define EDGE_RIGHT 4
+#define EDGE_BOTTOM 8
+#define EDGE_HORZ (EDGE_RIGHT | EDGE_LEFT)
+#define EDGE_VERT (EDGE_TOP | EDGE_BOTTOM)
+#define SMALL_DVALUE 0.0000001
+#define FSQRT2 1.4142135623730950488016887242097
+
+// -----------------------------------------------------------------------
+
+static ImplPolygonData aStaticImplPolygon =
+{
+ NULL, NULL, 0, 0
+};
+
+// =======================================================================
+
+ImplPolygon::ImplPolygon( USHORT nInitSize, BOOL bFlags )
+{
+ if ( nInitSize )
+ {
+ mpPointAry = (Point*)new char[(ULONG)nInitSize*sizeof(Point)];
+ memset( mpPointAry, 0, (ULONG)nInitSize*sizeof(Point) );
+ }
+ else
+ mpPointAry = NULL;
+
+ if( bFlags )
+ {
+ mpFlagAry = new BYTE[ nInitSize ];
+ memset( mpPointAry, 0, nInitSize );
+ }
+ else
+ mpFlagAry = NULL;
+
+ mnRefCount = 1;
+ mnPoints = nInitSize;
+}
+
+// -----------------------------------------------------------------------
+
+ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
+{
+ if ( rImpPoly.mnPoints )
+ {
+ mpPointAry = (Point*)new char[(ULONG)rImpPoly.mnPoints*sizeof(Point)];
+ memcpy( mpPointAry, rImpPoly.mpPointAry, (ULONG)rImpPoly.mnPoints*sizeof(Point) );
+
+ if( rImpPoly.mpFlagAry )
+ {
+ mpFlagAry = new BYTE[ rImpPoly.mnPoints ];
+ memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
+ }
+ else
+ mpFlagAry = NULL;
+ }
+ else
+ {
+ mpPointAry = NULL;
+ mpFlagAry = NULL;
+ }
+
+ mnRefCount = 1;
+ mnPoints = rImpPoly.mnPoints;
+}
+
+// -----------------------------------------------------------------------
+
+ImplPolygon::ImplPolygon( USHORT nInitSize, const Point* pInitAry, const BYTE* pInitFlags )
+{
+ if ( nInitSize )
+ {
+ mpPointAry = (Point*)new char[(ULONG)nInitSize*sizeof(Point)];
+ memcpy( mpPointAry, pInitAry, (ULONG)nInitSize*sizeof( Point ) );
+
+ if( pInitFlags )
+ {
+ mpFlagAry = new BYTE[ nInitSize ];
+ memcpy( mpFlagAry, pInitFlags, nInitSize );
+ }
+ else
+ mpFlagAry = NULL;
+ }
+ else
+ {
+ mpPointAry = NULL;
+ mpFlagAry = NULL;
+ }
+
+ mnRefCount = 1;
+ mnPoints = nInitSize;
+}
+
+// -----------------------------------------------------------------------
+
+ImplPolygon::~ImplPolygon()
+{
+ if ( mpPointAry )
+ {
+ delete[] (char*) mpPointAry;
+ }
+
+ if( mpFlagAry )
+ delete[] mpFlagAry;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplPolygon::ImplSetSize( USHORT nNewSize, BOOL bResize )
+{
+ if( mnPoints == nNewSize )
+ return;
+
+ Point* pNewAry;
+
+ if ( nNewSize )
+ {
+ pNewAry = (Point*)new char[(ULONG)nNewSize*sizeof(Point)];
+
+ if ( bResize )
+ {
+ // Alte Punkte kopieren
+ if ( mnPoints < nNewSize )
+ {
+ // Neue Punkte mit 0 initialisieren
+ memset( pNewAry+mnPoints, 0, (ULONG)(nNewSize-mnPoints)*sizeof(Point) );
+ if ( mpPointAry )
+ memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
+ }
+ else
+ {
+ if ( mpPointAry )
+ memcpy( pNewAry, mpPointAry, (ULONG)nNewSize*sizeof(Point) );
+ }
+ }
+ }
+ else
+ pNewAry = NULL;
+
+ if ( mpPointAry )
+ delete[] (char*) mpPointAry;
+
+ // ggf. FlagArray beruecksichtigen
+ if( mpFlagAry )
+ {
+ BYTE* pNewFlagAry;
+
+ if( nNewSize )
+ {
+ pNewFlagAry = new BYTE[ nNewSize ];
+
+ if( bResize )
+ {
+ // Alte Flags kopieren
+ if ( mnPoints < nNewSize )
+ {
+ // Neue Punkte mit 0 initialisieren
+ memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
+ memcpy( pNewFlagAry, mpFlagAry, mnPoints );
+ }
+ else
+ memcpy( pNewFlagAry, mpFlagAry, nNewSize );
+ }
+ }
+ else
+ pNewFlagAry = NULL;
+
+ delete[] mpFlagAry;
+ mpFlagAry = pNewFlagAry;
+ }
+
+ mpPointAry = pNewAry;
+ mnPoints = nNewSize;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplPolygon::ImplSplit( USHORT nPos, USHORT nSpace, ImplPolygon* pInitPoly )
+{
+ const ULONG nSpaceSize = nSpace * sizeof( Point );
+
+ //Can't fit this in :-(, throw ?
+ if (mnPoints + nSpace > USHRT_MAX)
+ return;
+
+ const USHORT nNewSize = mnPoints + nSpace;
+
+ if( nPos >= mnPoints )
+ {
+ // Hinten anhaengen
+ nPos = mnPoints;
+ ImplSetSize( nNewSize, TRUE );
+
+ if( pInitPoly )
+ {
+ memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
+
+ if( pInitPoly->mpFlagAry )
+ memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
+ }
+ }
+ else
+ {
+ // PointArray ist in diesem Zweig immer vorhanden
+ const USHORT nSecPos = nPos + nSpace;
+ const USHORT nRest = mnPoints - nPos;
+
+ Point* pNewAry = (Point*) new char[ (ULONG) nNewSize * sizeof( Point ) ];
+
+ memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
+
+ if( pInitPoly )
+ memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
+ else
+ memset( pNewAry + nPos, 0, nSpaceSize );
+
+ memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
+ delete[] (char*) mpPointAry;
+
+ // ggf. FlagArray beruecksichtigen
+ if( mpFlagAry )
+ {
+ BYTE* pNewFlagAry = new BYTE[ nNewSize ];
+
+ memcpy( pNewFlagAry, mpFlagAry, nPos );
+
+ if( pInitPoly && pInitPoly->mpFlagAry )
+ memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
+ else
+ memset( pNewFlagAry + nPos, 0, nSpace );
+
+ memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
+ delete[] mpFlagAry;
+ mpFlagAry = pNewFlagAry;
+ }
+
+ mpPointAry = pNewAry;
+ mnPoints = nNewSize;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplPolygon::ImplRemove( USHORT nPos, USHORT nCount )
+{
+ const USHORT nRemoveCount = Min( (USHORT) ( mnPoints - nPos ), (USHORT) nCount );
+
+ if( nRemoveCount )
+ {
+ const USHORT nNewSize = mnPoints - nRemoveCount;
+ const USHORT nSecPos = nPos + nRemoveCount;
+ const USHORT nRest = mnPoints - nSecPos;
+
+ Point* pNewAry = (Point*) new char[ (ULONG) nNewSize * sizeof( Point ) ];
+
+ memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
+ memcpy( pNewAry + nPos, mpPointAry + nSecPos, nRest * sizeof( Point ) );
+
+ delete[] (char*) mpPointAry;
+
+ // ggf. FlagArray beruecksichtigen
+ if( mpFlagAry )
+ {
+ BYTE* pNewFlagAry = new BYTE[ nNewSize ];
+
+ memcpy( pNewFlagAry, mpFlagAry, nPos );
+ memcpy( pNewFlagAry + nPos, mpFlagAry + nSecPos, nRest );
+ delete[] mpFlagAry;
+ mpFlagAry = pNewFlagAry;
+ }
+
+ mpPointAry = pNewAry;
+ mnPoints = nNewSize;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplPolygon::ImplCreateFlagArray()
+{
+ if( !mpFlagAry )
+ {
+ mpFlagAry = new BYTE[ mnPoints ];
+ memset( mpFlagAry, 0, mnPoints );
+ }
+}
+
+// =======================================================================
+
+inline void Polygon::ImplMakeUnique()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpImplPolygon->mnRefCount != 1 )
+ {
+ if ( mpImplPolygon->mnRefCount )
+ mpImplPolygon->mnRefCount--;
+ mpImplPolygon = new ImplPolygon( *mpImplPolygon );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+inline double ImplGetAngle( const Point& rCenter, const Point& rPt )
+{
+ const long nDX = rPt.X() - rCenter.X();
+ return( atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) ) );
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon()
+{
+ DBG_CTOR( Polygon, NULL );
+ mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon( USHORT nSize )
+{
+ DBG_CTOR( Polygon, NULL );
+
+ if ( nSize )
+ mpImplPolygon = new ImplPolygon( nSize );
+ else
+ mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon( USHORT nPoints, const Point* pPtAry, const BYTE* pFlagAry )
+{
+ DBG_CTOR( Polygon, NULL );
+
+ if( nPoints )
+ mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
+ else
+ mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon( const Polygon& rPoly )
+{
+ DBG_CTOR( Polygon, NULL );
+ DBG_CHKOBJ( &rPoly, Polygon, NULL );
+ DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
+
+ mpImplPolygon = rPoly.mpImplPolygon;
+ if ( mpImplPolygon->mnRefCount )
+ mpImplPolygon->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon( const Rectangle& rRect )
+{
+ DBG_CTOR( Polygon, NULL );
+
+ if ( rRect.IsEmpty() )
+ mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
+ else
+ {
+ mpImplPolygon = new ImplPolygon( 5 );
+ mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
+ mpImplPolygon->mpPointAry[1] = rRect.TopRight();
+ mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
+ mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
+ mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon( const Rectangle& rRect, ULONG nHorzRound, ULONG nVertRound )
+{
+ DBG_CTOR( Polygon, NULL );
+
+ if ( rRect.IsEmpty() )
+ mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
+ else
+ {
+ Rectangle aRect( rRect );
+ aRect.Justify(); // SJ: i9140
+
+ nHorzRound = Min( nHorzRound, (ULONG) labs( aRect.GetWidth() >> 1 ) );
+ nVertRound = Min( nVertRound, (ULONG) labs( aRect.GetHeight() >> 1 ) );
+
+ if( !nHorzRound && !nVertRound )
+ {
+ mpImplPolygon = new ImplPolygon( 5 );
+ mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
+ mpImplPolygon->mpPointAry[1] = aRect.TopRight();
+ mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
+ mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
+ mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
+ }
+ else
+ {
+ const Point aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
+ const Point aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
+ const Point aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
+ const Point aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
+ Polygon* pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
+ USHORT i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
+
+ mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
+
+ const Point* pSrcAry = pEllipsePoly->GetConstPointAry();
+ Point* pDstAry = mpImplPolygon->mpPointAry;
+
+ for( i = 0, nEnd = nSize4; i < nEnd; i++ )
+ ( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
+
+ for( nEnd = nEnd + nSize4; i < nEnd; i++ )
+ ( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
+
+ for( nEnd = nEnd + nSize4; i < nEnd; i++ )
+ ( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
+
+ for( nEnd = nEnd + nSize4; i < nEnd; i++ )
+ ( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
+
+ pDstAry[ nEnd ] = pDstAry[ 0 ];
+ delete pEllipsePoly;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, USHORT nPoints )
+{
+ DBG_CTOR( Polygon, NULL );
+
+ if( nRadX && nRadY )
+ {
+ // Default berechnen (abhaengig von Groesse)
+ if( !nPoints )
+ {
+ nPoints = (USHORT) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
+ sqrt( (double) labs( nRadX * nRadY ) ) ) );
+
+ nPoints = (USHORT) MinMax( nPoints, 32, 256 );
+
+ if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
+ nPoints >>= 1;
+ }
+
+ // Anzahl der Punkte auf durch 4 teilbare Zahl aufrunden
+ mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
+
+ Point* pPt;
+ USHORT i;
+ USHORT nPoints2 = nPoints >> 1;
+ USHORT nPoints4 = nPoints >> 2;
+ double nAngle;
+ double nAngleStep = F_PI2 / ( nPoints4 - 1 );
+
+ for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
+ {
+ long nX = FRound( nRadX * cos( nAngle ) );
+ long nY = FRound( -nRadY * sin( nAngle ) );
+
+ pPt = &(mpImplPolygon->mpPointAry[i]);
+ pPt->X() = nX + rCenter.X();
+ pPt->Y() = nY + rCenter.Y();
+ pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
+ pPt->X() = -nX + rCenter.X();
+ pPt->Y() = nY + rCenter.Y();
+ pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
+ pPt->X() = -nX + rCenter.X();
+ pPt->Y() = -nY + rCenter.Y();
+ pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
+ pPt->X() = nX + rCenter.X();
+ pPt->Y() = -nY + rCenter.Y();
+ }
+ }
+ else
+ mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon( const Rectangle& rBound,
+ const Point& rStart, const Point& rEnd, PolyStyle eStyle )
+{
+ DBG_CTOR( Polygon, NULL );
+
+ const long nWidth = rBound.GetWidth();
+ const long nHeight = rBound.GetHeight();
+
+ if( ( nWidth > 1 ) && ( nHeight > 1 ) )
+ {
+ const Point aCenter( rBound.Center() );
+ const long nRadX = aCenter.X() - rBound.Left();
+ const long nRadY = aCenter.Y() - rBound.Top();
+ USHORT nPoints;
+
+ nPoints = (USHORT) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
+ sqrt( (double) labs( nRadX * nRadY ) ) ) );
+
+ nPoints = (USHORT) MinMax( nPoints, 32, 256 );
+
+ if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
+ nPoints >>= 1;
+
+ // Winkel berechnen
+ const double fRadX = nRadX;
+ const double fRadY = nRadY;
+ const double fCenterX = aCenter.X();
+ const double fCenterY = aCenter.Y();
+ double fStart = ImplGetAngle( aCenter, rStart );
+ double fEnd = ImplGetAngle( aCenter, rEnd );
+ double fDiff = fEnd - fStart;
+ double fStep;
+ USHORT nStart;
+ USHORT nEnd;
+
+ if( fDiff < 0. )
+ fDiff += F_2PI;
+
+ // Punktanzahl proportional verkleinern ( fDiff / (2PI) );
+ // ist eingentlich nur fuer einen Kreis richtig; wir
+ // machen es hier aber trotzdem
+ nPoints = Max( (USHORT) ( ( fDiff * 0.1591549 ) * nPoints ), (USHORT) 16 );
+ fStep = fDiff / ( nPoints - 1 );
+
+ if( POLY_PIE == eStyle )
+ {
+ const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
+
+ nStart = 1;
+ nEnd = nPoints + 1;
+ mpImplPolygon = new ImplPolygon( nPoints + 2 );
+ mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
+ mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
+ }
+ else
+ {
+ mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
+ nStart = 0;
+ nEnd = nPoints;
+ }
+
+ for(; nStart < nEnd; nStart++, fStart += fStep )
+ {
+ Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
+
+ rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
+ rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
+ }
+
+ if( POLY_CHORD == eStyle )
+ mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
+ }
+ else
+ mpImplPolygon = (ImplPolygon*) &aStaticImplPolygon;
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
+ const Point& rBezPt2, const Point& rCtrlPt2,
+ USHORT nPoints )
+{
+ DBG_CTOR( Polygon, NULL );
+
+ nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
+
+ const double fInc = 1.0 / ( nPoints - 1 );
+ double fK_1 = 0.0, fK1_1 = 1.0;
+ double fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
+ const double fX0 = rBezPt1.X();
+ const double fY0 = rBezPt1.Y();
+ const double fX1 = 3.0 * rCtrlPt1.X();
+ const double fY1 = 3.0 * rCtrlPt1.Y();
+ const double fX2 = 3.0 * rCtrlPt2.X();;
+ const double fY2 = 3.0 * rCtrlPt2.Y();;
+ const double fX3 = rBezPt2.X();
+ const double fY3 = rBezPt2.Y();
+
+ mpImplPolygon = new ImplPolygon( nPoints );
+
+ for( USHORT i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
+ {
+ Point& rPt = mpImplPolygon->mpPointAry[ i ];
+
+ fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
+ fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
+ fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
+
+ rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
+ rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Polygon::~Polygon()
+{
+ DBG_DTOR( Polygon, NULL );
+
+ // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
+ // die letzte Referenz ist, sonst Referenzcounter decrementieren
+ if ( mpImplPolygon->mnRefCount )
+ {
+ if ( mpImplPolygon->mnRefCount > 1 )
+ mpImplPolygon->mnRefCount--;
+ else
+ delete mpImplPolygon;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Point* Polygon::ImplGetPointAry()
+{
+ DBG_CHKTHIS( Polygon, NULL );
+
+ ImplMakeUnique();
+ return (Point*)mpImplPolygon->mpPointAry;
+}
+
+// -----------------------------------------------------------------------
+
+BYTE* Polygon::ImplGetFlagAry()
+{
+ DBG_CHKTHIS( Polygon, NULL );
+
+ ImplMakeUnique();
+ mpImplPolygon->ImplCreateFlagArray();
+ return mpImplPolygon->mpFlagAry;
+}
+
+// -----------------------------------------------------------------------
+
+const Point* Polygon::GetConstPointAry() const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ return (Point*)mpImplPolygon->mpPointAry;
+}
+
+// -----------------------------------------------------------------------
+
+const BYTE* Polygon::GetConstFlagAry() const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ return mpImplPolygon->mpFlagAry;
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::SetPoint( const Point& rPt, USHORT nPos )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
+ "Polygon::SetPoint(): nPos >= nPoints" );
+
+ ImplMakeUnique();
+ mpImplPolygon->mpPointAry[nPos] = rPt;
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::SetFlags( USHORT nPos, PolyFlags eFlags )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
+ "Polygon::SetFlags(): nPos >= nPoints" );
+
+ // we do only want to create the flag array if there
+ // is at least one flag different to POLY_NORMAL
+ if ( mpImplPolygon || ( eFlags != POLY_NORMAL ) )
+ {
+ ImplMakeUnique();
+ mpImplPolygon->ImplCreateFlagArray();
+ mpImplPolygon->mpFlagAry[ nPos ] = (BYTE) eFlags;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Point& Polygon::GetPoint( USHORT nPos ) const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
+ "Polygon::GetPoint(): nPos >= nPoints" );
+
+ return mpImplPolygon->mpPointAry[nPos];
+}
+
+// -----------------------------------------------------------------------
+
+PolyFlags Polygon::GetFlags( USHORT nPos ) const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
+ "Polygon::GetFlags(): nPos >= nPoints" );
+ return( mpImplPolygon->mpFlagAry ?
+ (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
+ POLY_NORMAL );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool Polygon::HasFlags() const
+{
+ return mpImplPolygon->mpFlagAry != NULL;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Polygon::IsControl(USHORT nPos) const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
+ "Polygon::GetFlags(): nPos >= nPoints" );
+ PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
+ (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
+
+ return( POLY_CONTROL == eFlags );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Polygon::IsSmooth(USHORT nPos) const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
+ "Polygon::GetFlags(): nPos >= nPoints" );
+ PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
+ (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
+
+ return( ( POLY_SMOOTH == eFlags ) || ( POLY_SYMMTR == eFlags ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Polygon::IsRect() const
+{
+ BOOL bIsRect = FALSE;
+ if ( mpImplPolygon->mpFlagAry == NULL )
+ {
+ if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
+ ( mpImplPolygon->mnPoints == 4 ) )
+ {
+ if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
+ ( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
+ ( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
+ ( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
+ bIsRect = TRUE;
+ }
+ }
+ return bIsRect;
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::SetSize( USHORT nNewSize )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+
+ if( nNewSize != mpImplPolygon->mnPoints )
+ {
+ ImplMakeUnique();
+ mpImplPolygon->ImplSetSize( nNewSize );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Polygon::GetSize() const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+
+ return mpImplPolygon->mnPoints;
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Clear()
+{
+ DBG_CHKTHIS( Polygon, NULL );
+
+ if ( mpImplPolygon->mnRefCount )
+ {
+ if ( mpImplPolygon->mnRefCount > 1 )
+ mpImplPolygon->mnRefCount--;
+ else
+ delete mpImplPolygon;
+ }
+
+ mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
+}
+
+// -----------------------------------------------------------------------
+
+double Polygon::CalcDistance( USHORT nP1, USHORT nP2 )
+{
+ DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
+ "Polygon::CalcDistance(): nPos1 >= nPoints" );
+ DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
+ "Polygon::CalcDistance(): nPos2 >= nPoints" );
+
+ const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
+ const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
+ const double fDx = rP2.X() - rP1.X();
+ const double fDy = rP2.Y() - rP1.Y();
+
+ return sqrt( fDx * fDx + fDy * fDy );
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Optimize( ULONG nOptimizeFlags, const PolyOptimizeData* pData )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
+
+ USHORT nSize = mpImplPolygon->mnPoints;
+
+ if( nOptimizeFlags && nSize )
+ {
+ if( nOptimizeFlags & POLY_OPTIMIZE_EDGES )
+ {
+ const Rectangle aBound( GetBoundRect() );
+ const double fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
+ const USHORT nPercent = pData ? pData->GetPercentValue() : 50;
+
+ Optimize( POLY_OPTIMIZE_NO_SAME );
+ ImplReduceEdges( *this, fArea, nPercent );
+ }
+ else if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE | POLY_OPTIMIZE_NO_SAME ) )
+ {
+ Polygon aNewPoly;
+ const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
+ ULONG nReduce;
+
+ if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE ) )
+ nReduce = pData ? pData->GetAbsValue() : 4UL;
+ else
+ nReduce = 0UL;
+
+ while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
+ nSize--;
+
+ if( nSize > 1 )
+ {
+ USHORT nLast = 0, nNewCount = 1;
+
+ aNewPoly.SetSize( nSize );
+ aNewPoly[ 0 ] = rFirst;
+
+ for( USHORT i = 1; i < nSize; i++ )
+ {
+ if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
+ ( !nReduce || ( nReduce < (ULONG) FRound( CalcDistance( nLast, i ) ) ) ) )
+ {
+ aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
+ }
+ }
+
+ if( nNewCount == 1 )
+ aNewPoly.Clear();
+ else
+ aNewPoly.SetSize( nNewCount );
+ }
+
+ *this = aNewPoly;
+ }
+
+ nSize = mpImplPolygon->mnPoints;
+
+ if( nSize > 1 )
+ {
+ if( ( nOptimizeFlags & POLY_OPTIMIZE_CLOSE ) &&
+ ( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
+ {
+ SetSize( mpImplPolygon->mnPoints + 1 );
+ mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
+ }
+ else if( ( nOptimizeFlags & POLY_OPTIMIZE_OPEN ) &&
+ ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
+ {
+ const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
+
+ while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
+ nSize--;
+
+ SetSize( nSize );
+ }
+ }
+ }
+}
+
+// =======================================================================
+
+/* Recursively subdivide cubic bezier curve via deCasteljau.
+
+ @param rPointIter
+ Output iterator, where the subdivided polylines are written to.
+
+ @param d
+ Squared difference of curve to a straight line
+
+ @param P*
+ Exactly four points, interpreted as support and control points of
+ a cubic bezier curve. Must be in device coordinates, since stop
+ criterion is based on the following assumption: the device has a
+ finite resolution, it is thus sufficient to stop subdivision if the
+ curve does not deviate more than one pixel from a straight line.
+
+*/
+static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
+ const double old_d2,
+ int recursionDepth,
+ const double d2,
+ const double P1x, const double P1y,
+ const double P2x, const double P2y,
+ const double P3x, const double P3y,
+ const double P4x, const double P4y )
+{
+ // Hard limit on recursion depth, empiric number.
+ enum {maxRecursionDepth=128};
+
+ // Perform bezier flatness test (lecture notes from R. Schaback,
+ // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
+ //
+ // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)||
+ // 0<=j<=n
+ //
+ // What is calculated here is an upper bound to the distance from
+ // a line through b_0 and b_3 (P1 and P4 in our notation) and the
+ // curve. We can drop 0 and n from the running indices, since the
+ // argument of max becomes zero for those cases.
+ const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
+ const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
+ const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
+ const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
+ const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
+ fJ2x*fJ2x + fJ2y*fJ2y) );
+
+ // stop if error measure does not improve anymore. This is a
+ // safety guard against floating point inaccuracies.
+ // stop at recursion level 128. This is a safety guard against
+ // floating point inaccuracies.
+ // stop if distance from line is guaranteed to be bounded by d
+ if( old_d2 > d2 &&
+ recursionDepth < maxRecursionDepth &&
+ distance2 >= d2 )
+ {
+ // deCasteljau bezier arc, split at t=0.5
+ // Foley/vanDam, p. 508
+ const double L1x( P1x ), L1y( P1y );
+ const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
+ const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
+ const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 );
+ const double R4x( P4x ), R4y( P4y );
+ const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
+ const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 );
+ const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
+ const double L4x( R1x ), L4y( R1y );
+
+ // subdivide further
+ ++recursionDepth;
+ ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
+ ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
+ }
+ else
+ {
+ // requested resolution reached.
+ // Add end points to output iterator.
+ // order is preserved, since this is so to say depth first traversal.
+ *rPointIter++ = Point( FRound(P1x), FRound(P1y) );
+ }
+}
+
+// =======================================================================
+
+void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
+{
+ if( !mpImplPolygon->mpFlagAry )
+ {
+ rResult = *this;
+ }
+ else
+ {
+ USHORT i;
+ USHORT nPts( GetSize() );
+ ::std::vector< Point > aPoints;
+ aPoints.reserve( nPts );
+ ::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
+
+ for(i=0; i<nPts;)
+ {
+ if( ( i + 3 ) < nPts )
+ {
+ BYTE P1( mpImplPolygon->mpFlagAry[ i ] );
+ BYTE P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
+
+ if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
+ ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
+ ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
+ ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
+ {
+ ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
+ mpImplPolygon->mpPointAry[ i ].X(), mpImplPolygon->mpPointAry[ i ].Y(),
+ mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
+ mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
+ mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
+ i += 3;
+ continue;
+ }
+ }
+
+ *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
+ }
+
+ // fill result polygon
+ rResult = Polygon( (USHORT)aPoints.size() ); // ensure sufficient size for copy
+ ::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
+{
+ const PolyPolygon aTmp( *this );
+ aTmp.GetIntersection( rPolyPoly, rResult );
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
+{
+ const PolyPolygon aTmp( *this );
+ aTmp.GetUnion( rPolyPoly, rResult );
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
+{
+ const PolyPolygon aTmp( *this );
+ aTmp.GetDifference( rPolyPoly, rResult );
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
+{
+ const PolyPolygon aTmp( *this );
+ aTmp.GetXOR( rPolyPoly, rResult );
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, USHORT nPercent )
+{
+ const double fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
+ USHORT nNumNoChange = 0, nNumRuns = 0;
+
+ while( nNumNoChange < 2 )
+ {
+ USHORT nPntCnt = rPoly.GetSize(), nNewPos = 0;
+ Polygon aNewPoly( nPntCnt );
+ BOOL bChangeInThisRun = FALSE;
+
+ for( USHORT n = 0; n < nPntCnt; n++ )
+ {
+ BOOL bDeletePoint = FALSE;
+
+ if( ( n + nNumRuns ) % 2 )
+ {
+ USHORT nIndPrev = !n ? nPntCnt - 1 : n - 1;
+ USHORT nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
+ USHORT nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
+ USHORT nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
+ Vector2D aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
+ Vector2D aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
+ Vector2D aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
+ Vector2D aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
+ double fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
+ double fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
+ double fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
+
+ if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
+ bDeletePoint = TRUE;
+ else
+ {
+ Vector2D aVecB( rPoly[ nIndNext ] );
+ double fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
+ double fLenWithB = fDist2 + fDist3;
+ double fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
+ double fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
+ double fTurnNext = aVec3.Scalar( aVec4.Normalize() );
+ double fGradPrev, fGradB, fGradNext;
+
+ if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
+ fGradPrev = 0.0;
+ else
+ fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
+
+ fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
+
+ if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
+ fGradNext = 0.0;
+ else
+ fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
+
+ if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
+ ( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
+ {
+ if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
+ ( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
+ {
+ bDeletePoint = TRUE;
+ }
+ }
+ else
+ {
+ double fRelLen = 1.0 - sqrt( fDistB / rArea );
+
+ if( fRelLen < 0.0 )
+ fRelLen = 0.0;
+ else if( fRelLen > 1.0 )
+ fRelLen = 1.0;
+
+ if( ( (UINT32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
+ ( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
+ {
+ bDeletePoint = TRUE;
+ }
+ }
+ }
+ }
+
+ if( !bDeletePoint )
+ aNewPoly[ nNewPos++ ] = rPoly[ n ];
+ else
+ bChangeInThisRun = TRUE;
+ }
+
+ if( bChangeInThisRun && nNewPos )
+ {
+ aNewPoly.SetSize( nNewPos );
+ rPoly = aNewPoly;
+ nNumNoChange = 0;
+ }
+ else
+ nNumNoChange++;
+
+ nNumRuns++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Move( long nHorzMove, long nVertMove )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+
+ // Diese Abfrage sollte man fuer die DrawEngine durchfuehren
+ if ( !nHorzMove && !nVertMove )
+ return;
+
+ ImplMakeUnique();
+
+ // Punkte verschieben
+ USHORT nCount = mpImplPolygon->mnPoints;
+ for ( USHORT i = 0; i < nCount; i++ )
+ {
+ Point* pPt = &(mpImplPolygon->mpPointAry[i]);
+ pPt->X() += nHorzMove;
+ pPt->Y() += nVertMove;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Translate(const Point& rTrans)
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ ImplMakeUnique();
+
+ for ( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
+ mpImplPolygon->mpPointAry[ i ] += rTrans;
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Scale( double fScaleX, double fScaleY )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ ImplMakeUnique();
+
+ for ( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
+ {
+ Point& rPnt = mpImplPolygon->mpPointAry[i];
+ rPnt.X() = (long) ( fScaleX * rPnt.X() );
+ rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Rotate( const Point& rCenter, USHORT nAngle10 )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ nAngle10 %= 3600;
+
+ if( nAngle10 )
+ {
+ const double fAngle = F_PI1800 * nAngle10;
+ Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ ImplMakeUnique();
+
+ long nX, nY;
+ long nCenterX = rCenter.X();
+ long nCenterY = rCenter.Y();
+
+ for( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
+ {
+ Point& rPt = mpImplPolygon->mpPointAry[ i ];
+
+ nX = rPt.X() - nCenterX;
+ nY = rPt.Y() - nCenterY;
+ rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
+ rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::SlantX( long nYRef, double fSin, double fCos )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ ImplMakeUnique();
+
+ for( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
+ {
+ Point& rPnt = mpImplPolygon->mpPointAry[ i ];
+ const long nDy = rPnt.Y() - nYRef;
+
+ rPnt.X() += (long)( fSin * nDy );
+ rPnt.Y() = nYRef + (long)( fCos * nDy );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::SlantY( long nXRef, double fSin, double fCos )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ ImplMakeUnique();
+
+ for( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
+ {
+ Point& rPnt = mpImplPolygon->mpPointAry[ i ];
+ const long nDx = rPnt.X() - nXRef;
+
+ rPnt.X() = nXRef + (long)( fCos * nDx );
+ rPnt.Y() -= (long)( fSin * nDx );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ ImplMakeUnique();
+
+ long Xr, Wr, X1, X2, X3, X4;
+ long Yr, Hr, Y1, Y2, Y3, Y4;
+ double fTx, fTy, fUx, fUy;
+
+ Xr = rRefRect.Left();
+ Yr = rRefRect.Top();
+ Wr = rRefRect.GetWidth();
+ Hr = rRefRect.GetHeight();
+
+ if( Wr && Hr )
+ {
+ DBG_ASSERT( rDistortedRect.mpImplPolygon->mnPoints >= 4, "Distort rect too small!" );
+
+ X1 = rDistortedRect[0].X();
+ Y1 = rDistortedRect[0].Y();
+ X2 = rDistortedRect[1].X();
+ Y2 = rDistortedRect[1].Y();
+ X3 = rDistortedRect[3].X();
+ Y3 = rDistortedRect[3].Y();
+ X4 = rDistortedRect[2].X();
+ Y4 = rDistortedRect[2].Y();
+
+ for( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
+ {
+ Point& rPnt = mpImplPolygon->mpPointAry[ i ];
+
+ fTx = (double)( rPnt.X() - Xr) / Wr;
+ fTy = (double)( rPnt.Y() - Yr) / Hr;
+ fUx = 1.0 - fTx;
+ fUy = 1.0 - fTy;
+
+ rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) + fTy * (fUx * X3 + fTx * X4) );
+ rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) + fTx * (fUy * Y2 + fTy * Y4) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+class ImplPointFilter
+{
+public:
+ virtual void LastPoint() = 0;
+ virtual void Input( const Point& rPoint ) = 0;
+};
+
+class ImplPolygonPointFilter : public ImplPointFilter
+{
+public:
+ ImplPolygon* mpPoly; // Nicht loeschen, wird dem Polygon zugewiesen
+ USHORT mnSize;
+
+ ImplPolygonPointFilter( USHORT nDestSize ) :
+ mnSize( 0 )
+ {
+ mpPoly = new ImplPolygon( nDestSize );
+ }
+
+ virtual void LastPoint();
+ virtual void Input( const Point& rPoint );
+};
+
+void ImplPolygonPointFilter::Input( const Point& rPoint )
+{
+ if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
+ {
+ mnSize++;
+ if ( mnSize > mpPoly->mnPoints )
+ mpPoly->ImplSetSize( mnSize );
+ mpPoly->mpPointAry[mnSize-1] = rPoint;
+ }
+}
+
+void ImplPolygonPointFilter::LastPoint()
+{
+ if ( mnSize < mpPoly->mnPoints )
+ mpPoly->ImplSetSize( mnSize );
+};
+
+class ImplEdgePointFilter : public ImplPointFilter
+{
+ Point maFirstPoint;
+ Point maLastPoint;
+ ImplPointFilter& mrNextFilter;
+ const long mnLow;
+ const long mnHigh;
+ const int mnEdge;
+ int mnLastOutside;
+ BOOL mbFirst;
+
+public:
+ ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
+ ImplPointFilter& rNextFilter ) :
+ mrNextFilter( rNextFilter ),
+ mnLow( nLow ),
+ mnHigh( nHigh ),
+ mnEdge( nEdge ),
+ mbFirst( TRUE )
+ {
+ }
+
+ Point EdgeSection( const Point& rPoint, int nEdge ) const;
+ int VisibleSide( const Point& rPoint ) const;
+ int IsPolygon() const
+ { return maFirstPoint == maLastPoint; }
+
+ virtual void Input( const Point& rPoint );
+ virtual void LastPoint();
+};
+
+inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
+{
+ if ( mnEdge & EDGE_HORZ )
+ {
+ return rPoint.X() < mnLow ? EDGE_LEFT :
+ rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
+ }
+ else
+ {
+ return rPoint.Y() < mnLow ? EDGE_TOP :
+ rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
+ }
+}
+
+Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
+{
+ long lx = maLastPoint.X();
+ long ly = maLastPoint.Y();
+ long md = rPoint.X() - lx;
+ long mn = rPoint.Y() - ly;
+ long nNewX;
+ long nNewY;
+
+ if ( nEdge & EDGE_VERT )
+ {
+ nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
+ long dy = nNewY - ly;
+ if ( !md )
+ nNewX = lx;
+ else if ( (LONG_MAX / Abs(md)) >= Abs(dy) )
+ nNewX = (dy * md) / mn + lx;
+ else
+ {
+ BigInt ady = dy;
+ ady *= md;
+ if( ady.IsNeg() )
+ if( mn < 0 )
+ ady += mn/2;
+ else
+ ady -= (mn-1)/2;
+ else
+ if( mn < 0 )
+ ady -= (mn+1)/2;
+ else
+ ady += mn/2;
+ ady /= mn;
+ nNewX = (long)ady + lx;
+ }
+ }
+ else
+ {
+ nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
+ long dx = nNewX - lx;
+ if ( !mn )
+ nNewY = ly;
+ else if ( (LONG_MAX / Abs(mn)) >= Abs(dx) )
+ nNewY = (dx * mn) / md + ly;
+ else
+ {
+ BigInt adx = dx;
+ adx *= mn;
+ if( adx.IsNeg() )
+ if( md < 0 )
+ adx += md/2;
+ else
+ adx -= (md-1)/2;
+ else
+ if( md < 0 )
+ adx -= (md+1)/2;
+ else
+ adx += md/2;
+ adx /= md;
+ nNewY = (long)adx + ly;
+ }
+ }
+
+ return Point( nNewX, nNewY );
+}
+
+void ImplEdgePointFilter::Input( const Point& rPoint )
+{
+ int nOutside = VisibleSide( rPoint );
+
+ if ( mbFirst )
+ {
+ maFirstPoint = rPoint;
+ mbFirst = FALSE;
+ if ( !nOutside )
+ mrNextFilter.Input( rPoint );
+ }
+ else if ( rPoint == maLastPoint )
+ return;
+ else if ( !nOutside )
+ {
+ if ( mnLastOutside )
+ mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
+ mrNextFilter.Input( rPoint );
+ }
+ else if ( !mnLastOutside )
+ mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
+ else if ( nOutside != mnLastOutside )
+ {
+ mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
+ mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
+ }
+
+ maLastPoint = rPoint;
+ mnLastOutside = nOutside;
+}
+
+void ImplEdgePointFilter::LastPoint()
+{
+ if ( !mbFirst )
+ {
+ int nOutside = VisibleSide( maFirstPoint );
+
+ if ( nOutside != mnLastOutside )
+ Input( maFirstPoint );
+ mrNextFilter.LastPoint();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Clip( const Rectangle& rRect, BOOL bPolygon )
+{
+ // #105251# Justify rect befor edge filtering
+ Rectangle aJustifiedRect( rRect );
+ aJustifiedRect.Justify();
+
+ USHORT nSourceSize = mpImplPolygon->mnPoints;
+ ImplPolygonPointFilter aPolygon( nSourceSize );
+ ImplEdgePointFilter aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
+ aPolygon );
+ ImplEdgePointFilter aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
+ aHorzFilter );
+
+ for ( USHORT i = 0; i < nSourceSize; i++ )
+ aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
+ if ( bPolygon || aVertFilter.IsPolygon() )
+ aVertFilter.LastPoint();
+ else
+ aPolygon.LastPoint();
+
+ // Alte ImpPolygon-Daten loeschen und die vom ImpPolygonPointFilter
+ // zuweisen
+ if ( mpImplPolygon->mnRefCount )
+ {
+ if ( mpImplPolygon->mnRefCount > 1 )
+ mpImplPolygon->mnRefCount--;
+ else
+ delete mpImplPolygon;
+ }
+ mpImplPolygon = aPolygon.mpPoly;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle Polygon::GetBoundRect() const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ // Removing the assert. Bezier curves have the attribute that each single
+ // curve segment defined by four points can not exit the four-point polygon
+ // defined by that points. This allows to say that the curve segment can also
+ // never leave the Range of it's defining points.
+ // The result is that Polygon::GetBoundRect() may not create the minimal
+ // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
+ // but will always create a valid BoundRect, at least as long as this method
+ // 'blindly' travels over all points, including control points.
+ //
+ // DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
+
+ USHORT nCount = mpImplPolygon->mnPoints;
+ if( ! nCount )
+ return Rectangle();
+
+ long nXMin, nXMax, nYMin, nYMax;
+
+ const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
+ nXMin = nXMax = pPt->X();
+ nYMin = nYMax = pPt->Y();
+
+ for ( USHORT i = 0; i < nCount; i++ )
+ {
+ pPt = &(mpImplPolygon->mpPointAry[i]);
+
+ if ( pPt->X() < nXMin )
+ nXMin = pPt->X();
+ if ( pPt->X() > nXMax )
+ nXMax = pPt->X();
+ if ( pPt->Y() < nYMin )
+ nYMin = pPt->Y();
+ if ( pPt->Y() > nYMax )
+ nYMax = pPt->Y();
+ }
+
+ return Rectangle( nXMin, nYMin, nXMax, nYMax );
+}
+
+// -----------------------------------------------------------------------
+
+double Polygon::GetArea() const
+{
+ const double fArea = GetSignedArea();
+ return( ( fArea < 0.0 ) ? -fArea : fArea );
+}
+
+// -----------------------------------------------------------------------
+
+double Polygon::GetSignedArea() const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
+
+ double fArea = 0.0;
+
+ if( mpImplPolygon->mnPoints > 2 )
+ {
+ const USHORT nCount1 = mpImplPolygon->mnPoints - 1;
+
+ for( USHORT i = 0; i < nCount1; )
+ {
+ const Point& rPt = mpImplPolygon->mpPointAry[ i ];
+ const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
+ fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
+ }
+
+ const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
+ const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
+ fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
+ }
+
+ return fArea;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Polygon::IsInside( const Point& rPoint ) const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
+
+ const Rectangle aBound( GetBoundRect() );
+ const Line aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
+ USHORT nCount = mpImplPolygon->mnPoints;
+ USHORT nPCounter = 0;
+
+ if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
+ {
+ Point aPt1( mpImplPolygon->mpPointAry[ 0 ] );
+ Point aIntersection;
+ Point aLastIntersection;
+
+ while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
+ nCount--;
+
+ for ( USHORT i = 1; i <= nCount; i++ )
+ {
+ const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
+
+ if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
+ {
+ // Hiermit verhindern wir das Einfuegen von
+ // doppelten Intersections, die gleich hintereinander folgen
+ if ( nPCounter )
+ {
+ if ( aIntersection != aLastIntersection )
+ {
+ aLastIntersection = aIntersection;
+ nPCounter++;
+ }
+ }
+ else
+ {
+ aLastIntersection = aIntersection;
+ nPCounter++;
+ }
+ }
+
+ aPt1 = rPt2;
+ }
+ }
+
+ // innerhalb, wenn die Anzahl der Schnittpunkte ungerade ist
+ return ( ( nPCounter & 1 ) == 1 );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Polygon::IsRightOrientated() const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ return GetSignedArea() >= 0.0;
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Insert( USHORT nPos, const Point& rPt, PolyFlags eFlags )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ ImplMakeUnique();
+
+ if( nPos >= mpImplPolygon->mnPoints )
+ nPos = mpImplPolygon->mnPoints;
+
+ mpImplPolygon->ImplSplit( nPos, 1 );
+ mpImplPolygon->mpPointAry[ nPos ] = rPt;
+
+ if( POLY_NORMAL != eFlags )
+ {
+ mpImplPolygon->ImplCreateFlagArray();
+ mpImplPolygon->mpFlagAry[ nPos ] = (BYTE) eFlags;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Insert( USHORT nPos, const Polygon& rPoly )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ const USHORT nInsertCount = rPoly.mpImplPolygon->mnPoints;
+
+ if( nInsertCount )
+ {
+ ImplMakeUnique();
+
+ if( nPos >= mpImplPolygon->mnPoints )
+ nPos = mpImplPolygon->mnPoints;
+
+ if( rPoly.mpImplPolygon->mpFlagAry )
+ mpImplPolygon->ImplCreateFlagArray();
+
+ mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Remove( USHORT nPos, USHORT nCount )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ if( nCount && ( nPos < mpImplPolygon->mnPoints ) )
+ {
+ ImplMakeUnique();
+ mpImplPolygon->ImplRemove( nPos, nCount );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Point& Polygon::operator[]( USHORT nPos )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
+
+ ImplMakeUnique();
+ return mpImplPolygon->mpPointAry[nPos];
+}
+
+// -----------------------------------------------------------------------
+
+Polygon& Polygon::operator=( const Polygon& rPoly )
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_CHKOBJ( &rPoly, Polygon, NULL );
+ DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ // RefCount == 0 fuer statische Objekte
+ if ( rPoly.mpImplPolygon->mnRefCount )
+ rPoly.mpImplPolygon->mnRefCount++;
+
+ // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
+ // die letzte Referenz ist, sonst Referenzcounter decrementieren
+ if ( mpImplPolygon->mnRefCount )
+ {
+ if ( mpImplPolygon->mnRefCount > 1 )
+ mpImplPolygon->mnRefCount--;
+ else
+ delete mpImplPolygon;
+ }
+
+ mpImplPolygon = rPoly.mpImplPolygon;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Polygon::operator==( const Polygon& rPoly ) const
+{
+ DBG_CHKTHIS( Polygon, NULL );
+ DBG_CHKOBJ( &rPoly, Polygon, NULL );
+
+ if ( (rPoly.mpImplPolygon == mpImplPolygon) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
+{
+ sal_Bool bIsEqual = sal_True;;
+ sal_uInt16 i;
+ if ( GetSize() != rPoly.GetSize() )
+ bIsEqual = sal_False;
+ else
+ {
+ for ( i = 0; i < GetSize(); i++ )
+ {
+ if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
+ ( GetFlags( i ) != rPoly.GetFlags( i ) ) )
+ {
+ bIsEqual = sal_False;
+ break;
+ }
+ }
+ }
+ return bIsEqual;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
+{
+ DBG_CHKOBJ( &rPoly, Polygon, NULL );
+ DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
+
+ USHORT i;
+ USHORT nStart;
+ USHORT nCurPoints;
+ USHORT nPoints;
+ unsigned char bShort;
+ short nShortX;
+ short nShortY;
+ long nLongX;
+ long nLongY;
+
+ // Anzahl der Punkte einlesen und Array erzeugen
+ rIStream >> nPoints;
+ if ( rPoly.mpImplPolygon->mnRefCount != 1 )
+ {
+ if ( rPoly.mpImplPolygon->mnRefCount )
+ rPoly.mpImplPolygon->mnRefCount--;
+ rPoly.mpImplPolygon = new ImplPolygon( nPoints );
+ }
+ else
+ rPoly.mpImplPolygon->ImplSetSize( nPoints, FALSE );
+
+ // Je nach CompressMode das Polygon einlesen
+ if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
+ {
+ i = 0;
+ while ( i < nPoints )
+ {
+ rIStream >> bShort >> nCurPoints;
+
+ if ( bShort )
+ {
+ for ( nStart = i; i < nStart+nCurPoints; i++ )
+ {
+ rIStream >> nShortX >> nShortY;
+ rPoly.mpImplPolygon->mpPointAry[i].X() = nShortX;
+ rPoly.mpImplPolygon->mpPointAry[i].Y() = nShortY;
+ }
+ }
+ else
+ {
+ for ( nStart = i; i < nStart+nCurPoints; i++ )
+ {
+ rIStream >> nLongX >> nLongY;
+ rPoly.mpImplPolygon->mpPointAry[i].X() = nLongX;
+ rPoly.mpImplPolygon->mpPointAry[i].Y() = nLongY;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Feststellen, ob ueber die Operatoren geschrieben werden muss
+#if (SAL_TYPES_SIZEOFLONG) != 4
+ if ( 1 )
+#else
+#ifdef OSL_BIGENDIAN
+ if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
+#else
+ if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
+#endif
+#endif
+ {
+ for( i = 0; i < nPoints; i++ )
+ {
+ rIStream >> rPoly.mpImplPolygon->mpPointAry[i].X()
+ >> rPoly.mpImplPolygon->mpPointAry[i].Y();
+ }
+ }
+ else
+ rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
+ }
+
+ return rIStream;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
+{
+ DBG_CHKOBJ( &rPoly, Polygon, NULL );
+ DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
+
+ unsigned char bShort;
+ unsigned char bCurShort;
+ USHORT nStart;
+ USHORT i;
+ USHORT nPoints = rPoly.GetSize();
+
+ // Anzahl der Punkte rausschreiben
+ rOStream << nPoints;
+
+ // Je nach CompressMode das Polygon rausschreiben
+ if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
+ {
+ i = 0;
+ while ( i < nPoints )
+ {
+ nStart = i;
+
+ // Feststellen, welcher Typ geschrieben werden soll
+ if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
+ (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
+ ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
+ (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
+ bShort = TRUE;
+ else
+ bShort = FALSE;
+ while ( i < nPoints )
+ {
+ // Feststellen, welcher Typ geschrieben werden soll
+ if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
+ (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
+ ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
+ (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
+ bCurShort = TRUE;
+ else
+ bCurShort = FALSE;
+
+ // Wenn sich die Werte in einen anderen Bereich begeben,
+ // muessen wir neu rausschreiben
+ if ( bCurShort != bShort )
+ {
+ bShort = bCurShort;
+ break;
+ }
+
+ i++;
+ }
+
+ rOStream << bShort << (USHORT)(i-nStart);
+
+ if ( bShort )
+ {
+ for( ; nStart < i; nStart++ )
+ {
+ rOStream << (short)rPoly.mpImplPolygon->mpPointAry[nStart].X()
+ << (short)rPoly.mpImplPolygon->mpPointAry[nStart].Y();
+ }
+ }
+ else
+ {
+ for( ; nStart < i; nStart++ )
+ {
+ rOStream << rPoly.mpImplPolygon->mpPointAry[nStart].X()
+ << rPoly.mpImplPolygon->mpPointAry[nStart].Y();
+ }
+ }
+ }
+ }
+ else
+ {
+ // Feststellen, ob ueber die Operatoren geschrieben werden muss
+#if (SAL_TYPES_SIZEOFLONG) != 4
+ if ( 1 )
+#else
+#ifdef OSL_BIGENDIAN
+ if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
+#else
+ if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
+#endif
+#endif
+ {
+ for( i = 0; i < nPoints; i++ )
+ {
+ rOStream << rPoly.mpImplPolygon->mpPointAry[i].X()
+ << rPoly.mpImplPolygon->mpPointAry[i].Y();
+ }
+ }
+ else
+ {
+ if ( nPoints )
+ rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
+ }
+ }
+
+ return rOStream;
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::ImplRead( SvStream& rIStream )
+{
+ sal_uInt8 bHasPolyFlags;
+
+ rIStream >> *this
+ >> bHasPolyFlags;
+
+ if ( bHasPolyFlags )
+ {
+ mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
+ rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Read( SvStream& rIStream )
+{
+ VersionCompat aCompat( rIStream, STREAM_READ );
+
+ ImplRead( rIStream );
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::ImplWrite( SvStream& rOStream ) const
+{
+ sal_uInt8 bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
+ rOStream << *this
+ << bHasPolyFlags;
+
+ if ( bHasPolyFlags )
+ rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
+}
+
+// -----------------------------------------------------------------------
+
+void Polygon::Write( SvStream& rOStream ) const
+{
+ VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
+
+ ImplWrite( rOStream );
+}
+
+// -----------------------------------------------------------------------
+// #i74631# numerical correction method for B2DPolygon
+void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, BYTE nCFlag)
+{
+ const sal_uInt32 nPointCount(roPolygon.count());
+ OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
+
+ if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
+ {
+ if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
+ {
+ const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
+
+ if(POLY_SMOOTH == nCFlag)
+ {
+ // C1: apply inverse direction of prev to next, keep length of next
+ const basegfx::B2DVector aOriginalNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
+ basegfx::B2DVector aNewNext(aPoint - roPolygon.getPrevControlPoint(nIndex));
+
+ aNewNext.setLength(aOriginalNext.getLength());
+ roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aNewNext));
+ }
+ else // POLY_SYMMTR
+ {
+ // C2: apply inverse control point to next
+ roPolygon.setNextControlPoint(nIndex, (2.0 * aPoint) - roPolygon.getPrevControlPoint(nIndex));
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+// convert to basegfx::B2DPolygon and return
+basegfx::B2DPolygon Polygon::getB2DPolygon() const
+{
+ basegfx::B2DPolygon aRetval;
+ const sal_uInt16 nCount(mpImplPolygon->mnPoints);
+
+ if(nCount)
+ {
+ if(mpImplPolygon->mpFlagAry)
+ {
+ // handling for curves. Add start point
+ const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
+ BYTE nPointFlag(mpImplPolygon->mpFlagAry[0]);
+ aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
+ Point aControlA, aControlB;
+
+ for(sal_uInt16 a(1); a < nCount;)
+ {
+ bool bControlA(false);
+ bool bControlB(false);
+
+ if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
+ {
+ aControlA = mpImplPolygon->mpPointAry[a++];
+ bControlA = true;
+ }
+
+ if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
+ {
+ aControlB = mpImplPolygon->mpPointAry[a++];
+ bControlB = true;
+ }
+
+ // assert invalid polygons
+ OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
+
+ if(a < nCount)
+ {
+ const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
+
+ if(bControlA)
+ {
+ // bezier edge, add
+ aRetval.appendBezierSegment(
+ basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
+ basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
+ basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
+
+ impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
+ }
+ else
+ {
+ // no bezier edge, add end point
+ aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
+ }
+
+ nPointFlag = mpImplPolygon->mpFlagAry[a++];
+ }
+ }
+
+ // if exist, remove double first/last points, set closed and correct control points
+ basegfx::tools::checkClosed(aRetval);
+
+ if(aRetval.isClosed())
+ {
+ // closeWithGeometryChange did really close, so last point(s) were removed.
+ // Correct the continuity in the changed point
+ impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
+ }
+ }
+ else
+ {
+ // extra handling for non-curves (most-used case) for speedup
+ for(sal_uInt16 a(0); a < nCount; a++)
+ {
+ // get point and add
+ const Point aPoint(mpImplPolygon->mpPointAry[a]);
+ aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
+ }
+
+ // set closed flag
+ basegfx::tools::checkClosed(aRetval);
+ }
+ }
+
+ return aRetval;
+}
+
+// -----------------------------------------------------------------------
+// constructor to convert from basegfx::B2DPolygon
+// #i76891# Needed to change from adding all control points (even for unused
+// edges) and creating a fixed-size Polygon in the first run to creating the
+// minimal Polygon. This requires a temporary Point- and Flag-Array for curves
+// and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
+// for straight edges.
+Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
+: mpImplPolygon(0)
+{
+ DBG_CTOR( Polygon, NULL );
+
+ const bool bCurve(rPolygon.areControlPointsUsed());
+ const bool bClosed(rPolygon.isClosed());
+ sal_uInt32 nB2DLocalCount(rPolygon.count());
+
+ if(bCurve)
+ {
+ // #127979# Reduce source point count hard to the limit of the tools Polygon
+ if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
+ {
+ DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
+ nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
+ }
+
+ // calculate target point count
+ const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
+
+ if(nLoopCount)
+ {
+ // calculate maximum array size and allocate; prepare insert index
+ const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
+ mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
+
+ // prepare insert index and current point
+ sal_uInt32 nArrayInsert(0);
+ basegfx::B2DCubicBezier aBezier;
+ aBezier.setStartPoint(rPolygon.getB2DPoint(0));
+
+ for(sal_uInt32 a(0L); a < nLoopCount; a++)
+ {
+ // add current point (always) and remember StartPointIndex for evtl. later corrections
+ const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
+ const sal_uInt32 nStartPointIndex(nArrayInsert);
+ mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
+ mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_NORMAL;
+ nArrayInsert++;
+
+ // prepare next segment
+ const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
+ aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
+ aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
+ aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
+
+ if(aBezier.isBezier())
+ {
+ // if one is used, add always two control points due to the old schema
+ mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
+ mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_CONTROL;
+ nArrayInsert++;
+
+ mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
+ mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_CONTROL;
+ nArrayInsert++;
+ }
+
+ // test continuity with previous control point to set flag value
+ if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
+ {
+ const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
+
+ if(basegfx::CONTINUITY_C1 == eCont)
+ {
+ mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_SMOOTH;
+ }
+ else if(basegfx::CONTINUITY_C2 == eCont)
+ {
+ mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_SYMMTR;
+ }
+ }
+
+ // prepare next polygon step
+ aBezier.setStartPoint(aBezier.getEndPoint());
+ }
+
+ if(bClosed)
+ {
+ // add first point again as closing point due to old definition
+ mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
+ mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_NORMAL;
+ nArrayInsert++;
+ }
+ else
+ {
+ // add last point as closing point
+ const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
+ const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
+ mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
+ mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_NORMAL;
+ nArrayInsert++;
+ }
+
+ DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
+
+ if(nArrayInsert != nMaxTargetCount)
+ {
+ mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
+ }
+ }
+ }
+ else
+ {
+ // #127979# Reduce source point count hard to the limit of the tools Polygon
+ if(nB2DLocalCount > (0x0000ffff - 1L))
+ {
+ DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
+ nB2DLocalCount = (0x0000ffff - 1L);
+ }
+
+ if(nB2DLocalCount)
+ {
+ // point list creation
+ const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
+ mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
+ sal_uInt16 nIndex(0);
+
+ for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
+ {
+ basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
+ Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
+ mpImplPolygon->mpPointAry[nIndex++] = aPoint;
+ }
+
+ if(bClosed)
+ {
+ // add first point as closing point
+ mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
+ }
+ }
+ }
+
+ if(!mpImplPolygon)
+ {
+ // no content yet, create empty polygon
+ mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
+ }
+}
+
+// eof
diff --git a/tools/source/generic/poly2.cxx b/tools/source/generic/poly2.cxx
new file mode 100644
index 000000000000..46459353fa35
--- /dev/null
+++ b/tools/source/generic/poly2.cxx
@@ -0,0 +1,891 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _SV_POLY2_CXX
+
+#define POLY_CLIP_INT 0
+#define POLY_CLIP_UNION 1
+#define POLY_CLIP_DIFF 2
+#define POLY_CLIP_XOR 3
+
+#include <rtl/math.hxx>
+#include <poly.h>
+#include <tools/poly.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+
+// ---------------
+// - PolyPolygon -
+// ---------------
+
+DBG_NAME( PolyPolygon )
+
+// -----------------------------------------------------------------------
+
+ImplPolyPolygon::ImplPolyPolygon( USHORT nInitSize )
+{
+ mnRefCount = 1;
+ mnCount = nInitSize;
+ mnSize = nInitSize;
+ mnResize = 16;
+ mpPolyAry = new SVPPOLYGON[ nInitSize ];
+}
+
+// -----------------------------------------------------------------------
+
+ImplPolyPolygon::ImplPolyPolygon( const ImplPolyPolygon& rImplPolyPoly )
+{
+ mnRefCount = 1;
+ mnCount = rImplPolyPoly.mnCount;
+ mnSize = rImplPolyPoly.mnSize;
+ mnResize = rImplPolyPoly.mnResize;
+
+ if ( rImplPolyPoly.mpPolyAry )
+ {
+ mpPolyAry = new SVPPOLYGON[mnSize];
+ for ( USHORT i = 0; i < mnCount; i++ )
+ mpPolyAry[i] = new Polygon( *rImplPolyPoly.mpPolyAry[i] );
+ }
+ else
+ mpPolyAry = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplPolyPolygon::~ImplPolyPolygon()
+{
+ if ( mpPolyAry )
+ {
+ for ( USHORT i = 0; i < mnCount; i++ )
+ delete mpPolyAry[i];
+ delete[] mpPolyAry;
+ }
+}
+
+// =======================================================================
+
+PolyPolygon::PolyPolygon( USHORT nInitSize, USHORT nResize )
+{
+ DBG_CTOR( PolyPolygon, NULL );
+
+ if ( nInitSize > MAX_POLYGONS )
+ nInitSize = MAX_POLYGONS;
+ else if ( !nInitSize )
+ nInitSize = 1;
+ if ( nResize > MAX_POLYGONS )
+ nResize = MAX_POLYGONS;
+ else if ( !nResize )
+ nResize = 1;
+ mpImplPolyPolygon = new ImplPolyPolygon( nInitSize, nResize );
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon::PolyPolygon( const Polygon& rPoly )
+{
+ DBG_CTOR( PolyPolygon, NULL );
+
+ if ( rPoly.GetSize() )
+ {
+ mpImplPolyPolygon = new ImplPolyPolygon( 1 );
+ mpImplPolyPolygon->mpPolyAry[0] = new Polygon( rPoly );
+ }
+ else
+ mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon::PolyPolygon( USHORT nPoly, const USHORT* pPointCountAry,
+ const Point* pPtAry )
+{
+ DBG_CTOR( PolyPolygon, NULL );
+
+ if ( nPoly > MAX_POLYGONS )
+ nPoly = MAX_POLYGONS;
+
+ mpImplPolyPolygon = new ImplPolyPolygon( nPoly );
+ for ( USHORT i = 0; i < nPoly; i++ )
+ {
+ mpImplPolyPolygon->mpPolyAry[i] = new Polygon( *pPointCountAry, pPtAry );
+ pPtAry += *pPointCountAry;
+ pPointCountAry++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon::PolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ DBG_CTOR( PolyPolygon, NULL );
+ DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
+ DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
+
+ mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
+ mpImplPolyPolygon->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon::~PolyPolygon()
+{
+ DBG_DTOR( PolyPolygon, NULL );
+
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ mpImplPolyPolygon->mnRefCount--;
+ else
+ delete mpImplPolyPolygon;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Insert( const Polygon& rPoly, USHORT nPos )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ if ( mpImplPolyPolygon->mnCount >= MAX_POLYGONS )
+ return;
+
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ if ( nPos > mpImplPolyPolygon->mnCount )
+ nPos = mpImplPolyPolygon->mnCount;
+
+ if ( !mpImplPolyPolygon->mpPolyAry )
+ mpImplPolyPolygon->mpPolyAry = new SVPPOLYGON[mpImplPolyPolygon->mnSize];
+ else if ( mpImplPolyPolygon->mnCount == mpImplPolyPolygon->mnSize )
+ {
+ USHORT nOldSize = mpImplPolyPolygon->mnSize;
+ USHORT nNewSize = nOldSize + mpImplPolyPolygon->mnResize;
+ SVPPOLYGON* pNewAry;
+
+ if ( nNewSize >= MAX_POLYGONS )
+ nNewSize = MAX_POLYGONS;
+ pNewAry = new SVPPOLYGON[nNewSize];
+ memcpy( pNewAry, mpImplPolyPolygon->mpPolyAry, nPos*sizeof(SVPPOLYGON) );
+ memcpy( pNewAry+nPos+1, mpImplPolyPolygon->mpPolyAry+nPos,
+ (nOldSize-nPos)*sizeof(SVPPOLYGON) );
+ delete[] mpImplPolyPolygon->mpPolyAry;
+ mpImplPolyPolygon->mpPolyAry = pNewAry;
+ mpImplPolyPolygon->mnSize = nNewSize;
+ }
+ else if ( nPos < mpImplPolyPolygon->mnCount )
+ {
+ memmove( mpImplPolyPolygon->mpPolyAry+nPos+1,
+ mpImplPolyPolygon->mpPolyAry+nPos,
+ (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
+ }
+
+ mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
+ mpImplPolyPolygon->mnCount++;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Remove( USHORT nPos )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ DBG_ASSERT( nPos < Count(), "PolyPolygon::Remove(): nPos >= nSize" );
+
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ delete mpImplPolyPolygon->mpPolyAry[nPos];
+ mpImplPolyPolygon->mnCount--;
+ memmove( mpImplPolyPolygon->mpPolyAry+nPos,
+ mpImplPolyPolygon->mpPolyAry+nPos+1,
+ (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Replace( const Polygon& rPoly, USHORT nPos )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ DBG_ASSERT( nPos < Count(), "PolyPolygon::Replace(): nPos >= nSize" );
+
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ delete mpImplPolyPolygon->mpPolyAry[nPos];
+ mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
+}
+
+// -----------------------------------------------------------------------
+
+const Polygon& PolyPolygon::GetObject( USHORT nPos ) const
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ DBG_ASSERT( nPos < Count(), "PolyPolygon::GetObject(): nPos >= nSize" );
+
+ return *(mpImplPolyPolygon->mpPolyAry[nPos]);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PolyPolygon::IsRect() const
+{
+ BOOL bIsRect = FALSE;
+ if ( Count() == 1 )
+ bIsRect = mpImplPolyPolygon->mpPolyAry[ 0 ]->IsRect();
+ return bIsRect;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Clear()
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( mpImplPolyPolygon->mnResize,
+ mpImplPolyPolygon->mnResize );
+ }
+ else
+ {
+ if ( mpImplPolyPolygon->mpPolyAry )
+ {
+ for ( USHORT i = 0; i < mpImplPolyPolygon->mnCount; i++ )
+ delete mpImplPolyPolygon->mpPolyAry[i];
+ delete[] mpImplPolyPolygon->mpPolyAry;
+ mpImplPolyPolygon->mpPolyAry = NULL;
+ mpImplPolyPolygon->mnCount = 0;
+ mpImplPolyPolygon->mnSize = mpImplPolyPolygon->mnResize;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Optimize( ULONG nOptimizeFlags, const PolyOptimizeData* pData )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ if( nOptimizeFlags )
+ {
+ double fArea;
+ const BOOL bEdges = ( nOptimizeFlags & POLY_OPTIMIZE_EDGES ) == POLY_OPTIMIZE_EDGES;
+ USHORT nPercent = 0;
+
+ if( bEdges )
+ {
+ const Rectangle aBound( GetBoundRect() );
+
+ fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
+ nPercent = pData ? pData->GetPercentValue() : 50;
+ nOptimizeFlags &= ~POLY_OPTIMIZE_EDGES;
+ }
+
+ // watch for ref counter
+ if( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Optimize polygons
+ for( USHORT i = 0, nPolyCount = mpImplPolyPolygon->mnCount; i < nPolyCount; i++ )
+ {
+ if( bEdges )
+ {
+ mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( POLY_OPTIMIZE_NO_SAME );
+ Polygon::ImplReduceEdges( *( mpImplPolyPolygon->mpPolyAry[ i ] ), fArea, nPercent );
+ }
+
+ if( nOptimizeFlags )
+ mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( nOptimizeFlags, pData );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::AdaptiveSubdivide( PolyPolygon& rResult, const double d ) const
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ rResult.Clear();
+
+ Polygon aPolygon;
+
+ for( USHORT i = 0; i < mpImplPolyPolygon->mnCount; i++ )
+ {
+ mpImplPolyPolygon->mpPolyAry[ i ]->AdaptiveSubdivide( aPolygon, d );
+ rResult.Insert( aPolygon );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
+{
+ ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_INT );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
+{
+ ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_UNION );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
+{
+ ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_DIFF );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
+{
+ ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_XOR );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::ImplDoOperation( const PolyPolygon& rPolyPoly, PolyPolygon& rResult, ULONG nOperation ) const
+{
+ // Convert to B2DPolyPolygon, temporarily. It might be
+ // advantageous in the future, to have a PolyPolygon adaptor that
+ // just simulates a B2DPolyPolygon here...
+ basegfx::B2DPolyPolygon aMergePolyPolygonA( getB2DPolyPolygon() );
+ basegfx::B2DPolyPolygon aMergePolyPolygonB( rPolyPoly.getB2DPolyPolygon() );
+
+ // normalize the two polypolygons before. Force properly oriented
+ // polygons.
+ aMergePolyPolygonA = basegfx::tools::prepareForPolygonOperation( aMergePolyPolygonA );
+ aMergePolyPolygonB = basegfx::tools::prepareForPolygonOperation( aMergePolyPolygonB );
+
+ switch( nOperation )
+ {
+ // All code extracted from svx/source/svdraw/svedtv2.cxx
+ // -----------------------------------------------------
+
+ case POLY_CLIP_UNION:
+ {
+ // merge A and B (OR)
+ aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB);
+ break;
+ }
+
+ case POLY_CLIP_DIFF:
+ {
+ // substract B from A (DIFF)
+ aMergePolyPolygonA = basegfx::tools::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB);
+ break;
+ }
+
+ case POLY_CLIP_XOR:
+ {
+ // compute XOR between poly A and B
+ aMergePolyPolygonA = basegfx::tools::solvePolygonOperationXor(aMergePolyPolygonA, aMergePolyPolygonB);
+ break;
+ }
+
+ default:
+ case POLY_CLIP_INT:
+ {
+ // cut poly 1 against polys 2..n (AND)
+ aMergePolyPolygonA = basegfx::tools::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB);
+ break;
+ }
+ }
+
+ rResult = PolyPolygon( aMergePolyPolygonA );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT PolyPolygon::Count() const
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ return mpImplPolyPolygon->mnCount;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Move( long nHorzMove, long nVertMove )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ // Diese Abfrage sollte man fuer die DrawEngine durchfuehren
+ if( nHorzMove || nVertMove )
+ {
+ // Referenzcounter beruecksichtigen
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Punkte verschieben
+ USHORT nPolyCount = mpImplPolyPolygon->mnCount;
+ for ( USHORT i = 0; i < nPolyCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[i]->Move( nHorzMove, nVertMove );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Translate( const Point& rTrans )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ // Referenzcounter beruecksichtigen
+ if( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Punkte verschieben
+ for ( USHORT i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[ i ]->Translate( rTrans );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Scale( double fScaleX, double fScaleY )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ // Referenzcounter beruecksichtigen
+ if( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Punkte verschieben
+ for ( USHORT i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[ i ]->Scale( fScaleX, fScaleY );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Rotate( const Point& rCenter, USHORT nAngle10 )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ nAngle10 %= 3600;
+
+ if( nAngle10 )
+ {
+ const double fAngle = F_PI1800 * nAngle10;
+ Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Rotate( const Point& rCenter, double fSin, double fCos )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ // Referenzcounter beruecksichtigen
+ if( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Punkte verschieben
+ for ( USHORT i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[ i ]->Rotate( rCenter, fSin, fCos );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::SlantX( long nYRef, double fSin, double fCos )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ // Referenzcounter beruecksichtigen
+ if( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Punkte verschieben
+ for ( USHORT i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[ i ]->SlantX( nYRef, fSin, fCos );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::SlantY( long nXRef, double fSin, double fCos )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ // Referenzcounter beruecksichtigen
+ if( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Punkte verschieben
+ for ( USHORT i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[ i ]->SlantY( nXRef, fSin, fCos );
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ // Referenzcounter beruecksichtigen
+ if( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Punkte verschieben
+ for ( USHORT i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[ i ]->Distort( rRefRect, rDistortedRect );
+}
+
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Clip( const Rectangle& rRect )
+{
+ // Polygon-Clippen
+ USHORT nPolyCount = mpImplPolyPolygon->mnCount;
+ USHORT i;
+
+ if ( !nPolyCount )
+ return;
+
+ // Referenzcounter beruecksichtigen
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ // Erst jedes Polygon Clippen und dann die leeren entfernen
+ for ( i = 0; i < nPolyCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[i]->Clip( rRect );
+ while ( nPolyCount )
+ {
+ if ( GetObject( nPolyCount-1 ).GetSize() <= 2 )
+ Remove( nPolyCount-1 );
+ nPolyCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle PolyPolygon::GetBoundRect() const
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+
+ long nXMin=0, nXMax=0, nYMin=0, nYMax=0;
+ BOOL bFirst = TRUE;
+ USHORT nPolyCount = mpImplPolyPolygon->mnCount;
+
+ for ( USHORT n = 0; n < nPolyCount; n++ )
+ {
+ const Polygon* pPoly = mpImplPolyPolygon->mpPolyAry[n];
+ const Point* pAry = pPoly->GetConstPointAry();
+ USHORT nPointCount = pPoly->GetSize();
+
+ for ( USHORT i = 0; i < nPointCount; i++ )
+ {
+ const Point* pPt = &pAry[ i ];
+
+ if ( bFirst )
+ {
+ nXMin = nXMax = pPt->X();
+ nYMin = nYMax = pPt->Y();
+ bFirst = FALSE;
+ }
+ else
+ {
+ if ( pPt->X() < nXMin )
+ nXMin = pPt->X();
+ if ( pPt->X() > nXMax )
+ nXMax = pPt->X();
+ if ( pPt->Y() < nYMin )
+ nYMin = pPt->Y();
+ if ( pPt->Y() > nYMax )
+ nYMax = pPt->Y();
+ }
+ }
+ }
+
+ if ( !bFirst )
+ return Rectangle( nXMin, nYMin, nXMax, nYMax );
+ else
+ return Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+Polygon& PolyPolygon::operator[]( USHORT nPos )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ DBG_ASSERT( nPos < Count(), "PolyPolygon::[](): nPos >= nSize" );
+
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ {
+ mpImplPolyPolygon->mnRefCount--;
+ mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
+ }
+
+ return *(mpImplPolyPolygon->mpPolyAry[nPos]);
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon& PolyPolygon::operator=( const PolyPolygon& rPolyPoly )
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
+ DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
+
+ rPolyPoly.mpImplPolyPolygon->mnRefCount++;
+
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ mpImplPolyPolygon->mnRefCount--;
+ else
+ delete mpImplPolyPolygon;
+
+ mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PolyPolygon::operator==( const PolyPolygon& rPolyPoly ) const
+{
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
+
+ if ( rPolyPoly.mpImplPolyPolygon == mpImplPolyPolygon )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PolyPolygon::IsEqual( const PolyPolygon& rPolyPoly ) const
+{
+ sal_Bool bIsEqual = sal_True;
+ if ( Count() != rPolyPoly.Count() )
+ bIsEqual = sal_False;
+ else
+ {
+ sal_uInt16 i;
+ for ( i = 0; i < Count(); i++ )
+ {
+ if (!GetObject( i ).IsEqual( rPolyPoly.GetObject( i ) ) )
+ {
+ bIsEqual = sal_False;
+ break;
+ }
+ }
+ }
+ return bIsEqual;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStream, PolyPolygon& rPolyPoly )
+{
+ DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
+ DBG_ASSERTWARNING( rIStream.GetVersion(), "PolyPolygon::>> - Solar-Version not set on rIStream" );
+
+ Polygon* pPoly;
+ USHORT nPolyCount;
+
+ // Anzahl der Polygone einlesen
+ rIStream >> nPolyCount;
+
+ // Daten anlegen
+ if( nPolyCount )
+ {
+ // Referenzcounter beruecksichtigen
+ if ( rPolyPoly.mpImplPolyPolygon->mnRefCount > 1 )
+ rPolyPoly.mpImplPolyPolygon->mnRefCount--;
+ else
+ delete rPolyPoly.mpImplPolyPolygon;
+
+ rPolyPoly.mpImplPolyPolygon = new ImplPolyPolygon( nPolyCount );
+
+ for ( USHORT i = 0; i < nPolyCount; i++ )
+ {
+ pPoly = new Polygon;
+ rIStream >> *pPoly;
+ rPolyPoly.mpImplPolyPolygon->mpPolyAry[i] = pPoly;
+ }
+ }
+ else
+ rPolyPoly = PolyPolygon();
+
+ return rIStream;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const PolyPolygon& rPolyPoly )
+{
+ DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
+ DBG_ASSERTWARNING( rOStream.GetVersion(), "PolyPolygon::<< - Solar-Version not set on rOStream" );
+
+ // Anzahl der Polygone rausschreiben
+ USHORT nPolyCount = rPolyPoly.mpImplPolyPolygon->mnCount;
+ rOStream << nPolyCount;
+
+ // Die einzelnen Polygone ausgeben
+ for ( USHORT i = 0; i < nPolyCount; i++ )
+ rOStream << *(rPolyPoly.mpImplPolyPolygon->mpPolyAry[i]);
+
+ return rOStream;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Read( SvStream& rIStream )
+{
+ VersionCompat aCompat( rIStream, STREAM_READ );
+
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ DBG_ASSERTWARNING( rIStream.GetVersion(), "PolyPolygon::>> - Solar-Version not set on rIStream" );
+
+ Polygon* pPoly;
+ USHORT nPolyCount;
+
+ // Anzahl der Polygone einlesen
+ rIStream >> nPolyCount;
+
+ // Daten anlegen
+ if( nPolyCount )
+ {
+ // Referenzcounter beruecksichtigen
+ if ( mpImplPolyPolygon->mnRefCount > 1 )
+ mpImplPolyPolygon->mnRefCount--;
+ else
+ delete mpImplPolyPolygon;
+
+ mpImplPolyPolygon = new ImplPolyPolygon( nPolyCount );
+
+ for ( USHORT i = 0; i < nPolyCount; i++ )
+ {
+ pPoly = new Polygon;
+ pPoly->ImplRead( rIStream );
+ mpImplPolyPolygon->mpPolyAry[i] = pPoly;
+ }
+ }
+ else
+ *this = PolyPolygon();
+}
+
+// -----------------------------------------------------------------------
+
+void PolyPolygon::Write( SvStream& rOStream ) const
+{
+ VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
+
+ DBG_CHKTHIS( PolyPolygon, NULL );
+ DBG_ASSERTWARNING( rOStream.GetVersion(), "PolyPolygon::<< - Solar-Version not set on rOStream" );
+
+ // Anzahl der Polygone rausschreiben
+ USHORT nPolyCount = mpImplPolyPolygon->mnCount;
+ rOStream << nPolyCount;
+
+ // Die einzelnen Polygone ausgeben
+ for ( USHORT i = 0; i < nPolyCount; i++ )
+ mpImplPolyPolygon->mpPolyAry[i]->ImplWrite( rOStream );;
+}
+
+// -----------------------------------------------------------------------
+// convert to basegfx::B2DPolyPolygon and return
+basegfx::B2DPolyPolygon PolyPolygon::getB2DPolyPolygon() const
+{
+ basegfx::B2DPolyPolygon aRetval;
+
+ for(sal_uInt16 a(0); a < mpImplPolyPolygon->mnCount; a++)
+ {
+ Polygon* pCandidate = mpImplPolyPolygon->mpPolyAry[a];
+ aRetval.append(pCandidate->getB2DPolygon());
+ }
+
+ return aRetval;
+}
+
+// -----------------------------------------------------------------------
+// constructor to convert from basegfx::B2DPolyPolygon
+PolyPolygon::PolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ DBG_CTOR( PolyPolygon, NULL );
+ const sal_uInt16 nCount(sal_uInt16(rPolyPolygon.count()));
+ DBG_ASSERT(sal_uInt32(nCount) == rPolyPolygon.count(),
+ "PolyPolygon::PolyPolygon: Too many sub-polygons in given basegfx::B2DPolyPolygon (!)");
+
+ if ( nCount )
+ {
+ mpImplPolyPolygon = new ImplPolyPolygon( nCount );
+
+ for(sal_uInt16 a(0); a < nCount; a++)
+ {
+ basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(sal_uInt32(a)));
+ mpImplPolyPolygon->mpPolyAry[a] = new Polygon( aCandidate );
+ }
+ }
+ else
+ {
+ mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
+ }
+}
+
+// eof
diff --git a/tools/source/generic/svborder.cxx b/tools/source/generic/svborder.cxx
new file mode 100644
index 000000000000..eb254faf2310
--- /dev/null
+++ b/tools/source/generic/svborder.cxx
@@ -0,0 +1,77 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/svborder.hxx>
+#include <osl/diagnose.h>
+
+SvBorder::SvBorder( const Rectangle & rOuter, const Rectangle & rInner )
+{
+ Rectangle aOuter( rOuter );
+ aOuter.Justify();
+ Rectangle aInner( rInner );
+ if( aInner.IsEmpty() )
+ aInner = Rectangle( aOuter.Center(), aOuter.Center() );
+ else
+ aInner.Justify();
+
+ OSL_ENSURE( aOuter.IsInside( aInner ),
+ "SvBorder::SvBorder: FALSE == aOuter.IsInside( aInner )" );
+ nTop = aInner.Top() - aOuter.Top();
+ nRight = aOuter.Right() - aInner.Right();
+ nBottom = aOuter.Bottom() - aInner.Bottom();
+ nLeft = aInner.Left() - aOuter.Left();
+}
+
+Rectangle & operator += ( Rectangle & rRect, const SvBorder & rBorder )
+{
+ // wegen Empty-Rect, GetSize muss als erstes gerufen werden
+ Size aS( rRect.GetSize() );
+ aS.Width() += rBorder.Left() + rBorder.Right();
+ aS.Height() += rBorder.Top() + rBorder.Bottom();
+
+ rRect.Left() -= rBorder.Left();
+ rRect.Top() -= rBorder.Top();
+ rRect.SetSize( aS );
+ return rRect;
+}
+
+Rectangle & operator -= ( Rectangle & rRect, const SvBorder & rBorder )
+{
+ // wegen Empty-Rect, GetSize muss als erstes gerufen werden
+ Size aS( rRect.GetSize() );
+ aS.Width() -= rBorder.Left() + rBorder.Right();
+ aS.Height() -= rBorder.Top() + rBorder.Bottom();
+
+ rRect.Left() += rBorder.Left();
+ rRect.Top() += rBorder.Top();
+ rRect.SetSize( aS );
+ return rRect;
+}
+
diff --git a/tools/source/generic/svlibrary.cxx b/tools/source/generic/svlibrary.cxx
new file mode 100644
index 000000000000..6ebfd0086b5c
--- /dev/null
+++ b/tools/source/generic/svlibrary.cxx
@@ -0,0 +1,129 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/svlibrary.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/util/XMacroExpander.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/processfactory.hxx>
+#include <tools/string.hxx>
+#include <rtl/uri.hxx>
+
+using namespace com::sun::star;
+
+static uno::Sequence< rtl::OUString > GetMultiPaths_Impl()
+{
+ uno::Sequence< rtl::OUString > aRes;
+ uno::Sequence< rtl::OUString > aInternalPaths;
+ uno::Sequence< rtl::OUString > aUserPaths;
+
+ bool bSuccess = true;
+ uno::Reference< lang::XMultiServiceFactory > xMgr( comphelper::getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ try
+ {
+ String aInternal;
+ aInternal.AppendAscii("Libraries");
+ String aUser;
+ aUser.AppendAscii("Libraries");
+ aInternal .AppendAscii( "_internal" );
+ aUser .AppendAscii( "_user" );
+
+ uno::Reference< beans::XPropertySet > xPathSettings( xMgr->createInstance(
+ rtl::OUString::createFromAscii( "com.sun.star.util.PathSettings" ) ), uno::UNO_QUERY_THROW );
+ xPathSettings->getPropertyValue( aInternal ) >>= aInternalPaths;
+ xPathSettings->getPropertyValue( aUser ) >>= aUserPaths;
+ }
+ catch (uno::Exception &)
+ {
+ bSuccess = false;
+ }
+ }
+ if (bSuccess)
+ {
+ sal_Int32 nMaxEntries = aInternalPaths.getLength() + aUserPaths.getLength();
+ aRes.realloc( nMaxEntries );
+ rtl::OUString *pRes = aRes.getArray();
+ sal_Int32 nCount = 0; // number of actually added entries
+ for (int i = 0; i < 2; ++i)
+ {
+ const uno::Sequence< rtl::OUString > &rPathSeq = i == 0 ? aUserPaths : aInternalPaths;
+ const rtl::OUString *pPathSeq = rPathSeq.getConstArray();
+ for (sal_Int32 k = 0; k < rPathSeq.getLength(); ++k)
+ {
+ const bool bAddUser = (&rPathSeq == &aUserPaths);
+ const bool bAddInternal = (&rPathSeq == &aInternalPaths);
+ if ((bAddUser || bAddInternal) && pPathSeq[k].getLength() > 0)
+ pRes[ nCount++ ] = pPathSeq[k];
+ }
+ }
+ aRes.realloc( nCount );
+ }
+
+ return aRes;
+}
+
+bool SvLibrary::LoadModule( osl::Module& rModule, const rtl::OUString& rLibName, ::oslGenericFunction baseModule, ::sal_Int32 mode )
+{
+ static uno::Sequence < rtl::OUString > aPaths = GetMultiPaths_Impl();
+ bool bLoaded = false;
+
+ for (sal_Int32 n=0; n<aPaths.getLength(); n++)
+ {
+ rtl::OUString aMod = aPaths[n];
+ if ( aPaths[n].indexOfAsciiL("vnd.sun.star.expand",19) == 0)
+ {
+ uno::Reference< uno::XComponentContext > xComponentContext = comphelper::getProcessComponentContext();
+ uno::Reference< util::XMacroExpander > xMacroExpander;
+ xComponentContext->getValueByName(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.util.theMacroExpander") ) )
+ >>= xMacroExpander;
+
+ aMod = aMod.copy( sizeof("vnd.sun.star.expand:") -1 );
+ aMod = ::rtl::Uri::decode( aMod, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
+ aMod = xMacroExpander->expandMacros( aMod );
+ }
+
+ aMod += ::rtl::OUString( sal_Unicode('/') );
+ aMod += rLibName;
+ bLoaded = rModule.load( aMod, mode );
+ if ( bLoaded )
+ break;
+ }
+
+ if (!bLoaded )
+ bLoaded = rModule.loadRelative( baseModule, rLibName, mode );
+
+ return bLoaded;
+}
diff --git a/tools/source/generic/toolsin.cxx b/tools/source/generic/toolsin.cxx
new file mode 100644
index 000000000000..50c9c0187b16
--- /dev/null
+++ b/tools/source/generic/toolsin.cxx
@@ -0,0 +1,95 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _TOOLS_TOOLSIN_CXX
+
+#include <string.h>
+#include <tools/shl.hxx>
+#include <tools/debug.hxx>
+#include <toolsin.hxx>
+
+#if defined WNT || defined OS2
+#include <dll.hxx>
+#endif
+
+void ImplDeleteCharTabData();
+
+// =======================================================================
+
+TOOLSINDATA* ImplGetToolsInData()
+{
+ TOOLSINDATA** ppData = (TOOLSINDATA**)GetAppData( SHL_TOOLS );
+ if ( !(*ppData) )
+ {
+ TOOLSINDATA* pData = new TOOLSINDATA;
+ memset( pData, 0, sizeof( TOOLSINDATA ) );
+ *ppData = pData;
+ }
+
+ return *ppData;
+}
+
+// =======================================================================
+
+void InitTools()
+{
+ DBG_DEBUGSTART();
+}
+
+// -----------------------------------------------------------------------
+
+void DeInitTools()
+{
+ TOOLSINDATA** ppData = (TOOLSINDATA**)GetAppData( SHL_TOOLS );
+ TOOLSINDATA* pData = *ppData;
+
+ if ( pData )
+ {
+ ImplDeleteCharTabData();
+ delete pData;
+ *ppData = NULL;
+ }
+
+ DBG_DEBUGEND();
+}
+
+// -----------------------------------------------------------------------
+
+void GlobalDeInitTools()
+{
+ DBG_GLOBALDEBUGEND();
+
+#if defined WNT
+ ImpDeInitWinTools();
+#endif
+#ifdef OS2
+ ImpDeInitOS2Tools();
+#endif
+}
diff --git a/tools/source/inet/inetmime.cxx b/tools/source/inet/inetmime.cxx
new file mode 100644
index 000000000000..5324e9be07b8
--- /dev/null
+++ b/tools/source/inet/inetmime.cxx
@@ -0,0 +1,4563 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <cstddef>
+#include <limits>
+
+#include "rtl/tencinfo.h"
+#include <tools/datetime.hxx>
+#include <tools/inetmime.hxx>
+
+namespace unnamed_tools_inetmime {} using namespace unnamed_tools_inetmime;
+ // unnamed namespaces don't work well yet
+
+//============================================================================
+namespace unnamed_tools_inetmime {
+
+class Charset
+{
+ rtl_TextEncoding m_eEncoding;
+ const sal_uInt32 * m_pRanges;
+
+public:
+ inline Charset(rtl_TextEncoding eTheEncoding,
+ const sal_uInt32 * pTheRanges);
+
+ rtl_TextEncoding getEncoding() const { return m_eEncoding; }
+
+ bool contains(sal_uInt32 nChar) const;
+};
+
+inline Charset::Charset(rtl_TextEncoding eTheEncoding,
+ const sal_uInt32 * pTheRanges):
+ m_eEncoding(eTheEncoding),
+ m_pRanges(pTheRanges)
+{
+ DBG_ASSERT(m_pRanges, "Charset::Charset(): Bad ranges");
+}
+
+//============================================================================
+void appendISO88591(UniString & rText, sal_Char const * pBegin,
+ sal_Char const * pEnd);
+
+}
+
+//============================================================================
+class INetMIMECharsetList_Impl
+{
+ struct Node
+ {
+ Charset m_aCharset;
+ bool m_bDisabled;
+ Node * m_pNext;
+
+ inline Node(const Charset & rTheCharset, bool bTheDisabled,
+ Node * pTheNext);
+ };
+
+ Node * m_pFirst;
+
+public:
+ INetMIMECharsetList_Impl(): m_pFirst(0) {}
+
+ ~INetMIMECharsetList_Impl();
+
+ void prepend(const Charset & rCharset)
+ { m_pFirst = new Node(rCharset, false, m_pFirst); }
+
+ void includes(sal_uInt32 nChar);
+
+ rtl_TextEncoding getPreferredEncoding(rtl_TextEncoding eDefault
+ = RTL_TEXTENCODING_DONTKNOW)
+ const;
+
+ void reset();
+};
+
+inline INetMIMECharsetList_Impl::Node::Node(const Charset & rTheCharset,
+ bool bTheDisabled,
+ Node * pTheNext):
+ m_aCharset(rTheCharset),
+ m_bDisabled(bTheDisabled),
+ m_pNext(pTheNext)
+{}
+
+//============================================================================
+namespace unnamed_tools_inetmime {
+
+struct Parameter
+{
+ Parameter * m_pNext;
+ ByteString m_aAttribute;
+ ByteString m_aCharset;
+ ByteString m_aLanguage;
+ ByteString m_aValue;
+ sal_uInt32 m_nSection;
+ bool m_bExtended;
+
+ inline Parameter(Parameter * pTheNext, ByteString const & rTheAttribute,
+ ByteString const & rTheCharset,
+ ByteString const & rTheLanguage,
+ ByteString const & rTheValue, sal_uInt32 nTheSection,
+ bool bTheExtended);
+};
+
+inline Parameter::Parameter(Parameter * pTheNext,
+ ByteString const & rTheAttribute,
+ ByteString const & rTheCharset,
+ ByteString const & rTheLanguage,
+ ByteString const & rTheValue,
+ sal_uInt32 nTheSection, bool bTheExtended):
+ m_pNext(pTheNext),
+ m_aAttribute(rTheAttribute),
+ m_aCharset(rTheCharset),
+ m_aLanguage(rTheLanguage),
+ m_aValue(rTheValue),
+ m_nSection(nTheSection),
+ m_bExtended(bTheExtended)
+{}
+
+//============================================================================
+struct ParameterList
+{
+ Parameter * m_pList;
+
+ ParameterList(): m_pList(0) {}
+
+ inline ~ParameterList();
+
+ Parameter ** find(ByteString const & rAttribute, sal_uInt32 nSection,
+ bool & rPresent);
+};
+
+inline ParameterList::~ParameterList()
+{
+ while (m_pList)
+ {
+ Parameter * pNext = m_pList->m_pNext;
+ delete m_pList;
+ m_pList = pNext;
+ }
+}
+
+//============================================================================
+bool parseParameters(ParameterList const & rInput,
+ INetContentTypeParameterList * pOutput);
+
+}
+
+//============================================================================
+//
+// Charset
+//
+//============================================================================
+
+bool Charset::contains(sal_uInt32 nChar) const
+{
+ for (const sal_uInt32 * p = m_pRanges;;)
+ {
+ if (nChar < *p++)
+ return false;
+ if (nChar <= *p++)
+ return true;
+ }
+}
+
+//============================================================================
+//
+// appendISO88591
+//
+//============================================================================
+
+namespace unnamed_tools_inetmime {
+
+void appendISO88591(UniString & rText, sal_Char const * pBegin,
+ sal_Char const * pEnd)
+{
+ xub_StrLen nLength = static_cast< xub_StrLen >(pEnd - pBegin);
+ sal_Unicode * pBuffer = new sal_Unicode[nLength];
+ for (sal_Unicode * p = pBuffer; pBegin != pEnd;)
+ *p++ = sal_uChar(*pBegin++);
+ rText.Append(pBuffer, nLength);
+ delete[] pBuffer;
+}
+
+}
+
+//============================================================================
+//
+// INetMIMECharsetList_Impl
+//
+//============================================================================
+
+INetMIMECharsetList_Impl::~INetMIMECharsetList_Impl()
+{
+ while (m_pFirst)
+ {
+ Node * pRemove = m_pFirst;
+ m_pFirst = m_pFirst->m_pNext;
+ delete pRemove;
+ }
+}
+
+//============================================================================
+void INetMIMECharsetList_Impl::includes(sal_uInt32 nChar)
+{
+ for (Node * p = m_pFirst; p; p = p->m_pNext)
+ if (!(p->m_bDisabled || p->m_aCharset.contains(nChar)))
+ p->m_bDisabled = true;
+}
+
+//============================================================================
+rtl_TextEncoding
+INetMIMECharsetList_Impl::getPreferredEncoding(rtl_TextEncoding eDefault)
+ const
+{
+ for (Node * p = m_pFirst; p; p = p->m_pNext)
+ if (!p->m_bDisabled)
+ return p->m_aCharset.getEncoding();
+ return eDefault;
+}
+
+//============================================================================
+void INetMIMECharsetList_Impl::reset()
+{
+ for (Node * p = m_pFirst; p; p = p->m_pNext)
+ p->m_bDisabled = false;
+}
+
+//============================================================================
+//
+// ParameterList
+//
+//============================================================================
+
+Parameter ** ParameterList::find(ByteString const & rAttribute,
+ sal_uInt32 nSection, bool & rPresent)
+{
+ Parameter ** p = &m_pList;
+ for (; *p; p = &(*p)->m_pNext)
+ {
+ StringCompare eCompare = rAttribute.CompareTo((*p)->m_aAttribute);
+ if (eCompare == COMPARE_GREATER)
+ break;
+ else if (eCompare == COMPARE_EQUAL)
+ {
+ if (nSection > (*p)->m_nSection)
+ break;
+ else if (nSection == (*p)->m_nSection)
+ {
+ rPresent = true;
+ return p;
+ }
+ }
+ }
+ rPresent = false;
+ return p;
+}
+
+//============================================================================
+//
+// parseParameters
+//
+//============================================================================
+
+namespace unnamed_tools_inetmime {
+
+bool parseParameters(ParameterList const & rInput,
+ INetContentTypeParameterList * pOutput)
+{
+ if (pOutput)
+ pOutput->Clear();
+
+ Parameter * pPrev = 0;
+ for (Parameter * p = rInput.m_pList; p; p = p->m_pNext)
+ {
+ if (p->m_nSection > 0
+ && (!pPrev
+ || pPrev->m_nSection != p->m_nSection - 1
+ || pPrev->m_aAttribute != p->m_aAttribute))
+ return false;
+ pPrev = p;
+ }
+
+ if (pOutput)
+ for (Parameter * p = rInput.m_pList; p;)
+ {
+ bool bCharset = p->m_aCharset.Len() != 0;
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
+ if (bCharset)
+ eEncoding
+ = INetMIME::getCharsetEncoding(p->m_aCharset.GetBuffer(),
+ p->m_aCharset.GetBuffer()
+ + rInput.m_pList->
+ m_aCharset.
+ Len());
+ UniString aValue;
+ bool bBadEncoding = false;
+ Parameter * pNext = p;
+ do
+ {
+ sal_Size nSize;
+ sal_Unicode * pUnicode
+ = INetMIME::convertToUnicode(pNext->m_aValue.GetBuffer(),
+ pNext->m_aValue.GetBuffer()
+ + pNext->m_aValue.Len(),
+ bCharset && p->m_bExtended ?
+ eEncoding :
+ RTL_TEXTENCODING_UTF8,
+ nSize);
+ if (!pUnicode && !(bCharset && p->m_bExtended))
+ pUnicode = INetMIME::convertToUnicode(
+ pNext->m_aValue.GetBuffer(),
+ pNext->m_aValue.GetBuffer()
+ + pNext->m_aValue.Len(),
+ RTL_TEXTENCODING_ISO_8859_1, nSize);
+ if (!pUnicode)
+ {
+ bBadEncoding = true;
+ break;
+ }
+ aValue += UniString(pUnicode, static_cast< xub_StrLen >(nSize));
+ delete[] pUnicode;
+ pNext = pNext->m_pNext;
+ }
+ while (pNext && pNext->m_nSection > 0);
+ if (bBadEncoding)
+ {
+ aValue.Erase();
+ for (pNext = p;;)
+ {
+ if (pNext->m_bExtended)
+ for (xub_StrLen i = 0; i < pNext->m_aValue.Len(); ++i)
+ aValue += sal_Unicode(
+ sal_Unicode(
+ sal_uChar(pNext->m_aValue.GetChar(i)))
+ | 0xF800);
+ else
+ for (xub_StrLen i = 0; i < pNext->m_aValue.Len(); ++i)
+ aValue
+ += sal_Unicode(sal_uChar
+ (pNext->
+ m_aValue.GetChar(i)));
+ pNext = pNext->m_pNext;
+ if (!pNext || pNext->m_nSection == 0)
+ break;
+ };
+ }
+ pOutput->Insert(new INetContentTypeParameter(p->m_aAttribute,
+ p->m_aCharset,
+ p->m_aLanguage,
+ aValue,
+ !bBadEncoding),
+ LIST_APPEND);
+ p = pNext;
+ }
+ return true;
+}
+
+}
+
+//============================================================================
+//
+// INetMIME
+//
+//============================================================================
+
+// static
+bool INetMIME::isAtomChar(sal_uInt32 nChar)
+{
+ static const bool aMap[128]
+ = { false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, true, true, true, true, true, // !"#$%&'
+ false, false, true, true, false, true, false, true, //()*+,-./
+ true, true, true, true, true, true, true, true, //01234567
+ true, true, false, false, false, true, false, true, //89:;<=>?
+ false, true, true, true, true, true, true, true, //@ABCDEFG
+ true, true, true, true, true, true, true, true, //HIJKLMNO
+ true, true, true, true, true, true, true, true, //PQRSTUVW
+ true, true, true, false, false, false, true, true, //XYZ[\]^_
+ true, true, true, true, true, true, true, true, //`abcdefg
+ true, true, true, true, true, true, true, true, //hijklmno
+ true, true, true, true, true, true, true, true, //pqrstuvw
+ true, true, true, true, true, true, true, false //xyz{|}~
+ };
+ return isUSASCII(nChar) && aMap[nChar];
+}
+
+//============================================================================
+// static
+bool INetMIME::isTokenChar(sal_uInt32 nChar)
+{
+ static const sal_Char aMap[128]
+ = { false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, true, true, true, true, true, // !"#$%&'
+ false, false, true, true, false, true, true, false, //()*+,-./
+ true, true, true, true, true, true, true, true, //01234567
+ true, true, false, false, false, false, false, false, //89:;<=>?
+ false, true, true, true, true, true, true, true, //@ABCDEFG
+ true, true, true, true, true, true, true, true, //HIJKLMNO
+ true, true, true, true, true, true, true, true, //PQRSTUVW
+ true, true, true, false, false, false, true, true, //XYZ[\]^_
+ true, true, true, true, true, true, true, true, //`abcdefg
+ true, true, true, true, true, true, true, true, //hijklmno
+ true, true, true, true, true, true, true, true, //pqrstuvw
+ true, true, true, true, true, true, true, false //xyz{|}~
+ };
+ return isUSASCII(nChar) && aMap[nChar];
+}
+
+//============================================================================
+// static
+bool INetMIME::isEncodedWordTokenChar(sal_uInt32 nChar)
+{
+ static const sal_Char aMap[128]
+ = { false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, true, true, true, true, true, // !"#$%&'
+ false, false, true, true, false, true, false, false, //()*+,-./
+ true, true, true, true, true, true, true, true, //01234567
+ true, true, false, false, false, false, false, false, //89:;<=>?
+ false, true, true, true, true, true, true, true, //@ABCDEFG
+ true, true, true, true, true, true, true, true, //HIJKLMNO
+ true, true, true, true, true, true, true, true, //PQRSTUVW
+ true, true, true, false, false, false, true, true, //XYZ[\]^_
+ true, true, true, true, true, true, true, true, //`abcdefg
+ true, true, true, true, true, true, true, true, //hijklmno
+ true, true, true, true, true, true, true, true, //pqrstuvw
+ true, true, true, true, true, true, true, false //xyz{|}~
+ };
+ return isUSASCII(nChar) && aMap[nChar];
+}
+
+//============================================================================
+// static
+bool INetMIME::isIMAPAtomChar(sal_uInt32 nChar)
+{
+ static const sal_Char aMap[128]
+ = { false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, true, true, false, true, true, // !"#$%&'
+ false, false, false, true, true, true, true, true, //()*+,-./
+ true, true, true, true, true, true, true, true, //01234567
+ true, true, true, true, true, true, true, true, //89:;<=>?
+ true, true, true, true, true, true, true, true, //@ABCDEFG
+ true, true, true, true, true, true, true, true, //HIJKLMNO
+ true, true, true, true, true, true, true, true, //PQRSTUVW
+ true, true, true, true, false, true, true, true, //XYZ[\]^_
+ true, true, true, true, true, true, true, true, //`abcdefg
+ true, true, true, true, true, true, true, true, //hijklmno
+ true, true, true, true, true, true, true, true, //pqrstuvw
+ true, true, true, false, true, true, true, false //xyz{|}~
+ };
+ return isUSASCII(nChar) && aMap[nChar];
+}
+
+//============================================================================
+// static
+sal_uInt32 INetMIME::getDigit(int nWeight)
+{
+ DBG_ASSERT(nWeight >= 0 && nWeight < 10,
+ "INetMIME::getDigit(): Bad weight");
+
+ static const sal_Char aDigits[16]
+ = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
+ return aDigits[nWeight];
+}
+
+//============================================================================
+// static
+sal_uInt32 INetMIME::getHexDigit(int nWeight)
+{
+ DBG_ASSERT(nWeight >= 0 && nWeight < 16,
+ "INetMIME::getHexDigit(): Bad weight");
+
+ static const sal_Char aDigits[16]
+ = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
+ 'D', 'E', 'F' };
+ return aDigits[nWeight];
+}
+
+//============================================================================
+// static
+sal_uInt32 INetMIME::getBase64Digit(int nWeight)
+{
+ DBG_ASSERT(nWeight >= 0 && nWeight < 64,
+ "INetMIME::getBase64Digit(): Bad weight");
+
+ static const sal_Char aDigits[64]
+ = { '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', '+', '/' };
+ return aDigits[nWeight];
+}
+
+//============================================================================
+// static
+bool INetMIME::equalIgnoreCase(const sal_Char * pBegin1,
+ const sal_Char * pEnd1,
+ const sal_Char * pBegin2,
+ const sal_Char * pEnd2)
+{
+ DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pBegin2 && pBegin2 <= pEnd2,
+ "INetMIME::equalIgnoreCase(): Bad sequences");
+
+ if (pEnd1 - pBegin1 != pEnd2 - pBegin2)
+ return false;
+ while (pBegin1 != pEnd1)
+ if (toUpperCase(*pBegin1++) != toUpperCase(*pBegin2++))
+ return false;
+ return true;
+}
+
+//============================================================================
+// static
+bool INetMIME::equalIgnoreCase(const sal_Char * pBegin1,
+ const sal_Char * pEnd1,
+ const sal_Char * pString2)
+{
+ DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pString2,
+ "INetMIME::equalIgnoreCase(): Bad sequences");
+
+ while (*pString2 != 0)
+ if (pBegin1 == pEnd1
+ || toUpperCase(*pBegin1++) != toUpperCase(*pString2++))
+ return false;
+ return pBegin1 == pEnd1;
+}
+
+//============================================================================
+// static
+bool INetMIME::equalIgnoreCase(const sal_Unicode * pBegin1,
+ const sal_Unicode * pEnd1,
+ const sal_Char * pString2)
+{
+ DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pString2,
+ "INetMIME::equalIgnoreCase(): Bad sequences");
+
+ while (*pString2 != 0)
+ if (pBegin1 == pEnd1
+ || toUpperCase(*pBegin1++) != toUpperCase(*pString2++))
+ return false;
+ return pBegin1 == pEnd1;
+}
+
+//============================================================================
+// static
+const sal_Char * INetMIME::skipLinearWhiteSpace(const sal_Char * pBegin,
+ const sal_Char * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::skipLinearWhiteSpace(): Bad sequence");
+
+ while (pBegin != pEnd)
+ switch (*pBegin)
+ {
+ case '\t':
+ case ' ':
+ ++pBegin;
+ break;
+
+ case 0x0D: // CR
+ if (startsWithLineFolding(pBegin, pEnd))
+ pBegin += 3;
+ else
+ return pBegin;
+ break;
+
+ default:
+ return pBegin;
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Unicode * INetMIME::skipLinearWhiteSpace(const sal_Unicode * pBegin,
+ const sal_Unicode * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::skipLinearWhiteSpace(): Bad sequence");
+
+ while (pBegin != pEnd)
+ switch (*pBegin)
+ {
+ case '\t':
+ case ' ':
+ ++pBegin;
+ break;
+
+ case 0x0D: // CR
+ if (startsWithLineFolding(pBegin, pEnd))
+ pBegin += 3;
+ else
+ return pBegin;
+ break;
+
+ default:
+ return pBegin;
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Char * INetMIME::skipComment(const sal_Char * pBegin,
+ const sal_Char * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::skipComment(): Bad sequence");
+
+ if (pBegin != pEnd && *pBegin == '(')
+ {
+ sal_uInt32 nLevel = 0;
+ for (const sal_Char * p = pBegin; p != pEnd;)
+ switch (*p++)
+ {
+ case '(':
+ ++nLevel;
+ break;
+
+ case ')':
+ if (--nLevel == 0)
+ return p;
+ break;
+
+ case '\\':
+ if (p != pEnd)
+ ++p;
+ break;
+ }
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Unicode * INetMIME::skipComment(const sal_Unicode * pBegin,
+ const sal_Unicode * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::skipComment(): Bad sequence");
+
+ if (pBegin != pEnd && *pBegin == '(')
+ {
+ sal_uInt32 nLevel = 0;
+ for (const sal_Unicode * p = pBegin; p != pEnd;)
+ switch (*p++)
+ {
+ case '(':
+ ++nLevel;
+ break;
+
+ case ')':
+ if (--nLevel == 0)
+ return p;
+ break;
+
+ case '\\':
+ if (p != pEnd)
+ ++p;
+ break;
+ }
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Char * INetMIME::skipLinearWhiteSpaceComment(const sal_Char *
+ pBegin,
+ const sal_Char * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::skipLinearWhiteSpaceComment(): Bad sequence");
+
+ while (pBegin != pEnd)
+ switch (*pBegin)
+ {
+ case '\t':
+ case ' ':
+ ++pBegin;
+ break;
+
+ case 0x0D: // CR
+ if (startsWithLineFolding(pBegin, pEnd))
+ pBegin += 3;
+ else
+ return pBegin;
+ break;
+
+ case '(':
+ {
+ const sal_Char * p = skipComment(pBegin, pEnd);
+ if (p == pBegin)
+ return pBegin;
+ pBegin = p;
+ break;
+ }
+
+ default:
+ return pBegin;
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Unicode * INetMIME::skipLinearWhiteSpaceComment(const sal_Unicode *
+ pBegin,
+ const sal_Unicode *
+ pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::skipLinearWhiteSpaceComment(): Bad sequence");
+
+ while (pBegin != pEnd)
+ switch (*pBegin)
+ {
+ case '\t':
+ case ' ':
+ ++pBegin;
+ break;
+
+ case 0x0D: // CR
+ if (startsWithLineFolding(pBegin, pEnd))
+ pBegin += 3;
+ else
+ return pBegin;
+ break;
+
+ case '(':
+ {
+ const sal_Unicode * p = skipComment(pBegin, pEnd);
+ if (p == pBegin)
+ return pBegin;
+ pBegin = p;
+ break;
+ }
+
+ default:
+ return pBegin;
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Char * INetMIME::skipQuotedString(const sal_Char * pBegin,
+ const sal_Char * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::skipQuotedString(): Bad sequence");
+
+ if (pBegin != pEnd && *pBegin == '"')
+ for (const sal_Char * p = pBegin + 1; p != pEnd;)
+ switch (*p++)
+ {
+ case 0x0D: // CR
+ if (pEnd - p < 2 || *p++ != 0x0A // LF
+ || !isWhiteSpace(*p++))
+ return pBegin;
+ break;
+
+ case '"':
+ return p;
+
+ case '\\':
+ if (p != pEnd)
+ ++p;
+ break;
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Unicode * INetMIME::skipQuotedString(const sal_Unicode * pBegin,
+ const sal_Unicode * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::skipQuotedString(): Bad sequence");
+
+ if (pBegin != pEnd && *pBegin == '"')
+ for (const sal_Unicode * p = pBegin + 1; p != pEnd;)
+ switch (*p++)
+ {
+ case 0x0D: // CR
+ if (pEnd - p < 2 || *p++ != 0x0A // LF
+ || !isWhiteSpace(*p++))
+ return pBegin;
+ break;
+
+ case '"':
+ return p;
+
+ case '\\':
+ if (p != pEnd)
+ ++p;
+ break;
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Char * INetMIME::scanAtom(const sal_Char * pBegin,
+ const sal_Char * pEnd)
+{
+ while (pBegin != pEnd && isAtomChar(*pBegin))
+ ++pBegin;
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Unicode * INetMIME::scanAtom(const sal_Unicode * pBegin,
+ const sal_Unicode * pEnd)
+{
+ while (pBegin != pEnd && isAtomChar(*pBegin))
+ ++pBegin;
+ return pBegin;
+}
+
+//============================================================================
+// static
+bool INetMIME::scanUnsigned(const sal_Char *& rBegin, const sal_Char * pEnd,
+ bool bLeadingZeroes, sal_uInt32 & rValue)
+{
+ sal_uInt64 nTheValue = 0;
+ const sal_Char * p = rBegin;
+ for ( ; p != pEnd; ++p)
+ {
+ int nWeight = getWeight(*p);
+ if (nWeight < 0)
+ break;
+ nTheValue = 10 * nTheValue + nWeight;
+ if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
+ return false;
+ }
+ if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
+ return false;
+ rBegin = p;
+ rValue = sal_uInt32(nTheValue);
+ return true;
+}
+
+//============================================================================
+// static
+bool INetMIME::scanUnsigned(const sal_Unicode *& rBegin,
+ const sal_Unicode * pEnd, bool bLeadingZeroes,
+ sal_uInt32 & rValue)
+{
+ sal_uInt64 nTheValue = 0;
+ const sal_Unicode * p = rBegin;
+ for ( ; p != pEnd; ++p)
+ {
+ int nWeight = getWeight(*p);
+ if (nWeight < 0)
+ break;
+ nTheValue = 10 * nTheValue + nWeight;
+ if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
+ return false;
+ }
+ if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
+ return false;
+ rBegin = p;
+ rValue = sal_uInt32(nTheValue);
+ return true;
+}
+
+//============================================================================
+// static
+bool INetMIME::scanUnsignedHex(const sal_Char *& rBegin,
+ const sal_Char * pEnd, bool bLeadingZeroes,
+ sal_uInt32 & rValue)
+{
+ sal_uInt64 nTheValue = 0;
+ const sal_Char * p = rBegin;
+ for ( p = rBegin; p != pEnd; ++p)
+ {
+ int nWeight = getHexWeight(*p);
+ if (nWeight < 0)
+ break;
+ nTheValue = nTheValue << 4 | nWeight;
+ if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
+ return false;
+ }
+ if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
+ return false;
+ rBegin = p;
+ rValue = sal_uInt32(nTheValue);
+ return true;
+}
+
+//============================================================================
+// static
+bool INetMIME::scanUnsignedHex(const sal_Unicode *& rBegin,
+ const sal_Unicode * pEnd, bool bLeadingZeroes,
+ sal_uInt32 & rValue)
+{
+ sal_uInt64 nTheValue = 0;
+ const sal_Unicode * p = rBegin;
+ for ( ; p != pEnd; ++p)
+ {
+ int nWeight = getHexWeight(*p);
+ if (nWeight < 0)
+ break;
+ nTheValue = nTheValue << 4 | nWeight;
+ if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
+ return false;
+ }
+ if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
+ return false;
+ rBegin = p;
+ rValue = sal_uInt32(nTheValue);
+ return true;
+}
+
+//============================================================================
+// static
+const sal_Char * INetMIME::scanQuotedBlock(const sal_Char * pBegin,
+ const sal_Char * pEnd,
+ sal_uInt32 nOpening,
+ sal_uInt32 nClosing,
+ sal_Size & rLength,
+ bool & rModify)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::scanQuotedBlock(): Bad sequence");
+
+ if (pBegin != pEnd && static_cast< unsigned char >(*pBegin) == nOpening)
+ {
+ ++rLength;
+ ++pBegin;
+ while (pBegin != pEnd)
+ if (static_cast< unsigned char >(*pBegin) == nClosing)
+ {
+ ++rLength;
+ return ++pBegin;
+ }
+ else
+ {
+ sal_uInt32 c = *pBegin++;
+ switch (c)
+ {
+ case 0x0D: // CR
+ if (pBegin != pEnd && *pBegin == 0x0A) // LF
+ if (pEnd - pBegin >= 2 && isWhiteSpace(pBegin[1]))
+ {
+ ++rLength;
+ rModify = true;
+ pBegin += 2;
+ }
+ else
+ {
+ rLength += 3;
+ rModify = true;
+ ++pBegin;
+ }
+ else
+ ++rLength;
+ break;
+
+ case '\\':
+ ++rLength;
+ if (pBegin != pEnd)
+ {
+ if (startsWithLineBreak(pBegin, pEnd)
+ && (pEnd - pBegin < 3
+ || !isWhiteSpace(pBegin[2])))
+ {
+ rLength += 3;
+ rModify = true;
+ pBegin += 2;
+ }
+ else
+ ++pBegin;
+ }
+ break;
+
+ default:
+ ++rLength;
+ if (!isUSASCII(c))
+ rModify = true;
+ break;
+ }
+ }
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+const sal_Unicode * INetMIME::scanQuotedBlock(const sal_Unicode * pBegin,
+ const sal_Unicode * pEnd,
+ sal_uInt32 nOpening,
+ sal_uInt32 nClosing,
+ sal_Size & rLength,
+ bool & rModify)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIME::scanQuotedBlock(): Bad sequence");
+
+ if (pBegin != pEnd && *pBegin == nOpening)
+ {
+ ++rLength;
+ ++pBegin;
+ while (pBegin != pEnd)
+ if (*pBegin == nClosing)
+ {
+ ++rLength;
+ return ++pBegin;
+ }
+ else
+ {
+ sal_uInt32 c = *pBegin++;
+ switch (c)
+ {
+ case 0x0D: // CR
+ if (pBegin != pEnd && *pBegin == 0x0A) // LF
+ if (pEnd - pBegin >= 2 && isWhiteSpace(pBegin[1]))
+ {
+ ++rLength;
+ rModify = true;
+ pBegin += 2;
+ }
+ else
+ {
+ rLength += 3;
+ rModify = true;
+ ++pBegin;
+ }
+ else
+ ++rLength;
+ break;
+
+ case '\\':
+ ++rLength;
+ if (pBegin != pEnd)
+ {
+ if (startsWithLineBreak(pBegin, pEnd)
+ && (pEnd - pBegin < 3
+ || !isWhiteSpace(pBegin[2])))
+ {
+ rLength += 3;
+ rModify = true;
+ pBegin += 2;
+ }
+ else
+ ++pBegin;
+ }
+ break;
+
+ default:
+ ++rLength;
+ if (!isUSASCII(c))
+ rModify = true;
+ break;
+ }
+ }
+ }
+ return pBegin;
+}
+
+//============================================================================
+// static
+sal_Char const * INetMIME::scanParameters(sal_Char const * pBegin,
+ sal_Char const * pEnd,
+ INetContentTypeParameterList *
+ pParameters)
+{
+ ParameterList aList;
+ sal_Char const * pParameterBegin = pBegin;
+ for (sal_Char const * p = pParameterBegin;; pParameterBegin = p)
+ {
+ pParameterBegin = skipLinearWhiteSpaceComment(p, pEnd);
+ if (pParameterBegin == pEnd || *pParameterBegin != ';')
+ break;
+ p = pParameterBegin + 1;
+
+ sal_Char const * pAttributeBegin = skipLinearWhiteSpaceComment(p,
+ pEnd);
+ p = pAttributeBegin;
+ bool bDowncaseAttribute = false;
+ while (p != pEnd && isTokenChar(*p) && *p != '*')
+ {
+ bDowncaseAttribute = bDowncaseAttribute || isUpperCase(*p);
+ ++p;
+ }
+ if (p == pAttributeBegin)
+ break;
+ ByteString aAttribute(
+ pAttributeBegin, static_cast< xub_StrLen >(p - pAttributeBegin));
+ if (bDowncaseAttribute)
+ aAttribute.ToLowerAscii();
+
+ sal_uInt32 nSection = 0;
+ if (p != pEnd && *p == '*')
+ {
+ ++p;
+ if (p != pEnd && isDigit(*p)
+ && !scanUnsigned(p, pEnd, false, nSection))
+ break;
+ }
+
+ bool bPresent;
+ Parameter ** pPos = aList.find(aAttribute, nSection, bPresent);
+ if (bPresent)
+ break;
+
+ bool bExtended = false;
+ if (p != pEnd && *p == '*')
+ {
+ ++p;
+ bExtended = true;
+ }
+
+ p = skipLinearWhiteSpaceComment(p, pEnd);
+
+ if (p == pEnd || *p != '=')
+ break;
+
+ p = skipLinearWhiteSpaceComment(p + 1, pEnd);
+
+ ByteString aCharset;
+ ByteString aLanguage;
+ ByteString aValue;
+ if (bExtended)
+ {
+ if (nSection == 0)
+ {
+ sal_Char const * pCharsetBegin = p;
+ bool bDowncaseCharset = false;
+ while (p != pEnd && isTokenChar(*p) && *p != '\'')
+ {
+ bDowncaseCharset = bDowncaseCharset || isUpperCase(*p);
+ ++p;
+ }
+ if (p == pCharsetBegin)
+ break;
+ if (pParameters)
+ {
+ aCharset = ByteString(
+ pCharsetBegin,
+ static_cast< xub_StrLen >(p - pCharsetBegin));
+ if (bDowncaseCharset)
+ aCharset.ToLowerAscii();
+ }
+
+ if (p == pEnd || *p != '\'')
+ break;
+ ++p;
+
+ sal_Char const * pLanguageBegin = p;
+ bool bDowncaseLanguage = false;
+ int nLetters = 0;
+ for (; p != pEnd; ++p)
+ if (isAlpha(*p))
+ {
+ if (++nLetters > 8)
+ break;
+ bDowncaseLanguage = bDowncaseLanguage
+ || isUpperCase(*p);
+ }
+ else if (*p == '-')
+ {
+ if (nLetters == 0)
+ break;
+ nLetters = 0;
+ }
+ else
+ break;
+ if (nLetters == 0 || nLetters > 8)
+ break;
+ if (pParameters)
+ {
+ aLanguage = ByteString(
+ pLanguageBegin,
+ static_cast< xub_StrLen >(p - pLanguageBegin));
+ if (bDowncaseLanguage)
+ aLanguage.ToLowerAscii();
+ }
+
+ if (p == pEnd || *p != '\'')
+ break;
+ ++p;
+ }
+ if (pParameters)
+ while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
+ {
+ if (*p == '%')
+ {
+ if (p + 2 < pEnd)
+ {
+ int nWeight1 = getHexWeight(p[1]);
+ int nWeight2 = getHexWeight(p[2]);
+ if (nWeight1 >= 0 && nWeight2 >= 0)
+ {
+ aValue += sal_Char(nWeight1 << 4 | nWeight2);
+ p += 3;
+ continue;
+ }
+ }
+ }
+ aValue += *p++;
+ }
+ else
+ while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
+ ++p;
+ }
+ else if (p != pEnd && *p == '"')
+ if (pParameters)
+ {
+ bool bInvalid = false;
+ for (++p;;)
+ {
+ if (p == pEnd)
+ {
+ bInvalid = true;
+ break;
+ }
+ else if (*p == '"')
+ {
+ ++p;
+ break;
+ }
+ else if (*p == 0x0D) // CR
+ {
+ if (pEnd - p < 3 || p[1] != 0x0A // LF
+ || !isWhiteSpace(p[2]))
+ {
+ bInvalid = true;
+ break;
+ }
+ p += 2;
+ }
+ else if (*p == '\\' && ++p == pEnd)
+ {
+ bInvalid = true;
+ break;
+ }
+ aValue += *p++;
+ }
+ if (bInvalid)
+ break;
+ }
+ else
+ {
+ sal_Char const * pStringEnd = skipQuotedString(p, pEnd);
+ if (p == pStringEnd)
+ break;
+ p = pStringEnd;
+ }
+ else
+ {
+ sal_Char const * pTokenBegin = p;
+ while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
+ ++p;
+ if (p == pTokenBegin)
+ break;
+ if (pParameters)
+ aValue = ByteString(
+ pTokenBegin, static_cast< xub_StrLen >(p - pTokenBegin));
+ }
+
+ *pPos = new Parameter(*pPos, aAttribute, aCharset, aLanguage, aValue,
+ nSection, bExtended);
+ }
+ return parseParameters(aList, pParameters) ? pParameterBegin : pBegin;
+}
+
+//============================================================================
+// static
+sal_Unicode const * INetMIME::scanParameters(sal_Unicode const * pBegin,
+ sal_Unicode const * pEnd,
+ INetContentTypeParameterList *
+ pParameters)
+{
+ ParameterList aList;
+ sal_Unicode const * pParameterBegin = pBegin;
+ for (sal_Unicode const * p = pParameterBegin;; pParameterBegin = p)
+ {
+ pParameterBegin = skipLinearWhiteSpaceComment(p, pEnd);
+ if (pParameterBegin == pEnd || *pParameterBegin != ';')
+ break;
+ p = pParameterBegin + 1;
+
+ sal_Unicode const * pAttributeBegin
+ = skipLinearWhiteSpaceComment(p, pEnd);
+ p = pAttributeBegin;
+ bool bDowncaseAttribute = false;
+ while (p != pEnd && isTokenChar(*p) && *p != '*')
+ {
+ bDowncaseAttribute = bDowncaseAttribute || isUpperCase(*p);
+ ++p;
+ }
+ if (p == pAttributeBegin)
+ break;
+ ByteString aAttribute = ByteString(
+ pAttributeBegin, static_cast< xub_StrLen >(p - pAttributeBegin),
+ RTL_TEXTENCODING_ASCII_US);
+ if (bDowncaseAttribute)
+ aAttribute.ToLowerAscii();
+
+ sal_uInt32 nSection = 0;
+ if (p != pEnd && *p == '*')
+ {
+ ++p;
+ if (p != pEnd && isDigit(*p)
+ && !scanUnsigned(p, pEnd, false, nSection))
+ break;
+ }
+
+ bool bPresent;
+ Parameter ** pPos = aList.find(aAttribute, nSection, bPresent);
+ if (bPresent)
+ break;
+
+ bool bExtended = false;
+ if (p != pEnd && *p == '*')
+ {
+ ++p;
+ bExtended = true;
+ }
+
+ p = skipLinearWhiteSpaceComment(p, pEnd);
+
+ if (p == pEnd || *p != '=')
+ break;
+
+ p = skipLinearWhiteSpaceComment(p + 1, pEnd);
+
+ ByteString aCharset;
+ ByteString aLanguage;
+ ByteString aValue;
+ if (bExtended)
+ {
+ if (nSection == 0)
+ {
+ sal_Unicode const * pCharsetBegin = p;
+ bool bDowncaseCharset = false;
+ while (p != pEnd && isTokenChar(*p) && *p != '\'')
+ {
+ bDowncaseCharset = bDowncaseCharset || isUpperCase(*p);
+ ++p;
+ }
+ if (p == pCharsetBegin)
+ break;
+ if (pParameters)
+ {
+ aCharset = ByteString(
+ pCharsetBegin,
+ static_cast< xub_StrLen >(p - pCharsetBegin),
+ RTL_TEXTENCODING_ASCII_US);
+ if (bDowncaseCharset)
+ aCharset.ToLowerAscii();
+ }
+
+ if (p == pEnd || *p != '\'')
+ break;
+ ++p;
+
+ sal_Unicode const * pLanguageBegin = p;
+ bool bDowncaseLanguage = false;
+ int nLetters = 0;
+ for (; p != pEnd; ++p)
+ if (isAlpha(*p))
+ {
+ if (++nLetters > 8)
+ break;
+ bDowncaseLanguage = bDowncaseLanguage
+ || isUpperCase(*p);
+ }
+ else if (*p == '-')
+ {
+ if (nLetters == 0)
+ break;
+ nLetters = 0;
+ }
+ else
+ break;
+ if (nLetters == 0 || nLetters > 8)
+ break;
+ if (pParameters)
+ {
+ aLanguage = ByteString(
+ pLanguageBegin,
+ static_cast< xub_StrLen >(p - pLanguageBegin),
+ RTL_TEXTENCODING_ASCII_US);
+ if (bDowncaseLanguage)
+ aLanguage.ToLowerAscii();
+ }
+
+ if (p == pEnd || *p != '\'')
+ break;
+ ++p;
+ }
+ if (pParameters)
+ {
+ INetMIMEStringOutputSink
+ aSink(0, INetMIMEOutputSink::NO_LINE_LENGTH_LIMIT);
+ while (p != pEnd)
+ {
+ sal_uInt32 nChar = INetMIME::getUTF32Character(p, pEnd);
+ if (isUSASCII(nChar) && !isTokenChar(nChar))
+ break;
+ if (nChar == '%' && p + 1 < pEnd)
+ {
+ int nWeight1 = getHexWeight(p[0]);
+ int nWeight2 = getHexWeight(p[1]);
+ if (nWeight1 >= 0 && nWeight2 >= 0)
+ {
+ aSink << sal_Char(nWeight1 << 4 | nWeight2);
+ p += 2;
+ continue;
+ }
+ }
+ INetMIME::writeUTF8(aSink, nChar);
+ }
+ aValue = aSink.takeBuffer();
+ }
+ else
+ while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
+ ++p;
+ }
+ else if (p != pEnd && *p == '"')
+ if (pParameters)
+ {
+ INetMIMEStringOutputSink
+ aSink(0, INetMIMEOutputSink::NO_LINE_LENGTH_LIMIT);
+ bool bInvalid = false;
+ for (++p;;)
+ {
+ if (p == pEnd)
+ {
+ bInvalid = true;
+ break;
+ }
+ sal_uInt32 nChar = INetMIME::getUTF32Character(p, pEnd);
+ if (nChar == '"')
+ break;
+ else if (nChar == 0x0D) // CR
+ {
+ if (pEnd - p < 2 || *p++ != 0x0A // LF
+ || !isWhiteSpace(*p))
+ {
+ bInvalid = true;
+ break;
+ }
+ nChar = sal_uChar(*p++);
+ }
+ else if (nChar == '\\')
+ {
+ if (p == pEnd)
+ {
+ bInvalid = true;
+ break;
+ }
+ nChar = INetMIME::getUTF32Character(p, pEnd);
+ }
+ INetMIME::writeUTF8(aSink, nChar);
+ }
+ if (bInvalid)
+ break;
+ aValue = aSink.takeBuffer();
+ }
+ else
+ {
+ sal_Unicode const * pStringEnd = skipQuotedString(p, pEnd);
+ if (p == pStringEnd)
+ break;
+ p = pStringEnd;
+ }
+ else
+ {
+ sal_Unicode const * pTokenBegin = p;
+ while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
+ ++p;
+ if (p == pTokenBegin)
+ break;
+ if (pParameters)
+ aValue = ByteString(
+ pTokenBegin, static_cast< xub_StrLen >(p - pTokenBegin),
+ RTL_TEXTENCODING_UTF8);
+ }
+
+ *pPos = new Parameter(*pPos, aAttribute, aCharset, aLanguage, aValue,
+ nSection, bExtended);
+ }
+ return parseParameters(aList, pParameters) ? pParameterBegin : pBegin;
+}
+
+//============================================================================
+// static
+const sal_Char * INetMIME::getCharsetName(rtl_TextEncoding eEncoding)
+{
+ if (rtl_isOctetTextEncoding(eEncoding))
+ {
+ char const * p = rtl_getMimeCharsetFromTextEncoding(eEncoding);
+ DBG_ASSERT(p, "INetMIME::getCharsetName(): Unsupported encoding");
+ return p;
+ }
+ else
+ switch (eEncoding)
+ {
+ case RTL_TEXTENCODING_UCS4:
+ return "ISO-10646-UCS-4";
+
+ case RTL_TEXTENCODING_UCS2:
+ return "ISO-10646-UCS-2";
+
+ default:
+ DBG_ERROR("INetMIME::getCharsetName(): Unsupported encoding");
+ return 0;
+ }
+}
+
+//============================================================================
+namespace unnamed_tools_inetmime {
+
+struct EncodingEntry
+{
+ sal_Char const * m_aName;
+ rtl_TextEncoding m_eEncoding;
+};
+
+//============================================================================
+// The source for the following table is <ftp://ftp.iana.org/in-notes/iana/
+// assignments/character-sets> as of Jan, 21 2000 12:46:00, unless otherwise
+// noted:
+EncodingEntry const aEncodingMap[]
+ = { { "US-ASCII", RTL_TEXTENCODING_ASCII_US },
+ { "ANSI_X3.4-1968", RTL_TEXTENCODING_ASCII_US },
+ { "ISO-IR-6", RTL_TEXTENCODING_ASCII_US },
+ { "ANSI_X3.4-1986", RTL_TEXTENCODING_ASCII_US },
+ { "ISO_646.IRV:1991", RTL_TEXTENCODING_ASCII_US },
+ { "ASCII", RTL_TEXTENCODING_ASCII_US },
+ { "ISO646-US", RTL_TEXTENCODING_ASCII_US },
+ { "US", RTL_TEXTENCODING_ASCII_US },
+ { "IBM367", RTL_TEXTENCODING_ASCII_US },
+ { "CP367", RTL_TEXTENCODING_ASCII_US },
+ { "CSASCII", RTL_TEXTENCODING_ASCII_US },
+ { "ISO-8859-1", RTL_TEXTENCODING_ISO_8859_1 },
+ { "ISO_8859-1:1987", RTL_TEXTENCODING_ISO_8859_1 },
+ { "ISO-IR-100", RTL_TEXTENCODING_ISO_8859_1 },
+ { "ISO_8859-1", RTL_TEXTENCODING_ISO_8859_1 },
+ { "LATIN1", RTL_TEXTENCODING_ISO_8859_1 },
+ { "L1", RTL_TEXTENCODING_ISO_8859_1 },
+ { "IBM819", RTL_TEXTENCODING_ISO_8859_1 },
+ { "CP819", RTL_TEXTENCODING_ISO_8859_1 },
+ { "CSISOLATIN1", RTL_TEXTENCODING_ISO_8859_1 },
+ { "ISO-8859-2", RTL_TEXTENCODING_ISO_8859_2 },
+ { "ISO_8859-2:1987", RTL_TEXTENCODING_ISO_8859_2 },
+ { "ISO-IR-101", RTL_TEXTENCODING_ISO_8859_2 },
+ { "ISO_8859-2", RTL_TEXTENCODING_ISO_8859_2 },
+ { "LATIN2", RTL_TEXTENCODING_ISO_8859_2 },
+ { "L2", RTL_TEXTENCODING_ISO_8859_2 },
+ { "CSISOLATIN2", RTL_TEXTENCODING_ISO_8859_2 },
+ { "ISO-8859-3", RTL_TEXTENCODING_ISO_8859_3 },
+ { "ISO_8859-3:1988", RTL_TEXTENCODING_ISO_8859_3 },
+ { "ISO-IR-109", RTL_TEXTENCODING_ISO_8859_3 },
+ { "ISO_8859-3", RTL_TEXTENCODING_ISO_8859_3 },
+ { "LATIN3", RTL_TEXTENCODING_ISO_8859_3 },
+ { "L3", RTL_TEXTENCODING_ISO_8859_3 },
+ { "CSISOLATIN3", RTL_TEXTENCODING_ISO_8859_3 },
+ { "ISO-8859-4", RTL_TEXTENCODING_ISO_8859_4 },
+ { "ISO_8859-4:1988", RTL_TEXTENCODING_ISO_8859_4 },
+ { "ISO-IR-110", RTL_TEXTENCODING_ISO_8859_4 },
+ { "ISO_8859-4", RTL_TEXTENCODING_ISO_8859_4 },
+ { "LATIN4", RTL_TEXTENCODING_ISO_8859_4 },
+ { "L4", RTL_TEXTENCODING_ISO_8859_4 },
+ { "CSISOLATIN4", RTL_TEXTENCODING_ISO_8859_4 },
+ { "ISO-8859-5", RTL_TEXTENCODING_ISO_8859_5 },
+ { "ISO_8859-5:1988", RTL_TEXTENCODING_ISO_8859_5 },
+ { "ISO-IR-144", RTL_TEXTENCODING_ISO_8859_5 },
+ { "ISO_8859-5", RTL_TEXTENCODING_ISO_8859_5 },
+ { "CYRILLIC", RTL_TEXTENCODING_ISO_8859_5 },
+ { "CSISOLATINCYRILLIC", RTL_TEXTENCODING_ISO_8859_5 },
+ { "ISO-8859-6", RTL_TEXTENCODING_ISO_8859_6 },
+ { "ISO_8859-6:1987", RTL_TEXTENCODING_ISO_8859_6 },
+ { "ISO-IR-127", RTL_TEXTENCODING_ISO_8859_6 },
+ { "ISO_8859-6", RTL_TEXTENCODING_ISO_8859_6 },
+ { "ECMA-114", RTL_TEXTENCODING_ISO_8859_6 },
+ { "ASMO-708", RTL_TEXTENCODING_ISO_8859_6 },
+ { "ARABIC", RTL_TEXTENCODING_ISO_8859_6 },
+ { "CSISOLATINARABIC", RTL_TEXTENCODING_ISO_8859_6 },
+ { "ISO-8859-7", RTL_TEXTENCODING_ISO_8859_7 },
+ { "ISO_8859-7:1987", RTL_TEXTENCODING_ISO_8859_7 },
+ { "ISO-IR-126", RTL_TEXTENCODING_ISO_8859_7 },
+ { "ISO_8859-7", RTL_TEXTENCODING_ISO_8859_7 },
+ { "ELOT_928", RTL_TEXTENCODING_ISO_8859_7 },
+ { "ECMA-118", RTL_TEXTENCODING_ISO_8859_7 },
+ { "GREEK", RTL_TEXTENCODING_ISO_8859_7 },
+ { "GREEK8", RTL_TEXTENCODING_ISO_8859_7 },
+ { "CSISOLATINGREEK", RTL_TEXTENCODING_ISO_8859_7 },
+ { "ISO-8859-8", RTL_TEXTENCODING_ISO_8859_8 },
+ { "ISO_8859-8:1988", RTL_TEXTENCODING_ISO_8859_8 },
+ { "ISO-IR-138", RTL_TEXTENCODING_ISO_8859_8 },
+ { "ISO_8859-8", RTL_TEXTENCODING_ISO_8859_8 },
+ { "HEBREW", RTL_TEXTENCODING_ISO_8859_8 },
+ { "CSISOLATINHEBREW", RTL_TEXTENCODING_ISO_8859_8 },
+ { "ISO-8859-9", RTL_TEXTENCODING_ISO_8859_9 },
+ { "ISO_8859-9:1989", RTL_TEXTENCODING_ISO_8859_9 },
+ { "ISO-IR-148", RTL_TEXTENCODING_ISO_8859_9 },
+ { "ISO_8859-9", RTL_TEXTENCODING_ISO_8859_9 },
+ { "LATIN5", RTL_TEXTENCODING_ISO_8859_9 },
+ { "L5", RTL_TEXTENCODING_ISO_8859_9 },
+ { "CSISOLATIN5", RTL_TEXTENCODING_ISO_8859_9 },
+ { "ISO-8859-14", RTL_TEXTENCODING_ISO_8859_14 }, // RFC 2047
+ { "ISO_8859-15", RTL_TEXTENCODING_ISO_8859_15 },
+ { "ISO-8859-15", RTL_TEXTENCODING_ISO_8859_15 }, // RFC 2047
+ { "MACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN },
+ { "MAC", RTL_TEXTENCODING_APPLE_ROMAN },
+ { "CSMACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN },
+ { "IBM437", RTL_TEXTENCODING_IBM_437 },
+ { "CP437", RTL_TEXTENCODING_IBM_437 },
+ { "437", RTL_TEXTENCODING_IBM_437 },
+ { "CSPC8CODEPAGE437", RTL_TEXTENCODING_IBM_437 },
+ { "IBM850", RTL_TEXTENCODING_IBM_850 },
+ { "CP850", RTL_TEXTENCODING_IBM_850 },
+ { "850", RTL_TEXTENCODING_IBM_850 },
+ { "CSPC850MULTILINGUAL", RTL_TEXTENCODING_IBM_850 },
+ { "IBM860", RTL_TEXTENCODING_IBM_860 },
+ { "CP860", RTL_TEXTENCODING_IBM_860 },
+ { "860", RTL_TEXTENCODING_IBM_860 },
+ { "CSIBM860", RTL_TEXTENCODING_IBM_860 },
+ { "IBM861", RTL_TEXTENCODING_IBM_861 },
+ { "CP861", RTL_TEXTENCODING_IBM_861 },
+ { "861", RTL_TEXTENCODING_IBM_861 },
+ { "CP-IS", RTL_TEXTENCODING_IBM_861 },
+ { "CSIBM861", RTL_TEXTENCODING_IBM_861 },
+ { "IBM863", RTL_TEXTENCODING_IBM_863 },
+ { "CP863", RTL_TEXTENCODING_IBM_863 },
+ { "863", RTL_TEXTENCODING_IBM_863 },
+ { "CSIBM863", RTL_TEXTENCODING_IBM_863 },
+ { "IBM865", RTL_TEXTENCODING_IBM_865 },
+ { "CP865", RTL_TEXTENCODING_IBM_865 },
+ { "865", RTL_TEXTENCODING_IBM_865 },
+ { "CSIBM865", RTL_TEXTENCODING_IBM_865 },
+ { "IBM775", RTL_TEXTENCODING_IBM_775 },
+ { "CP775", RTL_TEXTENCODING_IBM_775 },
+ { "CSPC775BALTIC", RTL_TEXTENCODING_IBM_775 },
+ { "IBM852", RTL_TEXTENCODING_IBM_852 },
+ { "CP852", RTL_TEXTENCODING_IBM_852 },
+ { "852", RTL_TEXTENCODING_IBM_852 },
+ { "CSPCP852", RTL_TEXTENCODING_IBM_852 },
+ { "IBM855", RTL_TEXTENCODING_IBM_855 },
+ { "CP855", RTL_TEXTENCODING_IBM_855 },
+ { "855", RTL_TEXTENCODING_IBM_855 },
+ { "CSIBM855", RTL_TEXTENCODING_IBM_855 },
+ { "IBM857", RTL_TEXTENCODING_IBM_857 },
+ { "CP857", RTL_TEXTENCODING_IBM_857 },
+ { "857", RTL_TEXTENCODING_IBM_857 },
+ { "CSIBM857", RTL_TEXTENCODING_IBM_857 },
+ { "IBM862", RTL_TEXTENCODING_IBM_862 },
+ { "CP862", RTL_TEXTENCODING_IBM_862 },
+ { "862", RTL_TEXTENCODING_IBM_862 },
+ { "CSPC862LATINHEBREW", RTL_TEXTENCODING_IBM_862 },
+ { "IBM864", RTL_TEXTENCODING_IBM_864 },
+ { "CP864", RTL_TEXTENCODING_IBM_864 },
+ { "CSIBM864", RTL_TEXTENCODING_IBM_864 },
+ { "IBM866", RTL_TEXTENCODING_IBM_866 },
+ { "CP866", RTL_TEXTENCODING_IBM_866 },
+ { "866", RTL_TEXTENCODING_IBM_866 },
+ { "CSIBM866", RTL_TEXTENCODING_IBM_866 },
+ { "IBM869", RTL_TEXTENCODING_IBM_869 },
+ { "CP869", RTL_TEXTENCODING_IBM_869 },
+ { "869", RTL_TEXTENCODING_IBM_869 },
+ { "CP-GR", RTL_TEXTENCODING_IBM_869 },
+ { "CSIBM869", RTL_TEXTENCODING_IBM_869 },
+ { "WINDOWS-1250", RTL_TEXTENCODING_MS_1250 },
+ { "WINDOWS-1251", RTL_TEXTENCODING_MS_1251 },
+ { "WINDOWS-1253", RTL_TEXTENCODING_MS_1253 },
+ { "WINDOWS-1254", RTL_TEXTENCODING_MS_1254 },
+ { "WINDOWS-1255", RTL_TEXTENCODING_MS_1255 },
+ { "WINDOWS-1256", RTL_TEXTENCODING_MS_1256 },
+ { "WINDOWS-1257", RTL_TEXTENCODING_MS_1257 },
+ { "WINDOWS-1258", RTL_TEXTENCODING_MS_1258 },
+ { "SHIFT_JIS", RTL_TEXTENCODING_SHIFT_JIS },
+ { "MS_KANJI", RTL_TEXTENCODING_SHIFT_JIS },
+ { "CSSHIFTJIS", RTL_TEXTENCODING_SHIFT_JIS },
+ { "GB2312", RTL_TEXTENCODING_GB_2312 },
+ { "CSGB2312", RTL_TEXTENCODING_GB_2312 },
+ { "BIG5", RTL_TEXTENCODING_BIG5 },
+ { "CSBIG5", RTL_TEXTENCODING_BIG5 },
+ { "EUC-JP", RTL_TEXTENCODING_EUC_JP },
+ { "EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE",
+ RTL_TEXTENCODING_EUC_JP },
+ { "CSEUCPKDFMTJAPANESE", RTL_TEXTENCODING_EUC_JP },
+ { "ISO-2022-JP", RTL_TEXTENCODING_ISO_2022_JP },
+ { "CSISO2022JP", RTL_TEXTENCODING_ISO_2022_JP },
+ { "ISO-2022-CN", RTL_TEXTENCODING_ISO_2022_CN },
+ { "KOI8-R", RTL_TEXTENCODING_KOI8_R },
+ { "CSKOI8R", RTL_TEXTENCODING_KOI8_R },
+ { "UTF-7", RTL_TEXTENCODING_UTF7 },
+ { "UTF-8", RTL_TEXTENCODING_UTF8 },
+ { "ISO-8859-10", RTL_TEXTENCODING_ISO_8859_10 }, // RFC 2047
+ { "ISO-8859-13", RTL_TEXTENCODING_ISO_8859_13 }, // RFC 2047
+ { "EUC-KR", RTL_TEXTENCODING_EUC_KR },
+ { "CSEUCKR", RTL_TEXTENCODING_EUC_KR },
+ { "ISO-2022-KR", RTL_TEXTENCODING_ISO_2022_KR },
+ { "CSISO2022KR", RTL_TEXTENCODING_ISO_2022_KR },
+ { "ISO-10646-UCS-4", RTL_TEXTENCODING_UCS4 },
+ { "CSUCS4", RTL_TEXTENCODING_UCS4 },
+ { "ISO-10646-UCS-2", RTL_TEXTENCODING_UCS2 },
+ { "CSUNICODE", RTL_TEXTENCODING_UCS2 } };
+
+//============================================================================
+template< typename T >
+inline rtl_TextEncoding getCharsetEncoding_Impl(T const * pBegin,
+ T const * pEnd)
+{
+ for (sal_Size i = 0; i < sizeof aEncodingMap / sizeof (EncodingEntry);
+ ++i)
+ if (INetMIME::equalIgnoreCase(pBegin, pEnd, aEncodingMap[i].m_aName))
+ return aEncodingMap[i].m_eEncoding;
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+}
+
+//============================================================================
+// static
+rtl_TextEncoding INetMIME::getCharsetEncoding(sal_Char const * pBegin,
+ sal_Char const * pEnd)
+{
+ return getCharsetEncoding_Impl(pBegin, pEnd);
+}
+
+//============================================================================
+// static
+rtl_TextEncoding INetMIME::getCharsetEncoding(sal_Unicode const * pBegin,
+ sal_Unicode const * pEnd)
+{
+ return getCharsetEncoding_Impl(pBegin, pEnd);
+}
+
+//============================================================================
+// static
+INetMIMECharsetList_Impl *
+INetMIME::createPreferredCharsetList(rtl_TextEncoding eEncoding)
+{
+ static const sal_uInt32 aUSASCIIRanges[] = { 0, 0x7F, sal_uInt32(-1) };
+
+ static const sal_uInt32 aISO88591Ranges[] = { 0, 0xFF, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO88592Ranges[]
+ = { 0, 0xA0, 0xA4, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xB0, 0xB0,
+ 0xB4, 0xB4, 0xB8, 0xB8, 0xC1, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7,
+ 0xC9, 0xC9, 0xCB, 0xCB, 0xCD, 0xCE, 0xD3, 0xD4, 0xD6, 0xD7,
+ 0xDA, 0xDA, 0xDC, 0xDD, 0xDF, 0xDF, 0xE1, 0xE2, 0xE4, 0xE4,
+ 0xE7, 0xE7, 0xE9, 0xE9, 0xEB, 0xEB, 0xED, 0xEE, 0xF3, 0xF4,
+ 0xF6, 0xF7, 0xFA, 0xFA, 0xFC, 0xFD, 0x102, 0x107, 0x10C, 0x111,
+ 0x118, 0x11B, 0x139, 0x13A, 0x13D, 0x13E, 0x141, 0x144,
+ 0x147, 0x148, 0x150, 0x151, 0x154, 0x155, 0x158, 0x15B,
+ 0x15E, 0x165, 0x16E, 0x171, 0x179, 0x17E, 0x2C7, 0x2C7,
+ 0x2D8, 0x2D9, 0x2DB, 0x2DB, 0x2DD, 0x2DD, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-2.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO88593Ranges[]
+ = { 0, 0xA0, 0xA3, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xB0, 0xB0,
+ 0xB2, 0xB5, 0xB7, 0xB8, 0xBD, 0xBD, 0xC0, 0xC2, 0xC4, 0xC4,
+ 0xC7, 0xCF, 0xD1, 0xD4, 0xD6, 0xD7, 0xD9, 0xDC, 0xDF, 0xE2,
+ 0xE4, 0xE4, 0xE7, 0xEF, 0xF1, 0xF4, 0xF6, 0xF7, 0xF9, 0xFC,
+ 0x108, 0x10B, 0x11C, 0x121, 0x124, 0x127, 0x130, 0x131,
+ 0x134, 0x135, 0x15C, 0x15F, 0x16C, 0x16D, 0x17B, 0x17C,
+ 0x2D8, 0x2D9, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-3.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO88594Ranges[]
+ = { 0, 0xA0, 0xA4, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xAF, 0xB0,
+ 0xB4, 0xB4, 0xB8, 0xB8, 0xC1, 0xC6, 0xC9, 0xC9, 0xCB, 0xCB,
+ 0xCD, 0xCE, 0xD4, 0xD8, 0xDA, 0xDC, 0xDF, 0xDF, 0xE1, 0xE6,
+ 0xE9, 0xE9, 0xEB, 0xEB, 0xED, 0xEE, 0xF4, 0xF8, 0xFA, 0xFC,
+ 0x100, 0x101, 0x104, 0x105, 0x10C, 0x10D, 0x110, 0x113,
+ 0x116, 0x119, 0x122, 0x123, 0x128, 0x12B, 0x12E, 0x12F,
+ 0x136, 0x138, 0x13B, 0x13C, 0x145, 0x146, 0x14A, 0x14D,
+ 0x156, 0x157, 0x160, 0x161, 0x166, 0x16B, 0x172, 0x173,
+ 0x17D, 0x17E, 0x2C7, 0x2C7, 0x2D9, 0x2D9, 0x2DB, 0x2DB,
+ sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-4.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO88595Ranges[]
+ = { 0, 0xA0, 0xA7, 0xA7, 0xAD, 0xAD, 0x401, 0x40C, 0x40E, 0x44F,
+ 0x451, 0x45C, 0x45E, 0x45F, 0x2116, 0x2116, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-5.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO88596Ranges[]
+ = { 0, 0xA0, 0xA4, 0xA4, 0xAD, 0xAD, 0x60C, 0x60C, 0x61B, 0x61B,
+ 0x61F, 0x61F, 0x621, 0x63A, 0x640, 0x652, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-6.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO88597Ranges[]
+ = { 0, 0xA0, 0xA3, 0xA3, 0xA6, 0xA9, 0xAB, 0xAD, 0xB0, 0xB3,
+ 0xB7, 0xB7, 0xBB, 0xBB, 0xBD, 0xBD, 0x384, 0x386, 0x388, 0x38A,
+ 0x38C, 0x38C, 0x38E, 0x3A1, 0x3A3, 0x3CE, 0x2015, 0x2015,
+ 0x2018, 0x2019, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-7.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO88598Ranges[]
+ = { 0, 0xA0, 0xA2, 0xA9, 0xAB, 0xB9, 0xBB, 0xBE, 0xD7, 0xD7,
+ 0xF7, 0xF7, 0x5D0, 0x5EA, 0x200E, 0x200F, 0x2017, 0x2017,
+ sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-8.TXT> version
+ // 1.1 of 2000-Jan-03
+
+ static const sal_uInt32 aISO88599Ranges[]
+ = { 0, 0xCF, 0xD1, 0xDC, 0xDF, 0xEF, 0xF1, 0xFC, 0xFF, 0xFF,
+ 0x11E, 0x11F, 0x130, 0x131, 0x15E, 0x15F, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-9.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO885910Ranges[]
+ = { 0, 0xA0, 0xA7, 0xA7, 0xAD, 0xAD, 0xB0, 0xB0, 0xB7, 0xB7,
+ 0xC1, 0xC6, 0xC9, 0xC9, 0xCB, 0xCB, 0xCD, 0xD0, 0xD3, 0xD6,
+ 0xD8, 0xD8, 0xDA, 0xDF, 0xE1, 0xE6, 0xE9, 0xE9, 0xEB, 0xEB,
+ 0xED, 0xF0, 0xF3, 0xF6, 0xF8, 0xF8, 0xFA, 0xFE, 0x100, 0x101,
+ 0x104, 0x105, 0x10C, 0x10D, 0x110, 0x113, 0x116, 0x119,
+ 0x122, 0x123, 0x128, 0x12B, 0x12E, 0x12F, 0x136, 0x138,
+ 0x13B, 0x13C, 0x145, 0x146, 0x14A, 0x14D, 0x160, 0x161,
+ 0x166, 0x16B, 0x172, 0x173, 0x17D, 0x17E, 0x2015, 0x2015,
+ sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-10.TXT> version
+ // 1.1 of 1999 October 11
+
+ static const sal_uInt32 aISO885913Ranges[]
+ = { 0, 0xA0, 0xA2, 0xA4, 0xA6, 0xA7, 0xA9, 0xA9, 0xAB, 0xAE,
+ 0xB0, 0xB3, 0xB5, 0xB7, 0xB9, 0xB9, 0xBB, 0xBE, 0xC4, 0xC6,
+ 0xC9, 0xC9, 0xD3, 0xD3, 0xD5, 0xD8, 0xDC, 0xDC, 0xDF, 0xDF,
+ 0xE4, 0xE6, 0xE9, 0xE9, 0xF3, 0xF3, 0xF5, 0xF8, 0xFC, 0xFC,
+ 0x100, 0x101, 0x104, 0x107, 0x10C, 0x10D, 0x112, 0x113,
+ 0x116, 0x119, 0x122, 0x123, 0x12A, 0x12B, 0x12E, 0x12F,
+ 0x136, 0x137, 0x13B, 0x13C, 0x141, 0x146, 0x14C, 0x14D,
+ 0x156, 0x157, 0x15A, 0x15B, 0x160, 0x161, 0x16A, 0x16B,
+ 0x172, 0x173, 0x179, 0x17E, 0x2019, 0x2019, 0x201C, 0x201E,
+ sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-13.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO885914Ranges[]
+ = { 0, 0xA0, 0xA3, 0xA3, 0xA7, 0xA7, 0xA9, 0xA9, 0xAD, 0xAE,
+ 0xB6, 0xB6, 0xC0, 0xCF, 0xD1, 0xD6, 0xD8, 0xDD, 0xDF, 0xEF,
+ 0xF1, 0xF6, 0xF8, 0xFD, 0xFF, 0xFF, 0x10A, 0x10B, 0x120, 0x121,
+ 0x174, 0x178, 0x1E02, 0x1E03, 0x1E0A, 0x1E0B, 0x1E1E, 0x1E1F,
+ 0x1E40, 0x1E41, 0x1E56, 0x1E57, 0x1E60, 0x1E61, 0x1E6A, 0x1E6B,
+ 0x1E80, 0x1E85, 0x1EF2, 0x1EF3, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-14.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aISO885915Ranges[]
+ = { 0, 0xA3, 0xA5, 0xA5, 0xA7, 0xA7, 0xA9, 0xB3, 0xB5, 0xB7,
+ 0xB9, 0xBB, 0xBF, 0xFF, 0x152, 0x153, 0x160, 0x161, 0x178, 0x178,
+ 0x17D, 0x17E, 0x20AC, 0x20AC, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-15.TXT> version
+ // 1.0 of 1999 July 27
+
+ static const sal_uInt32 aKOI8RRanges[]
+ = { 0, 0x7F, 0xA0, 0xA0, 0xA9, 0xA9, 0xB0, 0xB0, 0xB2, 0xB2,
+ 0xB7, 0xB7, 0xF7, 0xF7, 0x401, 0x401, 0x410, 0x44F, 0x451, 0x451,
+ 0x2219, 0x221A, 0x2248, 0x2248, 0x2264, 0x2265, 0x2320, 0x2321,
+ 0x2500, 0x2500, 0x2502, 0x2502, 0x250C, 0x250C, 0x2510, 0x2510,
+ 0x2514, 0x2514, 0x2518, 0x2518, 0x251C, 0x251C, 0x2524, 0x2524,
+ 0x252C, 0x252C, 0x2534, 0x2534, 0x253C, 0x253C, 0x2550, 0x256C,
+ 0x2580, 0x2580, 0x2584, 0x2584, 0x2588, 0x2588, 0x258C, 0x258C,
+ 0x2590, 0x2593, 0x25A0, 0x25A0, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT>
+ // version 1.0 of 18 August 1999
+
+#if defined WNT
+ static const sal_uInt32 aWindows1252Ranges[]
+ = { 0, 0x7F, 0xA0, 0xFF, 0x152, 0x153, 0x160, 0x161, 0x178, 0x178,
+ 0x17D, 0x17E, 0x192, 0x192, 0x2C6, 0x2C6, 0x2DC, 0x2DC,
+ 0x2013, 0x2014, 0x2018, 0x201A, 0x201C, 0x201E, 0x2020, 0x2022,
+ 0x2026, 0x2026, 0x2030, 0x2030, 0x2039, 0x203A, 0x20AC, 0x20AC,
+ 0x2122, 0x2122, sal_uInt32(-1) };
+ // <ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/
+ // CP1252.TXT> version 2.01 of 04/15/98
+#endif // WNT
+
+ INetMIMECharsetList_Impl * pList = new INetMIMECharsetList_Impl;
+ switch (eEncoding)
+ {
+ case RTL_TEXTENCODING_MS_1252:
+#if defined WNT
+ pList->prepend(Charset(RTL_TEXTENCODING_MS_1252,
+ aWindows1252Ranges));
+#endif // WNT
+ case RTL_TEXTENCODING_ISO_8859_1:
+ case RTL_TEXTENCODING_UTF7:
+ case RTL_TEXTENCODING_UTF8:
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_2:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_2,
+ aISO88592Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_3:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_3,
+ aISO88593Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_4:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_4,
+ aISO88594Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_5:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
+ aISO88595Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_6:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_6,
+ aISO88596Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_7:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_7,
+ aISO88597Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_8:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_8,
+ aISO88598Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_9:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_9,
+ aISO88599Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_10:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_10,
+ aISO885910Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_13:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_13,
+ aISO885913Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_14:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_14,
+ aISO885914Ranges));
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_15:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_15,
+ aISO885915Ranges));
+ break;
+
+ case RTL_TEXTENCODING_MS_1250:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_2,
+ aISO88592Ranges));
+ break;
+
+ case RTL_TEXTENCODING_MS_1251:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
+ aISO88595Ranges));
+ break;
+
+ case RTL_TEXTENCODING_MS_1253:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_7,
+ aISO88597Ranges));
+ break;
+
+ case RTL_TEXTENCODING_MS_1254:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_9,
+ aISO88599Ranges));
+ break;
+
+ case RTL_TEXTENCODING_MS_1255:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_8,
+ aISO88598Ranges));
+ break;
+
+ case RTL_TEXTENCODING_MS_1256:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_6,
+ aISO88596Ranges));
+ break;
+
+ case RTL_TEXTENCODING_MS_1257:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_4,
+ aISO88594Ranges));
+ break;
+
+ case RTL_TEXTENCODING_KOI8_R:
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
+ aISO88595Ranges));
+ pList->prepend(Charset(RTL_TEXTENCODING_KOI8_R, aKOI8RRanges));
+ break;
+
+ default: //@@@ more cases are missing!
+ DBG_ERROR("INetMIME::createPreferredCharsetList():"
+ " Unsupported encoding");
+ break;
+ }
+ pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_1, aISO88591Ranges));
+ pList->prepend(Charset(RTL_TEXTENCODING_ASCII_US, aUSASCIIRanges));
+ return pList;
+}
+
+//============================================================================
+// static
+sal_Unicode * INetMIME::convertToUnicode(const sal_Char * pBegin,
+ const sal_Char * pEnd,
+ rtl_TextEncoding eEncoding,
+ sal_Size & rSize)
+{
+ if (eEncoding == RTL_TEXTENCODING_DONTKNOW)
+ return 0;
+ rtl_TextToUnicodeConverter hConverter
+ = rtl_createTextToUnicodeConverter(eEncoding);
+ rtl_TextToUnicodeContext hContext
+ = rtl_createTextToUnicodeContext(hConverter);
+ sal_Unicode * pBuffer;
+ sal_uInt32 nInfo;
+ for (sal_Size nBufferSize = pEnd - pBegin;;
+ nBufferSize += nBufferSize / 3 + 1)
+ {
+ pBuffer = new sal_Unicode[nBufferSize];
+ sal_Size nSrcCvtBytes;
+ rSize = rtl_convertTextToUnicode(
+ hConverter, hContext, pBegin, pEnd - pBegin, pBuffer,
+ nBufferSize,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
+ &nInfo, &nSrcCvtBytes);
+ if (nInfo != RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
+ break;
+ delete[] pBuffer;
+ rtl_resetTextToUnicodeContext(hConverter, hContext);
+ }
+ rtl_destroyTextToUnicodeContext(hConverter, hContext);
+ rtl_destroyTextToUnicodeConverter(hConverter);
+ if (nInfo != 0)
+ {
+ delete[] pBuffer;
+ pBuffer = 0;
+ }
+ return pBuffer;
+}
+
+//============================================================================
+// static
+sal_Char * INetMIME::convertFromUnicode(const sal_Unicode * pBegin,
+ const sal_Unicode * pEnd,
+ rtl_TextEncoding eEncoding,
+ sal_Size & rSize)
+{
+ if (eEncoding == RTL_TEXTENCODING_DONTKNOW)
+ return 0;
+ rtl_UnicodeToTextConverter hConverter
+ = rtl_createUnicodeToTextConverter(eEncoding);
+ rtl_UnicodeToTextContext hContext
+ = rtl_createUnicodeToTextContext(hConverter);
+ sal_Char * pBuffer;
+ sal_uInt32 nInfo;
+ for (sal_Size nBufferSize = pEnd - pBegin;;
+ nBufferSize += nBufferSize / 3 + 1)
+ {
+ pBuffer = new sal_Char[nBufferSize];
+ sal_Size nSrcCvtBytes;
+ rSize = rtl_convertUnicodeToText(
+ hConverter, hContext, pBegin, pEnd - pBegin, pBuffer,
+ nBufferSize,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
+ | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR,
+ &nInfo, &nSrcCvtBytes);
+ if (nInfo != RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL)
+ break;
+ delete[] pBuffer;
+ rtl_resetUnicodeToTextContext(hConverter, hContext);
+ }
+ rtl_destroyUnicodeToTextContext(hConverter, hContext);
+ rtl_destroyUnicodeToTextConverter(hConverter);
+ if (nInfo != 0)
+ {
+ delete[] pBuffer;
+ pBuffer = 0;
+ }
+ return pBuffer;
+}
+
+//============================================================================
+// static
+void INetMIME::writeUTF8(INetMIMEOutputSink & rSink, sal_uInt32 nChar)
+{
+ // See RFC 2279 for a discussion of UTF-8.
+ DBG_ASSERT(nChar < 0x80000000, "INetMIME::writeUTF8(): Bad char");
+
+ if (nChar < 0x80)
+ rSink << sal_Char(nChar);
+ else if (nChar < 0x800)
+ rSink << sal_Char(nChar >> 6 | 0xC0)
+ << sal_Char((nChar & 0x3F) | 0x80);
+ else if (nChar < 0x10000)
+ rSink << sal_Char(nChar >> 12 | 0xE0)
+ << sal_Char((nChar >> 6 & 0x3F) | 0x80)
+ << sal_Char((nChar & 0x3F) | 0x80);
+ else if (nChar < 0x200000)
+ rSink << sal_Char(nChar >> 18 | 0xF0)
+ << sal_Char((nChar >> 12 & 0x3F) | 0x80)
+ << sal_Char((nChar >> 6 & 0x3F) | 0x80)
+ << sal_Char((nChar & 0x3F) | 0x80);
+ else if (nChar < 0x4000000)
+ rSink << sal_Char(nChar >> 24 | 0xF8)
+ << sal_Char((nChar >> 18 & 0x3F) | 0x80)
+ << sal_Char((nChar >> 12 & 0x3F) | 0x80)
+ << sal_Char((nChar >> 6 & 0x3F) | 0x80)
+ << sal_Char((nChar & 0x3F) | 0x80);
+ else
+ rSink << sal_Char(nChar >> 30 | 0xFC)
+ << sal_Char((nChar >> 24 & 0x3F) | 0x80)
+ << sal_Char((nChar >> 18 & 0x3F) | 0x80)
+ << sal_Char((nChar >> 12 & 0x3F) | 0x80)
+ << sal_Char((nChar >> 6 & 0x3F) | 0x80)
+ << sal_Char((nChar & 0x3F) | 0x80);
+}
+
+//============================================================================
+// static
+void INetMIME::writeUnsigned(INetMIMEOutputSink & rSink, sal_uInt32 nValue,
+ int nMinDigits)
+{
+ sal_Char aBuffer[10];
+ // max unsigned 32 bit value (4294967295) has 10 places
+ sal_Char * p = aBuffer;
+ for (; nValue > 0; nValue /= 10)
+ *p++ = sal_Char(getDigit(nValue % 10));
+ nMinDigits -= p - aBuffer;
+ while (nMinDigits-- > 0)
+ rSink << '0';
+ while (p != aBuffer)
+ rSink << *--p;
+}
+
+//============================================================================
+// static
+void INetMIME::writeDateTime(INetMIMEOutputSink & rSink,
+ const DateTime & rUTC)
+{
+ static const sal_Char aDay[7][3]
+ = { { 'M', 'o', 'n' },
+ { 'T', 'u', 'e' },
+ { 'W', 'e', 'd' },
+ { 'T', 'h', 'u' },
+ { 'F', 'r', 'i' },
+ { 'S', 'a', 't' },
+ { 'S', 'u', 'n' } };
+ const sal_Char * pTheDay = aDay[rUTC.GetDayOfWeek()];
+ rSink.write(pTheDay, pTheDay + 3);
+ rSink << ", ";
+ writeUnsigned(rSink, rUTC.GetDay());
+ rSink << ' ';
+ static const sal_Char aMonth[12][3]
+ = { { 'J', 'a', 'n' },
+ { 'F', 'e', 'b' },
+ { 'M', 'a', 'r' },
+ { 'A', 'p', 'r' },
+ { 'M', 'a', 'y' },
+ { 'J', 'u', 'n' },
+ { 'J', 'u', 'l' },
+ { 'A', 'u', 'g' },
+ { 'S', 'e', 'p' },
+ { 'O', 'c', 't' },
+ { 'N', 'o', 'v' },
+ { 'D', 'e', 'c' } };
+ const sal_Char * pTheMonth = aMonth[rUTC.GetMonth() - 1];
+ rSink.write(pTheMonth, pTheMonth + 3);
+ rSink << ' ';
+ writeUnsigned(rSink, rUTC.GetYear());
+ rSink << ' ';
+ writeUnsigned(rSink, rUTC.GetHour(), 2);
+ rSink << ':';
+ writeUnsigned(rSink, rUTC.GetMin(), 2);
+ rSink << ':';
+ writeUnsigned(rSink, rUTC.GetSec(), 2);
+ rSink << " +0000";
+}
+
+//============================================================================
+// static
+void INetMIME::writeHeaderFieldBody(INetMIMEOutputSink & rSink,
+ HeaderFieldType eType,
+ const ByteString & rBody,
+ rtl_TextEncoding ePreferredEncoding,
+ bool bInitialSpace)
+{
+ writeHeaderFieldBody(rSink, eType,
+ UniString(rBody, RTL_TEXTENCODING_UTF8),
+ ePreferredEncoding, bInitialSpace);
+}
+
+//============================================================================
+// static
+void INetMIME::writeHeaderFieldBody(INetMIMEOutputSink & rSink,
+ HeaderFieldType eType,
+ const UniString & rBody,
+ rtl_TextEncoding ePreferredEncoding,
+ bool bInitialSpace)
+{
+ if (eType == HEADER_FIELD_TEXT)
+ {
+ INetMIMEEncodedWordOutputSink
+ aOutput(rSink, INetMIMEEncodedWordOutputSink::CONTEXT_TEXT,
+ bInitialSpace ?
+ INetMIMEEncodedWordOutputSink::SPACE_ALWAYS :
+ INetMIMEEncodedWordOutputSink::SPACE_NO,
+ ePreferredEncoding);
+ aOutput.write(rBody.GetBuffer(), rBody.GetBuffer() + rBody.Len());
+ aOutput.flush();
+ }
+ else
+ {
+ enum Brackets { BRACKETS_OUTSIDE, BRACKETS_OPENING, BRACKETS_INSIDE };
+ Brackets eBrackets = BRACKETS_OUTSIDE;
+
+ const sal_Unicode * pBodyPtr = rBody.GetBuffer();
+ const sal_Unicode * pBodyEnd = pBodyPtr + rBody.Len();
+ while (pBodyPtr != pBodyEnd)
+ switch (*pBodyPtr)
+ {
+ case '\t':
+ case ' ':
+ // A WSP adds to accumulated space:
+ bInitialSpace = true;
+ ++pBodyPtr;
+ break;
+
+ case '(':
+ {
+ // Write a pending '<' if necessary:
+ if (eBrackets == BRACKETS_OPENING)
+ {
+ if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '<';
+ bInitialSpace = false;
+ eBrackets = BRACKETS_INSIDE;
+ }
+
+ // Write the comment, introducing encoded-words where
+ // necessary:
+ int nLevel = 0;
+ INetMIMEEncodedWordOutputSink
+ aOutput(
+ rSink,
+ INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT,
+ INetMIMEEncodedWordOutputSink::SPACE_NO,
+ ePreferredEncoding);
+ while (pBodyPtr != pBodyEnd)
+ switch (*pBodyPtr)
+ {
+ case '(':
+ aOutput.flush();
+ if (rSink.getColumn()
+ + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '(';
+ bInitialSpace = false;
+ ++nLevel;
+ ++pBodyPtr;
+ break;
+
+ case ')':
+ aOutput.flush();
+ if (rSink.getColumn()
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ rSink << ')';
+ ++pBodyPtr;
+ if (--nLevel == 0)
+ goto comment_done;
+ break;
+
+ case '\\':
+ if (++pBodyPtr == pBodyEnd)
+ break;
+ default:
+ aOutput << *pBodyPtr++;
+ break;
+ }
+ comment_done:
+ break;
+ }
+
+ case '<':
+ // Write an already pending '<' if necessary:
+ if (eBrackets == BRACKETS_OPENING)
+ {
+ if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '<';
+ bInitialSpace = false;
+ }
+
+ // Remember this '<' as pending, and open a bracketed
+ // block:
+ eBrackets = BRACKETS_OPENING;
+ ++pBodyPtr;
+ break;
+
+ case '>':
+ // Write a pending '<' if necessary:
+ if (eBrackets == BRACKETS_OPENING)
+ {
+ if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '<';
+ bInitialSpace = false;
+ }
+
+ // Write this '>', and close any bracketed block:
+ if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '>';
+ bInitialSpace = false;
+ eBrackets = BRACKETS_OUTSIDE;
+ ++pBodyPtr;
+ break;
+
+ case ',':
+ case ':':
+ case ';':
+ case '\\':
+ case ']':
+ // Write a pending '<' if necessary:
+ if (eBrackets == BRACKETS_OPENING)
+ {
+ if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '<';
+ bInitialSpace = false;
+ eBrackets = BRACKETS_INSIDE;
+ }
+
+ // Write this specials:
+ if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << sal_Char(*pBodyPtr++);
+ bInitialSpace = false;
+ break;
+
+ case '\x0D': // CR
+ // A <CRLF WSP> adds to accumulated space, a <CR> not
+ // followed by <LF WSP> starts 'junk':
+ if (startsWithLineFolding(pBodyPtr, pBodyEnd))
+ {
+ bInitialSpace = true;
+ pBodyPtr += 3;
+ break;
+ }
+ default:
+ {
+ // The next token is either one of <"." / "@" / atom /
+ // quoted-string / domain-literal>, or it's 'junk'; if it
+ // is not 'junk', it is either a 'phrase' (i.e., it may
+ // contain encoded-words) or a 'non-phrase' (i.e., it may
+ // not contain encoded-words):
+ enum Entity { ENTITY_JUNK, ENTITY_NON_PHRASE,
+ ENTITY_PHRASE };
+ Entity eEntity = ENTITY_JUNK;
+ switch (*pBodyPtr)
+ {
+ case '.':
+ case '@':
+ case '[':
+ // A token of <"." / "@" / domain-literal> always
+ // starts a 'non-phrase':
+ eEntity = ENTITY_NON_PHRASE;
+ break;
+
+ default:
+ if (isUSASCII(*pBodyPtr)
+ && !isAtomChar(*pBodyPtr))
+ {
+ eEntity = ENTITY_JUNK;
+ break;
+ }
+ case '"':
+ // A token of <atom / quoted-string> can either be
+ // a 'phrase' or a 'non-phrase':
+ switch (eType)
+ {
+ case HEADER_FIELD_STRUCTURED:
+ eEntity = ENTITY_NON_PHRASE;
+ break;
+
+ case HEADER_FIELD_PHRASE:
+ eEntity = ENTITY_PHRASE;
+ break;
+
+ case HEADER_FIELD_MESSAGE_ID:
+ // A 'phrase' if and only if outside any
+ // bracketed block:
+ eEntity
+ = eBrackets == BRACKETS_OUTSIDE ?
+ ENTITY_PHRASE :
+ ENTITY_NON_PHRASE;
+ break;
+
+ case HEADER_FIELD_ADDRESS:
+ {
+ // A 'non-phrase' if and only if, after
+ // skipping this token and any following
+ // <linear-white-space> and <comment>s,
+ // there is no token left, or the next
+ // token is any of <"." / "@" / ">" / ","
+ // / ";">, or the next token is <":"> and
+ // is within a bracketed block:
+ const sal_Unicode * pLookAhead = pBodyPtr;
+ if (*pLookAhead == '"')
+ {
+ pLookAhead
+ = skipQuotedString(pLookAhead,
+ pBodyEnd);
+ if (pLookAhead == pBodyPtr)
+ pLookAhead = pBodyEnd;
+ }
+ else
+ while (pLookAhead != pBodyEnd
+ && (isAtomChar(*pLookAhead)
+ || !isUSASCII(
+ *pLookAhead)))
+ ++pLookAhead;
+ while (pLookAhead != pBodyEnd)
+ switch (*pLookAhead)
+ {
+ case '\t':
+ case ' ':
+ ++pLookAhead;
+ break;
+
+ case '(':
+ {
+ const sal_Unicode * pPast
+ = skipComment(pLookAhead,
+ pBodyEnd);
+ pLookAhead
+ = pPast == pLookAhead ?
+ pBodyEnd : pPast;
+ break;
+ }
+
+ case ',':
+ case '.':
+ case ';':
+ case '>':
+ case '@':
+ eEntity = ENTITY_NON_PHRASE;
+ goto entity_determined;
+
+ case ':':
+ eEntity
+ = eBrackets
+ == BRACKETS_OUTSIDE ?
+ ENTITY_PHRASE :
+ ENTITY_NON_PHRASE;
+ goto entity_determined;
+
+ case '\x0D': // CR
+ if (startsWithLineFolding(
+ pLookAhead, pBodyEnd))
+ {
+ pLookAhead += 3;
+ break;
+ }
+ default:
+ eEntity = ENTITY_PHRASE;
+ goto entity_determined;
+ }
+ eEntity = ENTITY_NON_PHRASE;
+ entity_determined:
+ break;
+ }
+
+ case HEADER_FIELD_TEXT:
+ OSL_ASSERT(false);
+ break;
+ }
+
+ // In a 'non-phrase', a non-US-ASCII character
+ // cannot be part of an <atom>, but instead the
+ // whole entity is 'junk' rather than 'non-
+ // phrase':
+ if (eEntity == ENTITY_NON_PHRASE
+ && !isUSASCII(*pBodyPtr))
+ eEntity = ENTITY_JUNK;
+ break;
+ }
+
+ switch (eEntity)
+ {
+ case ENTITY_JUNK:
+ {
+ // Write a pending '<' if necessary:
+ if (eBrackets == BRACKETS_OPENING)
+ {
+ if (rSink.getColumn()
+ + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '<';
+ bInitialSpace = false;
+ eBrackets = BRACKETS_INSIDE;
+ }
+
+ // Calculate the length of in- and output:
+ const sal_Unicode * pStart = pBodyPtr;
+ sal_Size nLength = 0;
+ bool bModify = false;
+ bool bEnd = false;
+ while (pBodyPtr != pBodyEnd && !bEnd)
+ switch (*pBodyPtr)
+ {
+ case '\x0D': // CR
+ if (startsWithLineFolding(pBodyPtr,
+ pBodyEnd))
+ bEnd = true;
+ else if (startsWithLineBreak(
+ pBodyPtr, pBodyEnd))
+ {
+ nLength += 3;
+ bModify = true;
+ pBodyPtr += 2;
+ }
+ else
+ {
+ ++nLength;
+ ++pBodyPtr;
+ }
+ break;
+
+ case '\t':
+ case ' ':
+ bEnd = true;
+ break;
+
+ default:
+ if (isVisible(*pBodyPtr))
+ bEnd = true;
+ else if (isUSASCII(*pBodyPtr))
+ {
+ ++nLength;
+ ++pBodyPtr;
+ }
+ else
+ {
+ nLength += getUTF8OctetCount(
+ *pBodyPtr++);
+ bModify = true;
+ }
+ break;
+ }
+
+ // Write the output:
+ if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
+ + nLength
+ > rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ bInitialSpace = false;
+ if (bModify)
+ while (pStart != pBodyPtr)
+ if (startsWithLineBreak(pStart, pBodyPtr))
+ {
+ rSink << "\x0D\\\x0A"; // CR, '\', LF
+ pStart += 2;
+ }
+ else
+ writeUTF8(rSink, *pStart++);
+ else
+ rSink.write(pStart, pBodyPtr);
+ break;
+ }
+
+ case ENTITY_NON_PHRASE:
+ {
+ // Calculate the length of in- and output:
+ const sal_Unicode * pStart = pBodyPtr;
+ sal_Size nLength = 0;
+ bool bBracketedBlock = false;
+ bool bSymbol = *pStart != '.' && *pStart != '@';
+ bool bModify = false;
+ bool bEnd = false;
+ while (pBodyPtr != pBodyEnd && !bEnd)
+ switch (*pBodyPtr)
+ {
+ case '\t':
+ case ' ':
+ case '\x0D': // CR
+ {
+ const sal_Unicode * pLookAhead
+ = skipLinearWhiteSpace(pBodyPtr,
+ pBodyEnd);
+ if (pLookAhead < pBodyEnd
+ && (bSymbol ?
+ isAtomChar(*pLookAhead)
+ || *pLookAhead == '"'
+ || *pLookAhead == '[' :
+ *pLookAhead == '.'
+ || *pLookAhead == '@'
+ || (*pLookAhead == '>'
+ && eType
+ >= HEADER_FIELD_MESSAGE_ID
+ && eBrackets
+ == BRACKETS_OPENING)))
+ {
+ bModify = true;
+ pBodyPtr = pLookAhead;
+ }
+ else
+ bEnd = true;
+ break;
+ }
+
+ case '"':
+ if (bSymbol)
+ {
+ pBodyPtr
+ = scanQuotedBlock(pBodyPtr,
+ pBodyEnd,
+ '"', '"',
+ nLength,
+ bModify);
+ bSymbol = false;
+ }
+ else
+ bEnd = true;
+ break;
+
+ case '[':
+ if (bSymbol)
+ {
+ pBodyPtr
+ = scanQuotedBlock(pBodyPtr,
+ pBodyEnd,
+ '[', ']',
+ nLength,
+ bModify);
+ bSymbol = false;
+ }
+ else
+ bEnd = true;
+ break;
+
+ case '.':
+ case '@':
+ if (bSymbol)
+ bEnd = true;
+ else
+ {
+ ++nLength;
+ bSymbol = true;
+ ++pBodyPtr;
+ }
+ break;
+
+ case '>':
+ if (eBrackets == BRACKETS_OPENING
+ && eType
+ >= HEADER_FIELD_MESSAGE_ID)
+ {
+ ++nLength;
+ bBracketedBlock = true;
+ ++pBodyPtr;
+ }
+ bEnd = true;
+ break;
+
+ default:
+ if (isAtomChar(*pBodyPtr) && bSymbol)
+ {
+ while (pBodyPtr != pBodyEnd
+ && isAtomChar(*pBodyPtr))
+ {
+ ++nLength;
+ ++pBodyPtr;
+ }
+ bSymbol = false;
+ }
+ else
+ {
+ if (!isUSASCII(*pBodyPtr))
+ bModify = true;
+ bEnd = true;
+ }
+ break;
+ }
+
+ // Write a pending '<' if necessary:
+ if (eBrackets == BRACKETS_OPENING
+ && !bBracketedBlock)
+ {
+ if (rSink.getColumn()
+ + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '<';
+ bInitialSpace = false;
+ eBrackets = BRACKETS_INSIDE;
+ }
+
+ // Write the output:
+ if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
+ + nLength
+ > rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ bInitialSpace = false;
+ if (bBracketedBlock)
+ {
+ rSink << '<';
+ eBrackets = BRACKETS_OUTSIDE;
+ }
+ if (bModify)
+ {
+ enum Mode { MODE_PLAIN, MODE_QUOTED_STRING,
+ MODE_DOMAIN_LITERAL };
+ Mode eMode = MODE_PLAIN;
+ while (pStart != pBodyPtr)
+ switch (*pStart)
+ {
+ case '\x0D': // CR
+ if (startsWithLineFolding(
+ pStart, pBodyPtr))
+ {
+ if (eMode != MODE_PLAIN)
+ rSink << sal_Char(
+ pStart[2]);
+ pStart += 3;
+ }
+ else if (startsWithLineBreak(
+ pStart, pBodyPtr))
+ {
+ rSink << "\x0D\\\x0A";
+ // CR, '\', LF
+ pStart += 2;
+ }
+ else
+ {
+ rSink << '\x0D'; // CR
+ ++pStart;
+ }
+ break;
+
+ case '\t':
+ case ' ':
+ if (eMode != MODE_PLAIN)
+ rSink << sal_Char(*pStart);
+ ++pStart;
+ break;
+
+ case '"':
+ if (eMode == MODE_PLAIN)
+ eMode = MODE_QUOTED_STRING;
+ else if (eMode
+ == MODE_QUOTED_STRING)
+ eMode = MODE_PLAIN;
+ rSink << '"';
+ ++pStart;
+ break;
+
+ case '[':
+ if (eMode == MODE_PLAIN)
+ eMode = MODE_DOMAIN_LITERAL;
+ rSink << '[';
+ ++pStart;
+ break;
+
+ case ']':
+ if (eMode == MODE_DOMAIN_LITERAL)
+ eMode = MODE_PLAIN;
+ rSink << ']';
+ ++pStart;
+ break;
+
+ case '\\':
+ rSink << '\\';
+ if (++pStart < pBodyPtr)
+ writeUTF8(rSink, *pStart++);
+ break;
+
+ default:
+ writeUTF8(rSink, *pStart++);
+ break;
+ }
+ }
+ else
+ rSink.write(pStart, pBodyPtr);
+ break;
+ }
+
+ case ENTITY_PHRASE:
+ {
+ // Write a pending '<' if necessary:
+ if (eBrackets == BRACKETS_OPENING)
+ {
+ if (rSink.getColumn()
+ + (bInitialSpace ? 1 : 0)
+ >= rSink.getLineLengthLimit())
+ rSink << INetMIMEOutputSink::endl << ' ';
+ else if (bInitialSpace)
+ rSink << ' ';
+ rSink << '<';
+ bInitialSpace = false;
+ eBrackets = BRACKETS_INSIDE;
+ }
+
+ // Calculate the length of in- and output:
+ const sal_Unicode * pStart = pBodyPtr;
+ bool bQuotedString = false;
+ bool bEnd = false;
+ while (pBodyPtr != pBodyEnd && !bEnd)
+ switch (*pBodyPtr)
+ {
+ case '\t':
+ case ' ':
+ case '\x0D': // CR
+ if (bQuotedString)
+ ++pBodyPtr;
+ else
+ {
+ const sal_Unicode * pLookAhead
+ = skipLinearWhiteSpace(
+ pBodyPtr, pBodyEnd);
+ if (pLookAhead != pBodyEnd
+ && (isAtomChar(*pLookAhead)
+ || !isUSASCII(*pLookAhead)
+ || *pLookAhead == '"'))
+ pBodyPtr = pLookAhead;
+ else
+ bEnd = true;
+ }
+ break;
+
+ case '"':
+ bQuotedString = !bQuotedString;
+ ++pBodyPtr;
+ break;
+
+ case '\\':
+ if (bQuotedString)
+ {
+ if (++pBodyPtr != pBodyEnd)
+ ++pBodyPtr;
+ }
+ else
+ bEnd = true;
+ break;
+
+ default:
+ if (bQuotedString
+ || isAtomChar(*pBodyPtr)
+ || !isUSASCII(*pBodyPtr))
+ ++pBodyPtr;
+ else
+ bEnd = true;
+ break;
+ }
+
+ // Write the phrase, introducing encoded-words
+ // where necessary:
+ INetMIMEEncodedWordOutputSink
+ aOutput(
+ rSink,
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,
+ bInitialSpace ?
+ INetMIMEEncodedWordOutputSink::SPACE_ALWAYS :
+ INetMIMEEncodedWordOutputSink::SPACE_ENCODED,
+ ePreferredEncoding);
+ while (pStart != pBodyPtr)
+ switch (*pStart)
+ {
+ case '"':
+ ++pStart;
+ break;
+
+ case '\\':
+ if (++pStart != pBodyPtr)
+ aOutput << *pStart++;
+ break;
+
+ case '\x0D': // CR
+ pStart += 2;
+ aOutput << *pStart++;
+ break;
+
+ default:
+ aOutput << *pStart++;
+ break;
+ }
+ bInitialSpace = aOutput.flush();
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+//============================================================================
+// static
+bool INetMIME::translateUTF8Char(const sal_Char *& rBegin,
+ const sal_Char * pEnd,
+ rtl_TextEncoding eEncoding,
+ sal_uInt32 & rCharacter)
+{
+ if (rBegin == pEnd || static_cast< unsigned char >(*rBegin) < 0x80
+ || static_cast< unsigned char >(*rBegin) >= 0xFE)
+ return false;
+
+ int nCount;
+ sal_uInt32 nMin;
+ sal_uInt32 nUCS4;
+ const sal_Char * p = rBegin;
+ if (static_cast< unsigned char >(*p) < 0xE0)
+ {
+ nCount = 1;
+ nMin = 0x80;
+ nUCS4 = static_cast< unsigned char >(*p) & 0x1F;
+ }
+ else if (static_cast< unsigned char >(*p) < 0xF0)
+ {
+ nCount = 2;
+ nMin = 0x800;
+ nUCS4 = static_cast< unsigned char >(*p) & 0xF;
+ }
+ else if (static_cast< unsigned char >(*p) < 0xF8)
+ {
+ nCount = 3;
+ nMin = 0x10000;
+ nUCS4 = static_cast< unsigned char >(*p) & 7;
+ }
+ else if (static_cast< unsigned char >(*p) < 0xFC)
+ {
+ nCount = 4;
+ nMin = 0x200000;
+ nUCS4 = static_cast< unsigned char >(*p) & 3;
+ }
+ else
+ {
+ nCount = 5;
+ nMin = 0x4000000;
+ nUCS4 = static_cast< unsigned char >(*p) & 1;
+ }
+ ++p;
+
+ for (; nCount-- > 0; ++p)
+ if ((static_cast< unsigned char >(*p) & 0xC0) == 0x80)
+ nUCS4 = (nUCS4 << 6) | (static_cast< unsigned char >(*p) & 0x3F);
+ else
+ return false;
+
+ if (nUCS4 < nMin || nUCS4 > 0x10FFFF)
+ return false;
+
+ if (eEncoding >= RTL_TEXTENCODING_UCS4)
+ rCharacter = nUCS4;
+ else
+ {
+ sal_Unicode aUTF16[2];
+ const sal_Unicode * pUTF16End = putUTF32Character(aUTF16, nUCS4);
+ sal_Size nSize;
+ sal_Char * pBuffer = convertFromUnicode(aUTF16, pUTF16End, eEncoding,
+ nSize);
+ if (!pBuffer)
+ return false;
+ DBG_ASSERT(nSize == 1,
+ "INetMIME::translateUTF8Char(): Bad conversion");
+ rCharacter = *pBuffer;
+ delete[] pBuffer;
+ }
+ rBegin = p;
+ return true;
+}
+
+//============================================================================
+// static
+ByteString INetMIME::decodeUTF8(const ByteString & rText,
+ rtl_TextEncoding eEncoding)
+{
+ const sal_Char * p = rText.GetBuffer();
+ const sal_Char * pEnd = p + rText.Len();
+ ByteString sDecoded;
+ while (p != pEnd)
+ {
+ sal_uInt32 nCharacter;
+ if (translateUTF8Char(p, pEnd, eEncoding, nCharacter))
+ sDecoded += sal_Char(nCharacter);
+ else
+ sDecoded += sal_Char(*p++);
+ }
+ return sDecoded;
+}
+
+//============================================================================
+// static
+UniString INetMIME::decodeHeaderFieldBody(HeaderFieldType eType,
+ const ByteString & rBody)
+{
+ // Due to a bug in INetCoreRFC822MessageStream::ConvertTo7Bit(), old
+ // versions of StarOffice send mails with header fields where encoded
+ // words can be preceded by '=', ',', '.', '"', or '(', and followed by
+ // '=', ',', '.', '"', ')', without any required white space in between.
+ // And there appear to exist some broken mailers that only encode single
+ // letters within words, like "Appel
+ // =?iso-8859-1?Q?=E0?=t=?iso-8859-1?Q?=E9?=moin", so it seems best to
+ // detect encoded words even when not propperly surrounded by white space.
+ //
+ // Non US-ASCII characters in rBody are treated as ISO-8859-1.
+ //
+ // encoded-word = "=?"
+ // 1*(%x21 / %x23-27 / %x2A-2B / %x2D / %30-39 / %x41-5A / %x5E-7E)
+ // ["*" 1*8ALPHA *("-" 1*8ALPHA)] "?"
+ // ("B?" *(4base64) (4base64 / 3base64 "=" / 2base64 "==")
+ // / "Q?" 1*(%x21-3C / %x3E / %x40-7E / "=" 2HEXDIG))
+ // "?="
+ //
+ // base64 = ALPHA / DIGIT / "+" / "/"
+
+ const sal_Char * pBegin = rBody.GetBuffer();
+ const sal_Char * pEnd = pBegin + rBody.Len();
+
+ UniString sDecoded;
+ const sal_Char * pCopyBegin = pBegin;
+
+ /* bool bStartEncodedWord = true; */
+ const sal_Char * pWSPBegin = pBegin;
+ UniString sEncodedText;
+ bool bQuotedEncodedText = false;
+ sal_uInt32 nCommentLevel = 0;
+
+ for (const sal_Char * p = pBegin; p != pEnd;)
+ {
+ if (p != pEnd && *p == '=' /* && bStartEncodedWord */)
+ {
+ const sal_Char * q = p + 1;
+ bool bEncodedWord = q != pEnd && *q++ == '?';
+
+ rtl_TextEncoding eCharsetEncoding = RTL_TEXTENCODING_DONTKNOW;
+ if (bEncodedWord)
+ {
+ const sal_Char * pCharsetBegin = q;
+ const sal_Char * pLanguageBegin = 0;
+ int nAlphaCount = 0;
+ for (bool bDone = false; !bDone;)
+ if (q == pEnd)
+ {
+ bEncodedWord = false;
+ bDone = true;
+ }
+ else
+ {
+ sal_Char cChar = *q++;
+ switch (cChar)
+ {
+ case '*':
+ pLanguageBegin = q - 1;
+ nAlphaCount = 0;
+ break;
+
+ case '-':
+ if (pLanguageBegin != 0)
+ {
+ if (nAlphaCount == 0)
+ pLanguageBegin = 0;
+ else
+ nAlphaCount = 0;
+ }
+ break;
+
+ case '?':
+ if (pCharsetBegin == q - 1)
+ bEncodedWord = false;
+ else
+ {
+ eCharsetEncoding
+ = getCharsetEncoding(
+ pCharsetBegin,
+ pLanguageBegin == 0
+ || nAlphaCount == 0 ?
+ q - 1 : pLanguageBegin);
+ bEncodedWord = isMIMECharsetEncoding(
+ eCharsetEncoding);
+ eCharsetEncoding
+ = translateFromMIME(eCharsetEncoding);
+ }
+ bDone = true;
+ break;
+
+ default:
+ if (pLanguageBegin != 0
+ && (!isAlpha(cChar) || ++nAlphaCount > 8))
+ pLanguageBegin = 0;
+ break;
+ }
+ }
+ }
+
+ bool bEncodingB = false;
+ if (bEncodedWord)
+ {
+ if (q == pEnd)
+ bEncodedWord = false;
+ else
+ {
+ switch (*q++)
+ {
+ case 'B':
+ case 'b':
+ bEncodingB = true;
+ break;
+
+ case 'Q':
+ case 'q':
+ bEncodingB = false;
+ break;
+
+ default:
+ bEncodedWord = false;
+ break;
+ }
+ }
+ }
+
+ bEncodedWord = bEncodedWord && q != pEnd && *q++ == '?';
+
+ ByteString sText;
+ if (bEncodedWord)
+ {
+ if (bEncodingB)
+ {
+ for (bool bDone = false; !bDone;)
+ {
+ if (pEnd - q < 4)
+ {
+ bEncodedWord = false;
+ bDone = true;
+ }
+ else
+ {
+ bool bFinal = false;
+ int nCount = 3;
+ sal_uInt32 nValue = 0;
+ for (int nShift = 18; nShift >= 0; nShift -= 6)
+ {
+ int nWeight = getBase64Weight(*q++);
+ if (nWeight == -2)
+ {
+ bEncodedWord = false;
+ bDone = true;
+ break;
+ }
+ if (nWeight == -1)
+ {
+ if (!bFinal)
+ {
+ if (nShift >= 12)
+ {
+ bEncodedWord = false;
+ bDone = true;
+ break;
+ }
+ bFinal = true;
+ nCount = nShift == 6 ? 1 : 2;
+ }
+ }
+ else
+ nValue |= nWeight << nShift;
+ }
+ if (bEncodedWord)
+ {
+ for (int nShift = 16; nCount-- > 0;
+ nShift -= 8)
+ sText += sal_Char(nValue >> nShift
+ & 0xFF);
+ if (*q == '?')
+ {
+ ++q;
+ bDone = true;
+ }
+ if (bFinal && !bDone)
+ {
+ bEncodedWord = false;
+ bDone = true;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ const sal_Char * pEncodedTextBegin = q;
+ const sal_Char * pEncodedTextCopyBegin = q;
+ for (bool bDone = false; !bDone;)
+ if (q == pEnd)
+ {
+ bEncodedWord = false;
+ bDone = true;
+ }
+ else
+ {
+ sal_uInt32 nChar = *q++;
+ switch (nChar)
+ {
+ case '=':
+ {
+ if (pEnd - q < 2)
+ {
+ bEncodedWord = false;
+ bDone = true;
+ break;
+ }
+ int nDigit1 = getHexWeight(q[0]);
+ int nDigit2 = getHexWeight(q[1]);
+ if (nDigit1 < 0 || nDigit2 < 0)
+ {
+ bEncodedWord = false;
+ bDone = true;
+ break;
+ }
+ sText += rBody.Copy(
+ static_cast< xub_StrLen >(
+ pEncodedTextCopyBegin - pBegin),
+ static_cast< xub_StrLen >(
+ q - 1 - pEncodedTextCopyBegin));
+ sText += sal_Char(nDigit1 << 4 | nDigit2);
+ q += 2;
+ pEncodedTextCopyBegin = q;
+ break;
+ }
+
+ case '?':
+ if (q - pEncodedTextBegin > 1)
+ sText += rBody.Copy(
+ static_cast< xub_StrLen >(
+ pEncodedTextCopyBegin - pBegin),
+ static_cast< xub_StrLen >(
+ q - 1 - pEncodedTextCopyBegin));
+ else
+ bEncodedWord = false;
+ bDone = true;
+ break;
+
+ case '_':
+ sText += rBody.Copy(
+ static_cast< xub_StrLen >(
+ pEncodedTextCopyBegin - pBegin),
+ static_cast< xub_StrLen >(
+ q - 1 - pEncodedTextCopyBegin));
+ sText += ' ';
+ pEncodedTextCopyBegin = q;
+ break;
+
+ default:
+ if (!isVisible(nChar))
+ {
+ bEncodedWord = false;
+ bDone = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ bEncodedWord = bEncodedWord && q != pEnd && *q++ == '=';
+
+// if (bEncodedWord && q != pEnd)
+// switch (*q)
+// {
+// case '\t':
+// case ' ':
+// case '"':
+// case ')':
+// case ',':
+// case '.':
+// case '=':
+// break;
+//
+// default:
+// bEncodedWord = false;
+// break;
+// }
+
+ sal_Unicode * pUnicodeBuffer = 0;
+ sal_Size nUnicodeSize = 0;
+ if (bEncodedWord)
+ {
+ pUnicodeBuffer
+ = convertToUnicode(sText.GetBuffer(),
+ sText.GetBuffer() + sText.Len(),
+ eCharsetEncoding, nUnicodeSize);
+ if (pUnicodeBuffer == 0)
+ bEncodedWord = false;
+ }
+
+ if (bEncodedWord)
+ {
+ appendISO88591(sDecoded, pCopyBegin, pWSPBegin);
+ if (eType == HEADER_FIELD_TEXT)
+ sDecoded.Append(
+ pUnicodeBuffer,
+ static_cast< xub_StrLen >(nUnicodeSize));
+ else if (nCommentLevel == 0)
+ {
+ sEncodedText.Append(
+ pUnicodeBuffer,
+ static_cast< xub_StrLen >(nUnicodeSize));
+ if (!bQuotedEncodedText)
+ {
+ const sal_Unicode * pTextPtr = pUnicodeBuffer;
+ const sal_Unicode * pTextEnd = pTextPtr
+ + nUnicodeSize;
+ for (; pTextPtr != pTextEnd; ++pTextPtr)
+ if (!isEncodedWordTokenChar(*pTextPtr))
+ {
+ bQuotedEncodedText = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ const sal_Unicode * pTextPtr = pUnicodeBuffer;
+ const sal_Unicode * pTextEnd = pTextPtr + nUnicodeSize;
+ for (; pTextPtr != pTextEnd; ++pTextPtr)
+ {
+ switch (*pTextPtr)
+ {
+ case '(':
+ case ')':
+ case '\\':
+ case '\x0D':
+ case '=':
+ sDecoded += '\\';
+ break;
+ }
+ sDecoded += *pTextPtr;
+ }
+ }
+ delete[] pUnicodeBuffer;
+ p = q;
+ pCopyBegin = p;
+
+ pWSPBegin = p;
+ while (p != pEnd && isWhiteSpace(*p))
+ ++p;
+ /* bStartEncodedWord = p != pWSPBegin; */
+ continue;
+ }
+ }
+
+ if (sEncodedText.Len() != 0)
+ {
+ if (bQuotedEncodedText)
+ {
+ sDecoded += '"';
+ const sal_Unicode * pTextPtr = sEncodedText.GetBuffer();
+ const sal_Unicode * pTextEnd = pTextPtr + sEncodedText.Len();
+ for (;pTextPtr != pTextEnd; ++pTextPtr)
+ {
+ switch (*pTextPtr)
+ {
+ case '"':
+ case '\\':
+ case '\x0D':
+ sDecoded += '\\';
+ break;
+ }
+ sDecoded += *pTextPtr;
+ }
+ sDecoded += '"';
+ }
+ else
+ sDecoded += sEncodedText;
+ sEncodedText.Erase();
+ bQuotedEncodedText = false;
+ }
+
+ if (p == pEnd)
+ break;
+
+ switch (*p++)
+ {
+// case '\t':
+// case ' ':
+// case ',':
+// case '.':
+// case '=':
+// bStartEncodedWord = true;
+// break;
+
+ case '"':
+ if (eType != HEADER_FIELD_TEXT && nCommentLevel == 0)
+ {
+ const sal_Char * pQuotedStringEnd
+ = skipQuotedString(p - 1, pEnd);
+ p = pQuotedStringEnd == p - 1 ? pEnd : pQuotedStringEnd;
+ }
+ /* bStartEncodedWord = true; */
+ break;
+
+ case '(':
+ if (eType != HEADER_FIELD_TEXT)
+ ++nCommentLevel;
+ /* bStartEncodedWord = true; */
+ break;
+
+ case ')':
+ if (nCommentLevel > 0)
+ --nCommentLevel;
+ /* bStartEncodedWord = false; */
+ break;
+
+ default:
+ {
+ const sal_Char * pUTF8Begin = p - 1;
+ const sal_Char * pUTF8End = pUTF8Begin;
+ sal_uInt32 nCharacter;
+ if (translateUTF8Char(pUTF8End, pEnd, RTL_TEXTENCODING_UCS4,
+ nCharacter))
+ {
+ appendISO88591(sDecoded, pCopyBegin, p - 1);
+ sal_Unicode aUTF16Buf[2];
+ xub_StrLen nUTF16Len = static_cast< xub_StrLen >(
+ putUTF32Character(aUTF16Buf, nCharacter) - aUTF16Buf);
+ sDecoded.Append(aUTF16Buf, nUTF16Len);
+ p = pUTF8End;
+ pCopyBegin = p;
+ }
+ /* bStartEncodedWord = false; */
+ break;
+ }
+ }
+ pWSPBegin = p;
+ }
+
+ appendISO88591(sDecoded, pCopyBegin, pEnd);
+ return sDecoded;
+}
+
+//============================================================================
+//
+// INetMIMEOutputSink
+//
+//============================================================================
+
+// virtual
+sal_Size INetMIMEOutputSink::writeSequence(const sal_Char * pSequence)
+{
+ sal_Size nLength = rtl_str_getLength(pSequence);
+ writeSequence(pSequence, pSequence + nLength);
+ return nLength;
+}
+
+//============================================================================
+// virtual
+void INetMIMEOutputSink::writeSequence(const sal_uInt32 * pBegin,
+ const sal_uInt32 * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIMEOutputSink::writeSequence(): Bad sequence");
+
+ sal_Char * pBufferBegin = new sal_Char[pEnd - pBegin];
+ sal_Char * pBufferEnd = pBufferBegin;
+ while (pBegin != pEnd)
+ {
+ DBG_ASSERT(*pBegin < 256,
+ "INetMIMEOutputSink::writeSequence(): Bad octet");
+ *pBufferEnd++ = sal_Char(*pBegin++);
+ }
+ writeSequence(pBufferBegin, pBufferEnd);
+ delete[] pBufferBegin;
+}
+
+//============================================================================
+// virtual
+void INetMIMEOutputSink::writeSequence(const sal_Unicode * pBegin,
+ const sal_Unicode * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIMEOutputSink::writeSequence(): Bad sequence");
+
+ sal_Char * pBufferBegin = new sal_Char[pEnd - pBegin];
+ sal_Char * pBufferEnd = pBufferBegin;
+ while (pBegin != pEnd)
+ {
+ DBG_ASSERT(*pBegin < 256,
+ "INetMIMEOutputSink::writeSequence(): Bad octet");
+ *pBufferEnd++ = sal_Char(*pBegin++);
+ }
+ writeSequence(pBufferBegin, pBufferEnd);
+ delete[] pBufferBegin;
+}
+
+//============================================================================
+// virtual
+ErrCode INetMIMEOutputSink::getError() const
+{
+ return ERRCODE_NONE;
+}
+
+//============================================================================
+void INetMIMEOutputSink::writeLineEnd()
+{
+ static const sal_Char aCRLF[2] = { 0x0D, 0x0A };
+ writeSequence(aCRLF, aCRLF + 2);
+ m_nColumn = 0;
+}
+
+//============================================================================
+//
+// INetMIMEStringOutputSink
+//
+//============================================================================
+
+// virtual
+void INetMIMEStringOutputSink::writeSequence(const sal_Char * pBegin,
+ const sal_Char * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIMEStringOutputSink::writeSequence(): Bad sequence");
+
+ m_bOverflow = m_bOverflow
+ || pEnd - pBegin > STRING_MAXLEN - m_aBuffer.Len();
+ if (!m_bOverflow)
+ m_aBuffer.Append(pBegin, static_cast< xub_StrLen >(pEnd - pBegin));
+}
+
+//============================================================================
+// virtual
+ErrCode INetMIMEStringOutputSink::getError() const
+{
+ return m_bOverflow ? ERRCODE_IO_OUTOFMEMORY : ERRCODE_NONE;
+}
+
+//============================================================================
+//
+// INetMIMEUnicodeOutputSink
+//
+//============================================================================
+
+// virtual
+void INetMIMEUnicodeOutputSink::writeSequence(const sal_Char * pBegin,
+ const sal_Char * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence");
+
+ sal_Unicode * pBufferBegin = new sal_Unicode[pEnd - pBegin];
+ sal_Unicode * pBufferEnd = pBufferBegin;
+ while (pBegin != pEnd)
+ *pBufferEnd++ = sal_uChar(*pBegin++);
+ writeSequence(pBufferBegin, pBufferEnd);
+ delete[] pBufferBegin;
+}
+
+//============================================================================
+// virtual
+void INetMIMEUnicodeOutputSink::writeSequence(const sal_uInt32 * pBegin,
+ const sal_uInt32 * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence");
+
+ sal_Unicode * pBufferBegin = new sal_Unicode[pEnd - pBegin];
+ sal_Unicode * pBufferEnd = pBufferBegin;
+ while (pBegin != pEnd)
+ {
+ DBG_ASSERT(*pBegin < 256,
+ "INetMIMEOutputSink::writeSequence(): Bad octet");
+ *pBufferEnd++ = sal_Unicode(*pBegin++);
+ }
+ writeSequence(pBufferBegin, pBufferEnd);
+ delete[] pBufferBegin;
+}
+
+//============================================================================
+// virtual
+void INetMIMEUnicodeOutputSink::writeSequence(const sal_Unicode * pBegin,
+ const sal_Unicode * pEnd)
+{
+ DBG_ASSERT(pBegin && pBegin <= pEnd,
+ "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence");
+
+ m_bOverflow = m_bOverflow
+ || pEnd - pBegin > STRING_MAXLEN - m_aBuffer.Len();
+ if (!m_bOverflow)
+ m_aBuffer.Append(pBegin, static_cast< xub_StrLen >(pEnd - pBegin));
+}
+
+//============================================================================
+// virtual
+ErrCode INetMIMEUnicodeOutputSink::getError() const
+{
+ return m_bOverflow ? ERRCODE_IO_OUTOFMEMORY : ERRCODE_NONE;
+}
+
+//============================================================================
+//
+// INetMIMEEncodedWordOutputSink
+//
+//============================================================================
+
+static const sal_Char aEscape[128]
+ = { INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x00
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x01
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x02
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x03
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x04
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x05
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x06
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x07
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x08
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x09
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0A
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0B
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0C
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0D
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0E
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0F
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x10
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x11
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x12
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x13
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x14
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x15
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x16
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x17
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x18
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x19
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1A
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1B
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1C
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1D
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1E
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1F
+ 0, // ' '
+ 0, // '!'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '"'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '#'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '$'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '%'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '&'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '''
+ INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '('
+ INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ')'
+ 0, // '*'
+ 0, // '+'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ','
+ 0, // '-'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '.'
+ 0, // '/'
+ 0, // '0'
+ 0, // '1'
+ 0, // '2'
+ 0, // '3'
+ 0, // '4'
+ 0, // '5'
+ 0, // '6'
+ 0, // '7'
+ 0, // '8'
+ 0, // '9'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ':'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ';'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '<'
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '='
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '>'
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '?'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '@'
+ 0, // 'A'
+ 0, // 'B'
+ 0, // 'C'
+ 0, // 'D'
+ 0, // 'E'
+ 0, // 'F'
+ 0, // 'G'
+ 0, // 'H'
+ 0, // 'I'
+ 0, // 'J'
+ 0, // 'K'
+ 0, // 'L'
+ 0, // 'M'
+ 0, // 'N'
+ 0, // 'O'
+ 0, // 'P'
+ 0, // 'Q'
+ 0, // 'R'
+ 0, // 'S'
+ 0, // 'T'
+ 0, // 'U'
+ 0, // 'V'
+ 0, // 'W'
+ 0, // 'X'
+ 0, // 'Y'
+ 0, // 'Z'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '['
+ INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '\'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ']'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '^'
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '_'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '`'
+ 0, // 'a'
+ 0, // 'b'
+ 0, // 'c'
+ 0, // 'd'
+ 0, // 'e'
+ 0, // 'f'
+ 0, // 'g'
+ 0, // 'h'
+ 0, // 'i'
+ 0, // 'j'
+ 0, // 'k'
+ 0, // 'l'
+ 0, // 'm'
+ 0, // 'n'
+ 0, // 'o'
+ 0, // 'p'
+ 0, // 'q'
+ 0, // 'r'
+ 0, // 's'
+ 0, // 't'
+ 0, // 'u'
+ 0, // 'v'
+ 0, // 'w'
+ 0, // 'x'
+ 0, // 'y'
+ 0, // 'z'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '{'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '|'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '}'
+ INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '~'
+ INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE }; // DEL
+
+inline bool
+INetMIMEEncodedWordOutputSink::needsEncodedWordEscape(sal_uInt32 nChar) const
+{
+ return !INetMIME::isUSASCII(nChar) || aEscape[nChar] & m_eContext;
+}
+
+//============================================================================
+void INetMIMEEncodedWordOutputSink::finish(bool bWriteTrailer)
+{
+ if (m_eInitialSpace == SPACE_ALWAYS && m_nExtraSpaces == 0)
+ m_nExtraSpaces = 1;
+
+ if (m_eEncodedWordState == STATE_SECOND_EQUALS)
+ {
+ // If the text is already an encoded word, copy it verbatim:
+ sal_uInt32 nSize = m_pBufferEnd - m_pBuffer;
+ switch (m_ePrevCoding)
+ {
+ case CODING_QUOTED:
+ m_rSink << '"';
+ case CODING_NONE:
+ if (m_eInitialSpace == SPACE_ENCODED && m_nExtraSpaces == 0)
+ m_nExtraSpaces = 1;
+ for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
+ {
+ if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ }
+ if (m_nExtraSpaces == 1)
+ {
+ if (m_rSink.getColumn() + nSize
+ >= m_rSink.getLineLengthLimit())
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ }
+ break;
+
+ case CODING_ENCODED:
+ {
+ const sal_Char * pCharsetName
+ = INetMIME::getCharsetName(m_ePrevMIMEEncoding);
+ while (m_nExtraSpaces-- > 0)
+ {
+ if (m_rSink.getColumn()
+ > m_rSink.getLineLengthLimit() - 3)
+ m_rSink << "?=" << INetMIMEOutputSink::endl << " =?"
+ << pCharsetName << "?Q?";
+ m_rSink << '_';
+ }
+ m_rSink << "?=";
+ }
+ case CODING_ENCODED_TERMINATED:
+ if (m_rSink.getColumn() + nSize
+ > m_rSink.getLineLengthLimit() - 1)
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ break;
+ }
+ m_rSink.write(m_pBuffer, m_pBufferEnd);
+ m_eCoding = CODING_ENCODED_TERMINATED;
+ }
+ else
+ {
+ // If the text itself is too long to fit into a single line, make it
+ // into multiple encoded words:
+ switch (m_eCoding)
+ {
+ case CODING_NONE:
+ if (m_nExtraSpaces == 0)
+ {
+ DBG_ASSERT(m_ePrevCoding == CODING_NONE
+ || m_pBuffer == m_pBufferEnd,
+ "INetMIMEEncodedWordOutputSink::finish():"
+ " Bad state");
+ if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
+ > m_rSink.getLineLengthLimit())
+ m_eCoding = CODING_ENCODED;
+ }
+ else
+ {
+ OSL_ASSERT(m_pBufferEnd >= m_pBuffer);
+ if (static_cast< std::size_t >(m_pBufferEnd - m_pBuffer)
+ > m_rSink.getLineLengthLimit() - 1)
+ {
+ m_eCoding = CODING_ENCODED;
+ }
+ }
+ break;
+
+ case CODING_QUOTED:
+ if (m_nExtraSpaces == 0)
+ {
+ DBG_ASSERT(m_ePrevCoding == CODING_NONE,
+ "INetMIMEEncodedWordOutputSink::finish():"
+ " Bad state");
+ if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
+ + m_nQuotedEscaped
+ > m_rSink.getLineLengthLimit() - 2)
+ m_eCoding = CODING_ENCODED;
+ }
+ else if ((m_pBufferEnd - m_pBuffer) + m_nQuotedEscaped
+ > m_rSink.getLineLengthLimit() - 3)
+ m_eCoding = CODING_ENCODED;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (m_eCoding)
+ {
+ case CODING_NONE:
+ switch (m_ePrevCoding)
+ {
+ case CODING_QUOTED:
+ if (m_rSink.getColumn() + m_nExtraSpaces
+ + (m_pBufferEnd - m_pBuffer)
+ < m_rSink.getLineLengthLimit())
+ m_eCoding = CODING_QUOTED;
+ else
+ m_rSink << '"';
+ break;
+
+ case CODING_ENCODED:
+ m_rSink << "?=";
+ break;
+
+ default:
+ break;
+ }
+ for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
+ {
+ if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ }
+ if (m_nExtraSpaces == 1)
+ {
+ if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
+ >= m_rSink.getLineLengthLimit())
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ }
+ m_rSink.write(m_pBuffer, m_pBufferEnd);
+ if (m_eCoding == CODING_QUOTED && bWriteTrailer)
+ {
+ m_rSink << '"';
+ m_eCoding = CODING_NONE;
+ }
+ break;
+
+ case CODING_QUOTED:
+ {
+ bool bInsertLeadingQuote = true;
+ sal_uInt32 nSize = (m_pBufferEnd - m_pBuffer)
+ + m_nQuotedEscaped + 2;
+ switch (m_ePrevCoding)
+ {
+ case CODING_QUOTED:
+ if (m_rSink.getColumn() + m_nExtraSpaces + nSize - 1
+ < m_rSink.getLineLengthLimit())
+ {
+ bInsertLeadingQuote = false;
+ --nSize;
+ }
+ else
+ m_rSink << '"';
+ break;
+
+ case CODING_ENCODED:
+ m_rSink << "?=";
+ break;
+
+ default:
+ break;
+ }
+ for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
+ {
+ if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ }
+ if (m_nExtraSpaces == 1)
+ {
+ if (m_rSink.getColumn() + nSize
+ >= m_rSink.getLineLengthLimit())
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ }
+ if (bInsertLeadingQuote)
+ m_rSink << '"';
+ for (const sal_Unicode * p = m_pBuffer; p != m_pBufferEnd;
+ ++p)
+ {
+ if (INetMIME::needsQuotedStringEscape(*p))
+ m_rSink << '\\';
+ m_rSink << sal_Char(*p);
+ }
+ if (bWriteTrailer)
+ {
+ m_rSink << '"';
+ m_eCoding = CODING_NONE;
+ }
+ break;
+ }
+
+ case CODING_ENCODED:
+ {
+ rtl_TextEncoding eCharsetEncoding
+ = m_pEncodingList->
+ getPreferredEncoding(RTL_TEXTENCODING_UTF8);
+ rtl_TextEncoding eMIMEEncoding
+ = INetMIME::translateToMIME(eCharsetEncoding);
+
+ // The non UTF-8 code will only work for stateless single byte
+ // character encodings (see also below):
+ sal_Char * pTargetBuffer = NULL;
+ sal_Size nTargetSize = 0;
+ sal_uInt32 nSize;
+ if (eMIMEEncoding == RTL_TEXTENCODING_UTF8)
+ {
+ nSize = 0;
+ for (sal_Unicode const * p = m_pBuffer;
+ p != m_pBufferEnd;)
+ {
+ sal_uInt32 nUTF32
+ = INetMIME::getUTF32Character(p, m_pBufferEnd);
+ nSize += needsEncodedWordEscape(nUTF32) ?
+ 3 * INetMIME::getUTF8OctetCount(nUTF32) :
+ 1;
+ // only US-ASCII characters (that are converted to
+ // a single byte by UTF-8) need no encoded word
+ // escapes...
+ }
+ }
+ else
+ {
+ rtl_UnicodeToTextConverter hConverter
+ = rtl_createUnicodeToTextConverter(eCharsetEncoding);
+ rtl_UnicodeToTextContext hContext
+ = rtl_createUnicodeToTextContext(hConverter);
+ for (sal_Size nBufferSize = m_pBufferEnd - m_pBuffer;;
+ nBufferSize += nBufferSize / 3 + 1)
+ {
+ pTargetBuffer = new sal_Char[nBufferSize];
+ sal_uInt32 nInfo;
+ sal_Size nSrcCvtBytes;
+ nTargetSize
+ = rtl_convertUnicodeToText(
+ hConverter, hContext, m_pBuffer,
+ m_pBufferEnd - m_pBuffer, pTargetBuffer,
+ nBufferSize,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_IGNORE
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_IGNORE,
+ &nInfo, &nSrcCvtBytes);
+ if (!(nInfo
+ & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL))
+ break;
+ delete[] pTargetBuffer;
+ pTargetBuffer = NULL;
+ rtl_resetUnicodeToTextContext(hConverter, hContext);
+ }
+ rtl_destroyUnicodeToTextContext(hConverter, hContext);
+ rtl_destroyUnicodeToTextConverter(hConverter);
+
+ nSize = nTargetSize;
+ for (sal_Size k = 0; k < nTargetSize; ++k)
+ if (needsEncodedWordEscape(sal_uChar(
+ pTargetBuffer[k])))
+ nSize += 2;
+ }
+
+ const sal_Char * pCharsetName
+ = INetMIME::getCharsetName(eMIMEEncoding);
+ sal_uInt32 nWrapperSize = rtl_str_getLength(pCharsetName) + 7;
+ // '=?', '?Q?', '?='
+
+ switch (m_ePrevCoding)
+ {
+ case CODING_QUOTED:
+ m_rSink << '"';
+ case CODING_NONE:
+ if (m_eInitialSpace == SPACE_ENCODED
+ && m_nExtraSpaces == 0)
+ m_nExtraSpaces = 1;
+ nSize += nWrapperSize;
+ for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
+ {
+ if (m_rSink.getColumn()
+ >= m_rSink.getLineLengthLimit())
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ }
+ if (m_nExtraSpaces == 1)
+ {
+ if (m_rSink.getColumn() + nSize
+ >= m_rSink.getLineLengthLimit())
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << ' ';
+ }
+ m_rSink << "=?" << pCharsetName << "?Q?";
+ break;
+
+ case CODING_ENCODED:
+ if (m_ePrevMIMEEncoding != eMIMEEncoding
+ || m_rSink.getColumn() + m_nExtraSpaces + nSize
+ > m_rSink.getLineLengthLimit() - 2)
+ {
+ m_rSink << "?=";
+ if (m_rSink.getColumn() + nWrapperSize
+ + m_nExtraSpaces + nSize
+ > m_rSink.getLineLengthLimit() - 1)
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << " =?" << pCharsetName << "?Q?";
+ }
+ while (m_nExtraSpaces-- > 0)
+ {
+ if (m_rSink.getColumn()
+ > m_rSink.getLineLengthLimit() - 3)
+ m_rSink << "?=" << INetMIMEOutputSink::endl
+ << " =?" << pCharsetName << "?Q?";
+ m_rSink << '_';
+ }
+ break;
+
+ case CODING_ENCODED_TERMINATED:
+ if (m_rSink.getColumn() + nWrapperSize
+ + m_nExtraSpaces + nSize
+ > m_rSink.getLineLengthLimit() - 1)
+ m_rSink << INetMIMEOutputSink::endl;
+ m_rSink << " =?" << pCharsetName << "?Q?";
+ while (m_nExtraSpaces-- > 0)
+ {
+ if (m_rSink.getColumn()
+ > m_rSink.getLineLengthLimit() - 3)
+ m_rSink << "?=" << INetMIMEOutputSink::endl
+ << " =?" << pCharsetName << "?Q?";
+ m_rSink << '_';
+ }
+ break;
+ }
+
+ // The non UTF-8 code will only work for stateless single byte
+ // character encodings (see also above):
+ if (eMIMEEncoding == RTL_TEXTENCODING_UTF8)
+ {
+ bool bInitial = true;
+ for (sal_Unicode const * p = m_pBuffer;
+ p != m_pBufferEnd;)
+ {
+ sal_uInt32 nUTF32
+ = INetMIME::getUTF32Character(p, m_pBufferEnd);
+ bool bEscape = needsEncodedWordEscape(nUTF32);
+ sal_uInt32 nWidth
+ = bEscape ?
+ 3 * INetMIME::getUTF8OctetCount(nUTF32) : 1;
+ // only US-ASCII characters (that are converted to
+ // a single byte by UTF-8) need no encoded word
+ // escapes...
+ if (!bInitial
+ && m_rSink.getColumn() + nWidth + 2
+ > m_rSink.getLineLengthLimit())
+ m_rSink << "?=" << INetMIMEOutputSink::endl
+ << " =?" << pCharsetName << "?Q?";
+ if (bEscape)
+ {
+ DBG_ASSERT(
+ nUTF32 < 0x10FFFF,
+ "INetMIMEEncodedWordOutputSink::finish():"
+ " Bad char");
+ if (nUTF32 < 0x80)
+ INetMIME::writeEscapeSequence(m_rSink,
+ nUTF32);
+ else if (nUTF32 < 0x800)
+ {
+ INetMIME::writeEscapeSequence(m_rSink,
+ (nUTF32 >> 6)
+ | 0xC0);
+ INetMIME::writeEscapeSequence(m_rSink,
+ (nUTF32 & 0x3F)
+ | 0x80);
+ }
+ else if (nUTF32 < 0x10000)
+ {
+ INetMIME::writeEscapeSequence(m_rSink,
+ (nUTF32 >> 12)
+ | 0xE0);
+ INetMIME::writeEscapeSequence(m_rSink,
+ ((nUTF32 >> 6)
+ & 0x3F)
+ | 0x80);
+ INetMIME::writeEscapeSequence(m_rSink,
+ (nUTF32 & 0x3F)
+ | 0x80);
+ }
+ else
+ {
+ INetMIME::writeEscapeSequence(m_rSink,
+ (nUTF32 >> 18)
+ | 0xF0);
+ INetMIME::writeEscapeSequence(m_rSink,
+ ((nUTF32 >> 12)
+ & 0x3F)
+ | 0x80);
+ INetMIME::writeEscapeSequence(m_rSink,
+ ((nUTF32 >> 6)
+ & 0x3F)
+ | 0x80);
+ INetMIME::writeEscapeSequence(m_rSink,
+ (nUTF32 & 0x3F)
+ | 0x80);
+ }
+ }
+ else
+ m_rSink << sal_Char(nUTF32);
+ bInitial = false;
+ }
+ }
+ else
+ {
+ for (sal_Size k = 0; k < nTargetSize; ++k)
+ {
+ sal_uInt32 nUCS4 = sal_uChar(pTargetBuffer[k]);
+ bool bEscape = needsEncodedWordEscape(nUCS4);
+ if (k > 0
+ && m_rSink.getColumn() + (bEscape ? 5 : 3)
+ > m_rSink.getLineLengthLimit())
+ m_rSink << "?=" << INetMIMEOutputSink::endl
+ << " =?" << pCharsetName << "?Q?";
+ if (bEscape)
+ INetMIME::writeEscapeSequence(m_rSink, nUCS4);
+ else
+ m_rSink << sal_Char(nUCS4);
+ }
+ delete[] pTargetBuffer;
+ }
+
+ if (bWriteTrailer)
+ {
+ m_rSink << "?=";
+ m_eCoding = CODING_ENCODED_TERMINATED;
+ }
+
+ m_ePrevMIMEEncoding = eMIMEEncoding;
+ break;
+ }
+
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+ }
+
+ m_eInitialSpace = SPACE_NO;
+ m_nExtraSpaces = 0;
+ m_pEncodingList->reset();
+ m_pBufferEnd = m_pBuffer;
+ m_ePrevCoding = m_eCoding;
+ m_eCoding = CODING_NONE;
+ m_nQuotedEscaped = 0;
+ m_eEncodedWordState = STATE_INITIAL;
+}
+
+//============================================================================
+INetMIMEEncodedWordOutputSink::~INetMIMEEncodedWordOutputSink()
+{
+ rtl_freeMemory(m_pBuffer);
+ delete m_pEncodingList;
+}
+
+//============================================================================
+INetMIMEEncodedWordOutputSink &
+INetMIMEEncodedWordOutputSink::operator <<(sal_uInt32 nChar)
+{
+ if (nChar == ' ')
+ {
+ if (m_pBufferEnd != m_pBuffer)
+ finish(false);
+ ++m_nExtraSpaces;
+ }
+ else
+ {
+ // Check for an already encoded word:
+ switch (m_eEncodedWordState)
+ {
+ case STATE_INITIAL:
+ if (nChar == '=')
+ m_eEncodedWordState = STATE_FIRST_EQUALS;
+ else
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_FIRST_EQUALS:
+ if (nChar == '?')
+ m_eEncodedWordState = STATE_FIRST_EQUALS;
+ else
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_FIRST_QUESTION:
+ if (INetMIME::isEncodedWordTokenChar(nChar))
+ m_eEncodedWordState = STATE_CHARSET;
+ else
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_CHARSET:
+ if (nChar == '?')
+ m_eEncodedWordState = STATE_SECOND_QUESTION;
+ else if (!INetMIME::isEncodedWordTokenChar(nChar))
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_SECOND_QUESTION:
+ if (nChar == 'B' || nChar == 'Q'
+ || nChar == 'b' || nChar == 'q')
+ m_eEncodedWordState = STATE_ENCODING;
+ else
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_ENCODING:
+ if (nChar == '?')
+ m_eEncodedWordState = STATE_THIRD_QUESTION;
+ else
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_THIRD_QUESTION:
+ if (INetMIME::isVisible(nChar) && nChar != '?')
+ m_eEncodedWordState = STATE_ENCODED_TEXT;
+ else
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_ENCODED_TEXT:
+ if (nChar == '?')
+ m_eEncodedWordState = STATE_FOURTH_QUESTION;
+ else if (!INetMIME::isVisible(nChar))
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_FOURTH_QUESTION:
+ if (nChar == '=')
+ m_eEncodedWordState = STATE_SECOND_EQUALS;
+ else
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_SECOND_EQUALS:
+ m_eEncodedWordState = STATE_BAD;
+ break;
+
+ case STATE_BAD:
+ break;
+ }
+
+ // Update encoding:
+ m_pEncodingList->includes(nChar);
+
+ // Update coding:
+ enum { TENQ = 1, // CONTEXT_TEXT, CODING_ENCODED
+ CENQ = 2, // CONTEXT_COMMENT, CODING_ENCODED
+ PQTD = 4, // CONTEXT_PHRASE, CODING_QUOTED
+ PENQ = 8 }; // CONTEXT_PHRASE, CODING_ENCODED
+ static const sal_Char aMinimal[128]
+ = { TENQ | CENQ | PENQ, // 0x00
+ TENQ | CENQ | PENQ, // 0x01
+ TENQ | CENQ | PENQ, // 0x02
+ TENQ | CENQ | PENQ, // 0x03
+ TENQ | CENQ | PENQ, // 0x04
+ TENQ | CENQ | PENQ, // 0x05
+ TENQ | CENQ | PENQ, // 0x06
+ TENQ | CENQ | PENQ, // 0x07
+ TENQ | CENQ | PENQ, // 0x08
+ TENQ | CENQ | PENQ, // 0x09
+ TENQ | CENQ | PENQ, // 0x0A
+ TENQ | CENQ | PENQ, // 0x0B
+ TENQ | CENQ | PENQ, // 0x0C
+ TENQ | CENQ | PENQ, // 0x0D
+ TENQ | CENQ | PENQ, // 0x0E
+ TENQ | CENQ | PENQ, // 0x0F
+ TENQ | CENQ | PENQ, // 0x10
+ TENQ | CENQ | PENQ, // 0x11
+ TENQ | CENQ | PENQ, // 0x12
+ TENQ | CENQ | PENQ, // 0x13
+ TENQ | CENQ | PENQ, // 0x14
+ TENQ | CENQ | PENQ, // 0x15
+ TENQ | CENQ | PENQ, // 0x16
+ TENQ | CENQ | PENQ, // 0x17
+ TENQ | CENQ | PENQ, // 0x18
+ TENQ | CENQ | PENQ, // 0x19
+ TENQ | CENQ | PENQ, // 0x1A
+ TENQ | CENQ | PENQ, // 0x1B
+ TENQ | CENQ | PENQ, // 0x1C
+ TENQ | CENQ | PENQ, // 0x1D
+ TENQ | CENQ | PENQ, // 0x1E
+ TENQ | CENQ | PENQ, // 0x1F
+ 0, // ' '
+ 0, // '!'
+ PQTD , // '"'
+ 0, // '#'
+ 0, // '$'
+ 0, // '%'
+ 0, // '&'
+ 0, // '''
+ CENQ | PQTD , // '('
+ CENQ | PQTD , // ')'
+ 0, // '*'
+ 0, // '+'
+ PQTD , // ','
+ 0, // '-'
+ PQTD , // '.'
+ 0, // '/'
+ 0, // '0'
+ 0, // '1'
+ 0, // '2'
+ 0, // '3'
+ 0, // '4'
+ 0, // '5'
+ 0, // '6'
+ 0, // '7'
+ 0, // '8'
+ 0, // '9'
+ PQTD , // ':'
+ PQTD , // ';'
+ PQTD , // '<'
+ 0, // '='
+ PQTD , // '>'
+ 0, // '?'
+ PQTD , // '@'
+ 0, // 'A'
+ 0, // 'B'
+ 0, // 'C'
+ 0, // 'D'
+ 0, // 'E'
+ 0, // 'F'
+ 0, // 'G'
+ 0, // 'H'
+ 0, // 'I'
+ 0, // 'J'
+ 0, // 'K'
+ 0, // 'L'
+ 0, // 'M'
+ 0, // 'N'
+ 0, // 'O'
+ 0, // 'P'
+ 0, // 'Q'
+ 0, // 'R'
+ 0, // 'S'
+ 0, // 'T'
+ 0, // 'U'
+ 0, // 'V'
+ 0, // 'W'
+ 0, // 'X'
+ 0, // 'Y'
+ 0, // 'Z'
+ PQTD , // '['
+ CENQ | PQTD , // '\'
+ PQTD , // ']'
+ 0, // '^'
+ 0, // '_'
+ 0, // '`'
+ 0, // 'a'
+ 0, // 'b'
+ 0, // 'c'
+ 0, // 'd'
+ 0, // 'e'
+ 0, // 'f'
+ 0, // 'g'
+ 0, // 'h'
+ 0, // 'i'
+ 0, // 'j'
+ 0, // 'k'
+ 0, // 'l'
+ 0, // 'm'
+ 0, // 'n'
+ 0, // 'o'
+ 0, // 'p'
+ 0, // 'q'
+ 0, // 'r'
+ 0, // 's'
+ 0, // 't'
+ 0, // 'u'
+ 0, // 'v'
+ 0, // 'w'
+ 0, // 'x'
+ 0, // 'y'
+ 0, // 'z'
+ 0, // '{'
+ 0, // '|'
+ 0, // '}'
+ 0, // '~'
+ TENQ | CENQ | PENQ }; // DEL
+ Coding eNewCoding = !INetMIME::isUSASCII(nChar) ? CODING_ENCODED :
+ m_eContext == CONTEXT_PHRASE ?
+ Coding(aMinimal[nChar] >> 2) :
+ aMinimal[nChar] & m_eContext ? CODING_ENCODED :
+ CODING_NONE;
+ if (eNewCoding > m_eCoding)
+ m_eCoding = eNewCoding;
+ if (m_eCoding == CODING_QUOTED
+ && INetMIME::needsQuotedStringEscape(nChar))
+ ++m_nQuotedEscaped;
+
+ // Append to buffer:
+ if (sal_uInt32(m_pBufferEnd - m_pBuffer) == m_nBufferSize)
+ {
+ m_pBuffer
+ = static_cast< sal_Unicode * >(
+ rtl_reallocateMemory(m_pBuffer,
+ (m_nBufferSize + BUFFER_SIZE)
+ * sizeof (sal_Unicode)));
+ m_pBufferEnd = m_pBuffer + m_nBufferSize;
+ m_nBufferSize += BUFFER_SIZE;
+ }
+ *m_pBufferEnd++ = sal_Unicode(nChar);
+ }
+ return *this;
+}
+
+//============================================================================
+//
+// INetContentTypeParameterList
+//
+//============================================================================
+
+void INetContentTypeParameterList::Clear()
+{
+ while (Count() > 0)
+ delete static_cast< INetContentTypeParameter * >(Remove(Count() - 1));
+}
+
+//============================================================================
+const INetContentTypeParameter *
+INetContentTypeParameterList::find(const ByteString & rAttribute) const
+{
+ for (ULONG i = 0; i < Count(); ++i)
+ {
+ const INetContentTypeParameter * pParameter = GetObject(i);
+ if (pParameter->m_sAttribute.EqualsIgnoreCaseAscii(rAttribute))
+ return pParameter;
+ }
+ return 0;
+}
+
diff --git a/tools/source/inet/inetmsg.cxx b/tools/source/inet/inetmsg.cxx
new file mode 100644
index 000000000000..feec97168b59
--- /dev/null
+++ b/tools/source/inet/inetmsg.cxx
@@ -0,0 +1,1653 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <sal/types.h>
+#include <tools/datetime.hxx>
+#ifndef _TOOLS_INETMIME_HXX
+#include <tools/inetmime.hxx>
+#endif
+#include <tools/inetmsg.hxx>
+#include <tools/inetstrm.hxx>
+#include <rtl/instance.hxx>
+
+#include <stdio.h>
+
+//=======================================================================
+
+inline sal_Bool ascii_isDigit( sal_Unicode ch )
+{
+ return ((ch >= 0x0030) && (ch <= 0x0039));
+}
+
+inline sal_Bool ascii_isLetter( sal_Unicode ch )
+{
+ return (( (ch >= 0x0041) && (ch <= 0x005A)) || ((ch >= 0x0061) && (ch <= 0x007A)));
+}
+
+inline sal_Unicode ascii_toLowerCase( sal_Unicode ch )
+{
+ if ( (ch >= 0x0041) && (ch <= 0x005A) )
+ return ch + 0x20;
+ else
+ return ch;
+}
+
+/*=======================================================================
+ *
+ * INetMessage Implementation.
+ *
+ *=====================================================================*/
+#define CONSTASCII_STRINGPARAM(a) (a), RTL_TEXTENCODING_ASCII_US
+#define HEADERFIELD INetMessageHeader
+
+/*
+ * ~INetMessage.
+ */
+INetMessage::~INetMessage (void)
+{
+ ListCleanup_Impl();
+}
+
+/*
+ * ListCleanup_Impl.
+ */
+void INetMessage::ListCleanup_Impl (void)
+{
+ // Cleanup.
+ ULONG i, n = m_aHeaderList.Count();
+ for (i = 0; i < n; i++)
+ delete ((HEADERFIELD*)(m_aHeaderList.GetObject(i)));
+ m_aHeaderList.Clear();
+}
+
+/*
+ * ListCopy.
+ */
+void INetMessage::ListCopy (const INetMessage &rMsg)
+{
+ if (!(this == &rMsg))
+ {
+ // Cleanup.
+ ListCleanup_Impl();
+
+ // Copy.
+ ULONG i, n = rMsg.GetHeaderCount();
+ for (i = 0; i < n; i++)
+ {
+ HEADERFIELD *p = (HEADERFIELD*)(rMsg.m_aHeaderList.GetObject(i));
+ m_aHeaderList.Insert (new HEADERFIELD(*p), LIST_APPEND);
+ }
+ }
+}
+
+/*
+ * SetHeaderField_Impl.
+ */
+void INetMessage::SetHeaderField_Impl (
+ INetMIME::HeaderFieldType eType,
+ const ByteString &rName,
+ const UniString &rValue,
+ ULONG &rnIndex)
+{
+ INetMIMEStringOutputSink aSink (0, STRING_MAXLEN);
+ INetMIME::writeHeaderFieldBody (
+ aSink, eType, rValue, gsl_getSystemTextEncoding(), false);
+ SetHeaderField_Impl (
+ INetMessageHeader (rName, aSink.takeBuffer()), rnIndex);
+}
+
+/*
+ * SetHeaderField.
+ */
+ULONG INetMessage::SetHeaderField (
+ const UniString& rName, const UniString& rValue, ULONG nIndex)
+{
+ ULONG nResult = nIndex;
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ ByteString (rName, RTL_TEXTENCODING_ASCII_US), rValue,
+ nResult);
+ return nResult;
+}
+
+/*
+ * SetHeaderField.
+ */
+ULONG INetMessage::SetHeaderField (
+ const INetMessageHeader &rHeader, ULONG nIndex)
+{
+ ULONG nResult = nIndex;
+ SetHeaderField_Impl (rHeader, nResult);
+ return nResult;
+}
+
+
+/*
+ * operator<<
+ */
+SvStream& INetMessage::operator<< (SvStream& rStrm) const
+{
+ rStrm << static_cast<sal_uInt32>(m_nDocSize);
+ rStrm.WriteByteString (m_aDocName, RTL_TEXTENCODING_UTF8);
+
+ ULONG i, n = m_aHeaderList.Count();
+ rStrm << static_cast<sal_uInt32>(n);
+
+ for (i = 0; i < n; i++)
+ rStrm << *((HEADERFIELD *)(m_aHeaderList.GetObject(i)));
+
+ return rStrm;
+}
+
+/*
+ * operator>>
+ */
+SvStream& INetMessage::operator>> (SvStream& rStrm)
+{
+ // Cleanup.
+ m_nDocSize = 0;
+ m_xDocLB.Clear();
+ ListCleanup_Impl();
+
+ sal_uInt32 nTemp;
+
+ // Copy.
+ rStrm >> nTemp;
+ m_nDocSize = nTemp;
+ rStrm.ReadByteString (m_aDocName, RTL_TEXTENCODING_UTF8);
+
+ ULONG i, n = 0;
+ rStrm >> nTemp;
+ n = nTemp;
+
+ for (i = 0; i < n; i++)
+ {
+ HEADERFIELD *p = new HEADERFIELD();
+ rStrm >> *p;
+ m_aHeaderList.Insert (p, LIST_APPEND);
+ }
+
+ // Done.
+ return rStrm;
+}
+
+/*=======================================================================
+ *
+ * INetMessageHeaderIterator Implementation.
+ *
+ *=====================================================================*/
+INetMessageHeaderIterator::INetMessageHeaderIterator (
+ const INetMessage& rMsg, const UniString& rHdrName)
+{
+ ULONG i, n = rMsg.GetHeaderCount();
+ for (i = 0; i < n; i++)
+ {
+ if (rHdrName.CompareIgnoreCaseToAscii (rMsg.GetHeaderName(i)) == 0)
+ {
+ UniString *pValue = new UniString (rMsg.GetHeaderValue(i));
+ aValueList.Insert (pValue, LIST_APPEND);
+ }
+ }
+ nValueCount = aValueList.Count();
+}
+
+INetMessageHeaderIterator::~INetMessageHeaderIterator (void)
+{
+ ULONG i, n = aValueList.Count();
+ for (i = 0; i < n; i++)
+ delete ((UniString*)(aValueList.GetObject(i)));
+ aValueList.Clear();
+}
+
+/*=======================================================================
+ *
+ * INetRFC822Message Implementation.
+ *
+ *=====================================================================*/
+/*
+ * ImplINetRFC822MessageHeaderData.
+ */
+namespace
+{
+ struct ImplINetRFC822MessageHeaderDataImpl
+ {
+ const ByteString* operator()()
+ {
+ static const ByteString _ImplINetRFC822MessageHeaderData[] =
+ {
+ ByteString ("BCC"),
+ ByteString ("CC"),
+ ByteString ("Comments"),
+ ByteString ("Date"),
+ ByteString ("From"),
+ ByteString ("In-Reply-To"),
+ ByteString ("Keywords"),
+ ByteString ("Message-ID"),
+ ByteString ("References"),
+ ByteString ("Reply-To"),
+ ByteString ("Return-Path"),
+ ByteString ("Subject"),
+ ByteString ("Sender"),
+ ByteString ("To"),
+ ByteString ("X-Mailer"),
+ ByteString ("Return-Receipt-To")
+ };
+ return &_ImplINetRFC822MessageHeaderData[0];
+ }
+ };
+
+ struct ImplINetRFC822MessageHeaderData
+ : public rtl::StaticAggregate< const ByteString, ImplINetRFC822MessageHeaderDataImpl > {};
+}
+
+#define HDR(n) ImplINetRFC822MessageHeaderData::get()[(n)]
+
+/*
+ * _ImplINetRFC822MessageHeaderState.
+ */
+enum _ImplINetRFC822MessageHeaderState
+{
+ INETMSG_RFC822_BEGIN,
+ INETMSG_RFC822_CHECK,
+ INETMSG_RFC822_OK,
+ INETMSG_RFC822_JUNK,
+
+ INETMSG_RFC822_TOKEN_RE,
+ INETMSG_RFC822_TOKEN_RETURNMINUS,
+ INETMSG_RFC822_TOKEN_XMINUS,
+ INETMSG_RFC822_LETTER_C,
+ INETMSG_RFC822_LETTER_S
+};
+
+/*
+ * INetRFC822Message.
+ */
+INetRFC822Message::INetRFC822Message (void)
+ : INetMessage()
+{
+ for (USHORT i = 0; i < INETMSG_RFC822_NUMHDR; i++)
+ m_nIndex[i] = LIST_ENTRY_NOTFOUND;
+}
+
+INetRFC822Message::INetRFC822Message (const INetRFC822Message& rMsg)
+ : INetMessage (rMsg)
+{
+ for (USHORT i = 0; i < INETMSG_RFC822_NUMHDR; i++)
+ m_nIndex[i] = rMsg.m_nIndex[i];
+}
+
+/*
+ * operator=
+ */
+INetRFC822Message& INetRFC822Message::operator= (const INetRFC822Message& rMsg)
+{
+ if (this != &rMsg)
+ {
+ INetMessage::operator= (rMsg);
+
+ for (USHORT i = 0; i < INETMSG_RFC822_NUMHDR; i++)
+ m_nIndex[i] = rMsg.m_nIndex[i];
+ }
+ return *this;
+}
+
+/*
+ * ~INetRFC822Message.
+ */
+INetRFC822Message::~INetRFC822Message (void)
+{
+}
+
+/*
+ * <Generate|Parse>DateField and local helper functions.
+ *
+ * GenerateDateField.
+ * Generates a String from Date and Time objects in format:
+ * Wkd, 00 Mon 0000 00:00:00 [GMT] (rfc822, rfc1123)
+ *
+ * ParseDateField.
+ * Parses a String in (implied) GMT format into class Date and Time objects.
+ * Four formats are accepted:
+ *
+ * [Wkd,] 1*2DIGIT Mon 2*4DIGIT 00:00:00 [GMT] (rfc1123)
+ * [Wkd,] 00 Mon 0000 00:00:00 [GMT]) (rfc822, rfc1123)
+ * Weekday, 00-Mon-00 00:00:00 [GMT] (rfc850, rfc1036)
+ * Wkd Mon 00 00:00:00 0000 [GMT] (ctime)
+ * 1*DIGIT (delta seconds)
+ *
+ */
+
+// Months and Weekdays.
+static const sal_Char *months[12] =
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const sal_Char *wkdays[7] =
+{
+ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
+};
+
+/*
+ * GenerateDateField.
+ */
+BOOL INetRFC822Message::GenerateDateField (
+ const DateTime& rDateTime, UniString& rDateFieldW)
+{
+ // Check arguments.
+ if (!rDateTime.IsValid() ||
+ (rDateTime.GetSec() > 59) ||
+ (rDateTime.GetMin() > 59) ||
+ (rDateTime.GetHour() > 23) ) return FALSE;
+
+ // Prepare output string.
+ ByteString rDateField;
+
+ // Insert Date.
+ rDateField += wkdays[(USHORT)(rDateTime.GetDayOfWeek())];
+ rDateField += ", ";
+
+ USHORT nNum = rDateTime.GetDay();
+ if (nNum < 10) rDateField += '0';
+ rDateField += ByteString::CreateFromInt32(nNum);
+ rDateField += ' ';
+
+ rDateField += months[(USHORT)(rDateTime.GetMonth() - 1)];
+ rDateField += ' ';
+
+ rDateField += ByteString::CreateFromInt32(rDateTime.GetYear());
+ rDateField += ' ';
+
+ // Insert Time.
+ nNum = rDateTime.GetHour();
+ if (nNum < 10) rDateField += '0';
+ rDateField += ByteString::CreateFromInt32(nNum);
+ rDateField += ':';
+
+ nNum = rDateTime.GetMin();
+ if (nNum < 10) rDateField += '0';
+ rDateField += ByteString::CreateFromInt32(nNum);
+ rDateField += ':';
+
+ nNum = rDateTime.GetSec();
+ if (nNum < 10) rDateField += '0';
+ rDateField += ByteString::CreateFromInt32(nNum);
+ rDateField += " GMT";
+
+ // Done.
+ rDateFieldW = UniString (rDateField, RTL_TEXTENCODING_ASCII_US);
+ return TRUE;
+}
+
+/*
+ * ParseDateField and local helper functions.
+ */
+static USHORT ParseNumber (const ByteString& rStr, USHORT& nIndex)
+{
+ USHORT n = nIndex;
+ while ((n < rStr.Len()) && ascii_isDigit(rStr.GetChar(n))) n++;
+
+ ByteString aNum (rStr.Copy (nIndex, (n - nIndex)));
+ nIndex = n;
+
+ return (USHORT)(aNum.ToInt32());
+}
+
+static USHORT ParseMonth (const ByteString& rStr, USHORT& nIndex)
+{
+ USHORT n = nIndex;
+ while ((n < rStr.Len()) && ascii_isLetter(rStr.GetChar(n))) n++;
+
+ ByteString aMonth (rStr.Copy (nIndex, 3));
+ nIndex = n;
+
+ USHORT i;
+ for (i = 0; i < 12; i++)
+ if (aMonth.CompareIgnoreCaseToAscii (months[i]) == 0) break;
+ return (i + 1);
+}
+
+BOOL INetRFC822Message::ParseDateField (
+ const UniString& rDateFieldW, DateTime& rDateTime)
+{
+ ByteString rDateField (rDateFieldW, RTL_TEXTENCODING_ASCII_US);
+ if (rDateField.Len() == 0) return FALSE;
+
+ if (rDateField.Search (':') != STRING_NOTFOUND)
+ {
+ // Some DateTime format.
+ USHORT nIndex = 0;
+
+ // Skip over <Wkd> or <Weekday>, leading and trailing space.
+ while ((nIndex < rDateField.Len()) &&
+ (rDateField.GetChar(nIndex) == ' '))
+ nIndex++;
+
+ while (
+ (nIndex < rDateField.Len()) &&
+ (ascii_isLetter (rDateField.GetChar(nIndex)) ||
+ (rDateField.GetChar(nIndex) == ',') ))
+ nIndex++;
+
+ while ((nIndex < rDateField.Len()) &&
+ (rDateField.GetChar(nIndex) == ' '))
+ nIndex++;
+
+ if (ascii_isLetter (rDateField.GetChar(nIndex)))
+ {
+ // Format: ctime().
+ if ((rDateField.Len() - nIndex) < 20) return FALSE;
+
+ rDateTime.SetMonth (ParseMonth (rDateField, nIndex)); nIndex++;
+ rDateTime.SetDay (ParseNumber (rDateField, nIndex)); nIndex++;
+
+ rDateTime.SetHour (ParseNumber (rDateField, nIndex)); nIndex++;
+ rDateTime.SetMin (ParseNumber (rDateField, nIndex)); nIndex++;
+ rDateTime.SetSec (ParseNumber (rDateField, nIndex)); nIndex++;
+ rDateTime.Set100Sec (0);
+
+ USHORT nYear = ParseNumber (rDateField, nIndex);
+ if (nYear < 100) nYear += 1900;
+ rDateTime.SetYear (nYear);
+ }
+ else
+ {
+ // Format: RFC1036 or RFC1123.
+ if ((rDateField.Len() - nIndex) < 17) return FALSE;
+
+ rDateTime.SetDay (ParseNumber (rDateField, nIndex)); nIndex++;
+ rDateTime.SetMonth (ParseMonth (rDateField, nIndex)); nIndex++;
+
+ USHORT nYear = ParseNumber (rDateField, nIndex); nIndex++;
+ if (nYear < 100) nYear += 1900;
+ rDateTime.SetYear (nYear);
+
+ rDateTime.SetHour (ParseNumber (rDateField, nIndex)); nIndex++;
+ rDateTime.SetMin (ParseNumber (rDateField, nIndex)); nIndex++;
+ rDateTime.SetSec (ParseNumber (rDateField, nIndex)); nIndex++;
+ rDateTime.Set100Sec (0);
+
+ if ((rDateField.GetChar(nIndex) == '+') ||
+ (rDateField.GetChar(nIndex) == '-') )
+ {
+ // Offset from GMT: "(+|-)HHMM".
+ BOOL bEast = (rDateField.GetChar(nIndex++) == '+');
+ USHORT nOffset = ParseNumber (rDateField, nIndex);
+ if (nOffset > 0)
+ {
+ Time aDiff;
+ aDiff.SetHour (nOffset / 100);
+ aDiff.SetMin (nOffset % 100);
+ aDiff.SetSec (0);
+ aDiff.Set100Sec (0);
+
+ if (bEast)
+ rDateTime -= aDiff;
+ else
+ rDateTime += aDiff;
+ }
+ }
+ }
+ }
+ else if (rDateField.IsNumericAscii())
+ {
+ // Format: delta seconds.
+ Time aDelta (0);
+ aDelta.SetTime (rDateField.ToInt32() * 100);
+
+ DateTime aNow;
+ aNow += aDelta;
+ aNow.ConvertToUTC();
+
+ rDateTime.SetDate (aNow.GetDate());
+ rDateTime.SetTime (aNow.GetTime());
+ }
+ else
+ {
+ // Junk.
+ return FALSE;
+ }
+
+ return (rDateTime.IsValid() &&
+ !((rDateTime.GetSec() > 59) ||
+ (rDateTime.GetMin() > 59) ||
+ (rDateTime.GetHour() > 23) ));
+}
+
+/*
+ * SetHeaderField.
+ * (Header Field Parser).
+ */
+ULONG INetRFC822Message::SetHeaderField (
+ const INetMessageHeader &rHeader, ULONG nNewIndex)
+{
+ ByteString aName (rHeader.GetName());
+ const sal_Char *pData = aName.GetBuffer();
+ const sal_Char *pStop = pData + aName.Len() + 1;
+ const sal_Char *check = "";
+
+ ULONG nIdx = LIST_APPEND;
+ int eState = INETMSG_RFC822_BEGIN;
+ int eOkState = INETMSG_RFC822_OK;
+
+ while (pData < pStop)
+ {
+ switch (eState)
+ {
+ case INETMSG_RFC822_BEGIN:
+ eState = INETMSG_RFC822_CHECK;
+ eOkState = INETMSG_RFC822_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'b':
+ check = "cc";
+ nIdx = INETMSG_RFC822_BCC;
+ break;
+
+ case 'c':
+ eState = INETMSG_RFC822_LETTER_C;
+ break;
+
+ case 'd':
+ check = "ate";
+ nIdx = INETMSG_RFC822_DATE;
+ break;
+
+ case 'f':
+ check = "rom";
+ nIdx = INETMSG_RFC822_FROM;
+ break;
+
+ case 'i':
+ check = "n-reply-to";
+ nIdx = INETMSG_RFC822_IN_REPLY_TO;
+ break;
+
+ case 'k':
+ check = "eywords";
+ nIdx = INETMSG_RFC822_KEYWORDS;
+ break;
+
+ case 'm':
+ check = "essage-id";
+ nIdx = INETMSG_RFC822_MESSAGE_ID;
+ break;
+
+ case 'r':
+ check = "e";
+ eOkState = INETMSG_RFC822_TOKEN_RE;
+ break;
+
+ case 's':
+ eState = INETMSG_RFC822_LETTER_S;
+ break;
+
+ case 't':
+ check = "o";
+ nIdx = INETMSG_RFC822_TO;
+ break;
+
+ case 'x':
+ check = "-";
+ eOkState = INETMSG_RFC822_TOKEN_XMINUS;
+ break;
+
+ default:
+ eState = INETMSG_RFC822_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_RFC822_TOKEN_RE:
+ eState = INETMSG_RFC822_CHECK;
+ eOkState = INETMSG_RFC822_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'f':
+ check = "erences";
+ nIdx = INETMSG_RFC822_REFERENCES;
+ break;
+
+ case 'p':
+ check = "ly-to";
+ nIdx = INETMSG_RFC822_REPLY_TO;
+ break;
+
+ case 't':
+ check = "urn-";
+ eOkState = INETMSG_RFC822_TOKEN_RETURNMINUS;
+ break;
+
+ default:
+ eState = INETMSG_RFC822_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_RFC822_TOKEN_RETURNMINUS:
+ eState = INETMSG_RFC822_CHECK;
+ eOkState = INETMSG_RFC822_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'p':
+ check = "ath";
+ nIdx = INETMSG_RFC822_RETURN_PATH;
+ break;
+
+ case 'r':
+ check = "eceipt-to";
+ nIdx = INETMSG_RFC822_RETURN_RECEIPT_TO;
+ break;
+
+ default:
+ eState = INETMSG_RFC822_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_RFC822_TOKEN_XMINUS:
+ eState = INETMSG_RFC822_CHECK;
+ eOkState = INETMSG_RFC822_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'm':
+ check = "ailer";
+ nIdx = INETMSG_RFC822_X_MAILER;
+ break;
+
+#if 0 /* NYI */
+ case 'p':
+ check = "riority";
+ eOkState = INETMSG_RFC822_X_PRIORITY;
+ break;
+#endif /* NYI */
+
+ default:
+ eState = INETMSG_RFC822_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_RFC822_LETTER_C:
+ eState = INETMSG_RFC822_CHECK;
+ eOkState = INETMSG_RFC822_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'c':
+ check = "";
+ nIdx = INETMSG_RFC822_CC;
+ break;
+
+ case 'o':
+ check = "mments";
+ nIdx = INETMSG_RFC822_COMMENTS;
+ break;
+
+ default:
+ eState = INETMSG_RFC822_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_RFC822_LETTER_S:
+ eState = INETMSG_RFC822_CHECK;
+ eOkState = INETMSG_RFC822_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'e':
+ check = "nder";
+ nIdx = INETMSG_RFC822_SENDER;
+ break;
+
+ case 'u':
+ check = "bject";
+ nIdx = INETMSG_RFC822_SUBJECT;
+ break;
+
+ default:
+ eState = INETMSG_RFC822_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_RFC822_CHECK:
+ if (*check)
+ {
+ while (*pData && *check &&
+ (ascii_toLowerCase (*pData) == *check))
+ {
+ pData++;
+ check++;
+ }
+ }
+ else
+ {
+ check = pData;
+ }
+ eState = (*check == '\0') ? eOkState : INETMSG_RFC822_JUNK;
+ break;
+
+ case INETMSG_RFC822_OK:
+ pData = pStop;
+ SetHeaderField_Impl (
+ HEADERFIELD (HDR(nIdx), rHeader.GetValue()),
+ m_nIndex[nIdx]);
+ nNewIndex = m_nIndex[nIdx];
+ break;
+
+ default: // INETMSG_RFC822_JUNK
+ pData = pStop;
+ nNewIndex = INetMessage::SetHeaderField (rHeader, nNewIndex);
+ break;
+ }
+ }
+ return nNewIndex;
+}
+
+/*
+ * Specific Set-Methods.
+ */
+void INetRFC822Message::SetBCC (const UniString& rBCC)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS,
+ HDR(INETMSG_RFC822_BCC), rBCC,
+ m_nIndex[INETMSG_RFC822_BCC]);
+}
+
+void INetRFC822Message::SetCC (const UniString& rCC)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS,
+ HDR(INETMSG_RFC822_CC), rCC,
+ m_nIndex[INETMSG_RFC822_CC]);
+}
+
+void INetRFC822Message::SetComments (const UniString& rComments)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ HDR(INETMSG_RFC822_COMMENTS), rComments,
+ m_nIndex[INETMSG_RFC822_COMMENTS]);
+}
+
+void INetRFC822Message::SetDate (const UniString& rDate)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_STRUCTURED,
+ HDR(INETMSG_RFC822_DATE), rDate,
+ m_nIndex[INETMSG_RFC822_DATE]);
+}
+
+void INetRFC822Message::SetFrom (const UniString& rFrom)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS,
+ HDR(INETMSG_RFC822_FROM), rFrom,
+ m_nIndex[INETMSG_RFC822_FROM]);
+}
+
+void INetRFC822Message::SetInReplyTo (const UniString& rInReplyTo)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS, // ??? MESSAGE_ID ???
+ HDR(INETMSG_RFC822_IN_REPLY_TO), rInReplyTo,
+ m_nIndex[INETMSG_RFC822_IN_REPLY_TO]);
+}
+
+void INetRFC822Message::SetKeywords (const UniString& rKeywords)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_PHRASE,
+ HDR(INETMSG_RFC822_KEYWORDS), rKeywords,
+ m_nIndex[INETMSG_RFC822_KEYWORDS]);
+}
+
+void INetRFC822Message::SetMessageID (const UniString& rMessageID)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_MESSAGE_ID,
+ HDR(INETMSG_RFC822_MESSAGE_ID), rMessageID,
+ m_nIndex[INETMSG_RFC822_MESSAGE_ID]);
+}
+
+void INetRFC822Message::SetReferences (const UniString& rReferences)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_MESSAGE_ID,
+ HDR(INETMSG_RFC822_REFERENCES), rReferences,
+ m_nIndex[INETMSG_RFC822_REFERENCES]);
+}
+
+void INetRFC822Message::SetReplyTo (const UniString& rReplyTo)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS,
+ HDR(INETMSG_RFC822_REPLY_TO), rReplyTo,
+ m_nIndex[INETMSG_RFC822_REPLY_TO]);
+}
+
+void INetRFC822Message::SetReturnPath (const UniString& rReturnPath)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS,
+ HDR(INETMSG_RFC822_RETURN_PATH), rReturnPath,
+ m_nIndex[INETMSG_RFC822_RETURN_PATH]);
+}
+
+void INetRFC822Message::SetReturnReceiptTo (const UniString& rValue)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS,
+ HDR(INETMSG_RFC822_RETURN_RECEIPT_TO), rValue,
+ m_nIndex[INETMSG_RFC822_RETURN_RECEIPT_TO]);
+}
+
+void INetRFC822Message::SetSender (const UniString& rSender)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS,
+ HDR(INETMSG_RFC822_SENDER), rSender,
+ m_nIndex[INETMSG_RFC822_SENDER]);
+}
+
+void INetRFC822Message::SetSubject (const UniString& rSubject)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ HDR(INETMSG_RFC822_SUBJECT), rSubject,
+ m_nIndex[INETMSG_RFC822_SUBJECT]);
+}
+
+void INetRFC822Message::SetTo (const UniString& rTo)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_ADDRESS,
+ HDR(INETMSG_RFC822_TO), rTo,
+ m_nIndex[INETMSG_RFC822_TO]);
+}
+
+void INetRFC822Message::SetXMailer (const UniString& rXMailer)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ HDR(INETMSG_RFC822_X_MAILER), rXMailer,
+ m_nIndex[INETMSG_RFC822_X_MAILER]);
+}
+
+/*
+ * operator<<
+ */
+SvStream& INetRFC822Message::operator<< (SvStream& rStrm) const
+{
+ INetMessage::operator<< (rStrm);
+
+ for (USHORT i = 0; i < INETMSG_RFC822_NUMHDR; i++)
+ rStrm << static_cast<sal_uInt32>(m_nIndex[i]);
+
+ return rStrm;
+}
+
+/*
+ * operator>>
+ */
+SvStream& INetRFC822Message::operator>> (SvStream& rStrm)
+{
+ INetMessage::operator>> (rStrm);
+
+ sal_uInt32 nTemp;
+ for (USHORT i = 0; i < INETMSG_RFC822_NUMHDR; i++)
+ {
+ rStrm >> nTemp;
+ m_nIndex[i] = nTemp;
+ }
+
+ return rStrm;
+}
+
+/*=======================================================================
+ *
+ * INetMIMEMessage Implementation.
+ *
+ *=====================================================================*/
+/*
+ * _ImplINetMIMEMessageHeaderData.
+ */
+namespace
+{
+ struct ImplINetMIMEMessageHeaderDataImpl
+ {
+ const ByteString* operator()()
+ {
+ static const ByteString _ImplINetMIMEMessageHeaderData[] =
+ {
+ ByteString ("MIME-Version"),
+ ByteString ("Content-Description"),
+ ByteString ("Content-Disposition"),
+ ByteString ("Content-ID"),
+ ByteString ("Content-Type"),
+ ByteString ("Content-Transfer-Encoding")
+ };
+ return &_ImplINetMIMEMessageHeaderData[0];
+ }
+ };
+
+ struct ImplINetMIMEMessageHeaderData
+ : public rtl::StaticAggregate< const ByteString, ImplINetMIMEMessageHeaderDataImpl > {};
+}
+
+#define MIMEHDR(n) ImplINetMIMEMessageHeaderData::get()[(n)]
+
+/*
+ * _ImplINetMIMEMessageHeaderState.
+ */
+enum _ImplINetMIMEMessageHeaderState
+{
+ INETMSG_MIME_BEGIN,
+ INETMSG_MIME_CHECK,
+ INETMSG_MIME_OK,
+ INETMSG_MIME_JUNK,
+
+ INETMSG_MIME_TOKEN_CONTENT,
+ INETMSG_MIME_TOKEN_CONTENT_D,
+ INETMSG_MIME_TOKEN_CONTENT_T
+};
+
+/*
+ * INetMIMEMessage.
+ */
+INetMIMEMessage::INetMIMEMessage (void)
+ : INetRFC822Message (),
+ pParent (NULL),
+ nNumChildren (0),
+ bHeaderParsed (FALSE)
+{
+ for (USHORT i = 0; i < INETMSG_MIME_NUMHDR; i++)
+ m_nIndex[i] = LIST_ENTRY_NOTFOUND;
+}
+
+INetMIMEMessage::INetMIMEMessage (const INetMIMEMessage& rMsg)
+ : INetRFC822Message (rMsg)
+{
+ // Copy.
+ CopyImp (rMsg);
+}
+
+/*
+ * operator=
+ */
+INetMIMEMessage& INetMIMEMessage::operator= (
+ const INetMIMEMessage& rMsg)
+{
+ if (this != &rMsg)
+ {
+ // Assign base.
+ INetRFC822Message::operator= (rMsg);
+
+ // Cleanup.
+ CleanupImp();
+
+ // Copy.
+ CopyImp (rMsg);
+ }
+ return *this;
+}
+
+/*
+ * ~INetMIMEMessage.
+ */
+INetMIMEMessage::~INetMIMEMessage (void)
+{
+ // Cleanup.
+ CleanupImp();
+}
+
+/*
+ * CleanupImp.
+ */
+void INetMIMEMessage::CleanupImp (void)
+{
+ INetMIMEMessage *pChild = NULL;
+ while ((pChild = (INetMIMEMessage *)(aChildren.Remove())) != NULL)
+ if (pChild->pParent == this) delete pChild;
+}
+
+/*
+ * CopyImp.
+ */
+void INetMIMEMessage::CopyImp (const INetMIMEMessage& rMsg)
+{
+ bHeaderParsed = rMsg.bHeaderParsed;
+
+ USHORT i;
+ for (i = 0; i < INETMSG_MIME_NUMHDR; i++)
+ m_nIndex[i] = rMsg.m_nIndex[i];
+
+ m_aBoundary = rMsg.m_aBoundary;
+ nNumChildren = rMsg.nNumChildren;
+
+ for (i = 0; i < rMsg.aChildren.Count(); i++)
+ {
+ INetMIMEMessage *pChild =
+ (INetMIMEMessage *)(rMsg.aChildren.GetObject (i));
+
+ if (pChild->pParent == &rMsg)
+ {
+ pChild = pChild->CreateMessage (*pChild);
+ pChild->pParent = this;
+ }
+ aChildren.Insert (pChild, LIST_APPEND);
+ }
+}
+
+/*
+ * CreateMessage.
+ */
+INetMIMEMessage *INetMIMEMessage::CreateMessage (
+ const INetMIMEMessage& rMsg) const
+{
+ return (new INetMIMEMessage (rMsg));
+}
+
+/*
+ * SetHeaderField.
+ * (Header Field Parser).
+ */
+ULONG INetMIMEMessage::SetHeaderField (
+ const INetMessageHeader &rHeader, ULONG nNewIndex)
+{
+ ByteString aName (rHeader.GetName());
+ const sal_Char *pData = aName.GetBuffer();
+ const sal_Char *pStop = pData + aName.Len() + 1;
+ const sal_Char *check = "";
+
+ ULONG nIdx = LIST_APPEND;
+ int eState = INETMSG_MIME_BEGIN;
+ int eOkState = INETMSG_MIME_OK;
+
+ while (pData < pStop)
+ {
+ switch (eState)
+ {
+ case INETMSG_MIME_BEGIN:
+ eState = INETMSG_MIME_CHECK;
+ eOkState = INETMSG_MIME_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'c':
+ check = "ontent-";
+ eOkState = INETMSG_MIME_TOKEN_CONTENT;
+ break;
+
+ case 'm':
+ check = "ime-version";
+ nIdx = INETMSG_MIME_VERSION;
+ break;
+
+ default:
+ eState = INETMSG_MIME_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_MIME_TOKEN_CONTENT:
+ eState = INETMSG_MIME_CHECK;
+ eOkState = INETMSG_MIME_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'd':
+ eState = INETMSG_MIME_TOKEN_CONTENT_D;
+ break;
+
+ case 'i':
+ check = "d";
+ nIdx = INETMSG_MIME_CONTENT_ID;
+ break;
+
+ case 't':
+ eState = INETMSG_MIME_TOKEN_CONTENT_T;
+ break;
+
+ default:
+ eState = INETMSG_MIME_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_MIME_TOKEN_CONTENT_D:
+ eState = INETMSG_MIME_CHECK;
+ eOkState = INETMSG_MIME_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'e':
+ check = "scription";
+ nIdx = INETMSG_MIME_CONTENT_DESCRIPTION;
+ break;
+
+ case 'i':
+ check = "sposition";
+ nIdx = INETMSG_MIME_CONTENT_DISPOSITION;
+ break;
+
+ default:
+ eState = INETMSG_MIME_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_MIME_TOKEN_CONTENT_T:
+ eState = INETMSG_MIME_CHECK;
+ eOkState = INETMSG_MIME_OK;
+
+ switch (ascii_toLowerCase (*pData))
+ {
+ case 'r':
+ check = "ansfer-encoding";
+ nIdx = INETMSG_MIME_CONTENT_TRANSFER_ENCODING;
+ break;
+
+ case 'y':
+ check = "pe";
+ nIdx = INETMSG_MIME_CONTENT_TYPE;
+ break;
+
+ default:
+ eState = INETMSG_MIME_JUNK;
+ break;
+ }
+ pData++;
+ break;
+
+ case INETMSG_MIME_CHECK:
+ if (*check)
+ {
+ while (*pData && *check &&
+ (ascii_toLowerCase (*pData) == *check))
+ {
+ pData++;
+ check++;
+ }
+ }
+ else
+ {
+ check = pData;
+ }
+ eState = (*check == '\0') ? eOkState : INETMSG_MIME_JUNK;
+ break;
+
+ case INETMSG_MIME_OK:
+ pData = pStop;
+ SetHeaderField_Impl (
+ HEADERFIELD (MIMEHDR(nIdx), rHeader.GetValue()),
+ m_nIndex[nIdx]);
+ nNewIndex = m_nIndex[nIdx];
+ break;
+
+ default: // INETMSG_MIME_JUNK
+ pData = pStop;
+ nNewIndex = INetRFC822Message::SetHeaderField (
+ rHeader, nNewIndex);
+ break;
+ }
+ }
+ return nNewIndex;
+}
+
+/*
+ * Specific Set-Methods.
+ */
+void INetMIMEMessage::SetMIMEVersion (const UniString& rVersion)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ MIMEHDR(INETMSG_MIME_VERSION), rVersion,
+ m_nIndex[INETMSG_MIME_VERSION]);
+}
+
+void INetMIMEMessage::SetContentDescription (const String& rDescription)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ MIMEHDR(INETMSG_MIME_CONTENT_DESCRIPTION), rDescription,
+ m_nIndex[INETMSG_MIME_CONTENT_DESCRIPTION]);
+}
+
+void INetMIMEMessage::SetContentDisposition (const String& rDisposition)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ MIMEHDR(INETMSG_MIME_CONTENT_DISPOSITION), rDisposition,
+ m_nIndex[INETMSG_MIME_CONTENT_DISPOSITION]);
+}
+
+void INetMIMEMessage::SetContentID (const String& rID)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ MIMEHDR(INETMSG_MIME_CONTENT_ID), rID,
+ m_nIndex[INETMSG_MIME_CONTENT_ID]);
+}
+
+void INetMIMEMessage::SetContentType (const String& rType)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ MIMEHDR(INETMSG_MIME_CONTENT_TYPE), rType,
+ m_nIndex[INETMSG_MIME_CONTENT_TYPE]);
+}
+
+void INetMIMEMessage::SetContentTransferEncoding (
+ const String& rEncoding)
+{
+ SetHeaderField_Impl (
+ INetMIME::HEADER_FIELD_TEXT,
+ MIMEHDR(INETMSG_MIME_CONTENT_TRANSFER_ENCODING), rEncoding,
+ m_nIndex[INETMSG_MIME_CONTENT_TRANSFER_ENCODING]);
+}
+
+/*
+ * GetDefaultContentType.
+ */
+void INetMIMEMessage::GetDefaultContentType (String& rContentType)
+{
+ String aDefaultCT (
+ "text/plain; charset=us-ascii", RTL_TEXTENCODING_ASCII_US);
+ if (pParent == NULL)
+ {
+ rContentType = aDefaultCT;
+ }
+ else
+ {
+ String aParentCT (pParent->GetContentType());
+ if (aParentCT.Len() == 0)
+ pParent->GetDefaultContentType (aParentCT);
+
+ if (aParentCT.CompareIgnoreCaseToAscii ("message/", 8) == 0)
+ {
+ rContentType = aDefaultCT;
+ }
+ else if (aParentCT.CompareIgnoreCaseToAscii ("multipart/", 10) == 0)
+ {
+ if (aParentCT.CompareIgnoreCaseToAscii ("multipart/digest") == 0)
+ rContentType.AssignAscii ("message/rfc822");
+ else
+ rContentType = aDefaultCT;
+ }
+ else
+ {
+ rContentType = aDefaultCT;
+ }
+ }
+}
+
+/*
+ * EnableAttachChild.
+ */
+BOOL INetMIMEMessage::EnableAttachChild (INetMessageContainerType eType)
+{
+ // Check context.
+ if (IsContainer())
+ return FALSE;
+
+ // Setup Content-Type header field.
+ ByteString aContentType;
+ switch (eType)
+ {
+ case INETMSG_MESSAGE_RFC822:
+ aContentType = "message/rfc822";
+ break;
+
+ case INETMSG_MULTIPART_ALTERNATIVE:
+ aContentType = "multipart/alternative";
+ break;
+
+ case INETMSG_MULTIPART_DIGEST:
+ aContentType = "multipart/digest";
+ break;
+
+ case INETMSG_MULTIPART_PARALLEL:
+ aContentType = "multipart/parallel";
+ break;
+
+ case INETMSG_MULTIPART_RELATED:
+ aContentType = "multipart/related";
+ break;
+
+ case INETMSG_MULTIPART_FORM_DATA:
+ aContentType = "multipart/form-data";
+ break;
+
+ default:
+ aContentType = "multipart/mixed";
+ break;
+ }
+
+ // Setup boundary for multipart types.
+ if (aContentType.CompareIgnoreCaseToAscii ("multipart/", 10) == 0)
+ {
+ // Generate a unique boundary from current time.
+ sal_Char sTail[16 + 1];
+ Time aCurTime;
+ sal_uInt64 nThis = reinterpret_cast< sal_uIntPtr >( this ); // we can be on a 64bit architecture
+ nThis = ( ( nThis >> 32 ) ^ nThis ) & SAL_MAX_UINT32;
+ sprintf (sTail, "%08X%08X",
+ static_cast< unsigned int >(aCurTime.GetTime()),
+ static_cast< unsigned int >(nThis));
+ m_aBoundary = "------------_4D48";
+ m_aBoundary += sTail;
+
+ // Append boundary as ContentType parameter.
+ aContentType += "; boundary=";
+ aContentType += m_aBoundary;
+ }
+
+ // Set header fields.
+ SetMIMEVersion (String (CONSTASCII_STRINGPARAM("1.0")));
+ SetContentType (String (aContentType, RTL_TEXTENCODING_ASCII_US));
+ SetContentTransferEncoding (String (CONSTASCII_STRINGPARAM("7bit")));
+
+ // Done.
+ return TRUE;
+}
+
+/*
+ * AttachChild.
+ */
+BOOL INetMIMEMessage::AttachChild (
+ INetMIMEMessage& rChildMsg, BOOL bOwner)
+{
+ if (IsContainer() /*&& rChildMsg.GetContentType().Len() */)
+ {
+ if (bOwner) rChildMsg.pParent = this;
+ aChildren.Insert (&rChildMsg, LIST_APPEND);
+ nNumChildren = aChildren.Count();
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * DetachChild.
+ */
+BOOL INetMIMEMessage::DetachChild (
+ ULONG nIndex, INetMIMEMessage& rChildMsg) const
+{
+ if (IsContainer())
+ {
+ // Check document stream.
+ if (GetDocumentLB() == NULL) return FALSE;
+ SvStream *pDocStrm = new SvStream (GetDocumentLB());
+
+ // Initialize message buffer.
+ char pMsgBuffer[1024];
+ char *pMsgRead, *pMsgWrite;
+ pMsgRead = pMsgWrite = pMsgBuffer;
+
+ // Initialize message parser stream.
+ INetMIMEMessageStream *pMsgStrm = NULL;
+
+ // Check for "multipart/uvw" or "message/xyz".
+ if (IsMultipart())
+ {
+ // Multipart message body. Initialize multipart delimiters.
+ ByteString aDelim ("--");
+ aDelim += GetMultipartBoundary();
+ ByteString aClose = aDelim;
+ aClose += "--";
+
+ // Initialize line buffer.
+ SvMemoryStream aLineBuf;
+
+ // Initialize control variables.
+ INetMessageStreamState eState = INETMSG_EOL_SCR;
+ int nCurIndex = -1;
+
+ // Go!
+ while (nCurIndex < (int)(nIndex + 1))
+ {
+ if ((pMsgRead - pMsgWrite) > 0)
+ {
+ // Bytes still in buffer.
+ if (eState == INETMSG_EOL_FCR)
+ {
+ // Check for 2nd line break character.
+ if ((*pMsgWrite == '\r') || (*pMsgWrite == '\n'))
+ aLineBuf << *pMsgWrite++;
+
+ // Check current index.
+ if (nCurIndex == (int)nIndex)
+ {
+ // Found requested part.
+ if (pMsgStrm == NULL)
+ {
+ // Create message parser stream.
+ pMsgStrm = new INetMIMEMessageStream;
+ pMsgStrm->SetTargetMessage (&rChildMsg);
+ }
+
+ // Put message down-stream.
+ int status = pMsgStrm->Write (
+ (const sal_Char *) aLineBuf.GetData(), aLineBuf.Tell());
+ if (status != INETSTREAM_STATUS_OK)
+ {
+ // Cleanup.
+ delete pDocStrm;
+ delete pMsgStrm;
+
+ // Finish.
+ return (!(status == INETSTREAM_STATUS_OK));
+ }
+ }
+
+ // Reset to <Begin-of-Line>.
+ aLineBuf.Seek (STREAM_SEEK_TO_BEGIN);
+ eState = INETMSG_EOL_SCR;
+ }
+ else if ((*pMsgWrite == '\r') || (*pMsgWrite == '\n'))
+ {
+ /*
+ * Found any line break character.
+ * Compare buffered line with part/close delimiter.
+ * Increment current part index upon match.
+ */
+ USHORT nLen = (USHORT)(aLineBuf.Tell() & 0xffff);
+ if (nLen == aDelim.Len())
+ {
+ if (aDelim.CompareTo ((const sal_Char *) aLineBuf.GetData(), nLen)
+ == COMPARE_EQUAL) nCurIndex++;
+ }
+ else if (nLen == aClose.Len())
+ {
+ if (aClose.CompareTo ((const sal_Char *) aLineBuf.GetData(), nLen)
+ == COMPARE_EQUAL) nCurIndex++;
+ }
+ aLineBuf << *pMsgWrite++;
+ eState = INETMSG_EOL_FCR;
+ }
+ else
+ {
+ // Insert into line buffer.
+ aLineBuf << *pMsgWrite;
+ }
+ }
+ else
+ {
+ // Buffer empty. Reset to <Begin-of-Buffer>.
+ pMsgRead = pMsgWrite = pMsgBuffer;
+
+ // Read document stream.
+ ULONG nRead = pDocStrm->Read (
+ pMsgBuffer, sizeof (pMsgBuffer));
+ if (nRead > 0)
+ {
+ // Set read pointer.
+ pMsgRead += nRead;
+ }
+ else
+ {
+ // Premature end.
+ if (pMsgStrm)
+ {
+ // Assume end of requested part.
+ nCurIndex++;
+ }
+ else
+ {
+ // Requested part not found.
+ delete pDocStrm;
+ return FALSE;
+ }
+ }
+ }
+ } // while (nCurIndex < (nIndex + 1))
+ }
+ else
+ {
+ // Encapsulated message body. Create message parser stream.
+ pMsgStrm = new INetMIMEMessageStream;
+ pMsgStrm->SetTargetMessage (&rChildMsg);
+
+ // Initialize control variables.
+ INetMessageStreamState eState = INETMSG_EOL_BEGIN;
+
+ // Go.
+ while (eState == INETMSG_EOL_BEGIN)
+ {
+ if ((pMsgRead - pMsgWrite) > 0)
+ {
+ // Bytes still in buffer. Put message down-stream.
+ int status = pMsgStrm->Write (
+ pMsgBuffer, (pMsgRead - pMsgWrite));
+ if (status != INETSTREAM_STATUS_OK)
+ {
+ // Cleanup.
+ delete pDocStrm;
+ delete pMsgStrm;
+
+ // Finish.
+ return (!(status == INETSTREAM_STATUS_ERROR));
+ }
+ pMsgWrite = pMsgBuffer + (pMsgRead - pMsgWrite);
+ }
+ else
+ {
+ // Buffer empty. Reset to <Begin-of-Buffer>.
+ pMsgRead = pMsgWrite = pMsgBuffer;
+
+ // Read document stream.
+ ULONG nRead = pDocStrm->Read (
+ pMsgBuffer, sizeof (pMsgBuffer));
+ if (nRead > 0)
+ {
+ // Set read pointer.
+ pMsgRead += nRead;
+ }
+ else
+ {
+ // Mark we're done.
+ eState = INETMSG_EOL_DONE;
+ }
+ }
+ } // while (eState == INETMSG_EOL_BEGIN)
+ }
+
+ // Done.
+ if (pDocStrm) delete pDocStrm;
+ if (pMsgStrm) delete pMsgStrm;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * operator<<
+ */
+SvStream& INetMIMEMessage::operator<< (SvStream& rStrm) const
+{
+ INetRFC822Message::operator<< (rStrm);
+
+ for (USHORT i = 0; i < INETMSG_MIME_NUMHDR; i++)
+ rStrm << static_cast<sal_uInt32>(m_nIndex[i]);
+
+#ifdef ENABLE_BYTESTRING_STREAM_OPERATORS
+ rStrm << m_aBoundary;
+#else
+ rStrm.WriteByteString (m_aBoundary);
+#endif
+ rStrm << static_cast<sal_uInt32>(nNumChildren);
+
+ return rStrm;
+}
+
+/*
+ * operator>>
+ */
+SvStream& INetMIMEMessage::operator>> (SvStream& rStrm)
+{
+ INetRFC822Message::operator>> (rStrm);
+
+ sal_uInt32 nTemp;
+ for (USHORT i = 0; i < INETMSG_MIME_NUMHDR; i++)
+ {
+ rStrm >> nTemp;
+ m_nIndex[i] = nTemp;
+ }
+
+#ifdef ENABLE_BYTESTRING_STREAM_OPERATORS
+ rStrm >> m_aBoundary;
+#else
+ rStrm.ReadByteString (m_aBoundary);
+#endif
+ rStrm >> nTemp;
+ nNumChildren = nTemp;
+
+ return rStrm;
+}
+
+
diff --git a/tools/source/inet/inetstrm.cxx b/tools/source/inet/inetstrm.cxx
new file mode 100644
index 000000000000..ca76d8750bf8
--- /dev/null
+++ b/tools/source/inet/inetstrm.cxx
@@ -0,0 +1,1821 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <sal/types.h>
+#include <rtl/memory.h>
+#include <tools/cachestr.hxx>
+#include <tools/debug.hxx>
+#include <tools/inetmsg.hxx>
+#include <tools/inetstrm.hxx>
+
+#include <ctype.h> // toupper
+
+inline sal_Bool SAL_CALL ascii_isWhitespace( sal_Unicode ch )
+{
+ return ((ch <= 0x20) && ch);
+}
+
+#define CONSTASCII_STRINGPARAM(a) (a), RTL_TEXTENCODING_ASCII_US
+
+/*=======================================================================
+ *
+ * INetMessageEncodeQPStream Interface.
+ * (Quoted-Printable Encoding)
+ *
+ *=====================================================================*/
+class INetMessageEncodeQPStream_Impl : public INetMessageIStream
+{
+ SvStream *pMsgStrm;
+
+ ULONG nMsgBufSiz;
+ sal_Char *pMsgBuffer;
+ sal_Char *pMsgRead;
+ sal_Char *pMsgWrite;
+
+ ULONG nTokBufSiz;
+ sal_Char *pTokBuffer;
+ sal_Char *pTokRead;
+ sal_Char *pTokWrite;
+
+ INetMessageStreamState eState;
+ BOOL bDone;
+
+ virtual int GetMsgLine (sal_Char *pData, ULONG nSize);
+
+public:
+ INetMessageEncodeQPStream_Impl (ULONG nMsgBufferSize = 1024);
+ virtual ~INetMessageEncodeQPStream_Impl (void);
+};
+
+/*=====================================================================
+ *
+ * INetMessageDecodeQPStream Interface.
+ * (Quoted-Printable Decoding)
+ *
+ *====================================================================*/
+class INetMessageDecodeQPStream_Impl : public INetMessageOStream
+{
+ INetMessageStreamState eState;
+ SvMemoryStream *pMsgBuffer;
+
+ ULONG nTokBufLen;
+ sal_Char pTokBuffer[4];
+
+ virtual int PutMsgLine (const sal_Char *pData, ULONG nSize);
+
+public:
+ INetMessageDecodeQPStream_Impl (void);
+ virtual ~INetMessageDecodeQPStream_Impl (void);
+};
+
+/*======================================================================
+ *
+ * INetMessageEncode64Stream Interface.
+ * (Base64 Encoding)
+ *
+ *====================================================================*/
+class INetMessageEncode64Stream_Impl : public INetMessageIStream
+{
+ SvStream *pMsgStrm;
+
+ ULONG nMsgBufSiz;
+ sal_uInt8 *pMsgBuffer;
+ sal_uInt8 *pMsgRead;
+ sal_uInt8 *pMsgWrite;
+
+ ULONG nTokBufSiz;
+ sal_Char *pTokBuffer;
+ sal_Char *pTokRead;
+ sal_Char *pTokWrite;
+
+ BOOL bDone;
+
+ virtual int GetMsgLine (sal_Char *pData, ULONG nSize);
+
+public:
+ INetMessageEncode64Stream_Impl (ULONG nMsgBufferSize = 2048);
+ virtual ~INetMessageEncode64Stream_Impl (void);
+};
+
+/*======================================================================
+ *
+ * INetMessageDecode64Stream Interface.
+ * (Base64 Decoding)
+ *
+ *====================================================================*/
+class INetMessageDecode64Stream_Impl : public INetMessageOStream
+{
+ INetMessageStreamState eState;
+
+ ULONG nMsgBufSiz;
+ sal_Char *pMsgBuffer;
+ sal_Char *pMsgRead;
+ sal_Char *pMsgWrite;
+
+ virtual int PutMsgLine (const sal_Char *pData, ULONG nSize);
+
+public:
+ INetMessageDecode64Stream_Impl (ULONG nMsgBufferSize = 128);
+ virtual ~INetMessageDecode64Stream_Impl (void);
+};
+
+/*=========================================================================
+ *
+ * INetIStream Implementation.
+ *
+ *=======================================================================*/
+/*
+ * INetIStream.
+ */
+INetIStream::INetIStream ()
+{
+}
+
+/*
+ * ~INetIStream.
+ */
+INetIStream::~INetIStream (void)
+{
+}
+
+/*
+ * Read.
+ */
+int INetIStream::Read (sal_Char *pData, ULONG nSize)
+{
+ return GetData (pData, nSize);
+}
+
+/*
+ * Decode64.
+ */
+void INetIStream::Decode64 (SvStream& rIn, SvStream& rOut)
+{
+ INetMessage aMsg;
+ aMsg.SetDocumentLB(new SvAsyncLockBytes(&rOut, FALSE));
+
+ INetMessageDecode64Stream_Impl aStream (8192);
+ aStream.SetTargetMessage (&aMsg);
+
+ sal_Char* pBuf = new sal_Char[8192];
+
+ int nRead = 0;
+ while ((nRead = rIn.Read (pBuf, 8192)) > 0)
+ aStream.Write( pBuf, nRead );
+ aStream.Write ("\r\n", 2);
+
+ delete[] pBuf;
+}
+
+/*
+ * Encode64.
+ */
+void INetIStream::Encode64 (SvStream& rIn, SvStream& rOut)
+{
+ INetMessage aMsg;
+ aMsg.SetDocumentLB (
+ new SvLockBytes (&rIn, FALSE));
+
+ INetMessageEncode64Stream_Impl aStream (8192);
+ aStream.SetSourceMessage (&aMsg);
+
+ sal_Char* pBuf = new sal_Char[8192];
+
+ int nRead = 0;
+ while ((nRead = aStream.Read (pBuf, 8192)) > 0)
+ rOut.Write( pBuf, nRead );
+
+ delete[] pBuf;
+}
+
+/*=========================================================================
+ *
+ * INetOStream Implementation.
+ *
+ *=======================================================================*/
+/*
+ * INetOStream.
+ */
+INetOStream::INetOStream ()
+{
+}
+
+/*
+ * ~INetOStream.
+ */
+INetOStream::~INetOStream (void)
+{
+}
+
+/*
+ * Write.
+ */
+int INetOStream::Write (const sal_Char *pData, ULONG nSize)
+{
+ return PutData (pData, nSize);
+}
+
+/*=========================================================================
+ *
+ * INetMessageIStream Implementation.
+ *
+ *=======================================================================*/
+/*
+ * INetMessageIStream.
+ */
+INetMessageIStream::INetMessageIStream (ULONG nBufferSize)
+ : pSourceMsg (NULL),
+ bHeaderGenerated (FALSE),
+ nBufSiz (nBufferSize),
+ pMsgStrm (NULL),
+ pMsgBuffer (new SvMemoryStream)
+{
+ pMsgBuffer->SetStreamCharSet (RTL_TEXTENCODING_ASCII_US);
+ pBuffer = new sal_Char[nBufSiz];
+ pRead = pWrite = pBuffer;
+}
+
+/*
+ * ~INetMessageIStream.
+ */
+INetMessageIStream::~INetMessageIStream (void)
+{
+ delete [] pBuffer;
+ delete pMsgBuffer;
+ delete pMsgStrm;
+}
+
+/*
+ * GetData.
+ */
+int INetMessageIStream::GetData (sal_Char *pData, ULONG nSize)
+{
+ if (pSourceMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ sal_Char *pWBuf = pData;
+ sal_Char *pWEnd = pData + nSize;
+
+ while (pWBuf < pWEnd)
+ {
+ // Caller's buffer not yet filled.
+ ULONG n = pRead - pWrite;
+ if (n > 0)
+ {
+ // Bytes still in buffer.
+ ULONG m = pWEnd - pWBuf;
+ if (m < n) n = m;
+ for (ULONG i = 0; i < n; i++) *pWBuf++ = *pWrite++;
+ }
+ else
+ {
+ // Buffer empty. Reset to <Begin-of-Buffer>.
+ pRead = pWrite = pBuffer;
+
+ // Read next message line.
+ int nRead = GetMsgLine (pBuffer, nBufSiz);
+ if (nRead > 0)
+ {
+ // Set read pointer.
+ pRead = pBuffer + nRead;
+ }
+ else
+ {
+ if (!bHeaderGenerated)
+ {
+ // Header generated. Insert empty line.
+ bHeaderGenerated = TRUE;
+ *pRead++ = '\r';
+ *pRead++ = '\n';
+ }
+ else
+ {
+ // Body generated.
+ return (pWBuf - pData);
+ }
+ }
+ }
+ }
+ return (pWBuf - pData);
+}
+
+/*
+ * GetMsgLine.
+ */
+int INetMessageIStream::GetMsgLine (sal_Char *pData, ULONG nSize)
+{
+ if (pSourceMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ sal_Char *pWBuf = pData;
+ sal_Char *pWEnd = pData + nSize;
+
+ if (!bHeaderGenerated)
+ {
+ ULONG i, n;
+
+ if (pMsgBuffer->Tell() == 0)
+ {
+ // Insert formatted header into buffer.
+ n = pSourceMsg->GetHeaderCount();
+ for (i = 0; i < n; i++)
+ {
+ INetMessageHeader aHeader (pSourceMsg->GetHeaderField(i));
+ if (aHeader.GetValue().Len())
+ {
+ // NYI: Folding long lines.
+ *pMsgBuffer << (sal_Char*)(aHeader.GetName().GetBuffer());
+ *pMsgBuffer << ": ";
+ *pMsgBuffer << (sal_Char*)(aHeader.GetValue().GetBuffer());
+ *pMsgBuffer << "\r\n";
+ }
+ }
+
+ pMsgWrite = (sal_Char *)(pMsgBuffer->GetData());
+ pMsgRead = pMsgWrite + pMsgBuffer->Tell();
+ }
+
+ n = pMsgRead - pMsgWrite;
+ if (n > 0)
+ {
+ // Move to caller.
+ if (nSize < n) n = nSize;
+ for (i = 0; i < n; i++) *pWBuf++ = *pMsgWrite++;
+ }
+ else
+ {
+ // Reset buffer.
+ pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
+ }
+ }
+ else
+ {
+ if (pSourceMsg->GetDocumentLB())
+ {
+ if (pMsgStrm == NULL)
+ pMsgStrm = new SvStream (pSourceMsg->GetDocumentLB());
+
+ ULONG nRead = pMsgStrm->Read (pWBuf, (pWEnd - pWBuf));
+ pWBuf += nRead;
+ }
+ }
+ return (pWBuf - pData);
+}
+
+/*=========================================================================
+ *
+ * INetMessageOStream Implementation.
+ *
+ *=======================================================================*/
+/*
+ * INetMessageOStream.
+ */
+INetMessageOStream::INetMessageOStream (void)
+ : pTargetMsg (NULL),
+ bHeaderParsed (FALSE),
+ eOState (INETMSG_EOL_BEGIN),
+ pMsgBuffer (new SvMemoryStream)
+{
+}
+
+/*
+ * ~INetMessageOStream.
+ */
+INetMessageOStream::~INetMessageOStream (void)
+{
+ if (pMsgBuffer->Tell() > 0)
+ PutMsgLine ((const sal_Char *) pMsgBuffer->GetData(), pMsgBuffer->Tell());
+ delete pMsgBuffer;
+
+ if (pTargetMsg)
+ {
+ SvOpenLockBytes *pLB =
+ PTR_CAST (SvOpenLockBytes, pTargetMsg->GetDocumentLB());
+ if (pLB)
+ {
+ pLB->Flush();
+ pLB->Terminate();
+ }
+ }
+}
+
+/*
+ * PutData.
+ * (Simple Field Parsing (RFC822, Appendix B)).
+ */
+int INetMessageOStream::PutData (const sal_Char *pData, ULONG nSize)
+{
+ if (pTargetMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ const sal_Char *pStop = (pData + nSize);
+
+ while (!bHeaderParsed && (pData < pStop))
+ {
+ if (eOState == INETMSG_EOL_BEGIN)
+ {
+ if ((*pData == '\r') || (*pData == '\n'))
+ {
+ /*
+ * Empty Line. Separates header fields from message body.
+ * Skip this and any 2nd line break character (if any).
+ */
+ pData++;
+ if ((pData < pStop) && ((*pData == '\r') || (*pData == '\n')))
+ pData++;
+
+ // Emit any buffered last header field.
+ if (pMsgBuffer->Tell() > 0)
+ {
+ *pMsgBuffer << '\0';
+ int status = PutMsgLine (
+ (const sal_Char *) pMsgBuffer->GetData(),
+ pMsgBuffer->Tell());
+ if (status != INETSTREAM_STATUS_OK) return status;
+ }
+
+ // Reset to begin.
+ eOState = INETMSG_EOL_BEGIN;
+ pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
+
+ // Mark header parsed.
+ bHeaderParsed = TRUE;
+ }
+ else if ((*pData == ' ') || (*pData == '\t'))
+ {
+ // Continuation line. Unfold multi-line field-body.
+ *pMsgBuffer << ' ';
+ pData++;
+ }
+ else
+ {
+ // Begin of new header field.
+ if (pMsgBuffer->Tell() > 0)
+ {
+ // Emit buffered header field now.
+ *pMsgBuffer << '\0';
+ int status = PutMsgLine (
+ (const sal_Char *) pMsgBuffer->GetData(),
+ pMsgBuffer->Tell());
+ if (status != INETSTREAM_STATUS_OK) return status;
+ }
+
+ // Reset to begin of buffer.
+ pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
+
+ // Insert current character into buffer.
+ *pMsgBuffer << *pData++;
+ }
+
+ // Search for next line break character.
+ if (!bHeaderParsed) eOState = INETMSG_EOL_SCR;
+ }
+ else if (eOState == INETMSG_EOL_FCR)
+ {
+ // Skip line break character.
+ pData++;
+
+ // Mark begin of line.
+ eOState = INETMSG_EOL_BEGIN;
+ }
+ else if ((*pData == '\r') || (*pData == '\n'))
+ {
+ if (*pData == '\r') pData++;
+ eOState = INETMSG_EOL_FCR;
+ }
+ else if (ascii_isWhitespace (*pData & 0x7f))
+ {
+ // Any <LWS> is folded into a single <SP> character.
+ sal_Char c = *((const sal_Char *) pMsgBuffer->GetData() + pMsgBuffer->Tell() - 1);
+ if (!ascii_isWhitespace (c & 0x7f)) *pMsgBuffer << ' ';
+
+ // Skip over this <LWS> character.
+ pData++;
+ }
+ else
+ {
+ // Any other character is inserted into line buffer.
+ *pMsgBuffer << *pData++;
+ }
+ }
+
+ if (bHeaderParsed && (pData < pStop))
+ {
+ // Put message body down-stream.
+ return PutMsgLine (pData, (pStop - pData));
+ }
+
+ return INETSTREAM_STATUS_OK;
+}
+
+/*
+ * PutMsgLine.
+ */
+int INetMessageOStream::PutMsgLine (const sal_Char *pData, ULONG nSize)
+{
+ // Check for message container.
+ if (pTargetMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ // Check for header or body.
+ if (!IsHeaderParsed())
+ {
+ ByteString aField (pData);
+ USHORT nPos = aField.Search (':');
+ if (nPos != STRING_NOTFOUND)
+ {
+ ByteString aName (
+ aField.Copy (0, nPos));
+ ByteString aValue (
+ aField.Copy (nPos + 1, aField.Len() - nPos + 1));
+ aValue.EraseLeadingChars (' ');
+
+ pTargetMsg->SetHeaderField (
+ INetMessageHeader (aName, aValue));
+ }
+ }
+ else
+ {
+ SvOpenLockBytes *pLB =
+ PTR_CAST(SvOpenLockBytes, pTargetMsg->GetDocumentLB());
+ if (pLB == NULL)
+ return INETSTREAM_STATUS_WOULDBLOCK;
+
+ sal_Size nDocSiz = pTargetMsg->GetDocumentSize();
+ sal_Size nWrite = 0;
+
+ pLB->FillAppend ((sal_Char *)pData, nSize, &nWrite);
+ pTargetMsg->SetDocumentSize (nDocSiz + nWrite);
+
+ if (nWrite < nSize) return INETSTREAM_STATUS_ERROR;
+ }
+ return INETSTREAM_STATUS_OK;
+}
+
+/*=========================================================================
+ *
+ * INetMessageIOStream Implementation.
+ *
+ *=======================================================================*/
+/*
+ * INetMessageIOStream.
+ */
+INetMessageIOStream::INetMessageIOStream (ULONG nBufferSize)
+ : INetMessageIStream (nBufferSize),
+ INetMessageOStream ()
+{
+}
+
+/*
+ * ~INetMessageIOStream.
+ */
+INetMessageIOStream::~INetMessageIOStream (void)
+{
+}
+
+/*=======================================================================
+ *
+ * INetMessageEncodeQPStream_Impl Implementation.
+ * (Quoted-Printable Encoding)
+ *
+ *=====================================================================*/
+static const sal_Char hex2pr[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static const sal_Char ebcdic[] = {
+ '!', '"', '#', '$', '@', '[', '\\', ']', '^', '`', '{', '|', '}', '~'
+};
+
+/*
+ * INetMessageEncodeQPStream_Impl.
+ */
+INetMessageEncodeQPStream_Impl::INetMessageEncodeQPStream_Impl (
+ ULONG nMsgBufferSize)
+ : INetMessageIStream (),
+ pMsgStrm (NULL),
+ nMsgBufSiz (nMsgBufferSize),
+ nTokBufSiz (80),
+ eState (INETMSG_EOL_SCR),
+ bDone (FALSE)
+{
+ GenerateHeader (FALSE);
+
+ pMsgBuffer = new sal_Char[nMsgBufSiz];
+ pMsgRead = pMsgWrite = pMsgBuffer;
+
+ pTokBuffer = new sal_Char[nTokBufSiz];
+ pTokRead = pTokWrite = pTokBuffer;
+}
+
+/*
+ * ~INetMessageEncodeQPStream_Impl.
+ */
+INetMessageEncodeQPStream_Impl::~INetMessageEncodeQPStream_Impl (void)
+{
+ delete pMsgStrm;
+ delete [] pMsgBuffer;
+ delete [] pTokBuffer;
+}
+
+/*
+ * GetMsgLine.
+ */
+int INetMessageEncodeQPStream_Impl::GetMsgLine (sal_Char *pData, ULONG nSize)
+{
+ INetMessage *pMsg = GetSourceMessage ();
+ if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ if (pMsg->GetDocumentLB() == NULL) return 0;
+ if (pMsgStrm == NULL) pMsgStrm = new SvStream (pMsg->GetDocumentLB());
+
+ sal_Char *pWBuf = pData;
+ while (pWBuf < (pData + nSize))
+ {
+ // Caller's buffer not yet filled.
+ if ((pMsgRead - pMsgWrite) > 0)
+ {
+ // Bytes still in message buffer.
+ if ((eState != INETMSG_EOL_BEGIN) &&
+ ((pTokRead - pTokBuffer) < 72))
+ {
+ // Token buffer not yet filled.
+ if (eState == INETMSG_EOL_FCR)
+ {
+ eState = INETMSG_EOL_BEGIN;
+ if (*pMsgWrite != '\n')
+ {
+ // Convert orphant <CR> into <CR><LF> sequence.
+ *pTokRead++ = '\n';
+ }
+ *pTokRead++ = *pMsgWrite++;
+ }
+ else if ((*pMsgWrite == ' ') || (*pMsgWrite == '\t'))
+ {
+ eState = INETMSG_EOL_FSP;
+ *pTokRead++ = *pMsgWrite++;
+ }
+ else if (*pMsgWrite == '\r')
+ {
+ // Found <CR>.
+ if (eState == INETMSG_EOL_FSP)
+ {
+ // Encode last (trailing space) character.
+ sal_uInt8 c = (sal_uInt8)(*(--pTokRead));
+ *pTokRead++ = '=';
+ *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
+ *pTokRead++ = hex2pr[((c & 0x0f) )];
+ }
+ eState = INETMSG_EOL_FCR;
+ *pTokRead++ = *pMsgWrite++;
+ }
+ else if (*pMsgWrite == '\n')
+ {
+ // Found <LF> only.
+ if (eState == INETMSG_EOL_FSP)
+ {
+ // Encode last (trailing space) character.
+ sal_uInt8 c = (sal_uInt8)(*(--pTokRead));
+ *pTokRead++ = '=';
+ *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
+ *pTokRead++ = hex2pr[((c & 0x0f) )];
+ }
+ eState = INETMSG_EOL_BEGIN;
+
+ // Convert orphant <LF> into <CR><LF> sequence.
+ *pTokRead++ = '\r';
+ *pTokRead++ = *pMsgWrite++;
+ }
+ else if (*pMsgWrite == '=')
+ {
+ // Escape character itself MUST be encoded, of course.
+ sal_uInt8 c = (sal_uInt8)(*pMsgWrite++);
+ *pTokRead++ = '=';
+ *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
+ *pTokRead++ = hex2pr[((c & 0x0f) )];
+
+ eState = INETMSG_EOL_SCR;
+ }
+ else if (((sal_uInt8)(*pMsgWrite) > 0x20) &&
+ ((sal_uInt8)(*pMsgWrite) < 0x7f) )
+ {
+ /*
+ * Some printable ASCII character.
+ * (Encode EBCDIC special characters (NYI)).
+ */
+ *pTokRead++ = *pMsgWrite++;
+ eState = INETMSG_EOL_SCR;
+ }
+ else
+ {
+ // Encode any other character.
+ sal_uInt8 c = (sal_uInt8)(*pMsgWrite++);
+ *pTokRead++ = '=';
+ *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
+ *pTokRead++ = hex2pr[((c & 0x0f) )];
+
+ eState = INETMSG_EOL_SCR;
+ }
+ }
+ else
+ {
+ // Check for maximum line length.
+ if (eState != INETMSG_EOL_BEGIN)
+ {
+ // Insert soft line break.
+ *pTokRead++ = '=';
+ *pTokRead++ = '\r';
+ *pTokRead++ = '\n';
+
+ eState = INETMSG_EOL_BEGIN;
+ }
+
+ // Copy to caller's buffer.
+ if ((pTokRead - pTokWrite) > 0)
+ {
+ // Bytes still in token buffer.
+ *pWBuf++ = *pTokWrite++;
+ }
+ else
+ {
+ // Token buffer empty. Reset to <Begin-of-Buffer>.
+ pTokRead = pTokWrite = pTokBuffer;
+ eState = INETMSG_EOL_SCR;
+ }
+ }
+ }
+ else
+ {
+ // Message buffer empty. Reset to <Begin-of-Buffer>.
+ pMsgRead = pMsgWrite = pMsgBuffer;
+
+ // Read next message block.
+ ULONG nRead = pMsgStrm->Read (pMsgBuffer, nMsgBufSiz);
+ if (nRead > 0)
+ {
+ // Set read pointer.
+ pMsgRead = (pMsgBuffer + nRead);
+ }
+ else
+ {
+ // Nothing more ro read.
+ if (!bDone)
+ {
+ // Append final <CR><LF> and mark we're done.
+ *pTokRead++ = '\r';
+ *pTokRead++ = '\n';
+
+ bDone = TRUE;
+ }
+ else
+ {
+ // Already done all encoding.
+ if ((pTokRead - pTokWrite) > 0)
+ {
+ // Bytes still in token buffer.
+ *pWBuf++ = *pTokWrite++;
+ }
+ else
+ {
+ // Token buffer empty. Reset to <Begin-of-Buffer>.
+ pTokRead = pTokWrite = pTokBuffer;
+
+ // Return.
+ return (pWBuf - pData);
+ }
+ }
+ }
+ }
+ }
+ return (pWBuf - pData);
+}
+
+/*=====================================================================
+ *
+ * INetMessageDecodeQPStream_Impl Implementation.
+ * (Quoted-Printable Decoding)
+ *
+ *====================================================================*/
+static const sal_uInt8 pr2hex[128] = {
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+
+ 0x10, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
+};
+
+/*
+ * INetMessageDecodeQPStream_Impl.
+ */
+INetMessageDecodeQPStream_Impl::INetMessageDecodeQPStream_Impl (void)
+ : INetMessageOStream (),
+ eState (INETMSG_EOL_BEGIN),
+ pMsgBuffer (new SvMemoryStream),
+ nTokBufLen (0)
+{
+ ParseHeader (FALSE);
+}
+
+/*
+ * ~INetMessageDecodeQPStream_Impl.
+ */
+INetMessageDecodeQPStream_Impl::~INetMessageDecodeQPStream_Impl (void)
+{
+ delete pMsgBuffer;
+}
+
+/*
+ * PutMsgLine.
+ */
+int INetMessageDecodeQPStream_Impl::PutMsgLine (
+ const sal_Char *pData, ULONG nSize)
+{
+ INetMessage *pMsg = GetTargetMessage();
+ if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ SvOpenLockBytes * pLB = PTR_CAST(SvOpenLockBytes, pMsg->GetDocumentLB());
+ if (pLB == NULL) return INETSTREAM_STATUS_WOULDBLOCK;
+
+ const sal_Char *pStop = pData + nSize;
+ while (pData < pStop)
+ {
+ if (eState == INETMSG_EOL_FESC)
+ {
+ *(pTokBuffer + nTokBufLen++) = static_cast< char >(toupper(*pData));
+ pData++;
+ if (nTokBufLen == 2)
+ {
+ if ((*pTokBuffer == '\r') || (*pTokBuffer == '\n'))
+ {
+ // Soft line break (=<CR><LF>). Emit buffer now.
+ eState = INETMSG_EOL_BEGIN;
+ }
+ else
+ {
+ // Decode token.
+ *pMsgBuffer << sal_uInt8 (
+ (pr2hex[(int)(pTokBuffer[0] & 0x7f)] << 4) |
+ (pr2hex[(int)(pTokBuffer[1] & 0x7f)] & 15) );
+
+ // Search for next <CR>.
+ eState = INETMSG_EOL_SCR;
+ }
+
+ // Reset token buffer.
+ nTokBufLen = 0;
+ }
+ }
+ else if (*pData == '=')
+ {
+ // Found escape character.
+ pData++;
+ eState = INETMSG_EOL_FESC;
+ }
+ else if (eState == INETMSG_EOL_FCR)
+ {
+ *pMsgBuffer << *pData++;
+ eState = INETMSG_EOL_BEGIN;
+ }
+ else if (*pData == '\r')
+ {
+ *pMsgBuffer << *pData++;
+ eState = INETMSG_EOL_FCR;
+ }
+ else
+ {
+ *pMsgBuffer << *pData++;
+ }
+
+ if (eState == INETMSG_EOL_BEGIN)
+ {
+ sal_Size nRead = pMsgBuffer->Tell();
+ if (nRead > 0)
+ {
+ // Emit buffer.
+ sal_Size nDocSiz = pMsg->GetDocumentSize();
+ sal_Size nWrite = 0;
+
+ pLB->FillAppend (
+ (sal_Char *)(pMsgBuffer->GetData()), nRead, &nWrite);
+ pMsg->SetDocumentSize (nDocSiz + nWrite);
+
+ if (nWrite < nRead) return INETSTREAM_STATUS_ERROR;
+
+ pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
+ }
+ eState = INETMSG_EOL_SCR;
+ }
+ }
+ return INETSTREAM_STATUS_OK;
+}
+
+/*======================================================================
+ *
+ * INetMessageEncode64Stream_Impl Implementation.
+ * (Base64 Encoding)
+ *
+ *====================================================================*/
+static const sal_Char six2pr[64] = {
+ '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', '+', '/'
+};
+
+/*
+ * INetMessageEncode64Stream_Impl.
+ */
+INetMessageEncode64Stream_Impl::INetMessageEncode64Stream_Impl (
+ ULONG nMsgBufferSize)
+ : INetMessageIStream (),
+ pMsgStrm (NULL),
+ nMsgBufSiz (nMsgBufferSize),
+ nTokBufSiz (80),
+ bDone (FALSE)
+{
+ GenerateHeader (FALSE);
+
+ pMsgBuffer = new sal_uInt8[nMsgBufSiz];
+ pMsgRead = pMsgWrite = pMsgBuffer;
+
+ pTokBuffer = new sal_Char[nTokBufSiz];
+ pTokRead = pTokWrite = pTokBuffer;
+}
+
+/*
+ * ~INetMessageEncode64Stream_Impl.
+ */
+INetMessageEncode64Stream_Impl::~INetMessageEncode64Stream_Impl (void)
+{
+ delete pMsgStrm;
+ delete [] pMsgBuffer;
+ delete [] pTokBuffer;
+}
+
+/*
+ * GetMsgLine.
+ */
+int INetMessageEncode64Stream_Impl::GetMsgLine (sal_Char *pData, ULONG nSize)
+{
+ INetMessage *pMsg = GetSourceMessage ();
+ if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ if (pMsg->GetDocumentLB() == NULL) return 0;
+ if (pMsgStrm == NULL) pMsgStrm = new SvStream (pMsg->GetDocumentLB());
+
+ sal_Char *pWBuf = pData;
+ while (pWBuf < (pData + nSize))
+ {
+ // Caller's buffer not yet filled.
+ if ((pMsgRead - pMsgWrite) > 0)
+ {
+ // Bytes still in message buffer.
+ if ((pTokRead - pTokBuffer) < 72)
+ {
+ // Token buffer not yet filled.
+ switch ((pTokRead - pTokBuffer) % 4)
+ {
+ case 0:
+ *pTokRead++ = six2pr[(int)(*pMsgWrite >> 2)];
+ break;
+
+ case 1:
+ *pTokRead++ = six2pr[
+ (int)(((*pMsgWrite << 4) & 060) |
+ (((*(pMsgWrite + 1)) >> 4) & 017))];
+ pMsgWrite++;
+ break;
+
+ case 2:
+ *pTokRead++ = six2pr[
+ (int)(((*pMsgWrite << 2) & 074) |
+ (((*(pMsgWrite + 1)) >> 6) & 003))];
+ pMsgWrite++;
+ break;
+
+ default: // == case 3
+ *pTokRead++ = six2pr[(int)(*pMsgWrite & 077)];
+ pMsgWrite++;
+ break;
+ }
+ }
+ else if ((pTokRead - pTokBuffer) == 72)
+ {
+ // Maximum line length. Append <CR><LF>.
+ *pTokRead++ = '\r';
+ *pTokRead++ = '\n';
+ }
+ else
+ {
+ if ((pTokRead - pTokWrite) > 0)
+ {
+ // Bytes still in token buffer.
+ *pWBuf++ = *pTokWrite++;
+ }
+ else
+ {
+ // Token buffer empty. Reset to <Begin-of-Buffer>.
+ pTokRead = pTokWrite = pTokBuffer;
+ }
+ }
+ }
+ else
+ {
+ // Message buffer empty. Reset to <Begin-of-Buffer>.
+ pMsgRead = pMsgWrite = pMsgBuffer;
+
+ // Read next message block.
+ ULONG nRead = pMsgStrm->Read (pMsgBuffer, nMsgBufSiz);
+ if (nRead > 0)
+ {
+ // Set read pointer.
+ pMsgRead = (pMsgBuffer + nRead);
+ }
+ else
+ {
+ // Nothing more to read.
+ if (!bDone)
+ {
+ // Append pad character(s) and final <CR><LF>.
+ switch ((pTokRead - pTokBuffer) % 4)
+ {
+ case 2:
+ *pTokRead++ = '=';
+ // Fall through for 2nd pad character.
+
+ case 3:
+ *pTokRead++ = '=';
+ break;
+
+ default:
+ break;
+ }
+ *pTokRead++ = '\r';
+ *pTokRead++ = '\n';
+
+ // Mark we're done.
+ bDone = TRUE;
+ }
+ else
+ {
+ // Already done all encoding.
+ if ((pTokRead - pTokWrite) > 0)
+ {
+ // Bytes still in token buffer.
+ *pWBuf++ = *pTokWrite++;
+ }
+ else
+ {
+ // Token buffer empty. Reset to <Begin-of-Buffer>.
+ pTokRead = pTokWrite = pTokBuffer;
+
+ // Reset done flag, if everything has been done.
+ // if (pWBuf == pData) bDone = FALSE;
+
+ // Return.
+ return (pWBuf - pData);
+ }
+ }
+ }
+ }
+ } // while (pWBuf < (pData + nSize))
+ return (pWBuf - pData);
+}
+
+/*======================================================================
+ *
+ * INetMessageDecode64Stream_Impl Implementation.
+ * (Base64 Decoding)
+ *
+ *====================================================================*/
+static const sal_uInt8 pr2six[256] = {
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x3E, 0x40, 0x40, 0x40, 0x3F,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
+ 0x3C, 0x3D, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+
+ 0x40, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40,
+
+ 0x40, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0x40, 0x40, 0x40, 0x40, 0x40,
+
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
+};
+
+/*
+ * INetMessageDecode64Stream_Impl.
+ */
+INetMessageDecode64Stream_Impl::INetMessageDecode64Stream_Impl (
+ ULONG nMsgBufferSize)
+ : INetMessageOStream (),
+ eState (INETMSG_EOL_SCR),
+ nMsgBufSiz (nMsgBufferSize)
+{
+ ParseHeader (FALSE);
+
+ pMsgBuffer = new sal_Char[nMsgBufSiz];
+ pMsgRead = pMsgWrite = pMsgBuffer;
+}
+
+/*
+ * ~INetMessageDecode64Stream_Impl.
+ */
+INetMessageDecode64Stream_Impl::~INetMessageDecode64Stream_Impl (void)
+{
+ delete [] pMsgBuffer;
+}
+
+/*
+ * PutMsgLine.
+ */
+int INetMessageDecode64Stream_Impl::PutMsgLine (
+ const sal_Char *pData, ULONG nSize)
+{
+ INetMessage *pMsg = GetTargetMessage ();
+ if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ SvOpenLockBytes * pLB = PTR_CAST(SvOpenLockBytes, pMsg->GetDocumentLB());
+ if (pLB == NULL) return INETSTREAM_STATUS_WOULDBLOCK;
+
+ const sal_Char *pStop = (pData + nSize);
+ while (pData < pStop)
+ {
+ if (pr2six[(int)(*pData)] > 63)
+ {
+ /*
+ * Character not in base64 alphabet.
+ * Check for <End-of-Stream> or Junk.
+ */
+ if (*pData == '=')
+ {
+ // Final pad character -> Done.
+ sal_Size nDocSiz = pMsg->GetDocumentSize();
+ sal_Size nRead = pMsgWrite - pMsgBuffer;
+ sal_Size nWrite = 0;
+
+ pLB->FillAppend (pMsgBuffer, nRead, &nWrite);
+ pMsg->SetDocumentSize (nDocSiz + nWrite);
+
+ if (nWrite < nRead)
+ return INETSTREAM_STATUS_ERROR;
+ else
+ return INETSTREAM_STATUS_LOADED;
+ }
+ else if (eState == INETMSG_EOL_FCR)
+ {
+ // Skip any line break character.
+ if ((*pData == '\r') || (*pData == '\n')) pData++;
+
+ // Store decoded message buffer contents.
+ sal_Size nDocSiz = pMsg->GetDocumentSize();
+ sal_Size nRead = pMsgWrite - pMsgBuffer;
+ sal_Size nWrite = 0;
+
+ pLB->FillAppend (pMsgBuffer, nRead, &nWrite);
+ pMsg->SetDocumentSize (nDocSiz + nWrite);
+
+ if (nWrite < nRead) return INETSTREAM_STATUS_ERROR;
+
+ // Reset to <Begin-of-Buffer>.
+ pMsgWrite = pMsgBuffer;
+ eState = INETMSG_EOL_SCR;
+ }
+ else if ((*pData == '\r') || (*pData == '\n'))
+ {
+ // Skip any line break character.
+ pData++;
+ eState = INETMSG_EOL_FCR;
+ }
+ else
+ {
+ // Skip any junk character (may be transmission error).
+ pData++;
+ }
+ }
+ else
+ {
+ // Decode any other character into message buffer.
+ switch ((pMsgRead - pMsgBuffer) % 4)
+ {
+ case 0:
+ *pMsgWrite = (pr2six[(int)(*pData++)] << 2);
+ pMsgRead++;
+ break;
+
+ case 1:
+ *pMsgWrite++ |= (pr2six[(int)(*pData )] >> 4);
+ *pMsgWrite = (pr2six[(int)(*pData++)] << 4);
+ pMsgRead++;
+ break;
+
+ case 2:
+ *pMsgWrite++ |= (pr2six[(int)(*pData )] >> 2);
+ *pMsgWrite = (pr2six[(int)(*pData++)] << 6);
+ pMsgRead++;
+ break;
+
+ default: // == case 3
+ *pMsgWrite++ |= (pr2six[(int)(*pData++)]);
+ pMsgRead = pMsgBuffer;
+ break;
+ } // switch ((pMsgRead - pMsgBuffer) % 4)
+ }
+ } // while (pData < pStop)
+ return INETSTREAM_STATUS_OK;
+}
+
+/*=========================================================================
+ *
+ * INetMIMEMessageStream Implementation.
+ *
+ *=======================================================================*/
+/*
+ * INetMIMEMessageStream.
+ */
+INetMIMEMessageStream::INetMIMEMessageStream (ULONG nBufferSize)
+ : INetMessageIOStream (nBufferSize),
+ eState (INETMSG_EOL_BEGIN),
+ nChildIndex (0),
+ pChildStrm (NULL),
+ eEncoding (INETMSG_ENCODING_BINARY),
+ pEncodeStrm (NULL),
+ pDecodeStrm (NULL),
+ pMsgBuffer (NULL)
+{
+}
+
+/*
+ * ~INetMIMEMessageStream.
+ */
+INetMIMEMessageStream::~INetMIMEMessageStream (void)
+{
+ delete pChildStrm;
+ delete pEncodeStrm;
+ delete pDecodeStrm;
+ delete pMsgBuffer;
+}
+
+/*
+ * GetMsgEncoding.
+ */
+INetMessageEncoding
+INetMIMEMessageStream::GetMsgEncoding (const String& rContentType)
+{
+ if ((rContentType.CompareIgnoreCaseToAscii ("message" , 7) == 0) ||
+ (rContentType.CompareIgnoreCaseToAscii ("multipart", 9) == 0) )
+ return INETMSG_ENCODING_7BIT;
+
+ if (rContentType.CompareIgnoreCaseToAscii ("text", 4) == 0)
+ {
+ if (rContentType.CompareIgnoreCaseToAscii ("text/plain", 10) == 0)
+ {
+ if (rContentType.GetTokenCount ('=') > 1)
+ {
+ String aCharset (rContentType.GetToken (1, '='));
+ aCharset.EraseLeadingChars (' ');
+ aCharset.EraseLeadingChars ('"');
+
+ if (aCharset.CompareIgnoreCaseToAscii ("us-ascii", 8) == 0)
+ return INETMSG_ENCODING_7BIT;
+ else
+ return INETMSG_ENCODING_QUOTED;
+ }
+ else
+ return INETMSG_ENCODING_7BIT;
+ }
+ else
+ return INETMSG_ENCODING_QUOTED;
+ }
+
+ return INETMSG_ENCODING_BASE64;
+}
+
+/*
+ * GetMsgLine.
+ * (Message Generator).
+ */
+int INetMIMEMessageStream::GetMsgLine (sal_Char *pData, ULONG nSize)
+{
+ // Check for message container.
+ INetMIMEMessage *pMsg = GetSourceMessage();
+ if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ // Check for header or body.
+ if (!IsHeaderGenerated())
+ {
+ if (eState == INETMSG_EOL_BEGIN)
+ {
+ // Prepare special header fields.
+ if (pMsg->GetParent())
+ {
+ String aPCT (pMsg->GetParent()->GetContentType());
+ if (aPCT.CompareIgnoreCaseToAscii ("message/rfc822", 14) == 0)
+ pMsg->SetMIMEVersion (
+ String(CONSTASCII_STRINGPARAM("1.0")));
+ else
+ pMsg->SetMIMEVersion (String());
+ }
+ else
+ {
+ pMsg->SetMIMEVersion (String(CONSTASCII_STRINGPARAM("1.0")));
+ }
+
+ // Check ContentType.
+ String aContentType (pMsg->GetContentType());
+ if (aContentType.Len())
+ {
+ // Determine default Content-Type.
+ String aDefaultType;
+ pMsg->GetDefaultContentType (aDefaultType);
+
+ if (aDefaultType.CompareIgnoreCaseToAscii (
+ aContentType, aContentType.Len()) == 0)
+ {
+ // No need to specify default.
+ pMsg->SetContentType (String());
+ }
+ }
+
+ // Check Encoding.
+ String aEncoding (pMsg->GetContentTransferEncoding());
+ if (aEncoding.Len())
+ {
+ // Use given Encoding.
+ if (aEncoding.CompareIgnoreCaseToAscii (
+ "base64", 6) == 0)
+ eEncoding = INETMSG_ENCODING_BASE64;
+ else if (aEncoding.CompareIgnoreCaseToAscii (
+ "quoted-printable", 16) == 0)
+ eEncoding = INETMSG_ENCODING_QUOTED;
+ else
+ eEncoding = INETMSG_ENCODING_7BIT;
+ }
+ else
+ {
+ // Use default Encoding for (given|default) Content-Type.
+ if (aContentType.Len() == 0)
+ {
+ // Determine default Content-Type.
+ pMsg->GetDefaultContentType (aContentType);
+ }
+ eEncoding = GetMsgEncoding (aContentType);
+ }
+
+ // Set Content-Transfer-Encoding header.
+ if (eEncoding == INETMSG_ENCODING_BASE64)
+ {
+ // Base64.
+ pMsg->SetContentTransferEncoding (
+ String(CONSTASCII_STRINGPARAM("base64")));
+ }
+ else if (eEncoding == INETMSG_ENCODING_QUOTED)
+ {
+ // Quoted-Printable.
+ pMsg->SetContentTransferEncoding (
+ String(CONSTASCII_STRINGPARAM("quoted-printable")));
+ }
+ else
+ {
+ // No need to specify default.
+ pMsg->SetContentTransferEncoding (String());
+ }
+
+ // Mark we're done.
+ eState = INETMSG_EOL_DONE;
+ }
+
+ // Generate the message header.
+ int nRead = INetMessageIOStream::GetMsgLine (pData, nSize);
+ if (nRead <= 0)
+ {
+ // Reset state.
+ eState = INETMSG_EOL_BEGIN;
+ }
+ return nRead;
+ }
+ else
+ {
+ // Generate the message body.
+ if (pMsg->IsContainer())
+ {
+ // Encapsulated message body.
+ while (eState == INETMSG_EOL_BEGIN)
+ {
+ if (pChildStrm == NULL)
+ {
+ INetMIMEMessage *pChild = pMsg->GetChild (nChildIndex);
+ if (pChild)
+ {
+ // Increment child index.
+ nChildIndex++;
+
+ // Create child stream.
+ pChildStrm = new INetMIMEMessageStream;
+ pChildStrm->SetSourceMessage (pChild);
+
+ if (pMsg->IsMultipart())
+ {
+ // Insert multipart delimiter.
+ ByteString aDelim ("--");
+ aDelim += pMsg->GetMultipartBoundary();
+ aDelim += "\r\n";
+
+ rtl_copyMemory (
+ pData, aDelim.GetBuffer(), aDelim.Len());
+ return aDelim.Len();
+ }
+ }
+ else
+ {
+ // No more parts. Mark we're done.
+ eState = INETMSG_EOL_DONE;
+ nChildIndex = 0;
+
+ if (pMsg->IsMultipart())
+ {
+ // Insert close delimiter.
+ ByteString aDelim ("--");
+ aDelim += pMsg->GetMultipartBoundary();
+ aDelim += "--\r\n";
+
+ rtl_copyMemory (
+ pData, aDelim.GetBuffer(), aDelim.Len());
+ return aDelim.Len();
+ }
+ }
+ }
+ else
+ {
+ // Read current child stream.
+ int nRead = pChildStrm->Read (pData, nSize);
+ if (nRead > 0)
+ {
+ return nRead;
+ }
+ else
+ {
+ // Cleanup exhausted child stream.
+ delete pChildStrm;
+ pChildStrm = NULL;
+ }
+ }
+ }
+ return 0;
+ }
+ else
+ {
+ // Single part message body.
+ if (pMsg->GetDocumentLB() == NULL)
+ {
+ // Empty message body.
+ return 0;
+ }
+ else
+ {
+ // Check whether message body needs to be encoded.
+ if (eEncoding == INETMSG_ENCODING_7BIT)
+ {
+ // No Encoding.
+ return INetMessageIOStream::GetMsgLine (pData, nSize);
+ }
+ else
+ {
+ // Apply appropriate Encoding.
+ while (eState == INETMSG_EOL_BEGIN)
+ {
+ if (pEncodeStrm == NULL)
+ {
+ // Create encoder stream.
+ if (eEncoding == INETMSG_ENCODING_QUOTED)
+ {
+ // Quoted-Printable Encoding.
+ pEncodeStrm
+ = new INetMessageEncodeQPStream_Impl;
+ }
+ else
+ {
+ // Base64 Encoding.
+ pEncodeStrm
+ = new INetMessageEncode64Stream_Impl;
+ }
+ pEncodeStrm->SetSourceMessage (pMsg);
+ }
+
+ // Read encoded message.
+ int nRead = pEncodeStrm->Read (pData, nSize);
+ if (nRead > 0)
+ {
+ return nRead;
+ }
+ else
+ {
+ // Cleanup exhausted encoder stream.
+ delete pEncodeStrm;
+ pEncodeStrm = NULL;
+
+ // Mark we're done.
+ eState = INETMSG_EOL_DONE;
+ }
+ }
+ return 0;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * PutMsgLine.
+ * (Message Parser).
+ */
+int INetMIMEMessageStream::PutMsgLine (const sal_Char *pData, ULONG nSize)
+{
+ // Check for message container.
+ INetMIMEMessage *pMsg = GetTargetMessage();
+ if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
+
+ // Check for header or body.
+ if (!IsHeaderParsed())
+ {
+ // Parse the message header.
+ int nRet = INetMessageIOStream::PutMsgLine (pData, nSize);
+ return nRet;
+ }
+ else
+ {
+ pMsg->SetHeaderParsed();
+ // Parse the message body.
+ if (pMsg->IsContainer())
+ {
+
+ // Content-Transfer-Encoding MUST be "7bit" (RFC1521).
+ if (pMsg->IsMessage())
+ {
+ if( !pChildStrm )
+ {
+ // Encapsulated message.
+ pMsg->SetChildCount( pMsg->GetChildCount() + 1);
+ INetMIMEMessage* pNewMessage = new INetMIMEMessage;
+ pNewMessage->SetDocumentLB (
+ new SvAsyncLockBytes(new SvCacheStream, FALSE));
+ pMsg->AttachChild( *pNewMessage, TRUE );
+
+ // Encapsulated message body. Create message parser stream.
+ pChildStrm = new INetMIMEMessageStream;
+ pChildStrm->SetTargetMessage ( pNewMessage );
+
+ // Initialize control variables.
+ eState = INETMSG_EOL_BEGIN;
+ }
+ if ( nSize > 0)
+ {
+ // Bytes still in buffer. Put message down-stream.
+ int status = pChildStrm->Write( pData, nSize );
+ if (status != INETSTREAM_STATUS_OK)
+ return status;
+ }
+
+ return INetMessageIOStream::PutMsgLine (pData, nSize);
+ }
+ else
+ {
+
+ // Multipart message body. Initialize multipart delimiters.
+ // Multipart message.
+ if (pMsg->GetMultipartBoundary().Len() == 0)
+ {
+ // Determine boundary.
+ ByteString aType (
+ pMsg->GetContentType(), RTL_TEXTENCODING_ASCII_US);
+ ByteString aLowerType (aType);
+ aLowerType.ToLowerAscii();
+
+ USHORT nPos = aLowerType.Search ("boundary=");
+ ByteString aBoundary (aType.Copy (nPos + 9));
+
+ aBoundary.EraseLeadingAndTrailingChars (' ');
+ aBoundary.EraseLeadingAndTrailingChars ('"');
+
+ // Save boundary.
+ pMsg->SetMultipartBoundary (aBoundary);
+ }
+
+ ByteString aPlainDelim (pMsg->GetMultipartBoundary());
+ ByteString aDelim ("--");
+ aDelim += aPlainDelim;
+
+ ByteString aPlainClose (aPlainDelim);
+ aPlainClose += "--";
+
+ ByteString aClose (aDelim);
+ aClose += "--";
+
+ if (pMsgBuffer == NULL) pMsgBuffer = new SvMemoryStream;
+ pMsgBuffer->Write (pData, nSize);
+ ULONG nBufSize = pMsgBuffer->Tell();
+
+ const sal_Char* pChar;
+ const sal_Char* pOldPos;
+ for( pOldPos = pChar = (const sal_Char *) pMsgBuffer->GetData(); nBufSize--;
+ pChar++ )
+ {
+ int status;
+ if( *pChar == '\r' || *pChar == '\n' )
+ {
+ if( aDelim.CompareTo (pOldPos, aDelim.Len())
+ != COMPARE_EQUAL &&
+ aClose.CompareTo (pOldPos, aClose.Len())
+ != COMPARE_EQUAL &&
+ aPlainDelim.CompareTo (pOldPos, aPlainDelim.Len())
+ != COMPARE_EQUAL &&
+ aPlainClose.CompareTo(pOldPos, aPlainClose.Len())
+ != COMPARE_EQUAL )
+ {
+ if( nBufSize &&
+ ( pChar[1] == '\r' || pChar[1] == '\n' ) )
+ nBufSize--, pChar++;
+ if( pChildStrm )
+ {
+ status = pChildStrm->Write(
+ pOldPos, pChar - pOldPos + 1 );
+ if( status != INETSTREAM_STATUS_OK )
+ return status;
+ }
+ else {
+ DBG_ERRORFILE( "Die Boundary nicht gefunden" );
+ }
+ status = INetMessageIOStream::PutMsgLine(
+ pOldPos, pChar - pOldPos + 1 );
+ if( status != INETSTREAM_STATUS_OK )
+ return status;
+ pOldPos = pChar + 1;
+ }
+ else
+ {
+ if( nBufSize &&
+ ( pChar[1] == '\r' || pChar[1] == '\n' ) )
+ nBufSize--, pChar++;
+ pOldPos = pChar + 1;
+ DELETEZ( pChildStrm );
+
+ if (aClose.CompareTo (pOldPos, aClose.Len())
+ != COMPARE_EQUAL &&
+ aPlainClose.CompareTo (pOldPos, aClose.Len())
+ != COMPARE_EQUAL )
+ {
+ // Encapsulated message.
+ pMsg->SetChildCount(pMsg->GetChildCount() + 1);
+ INetMIMEMessage* pNewMessage =
+ new INetMIMEMessage;
+ pNewMessage->SetDocumentLB (
+ new SvAsyncLockBytes (
+ new SvCacheStream, FALSE));
+
+ pMsg->AttachChild( *pNewMessage, TRUE );
+
+ // Encapsulated message body. Create message parser stream.
+ pChildStrm = new INetMIMEMessageStream;
+ pChildStrm->SetTargetMessage ( pNewMessage );
+
+ // Initialize control variables.
+ }
+ eState = INETMSG_EOL_BEGIN;
+ status = INetMessageIOStream::PutMsgLine(
+ pOldPos, pChar - pOldPos + 1 );
+ if( status != INETSTREAM_STATUS_OK )
+ return status;
+ }
+ }
+ }
+ if( pOldPos < pChar )
+ {
+ SvMemoryStream* pNewStream = new SvMemoryStream;
+ pNewStream->Write( pOldPos, pChar - pOldPos );
+ SvMemoryStream* pTmp = pMsgBuffer;
+ pMsgBuffer = pNewStream;
+ delete pTmp;
+ }
+ else
+ {
+ pMsgBuffer->Seek( 0L );
+ pMsgBuffer->SetStreamSize( 0 );
+ }
+ return INETSTREAM_STATUS_OK;
+ }
+ }
+ else
+ {
+ /*
+ * Single part message.
+ * Remove any ContentTransferEncoding.
+ */
+ if (pMsg->GetContentType().Len() == 0)
+ {
+ String aDefaultCT;
+ pMsg->GetDefaultContentType (aDefaultCT);
+ pMsg->SetContentType (aDefaultCT);
+ }
+
+ if (eEncoding == INETMSG_ENCODING_BINARY)
+ {
+ String aEncoding (pMsg->GetContentTransferEncoding());
+ if (aEncoding.CompareIgnoreCaseToAscii (
+ "base64", 6) == COMPARE_EQUAL)
+ eEncoding = INETMSG_ENCODING_BASE64;
+ else if (aEncoding.CompareIgnoreCaseToAscii (
+ "quoted-printable", 16) == COMPARE_EQUAL)
+ eEncoding = INETMSG_ENCODING_QUOTED;
+ else
+ eEncoding = INETMSG_ENCODING_7BIT;
+ }
+
+ if (eEncoding == INETMSG_ENCODING_7BIT)
+ {
+ // No decoding necessary.
+ return INetMessageIOStream::PutMsgLine (pData, nSize);
+ }
+ else
+ {
+ if (pDecodeStrm == NULL)
+ {
+ if (eEncoding == INETMSG_ENCODING_QUOTED)
+ pDecodeStrm = new INetMessageDecodeQPStream_Impl;
+ else
+ pDecodeStrm = new INetMessageDecode64Stream_Impl;
+
+ pDecodeStrm->SetTargetMessage (pMsg);
+ }
+ return pDecodeStrm->Write (pData, nSize);
+ }
+ }
+ }
+}
+
+
+
diff --git a/tools/source/inet/makefile.mk b/tools/source/inet/makefile.mk
new file mode 100644
index 000000000000..1e0bdfdd2391
--- /dev/null
+++ b/tools/source/inet/makefile.mk
@@ -0,0 +1,45 @@
+#*************************************************************************
+#
+# 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 = tools
+TARGET = inet
+
+.INCLUDE: settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+SLOFILES=\
+ $(SLO)$/inetmime.obj \
+ $(SLO)$/inetmsg.obj \
+ $(SLO)$/inetstrm.obj
+
+OBJFILES=\
+ $(OBJ)$/inetmime.obj \
+ $(OBJ)$/inetmsg.obj \
+ $(OBJ)$/inetstrm.obj
+
+.INCLUDE: target.mk
diff --git a/tools/source/makefile.mk b/tools/source/makefile.mk
new file mode 100644
index 000000000000..8c3f3167635e
--- /dev/null
+++ b/tools/source/makefile.mk
@@ -0,0 +1,58 @@
+#*************************************************************************
+#
+# 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=..
+
+TARGET=source
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUI)" == "UNX"
+SUBDIRS+= solar
+.ENDIF
+
+SUBDIRS+= \
+ datetime \
+ timestamp \
+ debug \
+ fsys \
+ generic \
+ intntl \
+ memtools \
+ misc \
+ rc \
+ ref \
+ stream \
+ zcodec
+
+
+.INCLUDE : target.mk
+
diff --git a/tools/source/memtools/contnr.cxx b/tools/source/memtools/contnr.cxx
new file mode 100644
index 000000000000..4a4ee47886ee
--- /dev/null
+++ b/tools/source/memtools/contnr.cxx
@@ -0,0 +1,1708 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#ifndef _LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef _STRING_H
+#include <string.h>
+#endif
+
+#ifndef _STDIO_H
+#include <stdio.h>
+#endif
+#include <tools/solar.h>
+#include <impcont.hxx>
+#include <tools/contnr.hxx>
+#include <tools/debug.hxx>
+
+// -----------------------------------------------------------------------
+
+DBG_NAME( CBlock )
+DBG_NAME( Container )
+
+/*************************************************************************
+|*
+|* DbgCheckCBlock()
+|*
+|* Beschreibung Pruefung eines CBlock fuer Debug-Utilities
+|* Ersterstellung MI 30.01.92
+|* Letzte Aenderung TH 24.01.96
+|*
+*************************************************************************/
+
+#ifdef DBG_UTIL
+const char* CBlock::DbgCheckCBlock( const void* pBlock )
+{
+ CBlock* p = (CBlock*)pBlock;
+
+ if ( p->nCount > p->nSize )
+ return "nCount > nSize";
+
+ if ( p->nSize && !p->pNodes )
+ return "nSize > 0 && pNodes == NULL";
+
+ return NULL;
+}
+#endif
+
+/*************************************************************************
+|*
+|* CBlock::CBlock()
+|*
+|* Beschreibung Construktor des Verwaltungsblocks
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+CBlock::CBlock( USHORT nInitSize, CBlock* _pPrev, CBlock* _pNext )
+{
+ DBG_CTOR( CBlock, DbgCheckCBlock );
+
+ pPrev = _pPrev;
+ pNext = _pNext;
+ nSize = nInitSize;
+ nCount = 0;
+
+ // Datenpuffer anlegen
+ pNodes = new PVOID[nSize];
+}
+
+/*************************************************************************
+|*
+|* CBlock::CBlock()
+|*
+|* Beschreibung Construktor des Verwaltungsblocks
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+CBlock::CBlock( USHORT _nSize, CBlock* _pPrev )
+{
+ DBG_CTOR( CBlock, DbgCheckCBlock );
+ DBG_ASSERT( _nSize, "CBlock::CBlock(): nSize == 0" );
+
+ pPrev = _pPrev;
+ pNext = NULL;
+ nSize = _nSize;
+ nCount = _nSize;
+
+ // Datenpuffer anlegen und initialisieren
+ pNodes = new PVOID[nSize];
+ memset( pNodes, 0, nSize*sizeof(PVOID) );
+}
+
+/*************************************************************************
+|*
+|* CBlock::CBlock()
+|*
+|* Beschreibung Copy-Construktor des Verwaltungsblocks
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+CBlock::CBlock( const CBlock& r, CBlock* _pPrev )
+{
+ DBG_CTOR( CBlock, DbgCheckCBlock );
+ DBG_CHKOBJ( &r, CBlock, DbgCheckCBlock );
+
+ pPrev = _pPrev;
+ pNext = NULL;
+ nSize = r.nSize;
+ nCount = r.nCount;
+
+ // Datenpuffer anlegen und Daten kopieren
+ pNodes = new PVOID[nSize];
+ memcpy( pNodes, r.pNodes, nCount*sizeof(PVOID) );
+}
+
+/*************************************************************************
+|*
+|* CBlock::~CBlock()
+|*
+|* Beschreibung Destruktor des Verwaltungsblocks
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+inline CBlock::~CBlock()
+{
+ DBG_DTOR( CBlock, DbgCheckCBlock );
+
+ // Daten loeschen
+ delete[] pNodes;
+}
+
+/*************************************************************************
+|*
+|* CBlock::Insert()
+|*
+|* Beschreibung Fuegt einen Pointer ein
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void CBlock::Insert( void* p, USHORT nIndex, USHORT nReSize )
+{
+ DBG_CHKTHIS( CBlock, DbgCheckCBlock );
+ DBG_ASSERT( nIndex <= nCount, "CBlock::Insert(): Index > nCount" );
+
+ // Muss Block realokiert werden
+ if ( nCount == nSize )
+ {
+ // Neue Daten anlegen
+ nSize = nSize + nReSize; // MSVC warns here if += is used
+ void** pNewNodes = new PVOID[nSize];
+
+ // Wird angehaengt
+ if ( nCount == nIndex )
+ {
+ // Daten kopieren
+ memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
+ }
+ else
+ {
+ // Daten kopieren
+ memcpy( pNewNodes, pNodes, nIndex*sizeof(PVOID) );
+ memcpy( pNewNodes + nIndex + 1,
+ pNodes + nIndex,
+ (nCount-nIndex)*sizeof(PVOID) );
+ }
+
+ // Alte Daten loeschen und neue setzen
+ delete[] pNodes;
+ pNodes = pNewNodes;
+ }
+ else
+ {
+ if ( nIndex < nCount )
+ {
+ memmove( pNodes + nIndex + 1,
+ pNodes + nIndex,
+ (nCount-nIndex)*sizeof(PVOID) );
+ }
+ }
+
+ // Neuen Pointer setzen und Elementgroesse erhoehen
+ pNodes[nIndex] = p;
+ nCount++;
+}
+
+/*************************************************************************
+|*
+|* CBlock::Split()
+|*
+|* Beschreibung Fuegt einen Pointer ein und splittet den Block
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+CBlock* CBlock::Split( void* p, USHORT nIndex, USHORT nReSize )
+{
+ DBG_CHKTHIS( CBlock, DbgCheckCBlock );
+
+ USHORT nNewSize;
+ USHORT nMiddle;
+ CBlock* pNewBlock;
+
+ nMiddle = nCount/2;
+
+ if ( ( nIndex == nCount ) || ( nIndex == 0 ) )
+ nNewSize = nReSize;
+ else
+ {
+ // Der aktuelle Block wird in der Mitte geteilt
+ nNewSize = (nCount+1) / 2;
+
+ if ( nNewSize < nReSize )
+ nNewSize = nReSize;
+ else
+ {
+ // Neue Groesse muss ein vielfaches von Resize sein
+ if ( nNewSize % nReSize )
+ nNewSize += nReSize - (nNewSize % nReSize);
+ else
+ nNewSize = nNewSize + nReSize; // MSVC warns here if += is used
+ }
+ }
+
+ // Vor oder hinter dem aktuellem Block einfuegen?
+ if ( nIndex > nMiddle )
+ {
+ // Neuen Split-Block anlegen und hinter dem aktuellem Block einfuegen
+ pNewBlock = new CBlock( nNewSize, this, pNext );
+
+ if ( pNext )
+ pNext->pPrev = pNewBlock;
+ pNext = pNewBlock;
+
+ if ( nIndex == nCount )
+ {
+ // Neuen Pointer einfuegen
+ pNewBlock->pNodes[0] = p;
+ pNewBlock->nCount = 1;
+ }
+ else
+ {
+ nIndex = nIndex - nMiddle; // MSVC warns here if += is used
+ // Alles von Mitte bis Index kopieren
+ if ( nIndex )
+ memcpy( pNewBlock->pNodes, pNodes+nMiddle, nIndex*sizeof(PVOID) );
+
+ // Neuen Pointer einfuegen
+ pNewBlock->pNodes[nIndex] = p;
+
+ // Alles von Mitte bis Ende hinter Index kopieren
+ memcpy( pNewBlock->pNodes+nIndex+1,
+ pNodes+nMiddle+nIndex,
+ (nCount-nMiddle-nIndex) * sizeof(PVOID) );
+
+ pNewBlock->nCount = (nCount-nMiddle+1);
+ nCount = nMiddle;
+
+ // Den aktuellen Datenbereich auch halbieren
+ if ( nSize != nNewSize )
+ {
+ void** pNewNodes = new PVOID[nNewSize];
+ memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
+ delete[] pNodes;
+ pNodes = pNewNodes;
+ nSize = nNewSize;
+ }
+ }
+ }
+ else
+ {
+ // Neuen Split-Block anlegen und vor dem aktuellem Block einfuegen
+ pNewBlock = new CBlock( nNewSize, pPrev, this );
+
+ if ( pPrev )
+ pPrev->pNext = pNewBlock;
+ pPrev = pNewBlock;
+
+ if ( nIndex == 0 )
+ {
+ // Neuen Pointer einfuegen
+ pNewBlock->pNodes[0] = p;
+ pNewBlock->nCount = 1;
+ }
+ else
+ {
+ // Alles von Anfang bis Index kopieren
+ memcpy( pNewBlock->pNodes, pNodes, nIndex*sizeof(PVOID) );
+
+ // Neuen Pointer einfuegen
+ pNewBlock->pNodes[nIndex] = p;
+
+ // Alles von Index bis Mitte hinter Index kopieren
+ if ( nIndex != nMiddle )
+ {
+ memcpy( pNewBlock->pNodes+nIndex+1,
+ pNodes+nIndex,
+ (nMiddle-nIndex) * sizeof(PVOID) );
+ }
+
+ pNewBlock->nCount = nMiddle+1;
+ nCount = nCount - nMiddle; // MSVC warns here if += is used
+
+ // Die zweite Haelfte in einen neuen Block kopieren
+ if ( nSize != nNewSize )
+ {
+ void** pNewNodes = new PVOID[nNewSize];
+ memcpy( pNewNodes, pNodes+nMiddle, nCount*sizeof(PVOID) );
+ delete[] pNodes;
+ pNodes = pNewNodes;
+ nSize = nNewSize;
+ }
+ else
+ memmove( pNodes, pNodes+nMiddle, nCount*sizeof(PVOID) );
+ }
+ }
+
+ // Neu angelegten Block zurueckgeben, da gegebenfalls die Blockpointer
+ // im Container angepast werden koennen
+ return pNewBlock;
+}
+
+/*************************************************************************
+|*
+|* CBlock::Remove()
+|*
+|* Beschreibung Entfernt einen Pointer
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* CBlock::Remove( USHORT nIndex, USHORT nReSize )
+{
+ DBG_CHKTHIS( CBlock, DbgCheckCBlock );
+
+ // Alten Pointer sichern
+ void* pOld = pNodes[nIndex];
+
+ // 1 Element weniger
+ nCount--;
+
+ // Block verkleinern (wenn Reallokationsgroesse um 4 unterschritten wird)
+ if ( nCount == (nSize-nReSize-4) )
+ {
+ // Neue Daten anlegen
+ nSize = nSize - nReSize; // MSVC warns here if += is used
+ void** pNewNodes = new PVOID[nSize];
+
+ // Wird letzter Eintrag geloescht
+ if ( nIndex == nCount )
+ {
+ // Daten kopieren
+ memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
+ }
+ else
+ {
+ // Daten kopieren
+ memcpy( pNewNodes, pNodes, nIndex*sizeof(PVOID) );
+ memcpy( pNewNodes + nIndex, pNodes + nIndex+1,
+ (nCount-nIndex)*sizeof(PVOID) );
+ }
+
+ // Alte Daten loeschen und neue setzen
+ delete[] pNodes;
+ pNodes = pNewNodes;
+ }
+ else
+ {
+ // Wenn nicht das letzte Element, dann zusammenschieben
+ if ( nIndex < nCount )
+ {
+ memmove( pNodes + nIndex, pNodes + nIndex + 1,
+ (nCount-nIndex)*sizeof(PVOID) );
+ }
+ }
+
+ // Alten Pointer zurueckgeben
+ return pOld;
+}
+
+/*************************************************************************
+|*
+|* CBlock::Replace()
+|*
+|* Beschreibung Ersetzt einen Pointer
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+inline void* CBlock::Replace( void* p, USHORT nIndex )
+{
+ DBG_CHKTHIS( CBlock, DbgCheckCBlock );
+
+ // Alten Pointer sichern, neuen setzen und alten zurueckgeben
+ void* pOld = pNodes[nIndex];
+ pNodes[nIndex] = p;
+ return pOld;
+}
+
+/*************************************************************************
+|*
+|* CBlock::GetObjectPtr()
+|*
+|* Beschreibung Gibt einen Pointer auf den Pointer aus dem Block
+|* zurueck
+|* Ersterstellung TH 26.01.93
+|* Letzte Aenderung TH 26.01.93
+|*
+*************************************************************************/
+
+inline void** CBlock::GetObjectPtr( USHORT nIndex )
+{
+ DBG_CHKTHIS( CBlock, DbgCheckCBlock );
+
+ return &(pNodes[nIndex]);
+}
+
+/*************************************************************************
+|*
+|* CBlock::SetSize()
+|*
+|* Beschreibung Aendert die Groesse des Blocks
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void CBlock::SetSize( USHORT nNewSize )
+{
+ DBG_CHKTHIS( CBlock, DbgCheckCBlock );
+ DBG_ASSERT( nNewSize, "CBlock::SetSize(): nNewSize == 0" );
+
+ // Unterscheidet sich die Groesse
+ if ( nNewSize != nCount )
+ {
+ // Array erweitern
+ void** pNewNodes = new PVOID[nNewSize];
+
+ // Alte Tabelle in die Neue kopieren
+ if ( nNewSize < nCount )
+ memcpy( pNewNodes, pNodes, nNewSize*sizeof(PVOID) );
+ else
+ {
+ memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
+
+ // Array mit 0 initialisieren
+ memset( pNewNodes+nCount, 0, (nNewSize-nCount)*sizeof(PVOID) );
+ }
+
+ // Altes Array loeschen und neue Werte setzen
+ nSize = nNewSize;
+ nCount = nSize;
+ delete[] pNodes;
+ pNodes = pNewNodes;
+ }
+}
+
+//------------------------------------------------------------------------
+
+/*************************************************************************
+|*
+|* DbgCheckContainer()
+|*
+|* Beschreibung Pruefung eines Container fuer Debug-Utilities
+|* Ersterstellung MI 30.01.92
+|* Letzte Aenderung TH 24.01.96
+|*
+*************************************************************************/
+
+#ifdef DBG_UTIL
+const char* Container::DbgCheckContainer( const void* pCont )
+{
+ Container* p = (Container*)pCont;
+
+ if ( p->nCount && (!p->pFirstBlock || !p->pLastBlock || !p->pCurBlock) )
+ return "nCount > 0 but no CBlocks";
+
+ return NULL;
+}
+#endif
+
+/*************************************************************************
+|*
+|* ImpCopyContainer()
+|*
+|* Beschreibung Kopiert alle Daten des Containers
+|* Ersterstellung TH 24.01.96
+|* Letzte Aenderung TH 24.01.96
+|*
+*************************************************************************/
+
+void Container::ImpCopyContainer( const Container* pCont2 )
+{
+ // Werte vom uebergebenen Container uebernehmen
+ nCount = pCont2->nCount;
+ nCurIndex = pCont2->nCurIndex;
+ nInitSize = pCont2->nInitSize;
+ nReSize = pCont2->nReSize;
+ nBlockSize = pCont2->nBlockSize;
+
+ // Alle Bloecke kopieren
+ if ( pCont2->nCount )
+ {
+ CBlock* pBlock1;
+ CBlock* pBlock2;
+ CBlock* pTempBlock;
+
+ // Erstmal ersten Block kopieren
+ pBlock2 = pCont2->pFirstBlock;
+ pFirstBlock = new CBlock( *pBlock2, NULL );
+ // Ist erster Block der Current-Block, dann Current-Block setzen
+ if ( pBlock2 == pCont2->pCurBlock )
+ pCurBlock = pFirstBlock;
+ pBlock1 = pFirstBlock;
+ pBlock2 = pBlock2->GetNextBlock();
+ while ( pBlock2 )
+ {
+ // Neuen Block anlegen und aus der uebergebenen Liste kopieren
+ pTempBlock = new CBlock( *pBlock2, pBlock1 );
+ pBlock1->SetNextBlock( pTempBlock );
+ pBlock1 = pTempBlock;
+
+ // Current-Block beruecksichtigen
+ if ( pBlock2 == pCont2->pCurBlock )
+ pCurBlock = pBlock1;
+
+ // Auf naechsten Block weitersetzen
+ pBlock2 = pBlock2->GetNextBlock();
+ }
+
+ // Letzten Block setzen
+ pLastBlock = pBlock1;
+ }
+ else
+ {
+ pFirstBlock = NULL;
+ pLastBlock = NULL;
+ pCurBlock = NULL;
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::Container()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+Container::Container( USHORT _nBlockSize, USHORT _nInitSize, USHORT _nReSize )
+{
+ DBG_CTOR( Container, DbgCheckContainer );
+
+ // BlockSize muss mindestens 4 sein und kleiner als 64 KB
+ if ( _nBlockSize < 4 )
+ nBlockSize = 4;
+ else
+ {
+ if ( _nBlockSize < CONTAINER_MAXBLOCKSIZE )
+ nBlockSize = _nBlockSize;
+ else
+ nBlockSize = CONTAINER_MAXBLOCKSIZE;
+ }
+
+ // ReSize muss mindestens 2 sein und kleiner als BlockSize
+ if ( _nReSize >= nBlockSize )
+ nReSize = nBlockSize;
+ else
+ {
+ if ( _nReSize < 2 )
+ nReSize = 2;
+ else
+ nReSize = _nReSize;
+
+ // BlockSize muss ein vielfaches der Resizegroesse sein
+ if ( nBlockSize % nReSize )
+ nBlockSize -= nReSize - (nBlockSize % nReSize);
+ }
+
+ // InitSize muss groesser gleich ReSize sein und kleiner als BlockSize
+ if ( _nInitSize <= nReSize )
+ nInitSize = nReSize;
+ else
+ {
+ if ( _nInitSize >= nBlockSize )
+ nInitSize = nBlockSize;
+ else
+ {
+ nInitSize = _nInitSize;
+
+ // InitSize muss ein vielfaches der Resizegroesse sein
+ if ( nInitSize % nReSize )
+ nInitSize -= nReSize - (nInitSize % nReSize);
+ }
+ }
+
+ // Werte initialisieren
+ pFirstBlock = NULL;
+ pLastBlock = NULL;
+ pCurBlock = NULL;
+ nCount = 0;
+ nCurIndex = 0;
+}
+
+/*************************************************************************
+|*
+|* Container::Container()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+Container::Container( ULONG nSize )
+{
+ DBG_CTOR( Container, DbgCheckContainer );
+
+ nCount = nSize;
+ nCurIndex = 0;
+ nBlockSize = CONTAINER_MAXBLOCKSIZE;
+ nInitSize = 1;
+ nReSize = 1;
+
+ if ( !nSize )
+ {
+ pFirstBlock = NULL;
+ pLastBlock = NULL;
+ pCurBlock = NULL;
+ }
+ else
+ {
+ // Muss mehr als ein Block angelegt werden
+ if ( nSize <= nBlockSize )
+ {
+ pFirstBlock = new CBlock( (USHORT)nSize, NULL );
+ pLastBlock = pFirstBlock;
+ }
+ else
+ {
+ CBlock* pBlock1;
+ CBlock* pBlock2;
+
+ pFirstBlock = new CBlock( nBlockSize, NULL );
+ pBlock1 = pFirstBlock;
+ nSize -= nBlockSize;
+
+ // Solange die Blockgroesse ueberschritten wird, neue Bloecke anlegen
+ while ( nSize > nBlockSize )
+ {
+ pBlock2 = new CBlock( nBlockSize, pBlock1 );
+ pBlock1->SetNextBlock( pBlock2 );
+ pBlock1 = pBlock2;
+ nSize -= nBlockSize;
+ }
+
+ pLastBlock = new CBlock( (USHORT)nSize, pBlock1 );
+ pBlock1->SetNextBlock( pLastBlock );
+ }
+
+ pCurBlock = pFirstBlock;
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::Container()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+Container::Container( const Container& r )
+{
+ DBG_CTOR( Container, DbgCheckContainer );
+
+ // Daten kopieren
+ ImpCopyContainer( &r );
+}
+
+/*************************************************************************
+|*
+|* Container::~Container()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+Container::~Container()
+{
+ DBG_DTOR( Container, DbgCheckContainer );
+
+ // Alle Bloecke loeschen
+ CBlock* pBlock = pFirstBlock;
+ while ( pBlock )
+ {
+ CBlock* pTemp = pBlock->GetNextBlock();
+ delete pBlock;
+ pBlock = pTemp;
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::ImpInsert()
+|*
+|* Beschreibung Interne Methode zum Einfuegen eines Pointers
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung DV 01.07.97
+|*
+*************************************************************************/
+
+void Container::ImpInsert( void* p, CBlock* pBlock, USHORT nIndex )
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ if ( !nCount )
+ {
+ if ( !pBlock )
+ {
+ pFirstBlock = new CBlock( nInitSize, NULL, NULL );
+ pLastBlock = pFirstBlock;
+ pCurBlock = pFirstBlock;
+ }
+ pFirstBlock->Insert( p, nIndex, nReSize );
+ }
+ else
+ {
+ // Ist im Block die maximale Blockgroesse erreicht,
+ // dann neuen Block anlegen
+ if ( pBlock->Count() == nBlockSize )
+ {
+ // Block auftrennen
+ CBlock* pNewBlock = pBlock->Split( p, nIndex, nReSize );
+
+ // Wurde Block dahinter angehaegnt
+ if ( pBlock->pNext == pNewBlock )
+ {
+ // Gegebenenfalls LastBlock anpassen
+ if ( pBlock == pLastBlock )
+ pLastBlock = pNewBlock;
+
+ // Current-Position nachfuehren
+ if ( pBlock == pCurBlock )
+ {
+ if ( pBlock->nCount <= nCurIndex )
+ {
+ if ( nIndex <= nCurIndex )
+ nCurIndex++;
+ pCurBlock = pNewBlock;
+ nCurIndex = nCurIndex - pBlock->nCount; // MSVC warns here if += is used
+ }
+ }
+ }
+ else
+ {
+ // Gegebenenfalls FirstBlock anpassen
+ if ( pBlock == pFirstBlock )
+ pFirstBlock = pNewBlock;
+
+ // Current-Position nachfuehren
+ if ( pBlock == pCurBlock )
+ {
+ if ( nIndex <= nCurIndex )
+ nCurIndex++;
+ if ( pNewBlock->nCount <= nCurIndex )
+ nCurIndex = nCurIndex - pNewBlock->nCount; // MSVC warns here if += is used
+ else
+ pCurBlock = pNewBlock;
+ }
+ }
+ }
+ else
+ {
+ // Sonst reicht normales einfuegen in den Block
+ pBlock->Insert( p, nIndex, nReSize );
+
+ // Current-Position nachfuehren
+ if ( (pBlock == pCurBlock) && (nIndex <= nCurIndex) )
+ nCurIndex++;
+ }
+ }
+
+ // Ein neues Item im Container
+ nCount++;
+}
+
+/*************************************************************************
+|*
+|* Container::Insert()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void Container::Insert( void* p )
+{
+ ImpInsert( p, pCurBlock, nCurIndex );
+}
+
+/*************************************************************************
+|*
+|* Container::Insert()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void Container::Insert( void* p, ULONG nIndex )
+{
+ if ( nCount <= nIndex )
+ {
+ if ( pLastBlock )
+ ImpInsert( p, pLastBlock, pLastBlock->Count() );
+ else
+ ImpInsert( p, NULL, 0 );
+ }
+ else
+ {
+ // Block suchen
+ CBlock* pTemp = pFirstBlock;
+ while ( pTemp->Count() < nIndex )
+ {
+ nIndex -= pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ ImpInsert( p, pTemp, (USHORT)nIndex );
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::Insert()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void Container::Insert( void* pNew, void* pOld )
+{
+ ULONG nIndex = GetPos( pOld );
+ if ( nIndex != CONTAINER_ENTRY_NOTFOUND )
+ Insert( pNew, nIndex );
+}
+
+/*************************************************************************
+|*
+|* Container::ImpRemove()
+|*
+|* Beschreibung Interne Methode zum Entfernen eines Pointers
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::ImpRemove( CBlock* pBlock, USHORT nIndex )
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ void* pOld;
+
+ // Ist Liste danach leer
+ if ( nCount == 1 )
+ {
+ // Block und CurIndex zuruecksetzen
+ pOld = pBlock->GetObject( nIndex );
+ pBlock->Reset();
+ nCurIndex = 0;
+ }
+ else
+ {
+ // Ist Block nach Remove leer
+ if ( pBlock->Count() == 1 )
+ {
+ // dann Block entfernen und Block-Pointer umsetzen
+ if ( pBlock->GetPrevBlock() )
+ (pBlock->GetPrevBlock())->SetNextBlock( pBlock->GetNextBlock() );
+ else
+ pFirstBlock = pBlock->GetNextBlock();
+
+ if ( pBlock->GetNextBlock() )
+ (pBlock->GetNextBlock())->SetPrevBlock( pBlock->GetPrevBlock() );
+ else
+ pLastBlock = pBlock->GetPrevBlock();
+
+ // Current-Position nachfuehren
+ if ( pBlock == pCurBlock )
+ {
+ if ( pBlock->GetNextBlock() )
+ {
+ pCurBlock = pBlock->GetNextBlock();
+ nCurIndex = 0;
+ }
+ else
+ {
+ pCurBlock = pBlock->GetPrevBlock();
+ nCurIndex = pCurBlock->Count()-1;
+ }
+ }
+
+ pOld = pBlock->GetObject( nIndex );
+ delete pBlock;
+ }
+ else
+ {
+ // Sonst Item aus dem Block entfernen
+ pOld = pBlock->Remove( nIndex, nReSize );
+
+ // Current-Position nachfuehren
+ if ( (pBlock == pCurBlock) &&
+ ((nIndex < nCurIndex) || ((nCurIndex == pBlock->Count()) && nCurIndex)) )
+ nCurIndex--;
+ }
+ }
+
+ // Jetzt gibt es ein Item weniger
+ nCount--;
+
+ // Und den Pointer zurueckgeben, der entfernt wurde
+ return pOld;
+}
+
+/*************************************************************************
+|*
+|* Container::Remove()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::Remove()
+{
+ // Wenn kein Item vorhanden ist, NULL zurueckgeben
+ if ( !nCount )
+ return NULL;
+ else
+ return ImpRemove( pCurBlock, nCurIndex );
+}
+
+/*************************************************************************
+|*
+|* Container::Remove()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::Remove( ULONG nIndex )
+{
+ // Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
+ if ( nCount <= nIndex )
+ return NULL;
+ else
+ {
+ // Block suchen
+ CBlock* pTemp = pFirstBlock;
+ while ( pTemp->Count() <= nIndex )
+ {
+ nIndex -= pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ return ImpRemove( pTemp, (USHORT)nIndex );
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::Replace()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::Replace( void* p )
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ if ( !nCount )
+ return NULL;
+ else
+ return pCurBlock->Replace( p, nCurIndex );
+}
+
+/*************************************************************************
+|*
+|* Container::Replace()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::Replace( void* p, ULONG nIndex )
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
+ if ( nCount <= nIndex )
+ return NULL;
+ else
+ {
+ // Block suchen
+ CBlock* pTemp = pFirstBlock;
+ while ( pTemp->Count() <= nIndex )
+ {
+ nIndex -= pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ return pTemp->Replace( p, (USHORT)nIndex );
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::SetSize()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void Container::SetSize( ULONG nNewSize )
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ if ( nNewSize )
+ {
+ // Unterscheiden sich die Groessen
+ if ( nNewSize != nCount )
+ {
+ CBlock* pTemp;
+ ULONG nTemp;
+
+ // Wird verkleinert
+ if ( nNewSize < nCount )
+ {
+ pTemp = pFirstBlock;
+ nTemp = 0;
+ while ( (nTemp+pTemp->Count()) < nNewSize )
+ {
+ nTemp += pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ // Alle folgenden Bloecke loeschen
+ BOOL bLast = FALSE;
+ CBlock* pDelNext;
+ CBlock* pDelBlock = pTemp->GetNextBlock();
+ while ( pDelBlock )
+ {
+ // Muss CurrentBlock umgesetzt werden
+ if ( pDelBlock == pCurBlock )
+ bLast = TRUE;
+ pDelNext = pDelBlock->GetNextBlock();
+ delete pDelBlock;
+ pDelBlock = pDelNext;
+ }
+
+ // Block in der Groesse anpassen, oder bei Groesse 0 loeschen
+ if ( nNewSize > nTemp )
+ {
+ pLastBlock = pTemp;
+ pTemp->SetNextBlock( NULL );
+ pTemp->SetSize( (USHORT)(nNewSize-nTemp) );
+ }
+ else
+ {
+ pLastBlock = pTemp->GetPrevBlock();
+ pLastBlock->SetNextBlock( NULL );
+ delete pTemp;
+ }
+
+ nCount = nNewSize;
+ if ( bLast )
+ {
+ pCurBlock = pLastBlock;
+ nCurIndex = pCurBlock->Count()-1;
+ }
+ }
+ else
+ {
+ // Auf den letzen Puffer setzen
+ pTemp = pLastBlock;
+ nTemp = nNewSize - nCount;
+
+ if ( !pTemp )
+ {
+ // Muss mehr als ein Block angelegt werden
+ if ( nNewSize <= nBlockSize )
+ {
+ pFirstBlock = new CBlock( (USHORT)nNewSize, NULL );
+ pLastBlock = pFirstBlock;
+ }
+ else
+ {
+ CBlock* pBlock1;
+ CBlock* pBlock2;
+
+ pFirstBlock = new CBlock( nBlockSize, NULL );
+ pBlock1 = pFirstBlock;
+ nNewSize -= nBlockSize;
+
+ // Solange die Blockgroesse ueberschritten wird, neue Bloecke anlegen
+ while ( nNewSize > nBlockSize )
+ {
+ pBlock2 = new CBlock( nBlockSize, pBlock1 );
+ pBlock1->SetNextBlock( pBlock2 );
+ pBlock1 = pBlock2;
+ nNewSize -= nBlockSize;
+ }
+
+ pLastBlock = new CBlock( (USHORT)nNewSize, pBlock1 );
+ pBlock1->SetNextBlock( pLastBlock );
+ }
+
+ pCurBlock = pFirstBlock;
+ }
+ // Reicht es, den letzen Puffer in der Groesse anzupassen
+ else if ( (nTemp+pTemp->Count()) <= nBlockSize )
+ pTemp->SetSize( (USHORT)(nTemp+pTemp->Count()) );
+ else
+ {
+ // Puffer auf max. Blockgroesse setzen
+ nTemp -= nBlockSize - pTemp->GetSize();
+ pTemp->SetSize( nBlockSize );
+
+ CBlock* pTemp2;
+ // Solange die Blockgroesse ueberschritten wird,
+ // neue Bloecke anlegen
+ while ( nTemp > nBlockSize )
+ {
+ pTemp2 = new CBlock( nBlockSize, pTemp );
+ pTemp->SetNextBlock( pTemp2 );
+ pTemp = pTemp2;
+ nTemp -= nBlockSize;
+ }
+
+ // Den letzten Block anlegen
+ if ( nTemp )
+ {
+ pLastBlock = new CBlock( (USHORT)nTemp, pTemp );
+ pTemp->SetNextBlock( pLastBlock );
+ }
+ else
+ pLastBlock = pTemp;
+ }
+
+ nCount = nNewSize;
+ }
+ }
+ }
+ else
+ Clear();
+}
+
+/*************************************************************************
+|*
+|* Container::Clear()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void Container::Clear()
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Erst alle Bloecke loeschen
+ CBlock* pBlock = pFirstBlock;
+ while ( pBlock )
+ {
+ CBlock* pTemp = pBlock->GetNextBlock();
+ delete pBlock;
+ pBlock = pTemp;
+ }
+
+ // Werte zuruecksetzen
+ pFirstBlock = NULL;
+ pLastBlock = NULL;
+ pCurBlock = NULL;
+ nCount = 0;
+ nCurIndex = 0;
+}
+
+/*************************************************************************
+|*
+|* Container::GetCurObject()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::GetCurObject() const
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // NULL, wenn Container leer
+ if ( !nCount )
+ return NULL;
+ else
+ return pCurBlock->GetObject( nCurIndex );
+}
+
+/*************************************************************************
+|*
+|* Container::GetCurPos()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+ULONG Container::GetCurPos() const
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // CONTAINER_ENTRY_NOTFOUND, wenn Container leer
+ if ( !nCount )
+ return CONTAINER_ENTRY_NOTFOUND;
+ else
+ {
+ // Block suchen
+ CBlock* pTemp = pFirstBlock;
+ ULONG nTemp = 0;
+ while ( pTemp != pCurBlock )
+ {
+ nTemp += pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ return nTemp+nCurIndex;
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::GetObjectPtr()
+|*
+|* Beschreibung Interne Methode fuer Referenz-Container
+|* Ersterstellung TH 26.01.93
+|* Letzte Aenderung TH 26.01.93
+|*
+*************************************************************************/
+
+void** Container::GetObjectPtr( ULONG nIndex )
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
+ if ( nCount <= nIndex )
+ return NULL;
+ else
+ {
+ // Block suchen
+ CBlock* pTemp = pFirstBlock;
+ while ( pTemp->Count() <= nIndex )
+ {
+ nIndex -= pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ // Item innerhalb des gefundenen Blocks zurueckgeben
+ return pTemp->GetObjectPtr( (USHORT)nIndex );
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::GetObject()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::GetObject( ULONG nIndex ) const
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
+ if ( nCount <= nIndex )
+ return NULL;
+ else
+ {
+ // Block suchen
+ CBlock* pTemp = pFirstBlock;
+ while ( pTemp->Count() <= nIndex )
+ {
+ nIndex -= pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ // Item innerhalb des gefundenen Blocks zurueckgeben
+ return pTemp->GetObject( (USHORT)nIndex );
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::GetPos()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+ULONG Container::GetPos( const void* p ) const
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ void** pNodes;
+ CBlock* pTemp;
+ ULONG nTemp;
+ USHORT nBlockCount;
+ USHORT i;
+
+ // Block suchen
+ pTemp = pFirstBlock;
+ nTemp = 0;
+ while ( pTemp )
+ {
+ pNodes = pTemp->GetNodes();
+ i = 0;
+ nBlockCount = pTemp->Count();
+ while ( i < nBlockCount )
+ {
+ if ( p == *pNodes )
+ return nTemp+i;
+ pNodes++;
+ i++;
+ }
+ nTemp += nBlockCount;
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ return CONTAINER_ENTRY_NOTFOUND;
+}
+
+/*************************************************************************
+|*
+|* Container::GetPos()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 14.09.94
+|* Letzte Aenderung TH 14.09.94
+|*
+*************************************************************************/
+
+ULONG Container::GetPos( const void* p, ULONG nStartIndex,
+ BOOL bForward ) const
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist Index nicht innerhalb des Containers, dann NOTFOUND zurueckgeben
+ if ( nCount <= nStartIndex )
+ return CONTAINER_ENTRY_NOTFOUND;
+ else
+ {
+ void** pNodes;
+ USHORT nBlockCount;
+ USHORT i;
+
+ // Block suchen
+ CBlock* pTemp = pFirstBlock;
+ ULONG nTemp = 0;
+ while ( nTemp+pTemp->Count() <= nStartIndex )
+ {
+ nTemp += pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ // Jetzt den Pointer suchen
+ if ( bForward )
+ {
+ // Alle Bloecke durchrsuchen
+ i = (USHORT)(nStartIndex - nTemp);
+ pNodes = pTemp->GetObjectPtr( i );
+ do
+ {
+ nBlockCount = pTemp->Count();
+ while ( i < nBlockCount )
+ {
+ if ( p == *pNodes )
+ return nTemp+i;
+ pNodes++;
+ i++;
+ }
+ nTemp += nBlockCount;
+ pTemp = pTemp->GetNextBlock();
+ if ( pTemp )
+ {
+ i = 0;
+ pNodes = pTemp->GetNodes();
+ }
+ else
+ break;
+ }
+ while ( TRUE );
+ }
+ else
+ {
+ // Alle Bloecke durchrsuchen
+ i = (USHORT)(nStartIndex-nTemp)+1;
+ pNodes = pTemp->GetObjectPtr( i-1 );
+ do
+ {
+ do
+ {
+ if ( p == *pNodes )
+ return nTemp+i-1;
+ pNodes--;
+ i--;
+ }
+ while ( i );
+ nTemp -= pTemp->Count();
+ pTemp = pTemp->GetPrevBlock();
+ if ( pTemp )
+ {
+ i = pTemp->Count();
+ // Leere Bloecke in der Kette darf es nicht geben. Nur
+ // wenn ein Block existiert, darf dieser leer sein
+ pNodes = pTemp->GetObjectPtr( i-1 );
+ }
+ else
+ break;
+ }
+ while ( TRUE );
+ }
+ }
+
+ return CONTAINER_ENTRY_NOTFOUND;
+}
+
+/*************************************************************************
+|*
+|* Container::Seek()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::Seek( ULONG nIndex )
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist der Container leer, dann NULL zurueckgeben
+ if ( nCount <= nIndex )
+ return NULL;
+ else
+ {
+ // Block suchen
+ CBlock* pTemp = pFirstBlock;
+ while ( pTemp->Count() <= nIndex )
+ {
+ nIndex -= pTemp->Count();
+ pTemp = pTemp->GetNextBlock();
+ }
+
+ // Item innerhalb des gefundenen Blocks zurueckgeben
+ pCurBlock = pTemp;
+ nCurIndex = (USHORT)nIndex;
+ return pCurBlock->GetObject( nCurIndex );
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::First()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::First()
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist Container leer, dann NULL zurueckgeben
+ if ( !nCount )
+ return NULL;
+ else
+ {
+ // Block und Index setzen und ersten Pointer zurueckgeben
+ pCurBlock = pFirstBlock;
+ nCurIndex = 0;
+ return pCurBlock->GetObject( nCurIndex );
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::Last()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::Last()
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist Container leer, dann NULL zurueckgeben
+ if ( !nCount )
+ return NULL;
+ else
+ {
+ // Block und Index setzen und ersten Pointer zurueckgeben
+ pCurBlock = pLastBlock;
+ nCurIndex = pCurBlock->Count()-1;
+ return pCurBlock->GetObject( nCurIndex );
+ }
+}
+
+/*************************************************************************
+|*
+|* Container::Next()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::Next()
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist Container leer, dann NULL zurueckgeben, ansonsten preufen ob
+ // naechste Position noch im aktuellen Block ist. Falls nicht, dann
+ // einen Block weiterschalten (geht ohne Gefahr, da leere Bloecke
+ // nicht vorkommen duerfen, es sein denn, es ist der einzige).
+ if ( !nCount )
+ return NULL;
+ else if ( (nCurIndex+1) < pCurBlock->Count() )
+ return pCurBlock->GetObject( ++nCurIndex );
+ else if ( pCurBlock->GetNextBlock() )
+ {
+ pCurBlock = pCurBlock->GetNextBlock();
+ nCurIndex = 0;
+ return pCurBlock->GetObject( nCurIndex );
+ }
+ else
+ return NULL;
+}
+
+/*************************************************************************
+|*
+|* Container::Prev()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+void* Container::Prev()
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Ist Container leer, dann NULL zurueckgeben, ansonsten preufen ob
+ // vorherige Position noch im aktuellen Block ist. Falls nicht, dann
+ // einen Block zurueckschalten (geht ohne Gefahr, da leere Bloecke
+ // nicht vorkommen duerfen, es sein denn, es ist der einzige).
+ if ( !nCount )
+ return NULL;
+ else if ( nCurIndex )
+ return pCurBlock->GetObject( --nCurIndex );
+ else if ( pCurBlock->GetPrevBlock() )
+ {
+ pCurBlock = pCurBlock->GetPrevBlock();
+ nCurIndex = pCurBlock->Count() - 1;
+ return pCurBlock->GetObject( nCurIndex );
+ }
+ else
+ return NULL;
+}
+
+/*************************************************************************
+|*
+|* Container::operator =()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+Container& Container::operator =( const Container& r )
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ // Erst alle Bloecke loeschen
+ CBlock* pBlock = pFirstBlock;
+ while ( pBlock )
+ {
+ CBlock* pTemp = pBlock->GetNextBlock();
+ delete pBlock;
+ pBlock = pTemp;
+ }
+
+ // Daten kopieren
+ ImpCopyContainer( &r );
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Container::operator ==()
+|*
+|* Beschreibung CONTNR.SDW
+|* Ersterstellung TH 17.09.91
+|* Letzte Aenderung TH 17.09.91
+|*
+*************************************************************************/
+
+BOOL Container::operator ==( const Container& r ) const
+{
+ DBG_CHKTHIS( Container, DbgCheckContainer );
+
+ if ( nCount != r.nCount )
+ return FALSE;
+
+ ULONG i = 0;
+ while ( i < nCount )
+ {
+ if ( GetObject( i ) != r.GetObject( i ) )
+ return FALSE;
+ i++;
+ }
+
+ return TRUE;
+}
diff --git a/tools/source/memtools/makefile.mk b/tools/source/memtools/makefile.mk
new file mode 100644
index 000000000000..de03a0d50cc3
--- /dev/null
+++ b/tools/source/memtools/makefile.mk
@@ -0,0 +1,56 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=mtools
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/contnr.obj \
+ $(SLO)$/table.obj \
+ $(SLO)$/unqidx.obj \
+ $(SLO)$/mempool.obj \
+ $(SLO)$/multisel.obj
+
+EXCEPTIONSFILES= $(SLO)$/multisel.obj $(OBJ)$/multisel.obj
+
+OBJFILES= $(OBJ)$/contnr.obj \
+ $(OBJ)$/table.obj \
+ $(OBJ)$/unqidx.obj \
+ $(OBJ)$/mempool.obj \
+ $(OBJ)$/multisel.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/memtools/mempool.cxx b/tools/source/memtools/mempool.cxx
new file mode 100644
index 000000000000..45d6d2ea9367
--- /dev/null
+++ b/tools/source/memtools/mempool.cxx
@@ -0,0 +1,83 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/mempool.hxx>
+#include "rtl/alloc.h"
+
+#ifndef INCLUDED_STDIO_H
+#include <stdio.h>
+#endif
+
+/*************************************************************************
+|*
+|* FixedMemPool::FixedMemPool()
+|*
+*************************************************************************/
+
+FixedMemPool::FixedMemPool (
+ USHORT _nTypeSize, USHORT, USHORT)
+{
+ char name[RTL_CACHE_NAME_LENGTH + 1];
+ snprintf (name, sizeof(name), "FixedMemPool_%d", (int)_nTypeSize);
+ m_pImpl = (FixedMemPool_Impl*)rtl_cache_create (name, _nTypeSize, 0, NULL, NULL, NULL, 0, NULL, 0);
+}
+
+/*************************************************************************
+|*
+|* FixedMemPool::~FixedMemPool()
+|*
+*************************************************************************/
+
+FixedMemPool::~FixedMemPool()
+{
+ rtl_cache_destroy ((rtl_cache_type*)(m_pImpl));
+}
+
+/*************************************************************************
+|*
+|* FixedMemPool::Alloc()
+|*
+*************************************************************************/
+
+void* FixedMemPool::Alloc()
+{
+ return rtl_cache_alloc ((rtl_cache_type*)(m_pImpl));
+}
+
+/*************************************************************************
+|*
+|* FixedMemPool::Free()
+|*
+*************************************************************************/
+
+void FixedMemPool::Free( void* pFree )
+{
+ rtl_cache_free ((rtl_cache_type*)(m_pImpl), pFree);
+}
diff --git a/tools/source/memtools/multisel.cxx b/tools/source/memtools/multisel.cxx
new file mode 100644
index 000000000000..1e4da74348f4
--- /dev/null
+++ b/tools/source/memtools/multisel.cxx
@@ -0,0 +1,1162 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _SV_MULTISEL_CXX
+
+#ifdef MI_DEBUG
+#define private public
+#include <stdio.h>
+#endif
+
+#include <tools/debug.hxx>
+#include <tools/multisel.hxx>
+
+#include "rtl/ustrbuf.hxx"
+
+#ifdef MI_DEBUG
+#define DBG(x) x
+#else
+#define DBG(x)
+#endif
+
+using namespace rtl;
+
+//==================================================================
+
+#ifdef MI_DEBUG
+
+static void Print( const MultiSelection* pSel )
+{
+ DbgOutf( "TotRange: %4ld-%4ld\n",
+ pSel->aTotRange.Min(), pSel->aTotRange.Max() );
+ if ( pSel->bCurValid )
+ {
+ DbgOutf( "CurSubSel: %4ld\n", pSel->nCurSubSel );
+ DbgOutf( "CurIndex: %4ld\n", pSel->nCurIndex );
+ }
+ DbgOutf( "SelCount: %4ld\n", pSel->nSelCount );
+ DbgOutf( "SubCount: %4ld\n", pSel->aSels.Count() );
+ for ( ULONG nPos = 0; nPos < pSel->aSels.Count(); ++nPos )
+ {
+ DbgOutf( "SubSel #%2ld: %4ld-%4ld\n", nPos,
+ pSel->aSels.GetObject(nPos)->Min(),
+ pSel->aSels.GetObject(nPos)->Max() );
+ }
+ DbgOutf( "\n" );
+ fclose( pFile );
+}
+
+#endif
+
+// -----------------------------------------------------------------------
+
+void MultiSelection::ImplClear()
+{
+ // no selected indexes
+ nSelCount = 0;
+
+ Range* pRange = aSels.First();
+ while ( pRange )
+ {
+ delete pRange;
+ pRange = aSels.Next();
+ }
+ aSels.Clear();
+}
+
+// -----------------------------------------------------------------------
+
+ULONG MultiSelection::ImplFindSubSelection( long nIndex ) const
+{
+ // iterate through the sub selections
+ ULONG n = 0;
+ for ( ;
+ n < aSels.Count() && nIndex > aSels.GetObject(n)->Max();
+ ++n ) {} /* empty loop */
+ return n;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MultiSelection::ImplMergeSubSelections( ULONG nPos1, ULONG nPos2 )
+{
+ // didn't a sub selection at nPos2 exist?
+ if ( nPos2 >= aSels.Count() )
+ return FALSE;
+
+ // did the sub selections touch each other?
+ if ( (aSels.GetObject(nPos1)->Max() + 1) == aSels.GetObject(nPos2)->Min() )
+ {
+ // merge them
+ aSels.GetObject(nPos1)->Max() = aSels.GetObject(nPos2)->Max();
+ delete aSels.Remove(nPos2);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+MultiSelection::MultiSelection():
+ aTotRange( 0, -1 ),
+ nCurSubSel(0),
+ nSelCount(0),
+ bCurValid(FALSE),
+ bSelectNew(FALSE)
+{
+}
+
+// -----------------------------------------------------------------------
+
+MultiSelection::MultiSelection( const UniString& rString, sal_Unicode cRange, sal_Unicode cSep ):
+ aTotRange(0,RANGE_MAX),
+ nCurSubSel(0),
+ nSelCount(0),
+ bCurValid(FALSE),
+ bSelectNew(FALSE)
+{
+ // Dies ist nur ein Schnellschuss und sollte bald optimiert,
+ // an die verschiedenen Systeme (UNIX etc.)
+ // und die gewuenschte Eingabe-Syntax angepasst werden.
+
+ UniString aStr( rString );
+ sal_Unicode* pStr = aStr.GetBufferAccess();
+ sal_Unicode* pOld = pStr;
+ BOOL bReady = FALSE;
+ BOOL bUntil = FALSE;
+ xub_StrLen nCut = 0;
+
+ // Hier normieren wir den String, sodass nur Ziffern,
+ // Semikola als Trenn- und Minus als VonBis-Zeichen
+ // uebrigbleiben, z.B. "99-117;55;34;-17;37-43"
+ while ( *pOld )
+ {
+ switch( *pOld )
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ DBG_ASSERT( *pOld != cRange, "digit for range char not allowed" );
+ DBG_ASSERT( *pOld != cSep, "digit for separator not allowed" );
+ if( bReady )
+ {
+ *pStr++ = ';';
+ nCut++;
+ bReady = FALSE;
+ }
+ *pStr++ = *pOld;
+ nCut++;
+ bUntil = FALSE;
+ break;
+
+ case '-':
+ case ':':
+ case '/':
+ if ( *pOld != cSep )
+ {
+ if ( !bUntil )
+ {
+ *pStr++ = '-';
+ nCut++;
+ bUntil = TRUE;
+ }
+ bReady = FALSE;
+ }
+ else
+ bReady = TRUE;
+ break;
+
+ case ' ':
+ DBG_ASSERT( *pOld != cRange, "SPACE for range char not allowed" );
+ DBG_ASSERT( *pOld != cSep, "SPACE for separator not allowed" );
+ bReady = !bUntil;
+ break;
+
+ default:
+ if ( *pOld == cRange )
+ {
+ if ( !bUntil )
+ {
+ *pStr++ = '-';
+ nCut++;
+ bUntil = TRUE;
+ }
+ bReady = FALSE;
+ }
+ else
+ bReady = TRUE;
+ break;
+ }
+
+ pOld++;
+ }
+ aStr.ReleaseBufferAccess( nCut );
+
+ // Jetzt wird der normierte String ausgewertet ..
+ UniString aNumStr;
+ Range aRg( 1, RANGE_MAX );
+ const sal_Unicode* pCStr = aStr.GetBuffer();
+ long nPage = 1;
+ long nNum = 1;
+ bUntil = FALSE;
+ while ( *pCStr )
+ {
+ switch ( *pCStr )
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ aNumStr += *pCStr;
+ break;
+ case ';':
+ nNum = aNumStr.ToInt32();
+ if ( bUntil )
+ {
+ if ( !aNumStr.Len() )
+ nNum = RANGE_MAX;
+ aRg.Min() = nPage;
+ aRg.Max() = nNum;
+ aRg.Justify();
+ Select( aRg );
+ }
+ else
+ Select( nNum );
+ nPage = 0;
+ aNumStr.Erase();
+ bUntil = FALSE;
+ break;
+
+ case '-':
+ nPage = aNumStr.ToInt32();
+ aNumStr.Erase();
+ bUntil = TRUE;
+ break;
+ }
+
+ pCStr++;
+ }
+
+ nNum = aNumStr.ToInt32();
+ if ( bUntil )
+ {
+ if ( !aNumStr.Len() )
+ nNum = RANGE_MAX;
+ aRg.Min() = nPage;
+ aRg.Max() = nNum;
+ aRg.Justify();
+ Select( aRg );
+ }
+ else
+ Select( nNum );
+}
+
+// -----------------------------------------------------------------------
+
+MultiSelection::MultiSelection( const MultiSelection& rOrig ) :
+ aTotRange(rOrig.aTotRange),
+ nSelCount(rOrig.nSelCount),
+ bCurValid(rOrig.bCurValid),
+ bSelectNew(FALSE)
+{
+ if ( bCurValid )
+ {
+ nCurSubSel = rOrig.nCurSubSel;
+ nCurIndex = rOrig.nCurIndex;
+ }
+
+ // copy the sub selections
+ for ( ULONG n = 0; n < rOrig.aSels.Count(); ++n )
+ aSels.Insert( new Range( *rOrig.aSels.GetObject(n) ), LIST_APPEND );
+}
+
+// -----------------------------------------------------------------------
+
+MultiSelection::MultiSelection( const Range& rRange ):
+ aTotRange(rRange),
+ nCurSubSel(0),
+ nSelCount(0),
+ bCurValid(FALSE),
+ bSelectNew(FALSE)
+{
+}
+
+// -----------------------------------------------------------------------
+
+MultiSelection::~MultiSelection()
+{
+ Range* pRange = aSels.First();
+ while ( pRange )
+ {
+ delete pRange;
+ pRange = aSels.Next();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+MultiSelection& MultiSelection::operator= ( const MultiSelection& rOrig )
+{
+ aTotRange = rOrig.aTotRange;
+ bCurValid = rOrig.bCurValid;
+ if ( bCurValid )
+ {
+ nCurSubSel = rOrig.nCurSubSel;
+ nCurIndex = rOrig.nCurIndex;
+ }
+
+ // clear the old and copy the sub selections
+ ImplClear();
+ for ( ULONG n = 0; n < rOrig.aSels.Count(); ++n )
+ aSels.Insert( new Range( *rOrig.aSels.GetObject(n) ), LIST_APPEND );
+ nSelCount = rOrig.nSelCount;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MultiSelection::operator== ( MultiSelection& rWith )
+{
+ if ( aTotRange != rWith.aTotRange || nSelCount != rWith.nSelCount ||
+ aSels.Count() != rWith.aSels.Count() )
+ return FALSE;
+
+ // compare the sub seletions
+ for ( ULONG n = 0; n < aSels.Count(); ++n )
+ if ( *aSels.GetObject(n) != *rWith.aSels.GetObject(n) )
+ return FALSE;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSelection::SelectAll( BOOL bSelect )
+{
+ DBG(DbgOutf( "::SelectAll(%s)\n", bSelect ? "TRUE" : "FALSE" ));
+
+ ImplClear();
+ if ( bSelect )
+ {
+ aSels.Insert( new Range(aTotRange), LIST_APPEND );
+ nSelCount = aTotRange.Len();
+ }
+
+ DBG(Print( this ));
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MultiSelection::Select( long nIndex, BOOL bSelect )
+{
+ DBG_ASSERT( aTotRange.IsInside(nIndex), "selected index out of range" );
+
+ // out of range?
+ if ( !aTotRange.IsInside(nIndex) )
+ return FALSE;
+
+ // find the virtual target position
+ ULONG nSubSelPos = ImplFindSubSelection( nIndex );
+
+ if ( bSelect )
+ {
+ // is it included in the found sub selection?
+ if ( nSubSelPos < aSels.Count() &&
+ aSels.GetObject(nSubSelPos)->IsInside( nIndex ) )
+ // already selected, nothing to do
+ return FALSE;
+
+ // it will become selected
+ ++nSelCount;
+
+ // is it at the end of the previous sub selection
+ if ( nSubSelPos > 0 &&
+ aSels.GetObject(nSubSelPos-1)->Max() == (nIndex-1) )
+ {
+ // expand the previous sub selection
+ aSels.GetObject(nSubSelPos-1)->Max() = nIndex;
+
+ // try to merge the previous sub selection
+ ImplMergeSubSelections( nSubSelPos-1, nSubSelPos );
+ }
+ // is is at the beginning of the found sub selection
+ else if ( nSubSelPos < aSels.Count() &&
+ aSels.GetObject(nSubSelPos)->Min() == (nIndex+1) )
+ // expand the found sub selection
+ aSels.GetObject(nSubSelPos)->Min() = nIndex;
+ else
+ {
+ // create a new sub selection
+ aSels.Insert( new Range( nIndex, nIndex ), nSubSelPos );
+ if ( bCurValid && nCurSubSel >= nSubSelPos )
+ ++nCurSubSel;
+ }
+ }
+ else
+ {
+ // is it excluded from the found sub selection?
+ if ( nSubSelPos >= aSels.Count() ||
+ !aSels.GetObject(nSubSelPos)->IsInside( nIndex ) )
+ {
+ // not selected, nothing to do
+ DBG(Print( this ));
+ return FALSE;
+ }
+
+ // it will become deselected
+ --nSelCount;
+
+ // is it the only index in the found sub selection?
+ if ( aSels.GetObject(nSubSelPos)->Len() == 1 )
+ {
+ // remove the complete sub selection
+ delete aSels.Remove( nSubSelPos );
+ DBG(Print( this ));
+ return TRUE;
+ }
+
+ // is it at the beginning of the found sub selection?
+ if ( aSels.GetObject(nSubSelPos)->Min() == nIndex )
+ ++aSels.GetObject(nSubSelPos)->Min();
+ // is it at the end of the found sub selection?
+ else if ( aSels.GetObject(nSubSelPos)->Max() == nIndex )
+ --aSels.GetObject(nSubSelPos)->Max();
+ // it is in the middle of the found sub selection?
+ else
+ {
+ // split the sub selection
+ aSels.Insert(
+ new Range( aSels.GetObject(nSubSelPos)->Min(), nIndex-1 ),
+ nSubSelPos );
+ aSels.GetObject(nSubSelPos+1)->Min() = nIndex + 1;
+ }
+ }
+
+ DBG(Print( this ));
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSelection::Select( const Range& rIndexRange, BOOL bSelect )
+{
+ Range* pRange;
+ long nOld;
+
+ ULONG nTmpMin = rIndexRange.Min();
+ ULONG nTmpMax = rIndexRange.Max();
+ ULONG nCurMin = FirstSelected();
+ ULONG nCurMax = LastSelected();
+ DBG_ASSERT(aTotRange.IsInside(nTmpMax), "selected index out of range" );
+ DBG_ASSERT(aTotRange.IsInside(nTmpMin), "selected index out of range" );
+
+ // gesamte Selektion ersetzen ?
+ if( nTmpMin <= nCurMin && nTmpMax >= nCurMax )
+ {
+ ImplClear();
+ if ( bSelect )
+ {
+ aSels.Insert( new Range(rIndexRange), LIST_APPEND );
+ nSelCount = rIndexRange.Len();
+ }
+ return;
+ }
+ // links erweitern ?
+ if( nTmpMax < nCurMin )
+ {
+ if( bSelect )
+ {
+ // ersten Range erweitern ?
+ if( nCurMin > (nTmpMax+1) )
+ {
+ pRange = new Range( rIndexRange );
+ aSels.Insert( pRange, (ULONG)0 );
+ nSelCount += pRange->Len();
+ }
+ else
+ {
+ pRange = aSels.First();
+ nOld = pRange->Min();
+ pRange->Min() = (long)nTmpMin;
+ nSelCount += ( nOld - nTmpMin );
+ }
+ bCurValid = FALSE;
+ }
+ return;
+ }
+ // rechts erweitern ?
+ else if( nTmpMin > nCurMax )
+ {
+ if( bSelect )
+ {
+ // letzten Range erweitern ?
+ if( nTmpMin > (nCurMax+1) )
+ {
+ pRange = new Range( rIndexRange );
+ aSels.Insert( pRange, LIST_APPEND );
+ nSelCount += pRange->Len();
+ }
+ else
+ {
+ pRange = aSels.Last();
+ nOld = pRange->Max();
+ pRange->Max() = (long)nTmpMax;
+ nSelCount += ( nTmpMax - nOld );
+ }
+ bCurValid = FALSE;
+ }
+ return;
+ }
+
+ //HACK(Hier muss noch optimiert werden)
+ while( nTmpMin <= nTmpMax )
+ {
+ Select( nTmpMin, bSelect );
+ nTmpMin++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MultiSelection::IsSelected( long nIndex ) const
+{
+ // find the virtual target position
+ ULONG nSubSelPos = ImplFindSubSelection( nIndex );
+
+ return nSubSelPos < aSels.Count() &&
+ aSels.GetObject(nSubSelPos)->IsInside(nIndex);
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSelection::Insert( long nIndex, long nCount )
+{
+ DBG(DbgOutf( "::Insert(%ld, %ld)\n", nIndex, nCount ));
+
+ // find the virtual target position
+ ULONG nSubSelPos = ImplFindSubSelection( nIndex );
+
+ // did we need to shift the sub selections?
+ if ( nSubSelPos < aSels.Count() )
+ {
+ // did we insert an unselected into an existing sub selection?
+ if ( !bSelectNew && aSels.GetObject(nSubSelPos)->Min() != nIndex &&
+ aSels.GetObject(nSubSelPos)->IsInside(nIndex) )
+ {
+ // split the sub selection
+ aSels.Insert(
+ new Range( aSels.GetObject(nSubSelPos)->Min(), nIndex-1 ),
+ nSubSelPos );
+ ++nSubSelPos;
+ aSels.GetObject(nSubSelPos)->Min() = nIndex;
+ }
+
+ // did we append an selected to an existing sub selection?
+ else if ( bSelectNew && nSubSelPos > 0 &&
+ aSels.GetObject(nSubSelPos)->Max() == nIndex-1 )
+ // expand the previous sub selection
+ aSels.GetObject(nSubSelPos-1)->Max() += nCount;
+
+ // did we insert an selected into an existing sub selection?
+ else if ( bSelectNew && aSels.GetObject(nSubSelPos)->Min() == nIndex )
+ {
+ // expand the sub selection
+ aSels.GetObject(nSubSelPos)->Max() += nCount;
+ ++nSubSelPos;
+ }
+
+ // shift the sub selections behind the inserting position
+ for ( ULONG nPos = nSubSelPos; nPos < aSels.Count(); ++nPos )
+ {
+ aSels.GetObject(nPos)->Min() += nCount;
+ aSels.GetObject(nPos)->Max() += nCount;
+ }
+ }
+
+ bCurValid = FALSE;
+ aTotRange.Max() += nCount;
+ if ( bSelectNew )
+ nSelCount += nCount;
+
+ DBG(Print( this ));
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSelection::Remove( long nIndex )
+{
+ DBG(DbgOutf( "::Remove(%ld)\n", nIndex ));
+
+ // find the virtual target position
+ ULONG nSubSelPos = ImplFindSubSelection( nIndex );
+
+ // did we remove from an existing sub selection?
+ if ( nSubSelPos < aSels.Count() &&
+ aSels.GetObject(nSubSelPos)->IsInside(nIndex) )
+ {
+ // does this sub selection only contain the index to be deleted
+ if ( aSels.GetObject(nSubSelPos)->Len() == 1 )
+ // completely remove the sub selection
+ aSels.Remove(nSubSelPos);
+ else
+ // shorten this sub selection
+ --( aSels.GetObject(nSubSelPos++)->Max() );
+
+ // adjust the selected counter
+ --nSelCount;
+ }
+
+ // shift the sub selections behind the removed index
+ for ( ULONG nPos = nSubSelPos; nPos < aSels.Count(); ++nPos )
+ {
+ --( aSels.GetObject(nPos)->Min() );
+ --( aSels.GetObject(nPos)->Max() );
+ }
+
+ bCurValid = FALSE;
+ aTotRange.Max() -= 1;
+
+ DBG(Print( this ));
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSelection::Append( long nCount )
+{
+ long nPrevLast = aTotRange.Max();
+ aTotRange.Max() += nCount;
+ if ( bSelectNew )
+ {
+ nSelCount += nCount;
+ aSels.Insert( new Range( nPrevLast+1, nPrevLast + nCount ),
+ LIST_APPEND );
+ if ( aSels.Count() > 1 )
+ ImplMergeSubSelections( aSels.Count() - 2, aSels.Count() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long MultiSelection::ImplFwdUnselected()
+{
+ if ( !bCurValid )
+ return SFX_ENDOFSELECTION;
+
+ if ( ( nCurSubSel < aSels.Count() ) &&
+ ( aSels.GetObject(nCurSubSel)->Min() <= nCurIndex ) )
+ nCurIndex = aSels.GetObject(nCurSubSel++)->Max() + 1;
+
+ if ( nCurIndex <= aTotRange.Max() )
+ return nCurIndex;
+ else
+ return SFX_ENDOFSELECTION;
+}
+
+// -----------------------------------------------------------------------
+
+long MultiSelection::ImplBwdUnselected()
+{
+ if ( !bCurValid )
+ return SFX_ENDOFSELECTION;
+
+ if ( aSels.GetObject(nCurSubSel)->Max() < nCurIndex )
+ return nCurIndex;
+
+ nCurIndex = aSels.GetObject(nCurSubSel--)->Min() - 1;
+ if ( nCurIndex >= 0 )
+ return nCurIndex;
+ else
+ return SFX_ENDOFSELECTION;
+}
+
+// -----------------------------------------------------------------------
+
+long MultiSelection::FirstSelected( BOOL bInverse )
+{
+ bInverseCur = bInverse;
+ nCurSubSel = 0;
+
+ if ( bInverseCur )
+ {
+ bCurValid = nSelCount < ULONG(aTotRange.Len());
+ if ( bCurValid )
+ {
+ nCurIndex = 0;
+ return ImplFwdUnselected();
+ }
+ }
+ else
+ {
+ bCurValid = aSels.Count() > 0;
+ if ( bCurValid )
+ return nCurIndex = aSels.GetObject(0)->Min();
+ }
+
+ return SFX_ENDOFSELECTION;
+}
+
+// -----------------------------------------------------------------------
+
+long MultiSelection::LastSelected()
+{
+ nCurSubSel = aSels.Count() - 1;
+ bCurValid = aSels.Count() > 0;
+
+ if ( bCurValid )
+ return nCurIndex = aSels.GetObject(nCurSubSel)->Max();
+
+ return SFX_ENDOFSELECTION;
+}
+
+// -----------------------------------------------------------------------
+
+long MultiSelection::NextSelected()
+{
+ if ( !bCurValid )
+ return SFX_ENDOFSELECTION;
+
+ if ( bInverseCur )
+ {
+ ++nCurIndex;
+ return ImplFwdUnselected();
+ }
+ else
+ {
+ // is the next index in the current sub selection too?
+ if ( nCurIndex < aSels.GetObject(nCurSubSel)->Max() )
+ return ++nCurIndex;
+
+ // are there further sub selections?
+ if ( ++nCurSubSel < aSels.Count() )
+ return nCurIndex = aSels.GetObject(nCurSubSel)->Min();
+
+ // we are at the end!
+ return SFX_ENDOFSELECTION;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long MultiSelection::PrevSelected()
+{
+ if ( !bCurValid )
+ return SFX_ENDOFSELECTION;
+
+ if ( bInverseCur )
+ {
+ --nCurIndex;
+ return ImplBwdUnselected();
+ }
+ else
+ {
+ // is the previous index in the current sub selection too?
+ if ( nCurIndex > aSels.GetObject(nCurSubSel)->Min() )
+ return --nCurIndex;
+
+ // are there previous sub selections?
+ if ( nCurSubSel > 0 )
+ {
+ --nCurSubSel;
+ return nCurIndex = aSels.GetObject(nCurSubSel)->Max();
+ }
+
+ // we are at the beginning!
+ return SFX_ENDOFSELECTION;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSelection::SetTotalRange( const Range& rTotRange )
+{
+ aTotRange = rTotRange;
+
+ // die untere Bereichsgrenze anpassen
+ Range* pRange = aSels.GetObject( 0 );
+ while( pRange )
+ {
+ if( pRange->Max() < aTotRange.Min() )
+ {
+ delete pRange;
+ aSels.Remove( (ULONG)0 );
+ }
+ else if( pRange->Min() < aTotRange.Min() )
+ {
+ pRange->Min() = aTotRange.Min();
+ break;
+ }
+ else
+ break;
+
+ pRange = aSels.GetObject( 0 );
+ }
+
+ // die obere Bereichsgrenze anpassen
+ ULONG nCount = aSels.Count();
+ while( nCount )
+ {
+ pRange = aSels.GetObject( nCount - 1 );
+ if( pRange->Min() > aTotRange.Max() )
+ {
+ delete pRange;
+ aSels.Remove( (ULONG)(nCount - 1) );
+ }
+ else if( pRange->Max() > aTotRange.Max() )
+ {
+ pRange->Max() = aTotRange.Max();
+ break;
+ }
+ else
+ break;
+
+ nCount = aSels.Count();
+ }
+
+ // Selection-Count neu berechnen
+ nSelCount = 0;
+ pRange = aSels.First();
+ while( pRange )
+ {
+ nSelCount += pRange->Len();
+ pRange = aSels.Next();
+ }
+
+ bCurValid = FALSE;
+ nCurIndex = 0;
+}
+
+// -----------------------------------------------------------------------
+//
+// StringRangeEnumerator
+//
+// -----------------------------------------------------------------------
+StringRangeEnumerator::StringRangeEnumerator( const rtl::OUString& i_rInput,
+ sal_Int32 i_nMinNumber,
+ sal_Int32 i_nMaxNumber,
+ sal_Int32 i_nLogicalOffset
+ )
+ : mnCount( 0 )
+ , mnMin( i_nMinNumber )
+ , mnMax( i_nMaxNumber )
+ , mnOffset( i_nLogicalOffset )
+{
+ setRange( i_rInput );
+}
+
+bool StringRangeEnumerator::checkValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const
+{
+ if( mnMin >= 0 && i_nValue < mnMin )
+ return false;
+ if( mnMax >= 0 && i_nValue > mnMax )
+ return false;
+ if( i_nValue < 0 )
+ return false;
+ if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() )
+ return false;
+ return true;
+}
+
+bool StringRangeEnumerator::insertRange( sal_Int32 i_nFirst, sal_Int32 i_nLast, bool bSequence, bool bMayAdjust )
+{
+ bool bSuccess = true;
+ if( bSequence )
+ {
+ if( i_nFirst == -1 )
+ i_nFirst = mnMin;
+ if( i_nLast == -1 )
+ i_nLast = mnMax;
+ if( bMayAdjust )
+ {
+ if( i_nFirst < mnMin )
+ i_nFirst = mnMin;
+ if( i_nFirst > mnMax )
+ i_nFirst = mnMax;
+ if( i_nLast < mnMin )
+ i_nLast = mnMin;
+ if( i_nLast > mnMax )
+ i_nLast = mnMax;
+ }
+ if( checkValue( i_nFirst ) && checkValue( i_nLast ) )
+ {
+ maSequence.push_back( Range( i_nFirst, i_nLast ) );
+ sal_Int32 nNumber = i_nLast - i_nFirst;
+ nNumber = nNumber < 0 ? -nNumber : nNumber;
+ mnCount += nNumber + 1;
+ }
+ else
+ bSuccess = false;
+ }
+ else
+ {
+ if( i_nFirst >= 0 )
+ {
+ if( checkValue( i_nFirst ) )
+ {
+ maSequence.push_back( Range( i_nFirst, i_nFirst ) );
+ mnCount++;
+ }
+ else
+ bSuccess = false;
+ }
+ if( i_nLast >= 0 )
+ {
+ if( checkValue( i_nLast ) )
+ {
+ maSequence.push_back( Range( i_nLast, i_nLast ) );
+ mnCount++;
+ }
+ else
+ bSuccess = false;
+ }
+ }
+
+ return bSuccess;
+}
+
+bool StringRangeEnumerator::setRange( const rtl::OUString& i_rNewRange, bool i_bStrict )
+{
+ mnCount = 0;
+ maSequence.clear();
+
+ // we love special cases
+ if( i_rNewRange.getLength() == 0 )
+ {
+ if( mnMin >= 0 && mnMax >= 0 )
+ {
+ insertRange( mnMin, mnMax, mnMin != mnMax, ! i_bStrict );
+ }
+ return true;
+ }
+
+ const sal_Unicode* pInput = i_rNewRange.getStr();
+ rtl::OUStringBuffer aNumberBuf( 16 );
+ sal_Int32 nLastNumber = -1, nNumber = -1;
+ bool bSequence = false;
+ bool bSuccess = true;
+ while( *pInput )
+ {
+ while( *pInput >= sal_Unicode('0') && *pInput <= sal_Unicode('9') )
+ aNumberBuf.append( *pInput++ );
+ if( aNumberBuf.getLength() )
+ {
+ if( nNumber != -1 )
+ {
+ if( bSequence )
+ {
+ if( ! insertRange( nLastNumber, nNumber, true, ! i_bStrict ) && i_bStrict )
+ {
+ bSuccess = false;
+ break;
+ }
+ nLastNumber = -1;
+ }
+ else
+ {
+ if( ! insertRange( nNumber, nNumber, false, ! i_bStrict ) && i_bStrict )
+ {
+ bSuccess = false;
+ break;
+ }
+ }
+ }
+ nNumber = aNumberBuf.makeStringAndClear().toInt32();
+ nNumber += mnOffset;
+ }
+ bool bInsertRange = false;
+ if( *pInput == sal_Unicode('-') )
+ {
+ nLastNumber = nNumber;
+ nNumber = -1;
+ bSequence = true;
+ }
+ else if( *pInput == ' ' )
+ {
+ }
+ else if( *pInput == sal_Unicode(',') || *pInput == sal_Unicode(';') )
+ bInsertRange = true;
+ else if( *pInput )
+ {
+
+ bSuccess = false;
+ break; // parse error
+ }
+
+ if( bInsertRange )
+ {
+ if( ! insertRange( nLastNumber, nNumber, bSequence, ! i_bStrict ) && i_bStrict )
+ {
+ bSuccess = false;
+ break;
+ }
+ nNumber = nLastNumber = -1;
+ bSequence = false;
+ }
+ if( *pInput )
+ pInput++;
+ }
+ // insert last entries
+ insertRange( nLastNumber, nNumber, bSequence, ! i_bStrict );
+
+ return bSuccess;
+}
+
+bool StringRangeEnumerator::hasValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const
+{
+ if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() )
+ return false;
+ size_t n = maSequence.size();
+ for( size_t i= 0; i < n; ++i )
+ {
+ const StringRangeEnumerator::Range rRange( maSequence[i] );
+ if( rRange.nFirst < rRange.nLast )
+ {
+ if( i_nValue >= rRange.nFirst && i_nValue <= rRange.nLast )
+ return true;
+ }
+ else
+ {
+ if( i_nValue >= rRange.nLast && i_nValue <= rRange.nFirst )
+ return true;
+ }
+ }
+ return false;
+}
+
+StringRangeEnumerator::Iterator& StringRangeEnumerator::Iterator::operator++()
+{
+ if( nRangeIndex >= 0 && nCurrent >= 0 && pEnumerator )
+ {
+ const StringRangeEnumerator::Range& rRange( pEnumerator->maSequence[nRangeIndex] );
+ bool bRangeChange = false;
+ if( rRange.nLast < rRange.nFirst )
+ {
+ // backward range
+ if( nCurrent > rRange.nLast )
+ nCurrent--;
+ else
+ bRangeChange = true;
+ }
+ else
+ {
+ // forward range
+ if( nCurrent < rRange.nLast )
+ nCurrent++;
+ else
+ bRangeChange = true;
+ }
+ if( bRangeChange )
+ {
+ nRangeIndex++;
+ if( size_t(nRangeIndex) == pEnumerator->maSequence.size() )
+ {
+ // reached the end
+ nRangeIndex = nCurrent = -1;
+ }
+ else
+ nCurrent = pEnumerator->maSequence[nRangeIndex].nFirst;
+ }
+ if( nRangeIndex != -1 && nCurrent != -1 )
+ {
+ if( ! pEnumerator->checkValue( nCurrent, pPossibleValues ) )
+ return ++(*this);
+ }
+ }
+ return *this;
+}
+
+sal_Int32 StringRangeEnumerator::Iterator::operator*() const
+{
+ return nCurrent;
+}
+
+bool StringRangeEnumerator::Iterator::operator==( const Iterator& i_rCompare ) const
+{
+ return i_rCompare.pEnumerator == pEnumerator && i_rCompare.nRangeIndex == nRangeIndex && i_rCompare.nCurrent == nCurrent;
+}
+
+StringRangeEnumerator::Iterator StringRangeEnumerator::begin( const std::set< sal_Int32 >* i_pPossibleValues ) const
+{
+ StringRangeEnumerator::Iterator it( this,
+ i_pPossibleValues,
+ maSequence.empty() ? -1 : 0,
+ maSequence.empty() ? -1 : maSequence[0].nFirst );
+ if( ! checkValue(*it, i_pPossibleValues ) )
+ ++it;
+ return it;
+}
+
+StringRangeEnumerator::Iterator StringRangeEnumerator::end( const std::set< sal_Int32 >* i_pPossibleValues ) const
+{
+ return StringRangeEnumerator::Iterator( this, i_pPossibleValues, -1, -1 );
+}
+
+bool StringRangeEnumerator::getRangesFromString( const OUString& i_rPageRange,
+ std::vector< sal_Int32 >& o_rPageVector,
+ sal_Int32 i_nMinNumber,
+ sal_Int32 i_nMaxNumber,
+ sal_Int32 i_nLogicalOffset,
+ std::set< sal_Int32 >* i_pPossibleValues
+ )
+{
+ StringRangeEnumerator aEnum;
+ aEnum.setMin( i_nMinNumber );
+ aEnum.setMax( i_nMaxNumber );
+ aEnum.setLogicalOffset( i_nLogicalOffset );
+
+ bool bRes = aEnum.setRange( i_rPageRange );
+ if( bRes )
+ {
+ o_rPageVector.clear();
+ o_rPageVector.reserve( aEnum.size() );
+ for( StringRangeEnumerator::Iterator it = aEnum.begin( i_pPossibleValues );
+ it != aEnum.end( i_pPossibleValues ); ++it )
+ {
+ o_rPageVector.push_back( *it );
+ }
+ }
+
+ return bRes;
+}
+
diff --git a/tools/source/memtools/table.cxx b/tools/source/memtools/table.cxx
new file mode 100644
index 000000000000..50ac46e99758
--- /dev/null
+++ b/tools/source/memtools/table.cxx
@@ -0,0 +1,413 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _TOOLS_TABLE_CXX
+
+// -----------------------------------------------------------------------
+#include <tools/debug.hxx>
+#include <impcont.hxx>
+#include <tools/table.hxx>
+
+// =======================================================================
+
+ULONG Table::ImplGetIndex( ULONG nKey, ULONG* pIndex ) const
+{
+ // Abpruefen, ob der erste Key groesser als der Vergleichskey ist
+ if ( !nCount || (nKey < (ULONG)Container::ImpGetObject(0)) )
+ return TABLE_ENTRY_NOTFOUND;
+
+ ULONG nLow;
+ ULONG nHigh;
+ ULONG nMid;
+ ULONG nCompareKey;
+ void** pNodes = Container::ImpGetOnlyNodes();
+
+ // Binaeres Suchen
+ nLow = 0;
+ nHigh = nCount-1;
+ if ( pNodes )
+ {
+ do
+ {
+ nMid = (nLow + nHigh) / 2;
+ nCompareKey = (ULONG)pNodes[nMid*2];
+ if ( nKey < nCompareKey )
+ nHigh = nMid-1;
+ else
+ {
+ if ( nKey > nCompareKey )
+ nLow = nMid + 1;
+ else
+ return nMid*2;
+ }
+ }
+ while ( nLow <= nHigh );
+ }
+ else
+ {
+ do
+ {
+ nMid = (nLow + nHigh) / 2;
+ nCompareKey = (ULONG)Container::ImpGetObject( nMid*2 );
+ if ( nKey < nCompareKey )
+ nHigh = nMid-1;
+ else
+ {
+ if ( nKey > nCompareKey )
+ nLow = nMid + 1;
+ else
+ return nMid*2;
+ }
+ }
+ while ( nLow <= nHigh );
+ }
+
+ if ( pIndex )
+ {
+ if ( nKey > nCompareKey )
+ *pIndex = (nMid+1)*2;
+ else
+ *pIndex = nMid*2;
+ }
+
+ return TABLE_ENTRY_NOTFOUND;
+}
+
+// =======================================================================
+
+Table::Table( USHORT _nInitSize, USHORT _nReSize ) :
+ Container( CONTAINER_MAXBLOCKSIZE, _nInitSize*2, _nReSize*2 )
+{
+ DBG_ASSERT( _nInitSize <= 32767, "Table::Table(): InitSize > 32767" );
+ DBG_ASSERT( _nReSize <= 32767, "Table::Table(): ReSize > 32767" );
+ nCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Table::Insert( ULONG nKey, void* p )
+{
+ // Tabellenelement einsortieren
+ ULONG i;
+ if ( nCount )
+ {
+ if ( nCount <= 24 )
+ {
+ USHORT n = 0;
+ USHORT nTempCount = (USHORT)nCount * 2;
+ //<!--Modified by PengYunQuan for resolving a NULL pointer access
+
+ if( void** pNodes = Container::ImpGetOnlyNodes() )
+ {
+ ULONG nCompareKey = (ULONG)(*pNodes);
+ while ( nKey > nCompareKey )
+ {
+ n += 2;
+ pNodes += 2;
+ if ( n < nTempCount )
+ nCompareKey = (ULONG)(*pNodes);
+ else
+ {
+ nCompareKey = 0;
+ break;
+ }
+ }
+
+ // Testen, ob sich der Key schon in der Tabelle befindet
+ if ( nKey == nCompareKey )
+ return FALSE;
+
+ i = n;
+ }
+ else
+ {
+ i = 0;
+ if ( ImplGetIndex( nKey, &i ) != TABLE_ENTRY_NOTFOUND )
+ return FALSE;
+ }
+ //-->Modified by PengYunQuan for resolving a NULL pointer access
+ }
+ else
+ {
+ i = 0;
+ if ( ImplGetIndex( nKey, &i ) != TABLE_ENTRY_NOTFOUND )
+ return FALSE;
+ }
+ }
+ else
+ i = 0;
+
+ // Eintrag einfuegen (Key vor Pointer)
+ Container::Insert( (void*)nKey, i );
+ Container::Insert( p, i+1 );
+
+ // Ein neuer Eintrag
+ nCount++;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::Remove( ULONG nKey )
+{
+ // Index besorgen
+ ULONG nIndex = ImplGetIndex( nKey );
+
+ // Testen, ob sich der Key in der Tabelle befindet
+ if ( nIndex == TABLE_ENTRY_NOTFOUND )
+ return NULL;
+
+ // Itemanzahl erniedrigen
+ nCount--;
+
+ // Key entfernen
+ Container::Remove( nIndex );
+
+ // Pointer entfernen und zurueckgeben
+ return Container::Remove( nIndex );
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::Replace( ULONG nKey, void* p )
+{
+ // Index abfragen
+ ULONG nIndex = ImplGetIndex( nKey );
+
+ // Existiert kein Eintrag mit dem Schluessel
+ if ( nIndex == TABLE_ENTRY_NOTFOUND )
+ return NULL;
+ else
+ return Container::Replace( p, nIndex+1 );
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::Get( ULONG nKey ) const
+{
+ // Index besorgen
+ ULONG nIndex = ImplGetIndex( nKey );
+
+ // Testen, ob sich der Key in der Tabelle befindet
+ if ( nIndex == TABLE_ENTRY_NOTFOUND )
+ return NULL;
+ else
+ return Container::ImpGetObject( nIndex+1 );
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::GetCurObject() const
+{
+ return Container::ImpGetObject( Container::GetCurPos()+1 );
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Table::GetKey( const void* p ) const
+{
+ ULONG nIndex = 0;
+
+ // Solange noch Eintraege Vorhanden sind
+ while ( nIndex < nCount )
+ {
+ // Stimmt der Pointer ueberein, wird der Key zurueckgegeben
+ if ( p == Container::ImpGetObject( (nIndex*2)+1 ) )
+ return (ULONG)Container::ImpGetObject( nIndex*2 );
+
+ nIndex++;
+ }
+
+ return TABLE_ENTRY_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Table::IsKeyValid( ULONG nKey ) const
+{
+ return (ImplGetIndex( nKey ) != TABLE_ENTRY_NOTFOUND) ? TRUE : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Table::GetUniqueKey( ULONG nStartKey ) const
+{
+ DBG_ASSERT( (nStartKey > 1) && (nStartKey < 0xFFFFFFFF),
+ "Table::GetUniqueKey() - nStartKey == 0 or nStartKey >= 0xFFFFFFFF" );
+
+ if ( !nCount )
+ return nStartKey;
+
+ ULONG nLastKey = (ULONG)Container::GetObject( (nCount*2)-2 );
+ if ( nLastKey < nStartKey )
+ return nStartKey;
+ else
+ {
+ if ( nLastKey < 0xFFFFFFFE )
+ return nLastKey+1;
+ else
+ {
+ ULONG nPos;
+ ULONG nTempPos = ImplGetIndex( nStartKey, &nPos );
+ if ( nTempPos != TABLE_ENTRY_NOTFOUND )
+ nPos = nTempPos;
+ nLastKey = (ULONG)Container::GetObject( nPos );
+ if ( nStartKey < nLastKey )
+ return nStartKey;
+ while ( nLastKey < 0xFFFFFFFE )
+ {
+ nPos += 2;
+ nLastKey++;
+ if ( nLastKey != (ULONG)Container::GetObject( nPos ) )
+ return nLastKey;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Table::SearchKey( ULONG nKey, ULONG* pPos ) const
+{
+ *pPos = 0;
+ ULONG nPos = ImplGetIndex( nKey, pPos );
+ if ( nPos != TABLE_ENTRY_NOTFOUND )
+ {
+ nPos /= 2;
+ *pPos = nPos;
+ }
+ else
+ *pPos /= 2;
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::Seek( ULONG nKey )
+{
+ // Testen, ob ein Eintrag vorhanden ist
+ if ( nCount )
+ {
+ ULONG nIndex = ImplGetIndex( nKey );
+
+ // Ist Key nicht enthalten
+ if ( nIndex == TABLE_ENTRY_NOTFOUND )
+ return NULL;
+ else
+ {
+ // Index setzen
+ Container::Seek( nIndex );
+
+ // Pointer zurueckgeben
+ return Container::ImpGetObject( Container::GetCurPos() + 1 );
+ }
+ }
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::Seek( void* p )
+{
+ ULONG nKey = GetKey( p );
+
+ // Ist Key vorhanden, dann als aktuellen Eintrag setzen
+ if ( nKey != TABLE_ENTRY_NOTFOUND )
+ return Seek( nKey );
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::First()
+{
+ // Testen, ob ein Eintrag vorhanden ist
+ if ( nCount )
+ {
+ // Auf ersten Eintag setzen
+ Container::First();
+
+ // Pointer zurueckgeben
+ return Container::ImpGetObject( 1 );
+ }
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::Last()
+{
+ // Testen, ob ein Eintrag vorhanden ist
+ if ( nCount )
+ {
+ // Last auf letzten Eintrag setzen
+ void* p = Container::Last();
+ Container::Prev();
+
+ // Pointer zurueckgeben
+ return p;
+ }
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::Next()
+{
+ // Ueber den Pointer weiterschalten
+ Container::Next();
+
+ // Nachsten Eintag
+ Container::Next();
+
+ // Pointer vom naechsten Key zurueckgeben
+ return Container::ImpGetObject( Container::GetCurPos() + 1 );
+}
+
+// -----------------------------------------------------------------------
+
+void* Table::Prev()
+{
+ // Ueber den Pointer weiterschalten
+ void* p = Container::Prev();
+
+ // Nachsten Eintag
+ Container::Prev();
+
+ // Pointer vom vorherigen Key zurueckgeben
+ return p;
+}
diff --git a/tools/source/memtools/unqidx.cxx b/tools/source/memtools/unqidx.cxx
new file mode 100644
index 000000000000..94624c3ac905
--- /dev/null
+++ b/tools/source/memtools/unqidx.cxx
@@ -0,0 +1,601 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <impcont.hxx>
+#include <tools/unqidx.hxx>
+#include <tools/unqid.hxx>
+
+/*************************************************************************
+|*
+|* UniqueIndex::UniqueIndex()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+UniqueIndex::UniqueIndex( ULONG _nStartIndex,
+ ULONG _nInitSize, ULONG _nReSize ) :
+ Container( _nInitSize )
+{
+ nReSize = _nReSize;
+ nStartIndex = _nStartIndex;
+ nUniqIndex = 0;
+ nCount = 0;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::UniqueIndex()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+UniqueIndex::UniqueIndex( const UniqueIndex& rIdx ) :
+ Container( rIdx )
+{
+ nReSize = rIdx.nReSize;
+ nStartIndex = rIdx.nStartIndex;
+ nUniqIndex = rIdx.nUniqIndex;
+ nCount = rIdx.nCount;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Insert()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+ULONG UniqueIndex::Insert( void* p )
+{
+ // NULL-Pointer ist nicht erlaubt
+ if ( !p )
+ return UNIQUEINDEX_ENTRY_NOTFOUND;
+
+ // Ist Array voll, dann expandieren
+ if ( nCount == Container::GetSize() )
+ SetSize( nCount + nReSize );
+
+ // Damit UniqIndex nicht ueberlaeuft, wenn Items geloescht wurden
+ nUniqIndex = nUniqIndex % Container::GetSize();
+
+ // Leeren Eintrag suchen
+ while ( Container::ImpGetObject( nUniqIndex ) != NULL )
+ nUniqIndex = (nUniqIndex+1) % Container::GetSize();
+
+ // Object im Array speichern
+ Container::Replace( p, nUniqIndex );
+
+ // Anzahl der Eintraege erhoehen und Index zurueckgeben
+ nCount++;
+ nUniqIndex++;
+ return ( nUniqIndex + nStartIndex - 1 );
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Insert()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung MM 21.04.96
+|* Letzte Aenderung MM 21.04.96
+|*
+*************************************************************************/
+
+ULONG UniqueIndex::Insert( ULONG nIndex, void* p )
+{
+ // NULL-Pointer ist nicht erlaubt
+ if ( !p )
+ return UNIQUEINDEX_ENTRY_NOTFOUND;
+
+ ULONG nContIndex = nIndex - nStartIndex;
+ // Ist Array voll, dann expandieren
+ if ( nContIndex >= Container::GetSize() )
+ SetSize( nContIndex + nReSize );
+
+ // Object im Array speichern
+ Container::Replace( p, nContIndex );
+
+ // Anzahl der Eintraege erhoehen und Index zurueckgeben
+ nCount++;
+ return nIndex;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Remove()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::Remove( ULONG nIndex )
+{
+ // Ist Index zulaessig
+ if ( (nIndex >= nStartIndex) &&
+ (nIndex < (Container::GetSize()+nStartIndex)) )
+ {
+ // Index-Eintrag als leeren Eintrag setzen und Anzahl der
+ // gespeicherten Indexe erniedriegen, wenn Eintrag belegt war
+ void* p = Container::Replace( NULL, nIndex-nStartIndex );
+ if ( p )
+ nCount--;
+ return p;
+ }
+ else
+ return NULL;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Replace()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::Replace( ULONG nIndex, void* p )
+{
+ // NULL-Pointer ist nicht erlaubt
+ if ( !p )
+ return NULL;
+
+ // Ist Index zulaessig
+ if ( IsIndexValid( nIndex ) )
+ {
+ // Index-Eintrag ersetzen und alten zurueckgeben
+ return Container::Replace( p, nIndex-nStartIndex );
+ }
+ else
+ return NULL;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Get()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::Get( ULONG nIndex ) const
+{
+ // Ist Index zulaessig
+ if ( (nIndex >= nStartIndex) &&
+ (nIndex < (Container::GetSize()+nStartIndex)) )
+ return Container::ImpGetObject( nIndex-nStartIndex );
+ else
+ return NULL;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::GetCurIndex()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+ULONG UniqueIndex::GetCurIndex() const
+{
+ ULONG nPos = Container::GetCurPos();
+
+ // Ist der Current-Index nicht belegt, dann gibt es keinen Current-Index
+ if ( !Container::ImpGetObject( nPos ) )
+ return UNIQUEINDEX_ENTRY_NOTFOUND;
+ else
+ return nPos+nStartIndex;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::GetIndex()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+ULONG UniqueIndex::GetIndex( const void* p ) const
+{
+ // Wird ein NULL-Pointer uebergeben, dann wurde Pointer nicht gefunden
+ if ( !p )
+ return UNIQUEINDEX_ENTRY_NOTFOUND;
+
+ ULONG nIndex = Container::GetPos( p );
+
+ if ( nIndex != CONTAINER_ENTRY_NOTFOUND )
+ return nIndex+nStartIndex;
+ else
+ return UNIQUEINDEX_ENTRY_NOTFOUND;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::IsIndexValid()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+BOOL UniqueIndex::IsIndexValid( ULONG nIndex ) const
+{
+ // Ist Index zulaessig
+ if ( (nIndex >= nStartIndex) &&
+ (nIndex < (Container::GetSize()+nStartIndex)) )
+ {
+ // Index ist nur zulaessig, wenn Eintrag auch belegt ist
+ if ( Container::ImpGetObject( nIndex-nStartIndex ) )
+ return TRUE;
+ else
+ return FALSE;
+ }
+ else
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Seek()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::Seek( ULONG nIndex )
+{
+ // Index-Eintrag als aktuellen setzten, wenn er gueltig ist
+ if ( IsIndexValid( nIndex ) )
+ return Container::Seek( nIndex-nStartIndex );
+ else
+ return NULL;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Seek()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::Seek( void* p )
+{
+ // Wird ein NULL-Pointer uebergeben, dann wurde Pointer nicht gefunden
+ if ( !p )
+ return NULL;
+
+ ULONG nIndex = GetIndex( p );
+
+ // Ist Index vorhanden, dann als aktuellen Eintrag setzen
+ if ( nIndex != UNIQUEINDEX_ENTRY_NOTFOUND )
+ return Container::Seek( nIndex-nStartIndex );
+ else
+ return NULL;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::First()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::First()
+{
+ void* p = Container::First();
+
+ while ( !p && (Container::GetCurPos() < (Container::GetSize()-1)) )
+ p = Container::Next();
+
+ return p;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Last()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::Last()
+{
+ void* p = Container::Last();
+
+ while ( !p && Container::GetCurPos() )
+ p = Container::Prev();
+
+ return p;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Next()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::Next()
+{
+ void* p = NULL;
+
+ while ( !p && (Container::GetCurPos() < (Container::GetSize()-1)) )
+ p = Container::Next();
+
+ return p;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::Prev()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+void* UniqueIndex::Prev()
+{
+ void* p = NULL;
+
+ while ( !p && Container::GetCurPos() )
+ p = Container::Prev();
+
+ return p;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::operator =()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+UniqueIndex& UniqueIndex::operator =( const UniqueIndex& rIdx )
+{
+ // Neue Werte zuweisen
+ Container::operator =( rIdx );
+ nReSize = rIdx.nReSize;
+ nStartIndex = rIdx.nStartIndex;
+ nUniqIndex = rIdx.nUniqIndex;
+ nCount = rIdx.nCount;
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* UniqueIndex::operator ==()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung TH 24.09.91
+|* Letzte Aenderung TH 24.09.91
+|*
+*************************************************************************/
+
+BOOL UniqueIndex::operator ==( const UniqueIndex& rIdx ) const
+{
+ // Neue Werte zuweisen
+ if ( (nStartIndex == rIdx.nStartIndex) &&
+ (nCount == rIdx.nCount) &&
+ (Container::operator ==( rIdx )) )
+ return TRUE;
+ else
+ return FALSE;
+}
+/*************************************************************************
+|*
+|* UniqueIdContainer::UniqueIdContainer ()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung MM 29.04.96
+|* Letzte Aenderung MM 29.04.96
+|*
+*************************************************************************/
+
+UniqueIdContainer::UniqueIdContainer( const UniqueIdContainer& rObj )
+ : UniqueIndex( rObj )
+ , nCollectCount( rObj.nCollectCount )
+{
+ ULONG nCur = GetCurIndex();
+
+ ImpUniqueId * pEle = (ImpUniqueId *)First();
+ while( pEle )
+ {
+ pEle->nRefCount++;
+ pEle = (ImpUniqueId *)Next();
+ }
+ Seek( nCur );
+}
+
+/*************************************************************************
+|*
+|* UniqueIdContainer::operator = ()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung MM 01.08.94
+|* Letzte Aenderung MM 01.08.94
+|*
+*************************************************************************/
+
+UniqueIdContainer& UniqueIdContainer::operator = ( const UniqueIdContainer & rObj )
+{
+ UniqueIndex::operator = ( rObj );
+ nCollectCount = rObj.nCollectCount;
+
+ ULONG nCur = GetCurIndex();
+
+ ImpUniqueId * pEle = (ImpUniqueId *)First();
+ while( pEle )
+ {
+ pEle->nRefCount++;
+ pEle = (ImpUniqueId *)Next();
+ }
+ Seek( nCur );
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* UniqueIdContainer::Clear()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung MM 01.08.94
+|* Letzte Aenderung MM 01.08.94
+|*
+*************************************************************************/
+
+void UniqueIdContainer::Clear( BOOL bAll )
+{
+ USHORT nFree = bAll ? 0xFFFF : 1;
+
+ ImpUniqueId* pId = (ImpUniqueId*)Last();
+ BOOL bLast = TRUE;
+ while ( pId )
+ {
+ if ( pId->nRefCount <= nFree )
+ {
+ ((ImpUniqueId *)Remove( pId->nId ))->Release();
+ if( bLast )
+ pId = (ImpUniqueId *)Last();
+ else
+ pId = (ImpUniqueId *)Prev();
+ }
+ else
+ {
+ pId = (ImpUniqueId *)Prev();
+ bLast = FALSE;
+ }
+ }
+}
+
+/*************************************************************************
+|*
+|* UniqueIdContainer::CreateId()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung MM 01.08.94
+|* Letzte Aenderung MM 01.08.94
+|*
+*************************************************************************/
+
+UniqueItemId UniqueIdContainer::CreateId()
+{
+ if( nCollectCount > 50 )
+ { // aufraeumen
+ Clear( FALSE );
+ nCollectCount = 0;
+ }
+ nCollectCount++;
+
+ ImpUniqueId * pId = new ImpUniqueId;
+ pId->nRefCount = 1;
+ pId->nId = Insert( pId );
+ return UniqueItemId( pId );
+}
+
+/*************************************************************************
+|*
+|* UniqueIdContainer::CreateIdProt()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung MM 01.08.94
+|* Letzte Aenderung MM 01.08.94
+|*
+*************************************************************************/
+
+UniqueItemId UniqueIdContainer::CreateFreeId( ULONG nId )
+{
+ // Einfach erzeugen, fuer abgeleitete Klasse
+ ImpUniqueId * pId = new ImpUniqueId;
+ pId->nRefCount = 0;
+ pId->nId = nId;
+ return UniqueItemId( pId );
+}
+
+/*************************************************************************
+|*
+|* UniqueIdContainer::CreateIdProt()
+|*
+|* Beschreibung UNQIDX.SDW
+|* Ersterstellung MM 01.08.94
+|* Letzte Aenderung MM 01.08.94
+|*
+*************************************************************************/
+
+UniqueItemId UniqueIdContainer::CreateIdProt( ULONG nId )
+{
+ if ( IsIndexValid( nId ) )
+ return UniqueItemId( (ImpUniqueId *)Get( nId ) );
+
+ ImpUniqueId * pId;
+ do
+ {
+ pId = new ImpUniqueId;
+ pId->nRefCount = 1;
+ pId->nId = Insert( pId );
+ }
+ while( pId->nId != nId );
+ return UniqueItemId( pId );
+}
diff --git a/tools/source/misc/appendunixshellword.cxx b/tools/source/misc/appendunixshellword.cxx
new file mode 100644
index 000000000000..af2a05b00716
--- /dev/null
+++ b/tools/source/misc/appendunixshellword.cxx
@@ -0,0 +1,76 @@
+/*************************************************************************
+ *
+ * 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 "precompiled_tools.hxx"
+#include "sal/config.h"
+
+#if defined UNX
+
+#include <cstddef>
+
+#include "osl/diagnose.h"
+#include "rtl/strbuf.hxx"
+#include "rtl/string.h"
+#include "rtl/string.hxx"
+#include "sal/types.h"
+#include "tools/appendunixshellword.hxx"
+
+namespace tools {
+
+void appendUnixShellWord(
+ rtl::OStringBuffer * accumulator, rtl::OString const & text)
+{
+ OSL_ASSERT(accumulator != NULL);
+ if (text.getLength() == 0) {
+ accumulator->append(RTL_CONSTASCII_STRINGPARAM("''"));
+ } else {
+ bool quoted = false;
+ for (sal_Int32 i = 0; i < text.getLength(); ++i) {
+ char c = text[i];
+ if (c == '\'') {
+ if (quoted) {
+ accumulator->append('\'');
+ quoted = false;
+ }
+ accumulator->append(RTL_CONSTASCII_STRINGPARAM("\\'"));
+ } else {
+ if (!quoted) {
+ accumulator->append('\'');
+ quoted = true;
+ }
+ accumulator->append(c);
+ }
+ }
+ if (quoted) {
+ accumulator->append('\'');
+ }
+ }
+}
+
+}
+
+#endif
diff --git a/tools/source/misc/extendapplicationenvironment.cxx b/tools/source/misc/extendapplicationenvironment.cxx
new file mode 100644
index 000000000000..fe76e5329cbb
--- /dev/null
+++ b/tools/source/misc/extendapplicationenvironment.cxx
@@ -0,0 +1,103 @@
+/*************************************************************************
+ *
+ * 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 "precompiled_tools.hxx"
+#include "sal/config.h"
+
+#include <stdlib.h>
+ // not <cstdlib> as putenv is POSIX-only; setenv instead of putenv would be
+ // better but is not supported by Solaris 9 and earlier
+
+#if defined UNX
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#endif
+
+#include "osl/process.h"
+#include "osl/thread.h"
+#include "rtl/bootstrap.hxx"
+#include "rtl/string.hxx"
+#include "rtl/textcvt.h"
+#include "rtl/ustrbuf.hxx"
+#include "rtl/ustring.h"
+#include "rtl/ustring.hxx"
+#include "sal/types.h"
+#include "tools/extendapplicationenvironment.hxx"
+
+namespace tools {
+
+void extendApplicationEnvironment() {
+#if defined UNX
+ // Try to set RLIMIT_NOFILE as large as possible (failure is harmless):
+ rlimit l;
+ if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
+ l.rlim_cur = l.rlim_max;
+ setrlimit(RLIMIT_NOFILE, &l);
+ }
+#endif
+
+ // Make sure URE_BOOTSTRAP environment variable is set (failure is fatal):
+ rtl::OUStringBuffer env;
+ env.appendAscii(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP="));
+ rtl::OUString uri;
+ if (rtl::Bootstrap::get(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URE_BOOTSTRAP")), uri))
+ {
+ if (!uri.matchIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.pathname:")))
+ {
+ uri = rtl::Bootstrap::encode(uri);
+ }
+ env.append(uri);
+ } else {
+ if (osl_getExecutableFile(&uri.pData) != osl_Process_E_None) {
+ abort();
+ }
+ sal_Int32 i = uri.lastIndexOf('/');
+ if (i >= 0) {
+ uri = uri.copy(0, i + 1);
+ }
+ env.append(rtl::Bootstrap::encode(uri));
+ env.appendAscii(
+ RTL_CONSTASCII_STRINGPARAM(SAL_CONFIGFILE("fundamental")));
+ }
+ rtl::OString s;
+ if (!env.makeStringAndClear().convertToString(
+ &s, osl_getThreadTextEncoding(),
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
+ {
+ abort();
+ }
+ rtl_string_acquire(s.pData); // argument to putenv must leak
+ if (putenv(const_cast< char * >(s.getStr())) != 0) {
+ abort();
+ }
+}
+
+}
diff --git a/tools/source/misc/getprocessworkingdir.cxx b/tools/source/misc/getprocessworkingdir.cxx
new file mode 100644
index 000000000000..8cad594befca
--- /dev/null
+++ b/tools/source/misc/getprocessworkingdir.cxx
@@ -0,0 +1,64 @@
+/*************************************************************************
+ *
+ * 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 "precompiled_tools.hxx"
+#include "sal/config.h"
+
+#include <cstddef>
+
+#include "osl/diagnose.h"
+#include "osl/file.hxx"
+#include "osl/process.h"
+#include "rtl/bootstrap.hxx"
+#include "rtl/ustring.h"
+#include "rtl/ustring.hxx"
+#include "tools/getprocessworkingdir.hxx"
+
+namespace tools {
+
+bool getProcessWorkingDir(rtl::OUString * url) {
+ OSL_ASSERT(url != NULL);
+ rtl::OUString s(RTL_CONSTASCII_USTRINGPARAM("$OOO_CWD"));
+ rtl::Bootstrap::expandMacros(s);
+ if (s.getLength() == 0) {
+ if (osl_getProcessWorkingDir(&url->pData) == osl_Process_E_None) {
+ return true;
+ }
+ } else if (s[0] == '1') {
+ *url = s.copy(1);
+ return true;
+ } else if (s[0] == '2' &&
+ (osl::FileBase::getFileURLFromSystemPath(s.copy(1), *url) ==
+ osl::FileBase::E_None))
+ {
+ return true;
+ }
+ *url = rtl::OUString();
+ return false;
+}
+
+}
diff --git a/tools/source/misc/makefile.mk b/tools/source/misc/makefile.mk
new file mode 100644
index 000000000000..a426bb4053c3
--- /dev/null
+++ b/tools/source/misc/makefile.mk
@@ -0,0 +1,47 @@
+#*************************************************************************
+#
+# 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 = tools
+TARGET = misc
+LIBTARGET = NO
+ENABLE_EXCEPTIONS = TRUE
+
+.INCLUDE: settings.mk
+.INCLUDE: $(PRJ)$/util$/makefile.pmk
+
+LIB1TARGET = $(SLB)$/$(TARGET).lib
+LIB1OBJFILES = \
+ $(SLO)$/appendunixshellword.obj \
+ $(SLO)$/extendapplicationenvironment.obj \
+ $(SLO)$/solarmutex.obj \
+ $(SLO)$/getprocessworkingdir.obj
+
+OBJFILES = $(OBJ)$/pathutils.obj
+SLOFILES = $(SLO)$/pathutils.obj $(LIB1OBJFILES) $(SLO)$/solarmutex.obj
+
+.INCLUDE: target.mk
diff --git a/tools/source/misc/pathutils.cxx b/tools/source/misc/pathutils.cxx
new file mode 100644
index 000000000000..397bade136e7
--- /dev/null
+++ b/tools/source/misc/pathutils.cxx
@@ -0,0 +1,219 @@
+/*************************************************************************
+ *
+ * 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 "precompiled_tools.hxx"
+#include "sal/config.h"
+
+#if defined WNT
+
+#include <cstddef>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "sal/types.h"
+#include "tools/pathutils.hxx"
+
+namespace tools {
+
+WCHAR * filename(WCHAR * path) {
+ WCHAR * f = path;
+ for (WCHAR * p = path;;) {
+ switch (*p++) {
+ case L'\0':
+ return f;
+ case L'\\':
+ f = p;
+ break;
+ }
+ }
+}
+
+WCHAR * buildPath(
+ WCHAR * path, WCHAR const * frontBegin, WCHAR const * frontEnd,
+ WCHAR const * backBegin, std::size_t backLength)
+{
+ // Remove leading ".." segments in the second path together with matching
+ // segments in the first path that are neither empty nor "." nor ".." nor
+ // end in ":" (which is not foolprove, as it can erroneously erase the start
+ // of a UNC path, but only if the input is bad data):
+ while (backLength >= 2 && backBegin[0] == L'.' && backBegin[1] == L'.' &&
+ (backLength == 2 || backBegin[2] == L'\\'))
+ {
+ if (frontEnd - frontBegin < 2 || frontEnd[-1] != L'\\' ||
+ frontEnd[-2] == L'\\' || frontEnd[-2] == L':' ||
+ (frontEnd[-2] == L'.' &&
+ (frontEnd - frontBegin < 3 || frontEnd[-3] == L'\\' ||
+ (frontEnd[-3] == L'.' &&
+ (frontEnd - frontBegin < 4 || frontEnd[-4] == L'\\')))))
+ {
+ break;
+ }
+ WCHAR const * p = frontEnd - 1;
+ while (p != frontBegin && p[-1] != L'\\') {
+ --p;
+ }
+ if (p == frontBegin) {
+ break;
+ }
+ frontEnd = p;
+ if (backLength == 2) {
+ backBegin += 2;
+ backLength -= 2;
+ } else {
+ backBegin += 3;
+ backLength -= 3;
+ }
+ }
+ if (backLength <
+ static_cast< std::size_t >(MAX_PATH - (frontEnd - frontBegin)))
+ // hopefully std::size_t is large enough
+ {
+ WCHAR * p;
+ if (frontBegin == path) {
+ p = const_cast< WCHAR * >(frontEnd);
+ } else {
+ p = path;
+ while (frontBegin != frontEnd) {
+ *p++ = *frontBegin++;
+ }
+ }
+ for (; backLength > 0; --backLength) {
+ *p++ = *backBegin++;
+ }
+ *p = L'\0';
+ return p;
+ } else {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return NULL;
+ }
+}
+
+WCHAR * resolveLink(WCHAR * path) {
+ HANDLE h = CreateFileW(
+ path, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (h == INVALID_HANDLE_VALUE) {
+ return NULL;
+ }
+ char p1[MAX_PATH];
+ DWORD n;
+ BOOL ok = ReadFile(h, p1, MAX_PATH, &n, NULL);
+ CloseHandle(h);
+ if (!ok) {
+ return NULL;
+ }
+ WCHAR p2[MAX_PATH];
+ std::size_t n2 = 0;
+ bool colon = false;
+ for (DWORD i = 0; i < n;) {
+ unsigned char c = static_cast< unsigned char >(p1[i++]);
+ switch (c) {
+ case '\0':
+ SetLastError(ERROR_BAD_PATHNAME);
+ return NULL;
+ case '\x0A':
+ case '\x0D':
+ if (n2 == MAX_PATH) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return NULL;
+ }
+ p2[n2] = L'\0';
+ break;
+ case ':':
+ colon = true;
+ // fall through
+ default:
+ // Convert from UTF-8 to UTF-16:
+ if (c <= 0x7F) {
+ p2[n2++] = c;
+ } else if (c >= 0xC2 && c <= 0xDF && i < n &&
+ static_cast< unsigned char >(p1[i]) >= 0x80 &&
+ static_cast< unsigned char >(p1[i]) <= 0xBF)
+ {
+ p2[n2++] = ((c & 0x1F) << 6) |
+ (static_cast< unsigned char >(p1[i++]) & 0x3F);
+ } else if (n - i > 1 &&
+ ((c == 0xE0 &&
+ static_cast< unsigned char >(p1[i]) >= 0xA0 &&
+ static_cast< unsigned char >(p1[i]) <= 0xBF) ||
+ ((c >= 0xE1 && c <= 0xEC || c >= 0xEE && c <= 0xEF) &&
+ static_cast< unsigned char >(p1[i]) >= 0x80 &&
+ static_cast< unsigned char >(p1[i]) <= 0xBF) ||
+ (c == 0xED &&
+ static_cast< unsigned char >(p1[i]) >= 0x80 &&
+ static_cast< unsigned char >(p1[i]) <= 0x9F)) &&
+ static_cast< unsigned char >(p1[i + 1]) >= 0x80 &&
+ static_cast< unsigned char >(p1[i + 1]) <= 0xBF)
+ {
+ p2[n2++] = ((c & 0x0F) << 12) |
+ ((static_cast< unsigned char >(p1[i]) & 0x3F) << 6) |
+ (static_cast< unsigned char >(p1[i + 1]) & 0x3F);
+ i += 2;
+ } else if (n - 2 > 1 &&
+ ((c == 0xF0 &&
+ static_cast< unsigned char >(p1[i]) >= 0x90 &&
+ static_cast< unsigned char >(p1[i]) <= 0xBF) ||
+ (c >= 0xF1 && c <= 0xF3 &&
+ static_cast< unsigned char >(p1[i]) >= 0x80 &&
+ static_cast< unsigned char >(p1[i]) <= 0xBF) ||
+ (c == 0xF4 &&
+ static_cast< unsigned char >(p1[i]) >= 0x80 &&
+ static_cast< unsigned char >(p1[i]) <= 0x8F)) &&
+ static_cast< unsigned char >(p1[i + 1]) >= 0x80 &&
+ static_cast< unsigned char >(p1[i + 1]) <= 0xBF &&
+ static_cast< unsigned char >(p1[i + 2]) >= 0x80 &&
+ static_cast< unsigned char >(p1[i + 2]) <= 0xBF)
+ {
+ sal_Int32 u = ((c & 0x07) << 18) |
+ ((static_cast< unsigned char >(p1[i]) & 0x3F) << 12) |
+ ((static_cast< unsigned char >(p1[i + 1]) & 0x3F) << 6) |
+ (static_cast< unsigned char >(p1[i + 2]) & 0x3F);
+ i += 3;
+ p2[n2++] = static_cast< WCHAR >(((u - 0x10000) >> 10) | 0xD800);
+ p2[n2++] = static_cast< WCHAR >(
+ ((u - 0x10000) & 0x3FF) | 0xDC00);
+ } else {
+ SetLastError(ERROR_BAD_PATHNAME);
+ return NULL;
+ }
+ break;
+ }
+ }
+ WCHAR * end;
+ if (colon || p2[0] == L'\\') {
+ // Interpret p2 as an absolute path:
+ end = path;
+ } else {
+ // Interpret p2 as a relative path:
+ end = filename(path);
+ }
+ return buildPath(path, path, end, p2, n2);
+}
+
+}
+
+#endif
diff --git a/tools/source/misc/solarmutex.cxx b/tools/source/misc/solarmutex.cxx
new file mode 100644
index 000000000000..5abdfef5e37f
--- /dev/null
+++ b/tools/source/misc/solarmutex.cxx
@@ -0,0 +1,60 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <tools/solarmutex.hxx>
+
+namespace tools
+{
+ static ::vos::IMutex* pSolarMutex = 0;
+
+ ::vos::IMutex* SolarMutex::GetSolarMutex()
+ {
+ return pSolarMutex;
+ }
+
+ void SolarMutex::SetSolarMutex( ::vos::IMutex* pMutex )
+ {
+ pSolarMutex = pMutex;
+ }
+
+ bool SolarMutex::Acquire()
+ {
+ if ( pSolarMutex )
+ pSolarMutex->acquire();
+ else
+ return false;
+ return true;
+ }
+
+ void SolarMutex::Release()
+ {
+ if ( pSolarMutex )
+ pSolarMutex->release();
+ }
+}
diff --git a/tools/source/rc/isofallback.cxx b/tools/source/rc/isofallback.cxx
new file mode 100644
index 000000000000..002a90f580aa
--- /dev/null
+++ b/tools/source/rc/isofallback.cxx
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/isofallback.hxx>
+
+// -----------------------------------------------------------------------
+
+// Return true if valid fallback found
+sal_Bool GetIsoFallback( ByteString& rLanguage )
+{
+ rLanguage.EraseLeadingAndTrailingChars();
+ if( rLanguage.Len() ){
+ xub_StrLen nSepPos = rLanguage.Search( '-' );
+ if ( nSepPos == STRING_NOTFOUND ){
+ if ( rLanguage.Equals("en"))
+ {
+ // en -> ""
+ rLanguage.Erase();
+ return false;
+ }
+ else
+ {
+ // de -> en-US ;
+ rLanguage = ByteString("en-US");
+ return true;
+ }
+ }
+ else if( !( nSepPos == 1 && ( rLanguage.GetChar(0) == 'x' || rLanguage.GetChar(0) == 'X' ) ) )
+ {
+ // de-CH -> de ;
+ // try erase from -
+ rLanguage = rLanguage.GetToken( 0, '-');
+ return true;
+ }
+ }
+ // "" -> ""; x-no-translate -> ""
+ rLanguage.Erase();
+ return false;
+}
+
diff --git a/tools/source/rc/makefile.mk b/tools/source/rc/makefile.mk
new file mode 100644
index 000000000000..f8b46f38a0f7
--- /dev/null
+++ b/tools/source/rc/makefile.mk
@@ -0,0 +1,53 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=rc
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/rc.obj \
+ $(SLO)$/isofallback.obj \
+ $(SLO)$/resmgr.obj \
+ $(SLO)$/resary.obj
+
+OBJFILES= $(OBJ)$/rc.obj \
+ $(OBJ)$/isofallback.obj \
+ $(OBJ)$/resmgr.obj \
+ $(OBJ)$/resary.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/rc/rc.cxx b/tools/source/rc/rc.cxx
new file mode 100644
index 000000000000..e24b8f8824d4
--- /dev/null
+++ b/tools/source/rc/rc.cxx
@@ -0,0 +1,97 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _TOOLS_RC_CXX
+
+#include <string.h>
+#include <tools/date.hxx>
+#include <tools/time.hxx>
+#include <tools/rc.hxx>
+#include <tools/rcid.h>
+
+// =======================================================================
+
+Resource::Resource( const ResId& rResId )
+{
+ GetRes( rResId.SetRT( RSC_RESOURCE ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Resource::GetRes( const ResId& rResId )
+{
+ if( rResId.GetResMgr() )
+ m_pResMgr = rResId.GetResMgr();
+ m_pResMgr->GetResource( rResId, this );
+ IncrementRes( sizeof( RSHEADER_TYPE ) );
+}
+
+// -----------------------------------------------------------------------
+
+// =======================================================================
+
+Time::Time( const ResId& rResId )
+{
+ nTime = 0;
+ rResId.SetRT( RSC_TIME );
+ ResMgr* pResMgr = NULL;
+
+ ResMgr::GetResourceSkipHeader( rResId, &pResMgr );
+
+ ULONG nObjMask = (USHORT)pResMgr->ReadLong();
+
+ if ( 0x01 & nObjMask )
+ SetHour( (USHORT)pResMgr->ReadShort() );
+ if ( 0x02 & nObjMask )
+ SetMin( (USHORT)pResMgr->ReadShort() );
+ if ( 0x04 & nObjMask )
+ SetSec( (USHORT)pResMgr->ReadShort() );
+ if ( 0x08 & nObjMask )
+ Set100Sec( (USHORT)pResMgr->ReadShort() );
+}
+
+// =======================================================================
+
+Date::Date( const ResId& rResId ) : nDate(0)
+{
+ rResId.SetRT( RSC_DATE );
+ ResMgr* pResMgr = NULL;
+
+ ResMgr::GetResourceSkipHeader( rResId, &pResMgr );
+
+ ULONG nObjMask = (USHORT)pResMgr->ReadLong();
+
+ if ( 0x01 & nObjMask )
+ SetYear( (USHORT)pResMgr->ReadShort() );
+ if ( 0x02 & nObjMask )
+ SetMonth( (USHORT)pResMgr->ReadShort() );
+ if ( 0x04 & nObjMask )
+ SetDay( (USHORT)pResMgr->ReadShort() );
+}
diff --git a/tools/source/rc/resary.cxx b/tools/source/rc/resary.cxx
new file mode 100644
index 000000000000..a55a4f644a9f
--- /dev/null
+++ b/tools/source/rc/resary.cxx
@@ -0,0 +1,78 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _TOOLS_RESARY_CXX
+#include <tools/resary.hxx>
+#include <tools/rcid.h>
+
+// =======================================================================
+
+ResStringArray::ResStringArray( const ResId& rResId )
+{
+ rResId.SetRT( RSC_STRINGARRAY );
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr && pMgr->GetResource( rResId ) )
+ {
+ pMgr->GetClass();
+ pMgr->Increment( sizeof( RSHEADER_TYPE ) );
+ const sal_uInt32 nItems = pMgr->ReadLong();
+ if ( nItems )
+ {
+ m_aStrings.reserve( nItems );
+ for ( sal_uInt32 i = 0; i < nItems; i++ )
+ {
+ // load string
+ m_aStrings.push_back( ImplResStringItem( pMgr->ReadString() ) );
+
+ // load value
+ m_aStrings[i].m_nValue = pMgr->ReadLong();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ResStringArray::~ResStringArray()
+{
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 ResStringArray::FindIndex( long nValue ) const
+{
+ const sal_uInt32 nItems = m_aStrings.size();
+ for ( sal_uInt32 i = 0; i < nItems; i++ )
+ {
+ if ( m_aStrings[i].m_nValue == nValue )
+ return i;
+ }
+ return RESARRAY_INDEX_NOTFOUND;
+}
diff --git a/tools/source/rc/resmgr.cxx b/tools/source/rc/resmgr.cxx
new file mode 100644
index 000000000000..daeaf8e4c3a5
--- /dev/null
+++ b/tools/source/rc/resmgr.cxx
@@ -0,0 +1,2074 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vos/signal.hxx>
+#include <tools/debug.hxx>
+#ifndef _TABLE_HXX
+#include <tools/table.hxx>
+#endif
+#include <tools/stream.hxx>
+#include <tools/resmgr.hxx>
+#include <tools/rc.hxx>
+#include <tools/rcid.h>
+#include <osl/endian.h>
+#include <osl/process.h>
+#include <osl/thread.h>
+#include <osl/file.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/urlobj.hxx>
+#include <rtl/instance.hxx>
+#include <rtl/bootstrap.hxx>
+#include <i18npool/mslangid.hxx>
+#include <tools/simplerm.hxx>
+
+#include <tools/isofallback.hxx>
+
+#include <functional>
+#include <algorithm>
+#include <hash_map>
+#include <list>
+#include <set>
+
+#ifdef UNX
+#define SEARCH_PATH_DELIMITER_CHAR_STRING ":"
+#define SEARCH_PATH_DELIMITER ':'
+#else
+#define SEARCH_PATH_DELIMITER_CHAR_STRING ";"
+#define SEARCH_PATH_DELIMITER ';'
+#endif
+
+#define SEARCH_PATH_DELIMITER_STRING ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SEARCH_PATH_DELIMITER_CHAR_STRING ) )
+
+using namespace rtl;
+using namespace osl;
+
+// for thread safety
+static osl::Mutex* pResMgrMutex = NULL;
+static osl::Mutex& getResMgrMutex()
+{
+ if( !pResMgrMutex )
+ {
+ osl::Guard<osl::Mutex> aGuard( *osl::Mutex::getGlobalMutex() );
+ if( ! pResMgrMutex )
+ pResMgrMutex = new osl::Mutex();
+ }
+ return *pResMgrMutex;
+}
+
+struct ImpContent;
+class InternalResMgr
+{
+ friend class ResMgr;
+ friend class SimpleResMgr;
+ friend class ResMgrContainer;
+
+ ImpContent * pContent;
+ UINT32 nOffCorrection;
+ BYTE * pStringBlock;
+ SvStream * pStm;
+ BOOL bEqual2Content;
+ UINT32 nEntries;
+ OUString aFileName;
+ OUString aPrefix;
+ OUString aResName;
+ bool bSingular;
+ com::sun::star::lang::Locale aLocale;
+ std::hash_map<sal_uInt64, int>* pResUseDump;
+
+ InternalResMgr( const OUString& rFileURL,
+ const OUString& aPrefix,
+ const OUString& aResName,
+ const com::sun::star::lang::Locale& rLocale );
+ ~InternalResMgr();
+ BOOL Create();
+
+ BOOL IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const;
+ void * LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
+ void **pResHandle );
+public:
+ void FreeGlobalRes( void *, void * );
+
+ SvStream * GetBitmapStream( sal_uInt32 nResId );
+};
+
+// =======================================================================
+
+class ResMgrContainer
+{
+ static ResMgrContainer* pOneInstance;
+
+ struct ContainerElement
+ {
+ InternalResMgr* pResMgr;
+ OUString aFileURL;
+ int nRefCount;
+ int nLoadCount;
+
+ ContainerElement() :
+ pResMgr( NULL ),
+ nRefCount( 0 ),
+ nLoadCount( 0 )
+ {}
+ };
+
+ std::hash_map< OUString, ContainerElement, OUStringHash> m_aResFiles;
+ com::sun::star::lang::Locale m_aDefLocale;
+
+ ResMgrContainer() { init(); }
+ ~ResMgrContainer();
+
+ void init();
+ public:
+
+ static ResMgrContainer& get();
+ static void release();
+
+ InternalResMgr* getResMgr( const OUString& rPrefix,
+ com::sun::star::lang::Locale& rLocale,
+ bool bForceNewInstance = false
+ );
+ InternalResMgr* getNextFallback( InternalResMgr* pResMgr );
+
+ void freeResMgr( InternalResMgr* pResMgr );
+
+ void setDefLocale( const com::sun::star::lang::Locale& rLocale )
+ { m_aDefLocale = rLocale; }
+ const com::sun::star::lang::Locale& getDefLocale() const
+ { return m_aDefLocale; }
+};
+
+ResMgrContainer* ResMgrContainer::pOneInstance = NULL;
+
+ResMgrContainer& ResMgrContainer::get()
+{
+ if( ! pOneInstance )
+ pOneInstance = new ResMgrContainer();
+ return *pOneInstance;
+}
+
+ResMgrContainer::~ResMgrContainer()
+{
+ for( std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it =
+ m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
+ {
+ OSL_TRACE( "Resource file %s loaded %d times\n",
+ OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr(),
+ it->second.nLoadCount );
+ delete it->second.pResMgr;
+ }
+}
+
+void ResMgrContainer::release()
+{
+ delete pOneInstance;
+ pOneInstance = NULL;
+}
+
+void ResMgrContainer::init()
+{
+ // get resource path
+ std::list< OUString > aDirs;
+ sal_Int32 nIndex = 0;
+
+ // 1. fixed locations
+ rtl::OUString uri(
+ RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program/resource"));
+ rtl::Bootstrap::expandMacros(uri);
+ aDirs.push_back(uri);
+ uri = rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/program/resource"));
+ rtl::Bootstrap::expandMacros(uri);
+ aDirs.push_back(uri);
+
+ // 2. in STAR_RESOURCEPATH
+ const sal_Char* pEnv = getenv( "STAR_RESOURCEPATH" );
+ if( pEnv )
+ {
+ OUString aEnvPath( OStringToOUString( OString( pEnv ), osl_getThreadTextEncoding() ) );
+ nIndex = 0;
+ while( nIndex >= 0 )
+ {
+ OUString aPathElement( aEnvPath.getToken( 0, SEARCH_PATH_DELIMITER, nIndex ) );
+ if( aPathElement.getLength() )
+ {
+ OUString aFileURL;
+ File::getFileURLFromSystemPath( aPathElement, aFileURL );
+ aDirs.push_back( aFileURL);
+ }
+ }
+ }
+
+ // collect all possible resource files
+ for( std::list< OUString >::const_iterator dir_it = aDirs.begin(); dir_it != aDirs.end(); ++dir_it )
+ {
+ Directory aDir( *dir_it );
+ if( aDir.open() == FileBase::E_None )
+ {
+ DirectoryItem aItem;
+ while( aDir.getNextItem( aItem ) == FileBase::E_None )
+ {
+ FileStatus aStatus(FileStatusMask_FileName);
+ if( aItem.getFileStatus( aStatus ) == FileBase::E_None )
+ {
+ OUString aFileName = aStatus.getFileName();
+ if( aFileName.getLength() < 5 )
+ continue;
+ if( ! aFileName.endsWithIgnoreAsciiCaseAsciiL( ".res", 4 ) )
+ continue;
+ OUString aResName = aFileName.copy( 0, aFileName.getLength()-4 );
+ if( m_aResFiles.find( aResName ) != m_aResFiles.end() )
+ continue;
+ OUStringBuffer aURL( dir_it->getLength() + aFileName.getLength() + 1 );
+ aURL.append( *dir_it );
+ if( !dir_it->endsWithIgnoreAsciiCaseAsciiL( "/", 1 ) )
+ aURL.append( sal_Unicode('/') );
+ aURL.append( aFileName );
+ m_aResFiles[ aResName ].aFileURL = aURL.makeStringAndClear();
+ }
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ OSL_TRACE( "opening dir %s failed\n", OUStringToOString( *dir_it, osl_getThreadTextEncoding() ).getStr() );
+ #endif
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ for( std::hash_map< OUString, ContainerElement, OUStringHash >::const_iterator it =
+ m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
+ {
+ OSL_TRACE( "ResMgrContainer: %s -> %s\n",
+ OUStringToOString( it->first, osl_getThreadTextEncoding() ).getStr(),
+ OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr() );
+ }
+ #endif
+
+ // set default language
+ LanguageType nLang = MsLangId::getSystemUILanguage();
+ MsLangId::convertLanguageToLocale(nLang, m_aDefLocale);
+}
+
+InternalResMgr* ResMgrContainer::getResMgr( const OUString& rPrefix,
+ com::sun::star::lang::Locale& rLocale,
+ bool bForceNewInstance
+ )
+{
+ com::sun::star::lang::Locale aLocale( rLocale );
+ OUStringBuffer aSearch( rPrefix.getLength() + 16 );
+ std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it = m_aResFiles.end();
+
+ int nTries = 0;
+ if( aLocale.Language.getLength() > 0 )
+ nTries = 1;
+ if( aLocale.Country.getLength() > 0 )
+ nTries = 2;
+ if( aLocale.Variant.getLength() > 0 )
+ nTries = 3;
+ while( nTries-- )
+ {
+ aSearch.append( rPrefix );
+ if( nTries > -1 )
+ {
+ aSearch.append( aLocale.Language );
+ }
+ if( nTries > 0 )
+ {
+ aSearch.append( sal_Unicode('-') );
+ aSearch.append( aLocale.Country );
+ }
+ if( nTries > 1 )
+ {
+ aSearch.append( sal_Unicode('-') );
+ aSearch.append( aLocale.Variant );
+ }
+ it = m_aResFiles.find( aSearch.makeStringAndClear() );
+ if( it != m_aResFiles.end() )
+ {
+ // ensure InternalResMgr existance
+ if( ! it->second.pResMgr )
+ {
+ InternalResMgr* pImp =
+ new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
+ if( ! pImp->Create() )
+ {
+ delete pImp;
+ continue;
+ }
+ it->second.pResMgr = pImp;
+ }
+ break;
+ }
+ if( nTries == 0 && !aLocale.Language.equalsIgnoreAsciiCaseAscii( "en" ) )
+ {
+ // locale fallback failed
+ // fallback to en-US locale
+ nTries = 2;
+ aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) );
+ aLocale.Country = OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) );
+ aLocale.Variant = OUString();
+ }
+ }
+ // try if there is anything with this prefix at all
+ if( it == m_aResFiles.end() )
+ {
+ aLocale = com::sun::star::lang::Locale();
+ it = m_aResFiles.find( rPrefix );
+ if( it == m_aResFiles.end() )
+ {
+ for( it = m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
+ {
+ if( it->first.matchIgnoreAsciiCase( rPrefix ) )
+ {
+ // ensure InternalResMgr existance
+ if( ! it->second.pResMgr )
+ {
+ InternalResMgr* pImp =
+ new InternalResMgr( it->second.aFileURL,
+ rPrefix,
+ it->first,
+ aLocale );
+ if( ! pImp->Create() )
+ {
+ delete pImp;
+ continue;
+ }
+ it->second.pResMgr = pImp;
+ }
+ // try to guess locale
+ sal_Int32 nIndex = rPrefix.getLength();
+ aLocale.Language = it->first.getToken( 0, '-', nIndex );
+ if( nIndex > 0 )
+ aLocale.Country = it->first.getToken( 0, '-', nIndex );
+ if( nIndex > 0 )
+ aLocale.Variant = it->first.getToken( 0, '-', nIndex );
+ break;
+ }
+ }
+ }
+ }
+ // give up
+ if( it == m_aResFiles.end() )
+ {
+ OUStringBuffer sKey = rPrefix;
+ sKey.append( rLocale.Language );
+ if( rLocale.Country.getLength() )
+ {
+ sKey.append( sal_Unicode('-') );
+ sKey.append( rLocale.Country );
+ }
+ if( rLocale.Variant.getLength() )
+ {
+ sKey.append( sal_Unicode('-') );
+ sKey.append( rLocale.Variant );
+ } // if( aLocale.Variant.getLength() )
+ ::rtl::OUString sURL = sKey.makeStringAndClear();
+ sURL += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".res"));
+ if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
+ {
+ m_aResFiles[ sURL ].aFileURL = sURL;
+ return getResMgr(rPrefix,rLocale,bForceNewInstance);
+ } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
+ return NULL;
+ }
+
+ rLocale = aLocale;
+ // at this point it->second.pResMgr must be filled either by creating a new one
+ // (then the refcount is still 0) or because we already had one
+ InternalResMgr* pImp = it->second.pResMgr;
+
+ if( it->second.nRefCount == 0 )
+ it->second.nLoadCount++;
+
+ // for SimpleResMgr
+ if( bForceNewInstance )
+ {
+ if( it->second.nRefCount == 0 )
+ {
+ // shortcut: the match algorithm already created the InternalResMgr
+ // take it instead of creating yet another one
+ it->second.pResMgr = NULL;
+ pImp->bSingular = true;
+ }
+ else
+ {
+ pImp = new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
+ pImp->bSingular = true;
+ if( !pImp->Create() )
+ {
+ delete pImp;
+ pImp = NULL;
+ }
+ else
+ it->second.nLoadCount++;
+ }
+ }
+ else
+ it->second.nRefCount++;
+
+ return pImp;
+}
+
+InternalResMgr* ResMgrContainer::getNextFallback( InternalResMgr* pMgr )
+{
+ com::sun::star::lang::Locale aLocale = pMgr->aLocale;
+ if( aLocale.Variant.getLength() )
+ aLocale.Variant = OUString();
+ else if( aLocale.Country.getLength() )
+ aLocale.Country = OUString();
+ else if( ! aLocale.Language.equalsIgnoreAsciiCaseAscii( "en" ) )
+ {
+ aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) );
+ aLocale.Country = OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) );
+ }
+ InternalResMgr* pNext = getResMgr( pMgr->aPrefix, aLocale, pMgr->bSingular );
+ // prevent recursion
+ if( pNext == pMgr || pNext->aResName.equals( pMgr->aResName ) )
+ {
+ if( pNext->bSingular )
+ delete pNext;
+ pNext = NULL;
+ }
+ return pNext;
+}
+
+void ResMgrContainer::freeResMgr( InternalResMgr* pResMgr )
+{
+ if( pResMgr->bSingular )
+ delete pResMgr;
+ else
+ {
+ std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it =
+ m_aResFiles.find( pResMgr->aResName );
+ if( it != m_aResFiles.end() )
+ {
+ DBG_ASSERT( it->second.nRefCount > 0, "InternalResMgr freed too often" );
+ if( it->second.nRefCount > 0 )
+ it->second.nRefCount--;
+ if( it->second.nRefCount == 0 )
+ {
+ delete it->second.pResMgr;
+ it->second.pResMgr = NULL;
+ }
+ }
+ }
+}
+
+// =======================================================================
+
+void Resource::TestRes()
+{
+ if( m_pResMgr )
+ m_pResMgr->TestStack( this );
+}
+
+struct ImpContent
+{
+ sal_uInt64 nTypeAndId;
+ sal_uInt32 nOffset;
+};
+
+struct ImpContentLessCompare : public ::std::binary_function< ImpContent, ImpContent, bool>
+{
+ inline bool operator() (const ImpContent& lhs, const ImpContent& rhs) const
+ {
+ return lhs.nTypeAndId < rhs.nTypeAndId;
+ }
+};
+
+struct ImpContentMixLessCompare : public ::std::binary_function< ImpContent, sal_uInt64, bool>
+{
+ inline bool operator() (const ImpContent& lhs, const sal_uInt64& rhs) const
+ {
+ return lhs.nTypeAndId < rhs;
+ }
+ inline bool operator() (const sal_uInt64& lhs, const ImpContent& rhs) const
+ {
+ return lhs < rhs.nTypeAndId;
+ }
+};
+
+
+// =======================================================================
+
+static ResHookProc pImplResHookProc = 0;
+
+// =======================================================================
+
+SvStream * InternalResMgr::GetBitmapStream( sal_uInt32 nId )
+{
+ // Anfang der Strings suchen
+ ImpContent * pFind = ::std::lower_bound(pContent,
+ pContent + nEntries,
+ ((sal_uInt64(RT_SYS_BITMAP) << 32) | nId),
+ ImpContentMixLessCompare());
+ if ( (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == ((sal_uInt64(RT_SYS_BITMAP) << 32) | nId)) )
+ {
+ pStm->Seek( pFind->nOffset );
+ return pStm;
+ }
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+InternalResMgr::InternalResMgr( const OUString& rFileURL,
+ const OUString& rPrefix,
+ const OUString& rResName,
+ const com::sun::star::lang::Locale& rLocale )
+ : pContent( NULL )
+ , pStringBlock( NULL )
+ , pStm( NULL )
+ , bEqual2Content( TRUE )
+ , nEntries( 0 )
+ , aFileName( rFileURL )
+ , aPrefix( rPrefix )
+ , aResName( rResName )
+ , bSingular( false )
+ , aLocale( rLocale )
+ , pResUseDump( 0 )
+{
+}
+
+// -----------------------------------------------------------------------
+
+InternalResMgr::~InternalResMgr()
+{
+ rtl_freeMemory(pContent);
+ rtl_freeMemory(pStringBlock);
+ delete pStm;
+
+#ifdef DBG_UTIL
+ if( pResUseDump )
+ {
+ const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
+ if ( pLogFile )
+ {
+ SvFileStream aStm( UniString( pLogFile, RTL_TEXTENCODING_ASCII_US ), STREAM_WRITE );
+ aStm.Seek( STREAM_SEEK_TO_END );
+ ByteString aLine( "FileName: " );
+ aLine.Append( ByteString( OUStringToOString( aFileName, RTL_TEXTENCODING_UTF8 ) ) );
+ aStm.WriteLine( aLine );
+
+ for( std::hash_map<sal_uInt64, int>::const_iterator it = pResUseDump->begin();
+ it != pResUseDump->end(); ++it )
+ {
+ sal_uInt64 nKeyId = it->first;
+ aLine.Assign( "Type/Id: " );
+ aLine.Append( ByteString::CreateFromInt32( sal::static_int_cast< sal_Int32 >((nKeyId >> 32) & 0xFFFFFFFF) ) );
+ aLine.Append( '/' );
+ aLine.Append( ByteString::CreateFromInt32( sal::static_int_cast< sal_Int32 >(nKeyId & 0xFFFFFFFF) ) );
+ aStm.WriteLine( aLine );
+ }
+ }
+ }
+#endif
+
+ delete pResUseDump;
+}
+
+// -----------------------------------------------------------------------
+
+
+BOOL InternalResMgr::Create()
+{
+ ResMgrContainer::get();
+ BOOL bDone = FALSE;
+
+ pStm = new SvFileStream( aFileName, (STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE) );
+ if( pStm->GetError() == 0 )
+ {
+ INT32 lContLen = 0;
+
+ pStm->Seek( STREAM_SEEK_TO_END );
+ /*
+ if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize,
+ PROT_READ, MAP_PRIVATE,
+ fRes, 0 ) ) != (RSHEADER_TYPE *)-1)
+ */
+ pStm->SeekRel( - (int)sizeof( lContLen ) );
+ pStm->Read( &lContLen, sizeof( lContLen ) );
+ // is bigendian, swab to the right endian
+ lContLen = ResMgr::GetLong( &lContLen );
+ pStm->SeekRel( -lContLen );
+ // allocate stored ImpContent data (12 bytes per unit)
+ BYTE* pContentBuf = (BYTE*)rtl_allocateMemory( lContLen );
+ pStm->Read( pContentBuf, lContLen );
+ // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12)
+ pContent = (ImpContent *)rtl_allocateMemory( sizeof(ImpContent)*lContLen/12 );
+ // Auf die Anzahl der ImpContent k�rzen
+ nEntries = (UINT32)lContLen / 12;
+ bEqual2Content = TRUE; // Die Daten der Resourcen liegen
+ // genauso wie das Inhaltsverzeichnis
+ BOOL bSorted = TRUE;
+ if( nEntries )
+ {
+#ifdef DBG_UTIL
+ const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
+ if ( pLogFile )
+ {
+ pResUseDump = new std::hash_map<sal_uInt64, int>;
+ for( sal_uInt32 i = 0; i < nEntries; ++i )
+ (*pResUseDump)[pContent[i].nTypeAndId] = 1;
+ }
+#endif
+ // swap the content to the right endian
+ pContent[0].nTypeAndId = ResMgr::GetUInt64( pContentBuf );
+ pContent[0].nOffset = ResMgr::GetLong( pContentBuf+8 );
+ sal_uInt32 nCount = nEntries - 1;
+ for( sal_uInt32 i = 0,j=1; i < nCount; ++i,++j )
+ {
+ // swap the content to the right endian
+ pContent[j].nTypeAndId = ResMgr::GetUInt64( pContentBuf + (12*j) );
+ pContent[j].nOffset = ResMgr::GetLong( pContentBuf + (12*j+8) );
+ if( pContent[i].nTypeAndId >= pContent[j].nTypeAndId )
+ bSorted = FALSE;
+ if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL)
+ && pContent[i].nOffset >= pContent[j].nOffset )
+ bEqual2Content = FALSE;
+ }
+ }
+ rtl_freeMemory( pContentBuf );
+#ifndef OS2
+ OSL_ENSURE( bSorted, "content not sorted" );
+#endif
+ OSL_ENSURE( bEqual2Content, "resource structure wrong" );
+ if( !bSorted )
+ ::std::sort(pContent,pContent+nEntries,ImpContentLessCompare());
+ // qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
+
+ bDone = TRUE;
+ }
+
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const
+{
+ // Anfang der Strings suchen
+ sal_uInt64 nValue = ((sal_uInt64(nRT) << 32) | nId);
+ ImpContent * pFind = ::std::lower_bound(pContent,
+ pContent + nEntries,
+ nValue,
+ ImpContentMixLessCompare());
+ return (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == nValue);
+}
+
+// -----------------------------------------------------------------------
+
+void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
+ void **pResHandle )
+{
+#ifdef DBG_UTIL
+ if( pResUseDump )
+ pResUseDump->erase( (sal_uInt64(nRT) << 32) | nId );
+#endif
+ // Anfang der Strings suchen
+ sal_uInt64 nValue = ((sal_uInt64(nRT) << 32) | nId);
+ ImpContent* pEnd = (pContent + nEntries);
+ ImpContent* pFind = ::std::lower_bound( pContent,
+ pEnd,
+ nValue,
+ ImpContentMixLessCompare());
+ if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
+ {
+ if( nRT == RSC_STRING && bEqual2Content )
+ {
+ // String Optimierung
+ if( !pStringBlock )
+ {
+ // Anfang der Strings suchen
+ ImpContent * pFirst = pFind;
+ ImpContent * pLast = pFirst;
+ while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 32) == RSC_STRING )
+ --pFirst;
+ while( pLast < pEnd && (pLast->nTypeAndId >> 32) == RSC_STRING )
+ ++pLast;
+ nOffCorrection = pFirst->nOffset;
+ UINT32 nSize;
+ --pLast;
+ pStm->Seek( pLast->nOffset );
+ RSHEADER_TYPE aHdr;
+ pStm->Read( &aHdr, sizeof( aHdr ) );
+ nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection;
+ pStringBlock = (BYTE*)rtl_allocateMemory( nSize );
+ pStm->Seek( pFirst->nOffset );
+ pStm->Read( pStringBlock, nSize );
+ }
+ *pResHandle = pStringBlock;
+ return (BYTE*)pStringBlock + pFind->nOffset - nOffCorrection;
+ } // if( nRT == RSC_STRING && bEqual2Content )
+ else
+ {
+ *pResHandle = 0;
+ RSHEADER_TYPE aHeader;
+ pStm->Seek( pFind->nOffset );
+ pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) );
+ void * pRes = rtl_allocateMemory( aHeader.GetGlobOff() );
+ memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) );
+ pStm->Read( (BYTE*)pRes + sizeof( RSHEADER_TYPE ),
+ aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) );
+ return pRes;
+ }
+ } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
+ *pResHandle = 0;
+ //Resource holen
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource )
+{
+ if ( !pResHandle )
+ // REsource wurde extra allokiert
+ rtl_freeMemory(pResource);
+}
+
+// =======================================================================
+
+#ifdef DBG_UTIL
+
+UniString GetTypeRes_Impl( const ResId& rTypeId )
+{
+ // Funktion verlassen, falls Resourcefehler in dieser Funktion
+ static int bInUse = FALSE;
+ UniString aTypStr( UniString::CreateFromInt32( rTypeId.GetId() ) );
+
+ if ( !bInUse )
+ {
+ bInUse = TRUE;
+
+ ResId aResId( sal_uInt32(RSCVERSION_ID), *rTypeId.GetResMgr() );
+ aResId.SetRT( RSC_VERSIONCONTROL );
+
+ if ( rTypeId.GetResMgr()->GetResource( aResId ) )
+ {
+ rTypeId.SetRT( RSC_STRING );
+ if ( rTypeId.GetResMgr()->IsAvailable( rTypeId ) )
+ {
+ aTypStr = UniString( rTypeId );
+ // Versions Resource Klassenzeiger ans Ende setzen
+ rTypeId.GetResMgr()->Increment( sizeof( RSHEADER_TYPE ) );
+ }
+ }
+ bInUse = FALSE;
+ }
+
+ return aTypStr;
+}
+
+// -----------------------------------------------------------------------
+
+void ResMgr::RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr,
+ RESOURCE_TYPE nRT, sal_uInt32 nId,
+ std::vector< ImpRCStack >& rResStack, int nDepth )
+{
+ // create a separate ResMgr with its own stack
+ // first get a second reference of the InternalResMgr
+ InternalResMgr* pImp =
+ ResMgrContainer::get().getResMgr( pResMgr->pImpRes->aPrefix,
+ pResMgr->pImpRes->aLocale,
+ true );
+
+ ResMgr* pNewResMgr = new ResMgr( pImp );
+
+ ByteString aStr = OUStringToOString( pResMgr->GetFileName(), RTL_TEXTENCODING_UTF8 );
+ if ( aStr.Len() )
+ aStr += '\n';
+
+ aStr.Append( "Class: " );
+ aStr.Append( ByteString( GetTypeRes_Impl( ResId( nRT, *pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) );
+ aStr.Append( ", Id: " );
+ aStr.Append( ByteString::CreateFromInt32( (long)nId ) );
+ aStr.Append( ". " );
+ aStr.Append( pMessage );
+
+ aStr.Append( "\nResource Stack\n" );
+ while( nDepth > 0 )
+ {
+ aStr.Append( "Class: " );
+ aStr.Append( ByteString( GetTypeRes_Impl( ResId( rResStack[nDepth].pResource->GetRT(), *pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) );
+ aStr.Append( ", Id: " );
+ aStr.Append( ByteString::CreateFromInt32( (long)rResStack[nDepth].pResource->GetId() ) );
+ nDepth--;
+ }
+
+ // clean up
+ delete pNewResMgr;
+
+ DBG_ERROR( aStr.GetBuffer() );
+}
+
+#endif
+
+// =======================================================================
+
+static void RscException_Impl()
+{
+ switch ( NAMESPACE_VOS(OSignalHandler)::raise( OSL_SIGNAL_USER_RESOURCEFAILURE, (void*)"" ) )
+ {
+ case NAMESPACE_VOS(OSignalHandler)::TAction_CallNextHandler:
+ abort();
+
+ case NAMESPACE_VOS(OSignalHandler)::TAction_Ignore:
+ return;
+
+ case NAMESPACE_VOS(OSignalHandler)::TAction_AbortApplication:
+ abort();
+
+ case NAMESPACE_VOS(OSignalHandler)::TAction_KillApplication:
+ exit(-1);
+ }
+}
+
+// =======================================================================
+
+void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, sal_uInt32 Id )
+{
+ pResource = NULL;
+ pClassRes = NULL;
+ Flags = RC_NOTYPE;
+ aResHandle = NULL;
+ pResObj = pObj;
+ nId = Id & ~RSC_DONTRELEASE; //TLX: Besser Init aendern
+ pResMgr = pMgr;
+ if ( !(Id & RSC_DONTRELEASE) )
+ Flags |= RC_AUTORELEASE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImpRCStack::Clear()
+{
+ pResource = NULL;
+ pClassRes = NULL;
+ Flags = RC_NOTYPE;
+ aResHandle = NULL;
+ pResObj = NULL;
+ nId = 0;
+ pResMgr = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+static RSHEADER_TYPE* LocalResource( const ImpRCStack* pStack,
+ RESOURCE_TYPE nRTType,
+ sal_uInt32 nId )
+{
+ // Gibt die Position der Resource zurueck, wenn sie gefunden wurde.
+ // Ansonsten gibt die Funktion Null zurueck.
+ RSHEADER_TYPE* pTmp; // Zeiger auf Kind-Resourceobjekte
+ RSHEADER_TYPE* pEnd; // Zeiger auf das Ende der Resource
+
+ if ( pStack->pResource && pStack->pClassRes )
+ {
+ pTmp = (RSHEADER_TYPE*)
+ ((BYTE*)pStack->pResource + pStack->pResource->GetLocalOff());
+ pEnd = (RSHEADER_TYPE*)
+ ((BYTE*)pStack->pResource + pStack->pResource->GetGlobOff());
+ while ( pTmp != pEnd )
+ {
+ if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId )
+ return pTmp;
+ pTmp = (RSHEADER_TYPE*)((BYTE*)pTmp + pTmp->GetGlobOff());
+ }
+ }
+
+ return NULL;
+}
+
+// =======================================================================
+
+void* ResMgr::pEmptyBuffer = NULL;
+
+void* ResMgr::getEmptyBuffer()
+{
+ if( ! pEmptyBuffer )
+ pEmptyBuffer = rtl_allocateZeroMemory( 1024 );
+ return pEmptyBuffer;
+}
+
+void ResMgr::DestroyAllResMgr()
+{
+ {
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+ if( pEmptyBuffer )
+ {
+ rtl_freeMemory( pEmptyBuffer );
+ pEmptyBuffer = NULL;
+ }
+ ResMgrContainer::release();
+ }
+ delete pResMgrMutex;
+ pResMgrMutex = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void ResMgr::Init( const OUString& rFileName )
+{
+ (void) rFileName; // avoid warning about unused parameter
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if ( !pImpRes )
+ {
+#ifdef DBG_UTIL
+ ByteString aStr( "Resourcefile not found:\n" );
+ aStr += ByteString( OUStringToOString( rFileName, RTL_TEXTENCODING_UTF8 ) );
+ DBG_ERROR( aStr.GetBuffer() );
+#endif
+ RscException_Impl();
+ }
+#ifdef DBG_UTIL
+ else
+ {
+ void* aResHandle = 0; // Hilfvariable fuer Resource
+ void* pVoid; // Zeiger auf die Resource
+
+ pVoid = pImpRes->LoadGlobalRes( RSC_VERSIONCONTROL, RSCVERSION_ID,
+ &aResHandle );
+ if ( pVoid )
+ pImpRes->FreeGlobalRes( aResHandle, pVoid );
+ else
+ {
+ ByteString aStr( "Wrong version:\n" );
+ aStr += ByteString( OUStringToOString( pImpRes->aFileName, RTL_TEXTENCODING_UTF8 ) );
+ DbgError( aStr.GetBuffer() );
+ }
+ }
+#endif
+ nCurStack = -1;
+ aStack.clear();
+ pFallbackResMgr = pOriginalResMgr = NULL;
+ incStack();
+}
+
+// -----------------------------------------------------------------------
+
+ResMgr::ResMgr( InternalResMgr * pImpMgr )
+{
+ pImpRes = pImpMgr;
+ Init( pImpMgr->aFileName );
+}
+
+// -----------------------------------------------------------------------
+
+ResMgr::~ResMgr()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ ResMgrContainer::get().freeResMgr( pImpRes );
+
+ // clean up possible left rc stack frames
+ while( nCurStack > 0 )
+ {
+ if( ( aStack[nCurStack].Flags & (RC_GLOBAL | RC_NOTFOUND) ) == RC_GLOBAL )
+ pImpRes->FreeGlobalRes( aStack[nCurStack].aResHandle,
+ aStack[nCurStack].pResource );
+ nCurStack--;
+ }
+}
+
+
+void ResMgr::incStack()
+{
+ nCurStack++;
+ if( nCurStack >= int(aStack.size()) )
+ aStack.push_back( ImpRCStack() );
+ aStack[nCurStack].Clear();
+
+ DBG_ASSERT( nCurStack < 32, "Resource stack unreasonably large" );
+}
+
+void ResMgr::decStack()
+{
+ DBG_ASSERT( nCurStack > 0, "resource stack underrun !" );
+ if( (aStack[nCurStack].Flags & RC_FALLBACK_UP) )
+ {
+ nCurStack--;
+ // warning: this will delete *this, see below
+ pOriginalResMgr->decStack();
+ }
+ else
+ {
+ ImpRCStack& rTop = aStack[nCurStack];
+ if( (rTop.Flags & RC_FALLBACK_DOWN) )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ OSL_TRACE( "returning from fallback %s\n",
+ OUStringToOString(pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ).getStr() );
+ #endif
+ delete pFallbackResMgr;
+ pFallbackResMgr = NULL;
+ }
+ nCurStack--;
+ }
+}
+
+#ifdef DBG_UTIL
+
+void ResMgr::TestStack( const Resource* pResObj )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if ( DbgIsResource() )
+ {
+ for( int i = 1; i <= nCurStack; ++i )
+ {
+ if ( aStack[i].pResObj == pResObj )
+ {
+#ifdef DBG_UTIL
+ RscError_Impl( "Resource not freed! ", this,
+ aStack[i].pResource->GetRT(),
+ aStack[i].pResource->GetId(),
+ aStack, i-1 );
+#endif
+ }
+ }
+ }
+}
+
+#else
+
+void ResMgr::TestStack( const Resource* )
+{
+}
+
+#endif
+
+// -----------------------------------------------------------------------
+BOOL ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ BOOL bAvailable = FALSE;
+ RSHEADER_TYPE* pClassRes = rId.GetpResource();
+ RESOURCE_TYPE nRT = rId.GetRT2();
+ sal_uInt32 nId = rId.GetId();
+ const ResMgr* pMgr = rId.GetResMgr();
+
+ if ( !pMgr )
+ pMgr = this;
+
+ if( pMgr->pFallbackResMgr )
+ {
+ ResId aId( rId );
+ aId.SetResMgr( NULL );
+ return pMgr->pFallbackResMgr->IsAvailable( aId, pResObj );
+ }
+
+ if ( !pResObj || pResObj == pMgr->aStack[pMgr->nCurStack].pResObj )
+ {
+ if ( !pClassRes )
+ pClassRes = LocalResource( &pMgr->aStack[pMgr->nCurStack], nRT, nId );
+ if ( pClassRes )
+ {
+ if ( pClassRes->GetRT() == nRT )
+ bAvailable = TRUE;
+ }
+ }
+
+ // vieleicht globale Resource
+ if ( !pClassRes )
+ bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId );
+
+ return bAvailable;
+}
+
+// -----------------------------------------------------------------------
+
+void* ResMgr::GetClass()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->GetClass();
+
+ return aStack[nCurStack].pClassRes;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ResMgr::GetResource( const ResId& rId, const Resource* pResObj )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ {
+ ResId aId( rId );
+ aId.SetResMgr( NULL );
+ return pFallbackResMgr->GetResource( aId, pResObj );
+ }
+
+ ResMgr* pMgr = rId.GetResMgr();
+ if ( pMgr && (this != pMgr) )
+ return pMgr->GetResource( rId, pResObj );
+
+ // normally Increment will pop the context; this is
+ // not possible in RC_NOTFOUND case, so pop a frame here
+ ImpRCStack* pTop = &aStack[nCurStack];
+ if( (pTop->Flags & RC_NOTFOUND) )
+ {
+ decStack();
+ }
+
+ RSHEADER_TYPE* pClassRes = rId.GetpResource();
+ RESOURCE_TYPE nRT = rId.GetRT2();
+ sal_uInt32 nId = rId.GetId();
+
+ incStack();
+ pTop = &aStack[nCurStack];
+ pTop->Init( pMgr, pResObj, nId |
+ (rId.IsAutoRelease() ? 0 : RSC_DONTRELEASE) );
+
+ if ( pClassRes )
+ {
+ if ( pClassRes->GetRT() == nRT )
+ pTop->pClassRes = pClassRes;
+ else
+ {
+#ifdef DBG_UTIL
+ RscError_Impl( "Different class and resource type!",
+ this, nRT, nId, aStack, nCurStack-1 );
+#endif
+ pTop->Flags |= RC_NOTFOUND;
+ pTop->pClassRes = getEmptyBuffer();
+ pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes;
+ return FALSE;
+ }
+ }
+ else
+ {
+ OSL_ENSURE( nCurStack > 0, "stack of 1 to shallow" );
+ pTop->pClassRes = LocalResource( &aStack[nCurStack-1], nRT, nId );
+ }
+
+ if ( pTop->pClassRes )
+ // lokale Resource, nicht system Resource
+ pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
+ else
+ {
+ pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle );
+ if ( pTop->pClassRes )
+ {
+ pTop->Flags |= RC_GLOBAL;
+ pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
+ }
+ else
+ {
+ // try to get a fallback resource
+ pFallbackResMgr = CreateFallbackResMgr( rId, pResObj );
+ if( pFallbackResMgr )
+ {
+ pTop->Flags |= RC_FALLBACK_DOWN;
+ #ifdef DBG_UTIL
+ ByteString aMess( "found resource " );
+ aMess.Append( ByteString::CreateFromInt32( nId ) );
+ aMess.Append( " in fallback " );
+ aMess.Append( ByteString( OUStringToOString( pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ) ) );
+ aMess.Append( "\n" );
+ RscError_Impl( aMess.GetBuffer(),
+ this, nRT, nId, aStack, nCurStack-1 );
+ #endif
+ }
+ else
+ {
+ #ifdef DBG_UTIL
+ RscError_Impl( "Cannot load resource! ",
+ this, nRT, nId, aStack, nCurStack-1 );
+ #endif
+ pTop->Flags |= RC_NOTFOUND;
+ pTop->pClassRes = getEmptyBuffer();
+ pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes;
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ DBG_ASSERT( rResId.GetResMgr(), "illegal ResId without ResMgr" );
+ *ppResMgr = rResId.GetResMgr();
+ if( *ppResMgr )
+ {
+ (*ppResMgr)->GetResource( rResId );
+ (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) );
+ return (*ppResMgr)->GetClass();
+ }
+ return getEmptyBuffer();
+}
+
+// -----------------------------------------------------------------------
+
+void ResMgr::PopContext( const Resource* pResObj )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ {
+ pFallbackResMgr->PopContext( pResObj );
+ return;
+ }
+
+#ifdef DBG_UTIL
+ if ( DbgIsResource() )
+ {
+ if ( (aStack[nCurStack].pResObj != pResObj) || nCurStack == 0 )
+ {
+ RscError_Impl( "Cannot free resource! ", this,
+ RSC_NOTYPE, 0, aStack, nCurStack );
+ }
+ }
+#endif
+
+ if ( nCurStack > 0 )
+ {
+ ImpRCStack* pTop = &aStack[nCurStack];
+#ifdef DBG_UTIL
+ if ( DbgIsResource() && !(pTop->Flags & RC_NOTFOUND) )
+ {
+ void* pRes = (BYTE*)pTop->pResource +
+ pTop->pResource->GetLocalOff();
+
+ if ( pTop->pClassRes != pRes )
+ {
+ RscError_Impl( "Classpointer not at the end!",
+ this, pTop->pResource->GetRT(),
+ pTop->pResource->GetId(),
+ aStack, nCurStack-1 );
+ }
+ }
+#endif
+
+ // Resource freigeben
+ if( (pTop->Flags & (RC_GLOBAL | RC_NOTFOUND)) == RC_GLOBAL )
+ // kann auch Fremd-Ressource sein
+ pImpRes->FreeGlobalRes( pTop->aResHandle, pTop->pResource );
+ decStack();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ {
+ ResId aId( rId );
+ aId.SetResMgr( NULL );
+ return pFallbackResMgr->CreateBlock( aId );
+ }
+
+ RSHEADER_TYPE* pHeader = NULL;
+ if ( GetResource( rId ) )
+ {
+ // Der Zeiger steht am Anfang, deswegen zeigt der Klassen-Pointer
+ // auf den Header und die restliche Groesse ist die Gesammte.
+ pHeader = (RSHEADER_TYPE*)rtl_allocateMemory( GetRemainSize() );
+ memcpy( pHeader, GetClass(), GetRemainSize() );
+ Increment( pHeader->GetLocalOff() ); //ans Ende setzen
+ if ( pHeader->GetLocalOff() != pHeader->GetGlobOff() )
+ // Hat Sub-Ressourcen, deshalb extra freigeben
+ PopContext();
+ }
+
+ return pHeader;
+}
+
+// ------------------------------------------------------------------
+
+INT16 ResMgr::GetShort( void * pShort )
+{
+ return ((*((sal_uInt8*)pShort + 0) << 8) |
+ (*((sal_uInt8*)pShort + 1) << 0) );
+}
+
+// ------------------------------------------------------------------
+
+INT32 ResMgr::GetLong( void * pLong )
+{
+ return ((*((sal_uInt8*)pLong + 0) << 24) |
+ (*((sal_uInt8*)pLong + 1) << 16) |
+ (*((sal_uInt8*)pLong + 2) << 8) |
+ (*((sal_uInt8*)pLong + 3) << 0) );
+}
+
+// ------------------------------------------------------------------
+
+sal_uInt64 ResMgr::GetUInt64( void* pDatum )
+{
+ return ((sal_uInt64(*((sal_uInt8*)pDatum + 0)) << 56) |
+ (sal_uInt64(*((sal_uInt8*)pDatum + 1)) << 48) |
+ (sal_uInt64(*((sal_uInt8*)pDatum + 2)) << 40) |
+ (sal_uInt64(*((sal_uInt8*)pDatum + 3)) << 32) |
+ (sal_uInt64(*((sal_uInt8*)pDatum + 4)) << 24) |
+ (sal_uInt64(*((sal_uInt8*)pDatum + 5)) << 16) |
+ (sal_uInt64(*((sal_uInt8*)pDatum + 6)) << 8) |
+ (sal_uInt64(*((sal_uInt8*)pDatum + 7)) << 0) );
+}
+
+// -----------------------------------------------------------------------
+sal_uInt32 ResMgr::GetStringWithoutHook( UniString& rStr, const BYTE* pStr )
+{
+ sal_uInt32 nRet = GetStringSize( pStr );
+ UniString aString( (sal_Char*)pStr, RTL_TEXTENCODING_UTF8,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
+ rStr = aString;
+ return nRet;
+}
+
+sal_uInt32 ResMgr::GetString( UniString& rStr, const BYTE* pStr )
+{
+ UniString aString;
+ sal_uInt32 nRet = GetStringWithoutHook( aString, pStr );
+ if ( pImplResHookProc )
+ pImplResHookProc( aString );
+ rStr = aString;
+ return nRet;
+}
+
+// ------------------------------------------------------------------
+
+sal_uInt32 ResMgr::GetStringSize( const BYTE* pStr )
+{
+ return GetStringSize( strlen( (const char*)pStr ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 ResMgr::GetRemainSize()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->GetRemainSize();
+
+ const ImpRCStack& rTop = aStack[nCurStack];
+ return (sal_uInt32)((long)(BYTE *)rTop.pResource +
+ rTop.pResource->GetLocalOff() -
+ (long)(BYTE *)rTop.pClassRes);
+}
+
+// -----------------------------------------------------------------------
+
+void* ResMgr::Increment( sal_uInt32 nSize )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->Increment( nSize );
+
+ ImpRCStack& rStack = aStack[nCurStack];
+ if( (rStack.Flags & RC_NOTFOUND) )
+ return rStack.pClassRes;
+
+ BYTE* pClassRes = (BYTE*)rStack.pClassRes + nSize;
+
+ rStack.pClassRes = pClassRes;
+
+ RSHEADER_TYPE* pRes = rStack.pResource;
+
+ sal_uInt32 nLocalOff = pRes->GetLocalOff();
+ if ( (pRes->GetGlobOff() == nLocalOff) &&
+ (((char*)pRes + nLocalOff) == rStack.pClassRes) &&
+ (rStack.Flags & RC_AUTORELEASE))
+ {
+ PopContext( rStack.pResObj );
+ }
+
+ return pClassRes;
+}
+
+ResMgr* ResMgr::CreateFallbackResMgr( const ResId& rId, const Resource* pResource )
+{
+ ResMgr *pFallback = NULL;
+ if( nCurStack > 0 )
+ {
+ // get the next fallback level in resource file scope
+ InternalResMgr* pRes = ResMgrContainer::get().getNextFallback( pImpRes );
+ if( pRes )
+ {
+ // check that the fallback locale is not already in the chain of
+ // fallbacks - prevent fallback loops
+ ResMgr* pResMgr = this;
+ while( pResMgr &&
+ ( pResMgr->pImpRes->aLocale.Language != pRes->aLocale.Language ||
+ pResMgr->pImpRes->aLocale.Country != pRes->aLocale.Country ||
+ pResMgr->pImpRes->aLocale.Variant != pRes->aLocale.Variant )
+ )
+ {
+ pResMgr = pResMgr->pOriginalResMgr;
+ }
+ if( pResMgr )
+ {
+ // found a recursion, no fallback possible
+ ResMgrContainer::get().freeResMgr( pRes );
+ return NULL;
+ }
+ OSL_TRACE( "trying fallback: %s\n", OUStringToOString( pRes->aFileName, osl_getThreadTextEncoding() ).getStr() );
+ pFallback = new ResMgr( pRes );
+ pFallback->pOriginalResMgr = this;
+ // try to recreate the resource stack
+ bool bHaveStack = true;
+ for( int i = 1; i < nCurStack; i++ )
+ {
+ if( !aStack[i].pResource )
+ {
+ bHaveStack = false;
+ break;
+ }
+ ResId aId( aStack[i].pResource->GetId(), *pFallbackResMgr );
+ aId.SetRT( aStack[i].pResource->GetRT() );
+ if( !pFallback->GetResource( aId ) )
+ {
+ bHaveStack = false;
+ break;
+ }
+ }
+ if( bHaveStack )
+ {
+ ResId aId( rId.GetId(), *pFallback );
+ aId.SetRT( rId.GetRT() );
+ if( !pFallback->GetResource( aId, pResource ) )
+ bHaveStack = false;
+ else
+ pFallback->aStack[pFallback->nCurStack].Flags |= RC_FALLBACK_UP;
+ }
+ if( !bHaveStack )
+ {
+ delete pFallback;
+ pFallback = NULL;
+ }
+ }
+ }
+ return pFallback;
+}
+
+//---------------------------------------------------------------------------
+//
+// method left here for SDK compatibility,
+// used in "framework/source/services/substitutepathvars.cxx"
+//
+// phone numbers no longer in use for resource files
+//
+//---------------------------------------------------------------------------
+
+const char* ResMgr::GetLang( LanguageType& nType, USHORT nPrio )
+{
+ if ( nType == LANGUAGE_SYSTEM || nType == LANGUAGE_DONTKNOW )
+ nType = MsLangId::getSystemUILanguage();
+
+ if ( nPrio == 0 )
+ {
+ switch ( nType )
+ {
+ case LANGUAGE_DANISH:
+ return "45";
+
+ case LANGUAGE_DUTCH:
+ case LANGUAGE_DUTCH_BELGIAN:
+ return "31";
+
+ case LANGUAGE_ENGLISH:
+ case LANGUAGE_ENGLISH_UK:
+ case LANGUAGE_ENGLISH_EIRE:
+ case LANGUAGE_ENGLISH_SAFRICA:
+ case LANGUAGE_ENGLISH_JAMAICA:
+ case LANGUAGE_ENGLISH_BELIZE:
+ case LANGUAGE_ENGLISH_TRINIDAD:
+ case LANGUAGE_ENGLISH_ZIMBABWE:
+ case LANGUAGE_ENGLISH_PHILIPPINES:
+ return "44";
+
+ case LANGUAGE_ENGLISH_US:
+ case LANGUAGE_ENGLISH_CAN:
+ return "01";
+
+ case LANGUAGE_ENGLISH_AUS:
+ case LANGUAGE_ENGLISH_NZ:
+ return "61";
+ case LANGUAGE_ESTONIAN:
+ return "77";
+
+
+ case LANGUAGE_FINNISH:
+ return "35";
+
+ case LANGUAGE_FRENCH_CANADIAN:
+ return "02";
+
+ case LANGUAGE_FRENCH:
+ case LANGUAGE_FRENCH_BELGIAN:
+ case LANGUAGE_FRENCH_SWISS:
+ case LANGUAGE_FRENCH_LUXEMBOURG:
+ case LANGUAGE_FRENCH_MONACO:
+ return "33";
+
+ case LANGUAGE_GERMAN:
+ case LANGUAGE_GERMAN_SWISS:
+ case LANGUAGE_GERMAN_AUSTRIAN:
+ case LANGUAGE_GERMAN_LUXEMBOURG:
+ case LANGUAGE_GERMAN_LIECHTENSTEIN:
+ return "49";
+
+ case LANGUAGE_ITALIAN:
+ case LANGUAGE_ITALIAN_SWISS:
+ return "39";
+
+ case LANGUAGE_NORWEGIAN:
+ case LANGUAGE_NORWEGIAN_BOKMAL:
+ return "47";
+
+ case LANGUAGE_PORTUGUESE:
+ return "03";
+
+ case LANGUAGE_PORTUGUESE_BRAZILIAN:
+ return "55";
+
+ case LANGUAGE_SPANISH_DATED:
+ case LANGUAGE_SPANISH_MEXICAN:
+ case LANGUAGE_SPANISH_MODERN:
+ case LANGUAGE_SPANISH_GUATEMALA:
+ case LANGUAGE_SPANISH_COSTARICA:
+ case LANGUAGE_SPANISH_PANAMA:
+ case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC:
+ case LANGUAGE_SPANISH_VENEZUELA:
+ case LANGUAGE_SPANISH_COLOMBIA:
+ case LANGUAGE_SPANISH_PERU:
+ case LANGUAGE_SPANISH_ARGENTINA:
+ case LANGUAGE_SPANISH_ECUADOR:
+ case LANGUAGE_SPANISH_CHILE:
+ case LANGUAGE_SPANISH_URUGUAY:
+ case LANGUAGE_SPANISH_PARAGUAY:
+ case LANGUAGE_SPANISH_BOLIVIA:
+ return "34";
+
+ case LANGUAGE_SWEDISH:
+ return "46";
+
+ case LANGUAGE_POLISH:
+ return "48";
+ case LANGUAGE_CZECH:
+ return "42";
+ case LANGUAGE_SLOVENIAN:
+ return "50";
+ case LANGUAGE_HUNGARIAN:
+ return "36";
+ case LANGUAGE_RUSSIAN:
+ return "07";
+ case LANGUAGE_SLOVAK:
+ return "43";
+ case LANGUAGE_GREEK:
+ return "30";
+ case LANGUAGE_TURKISH:
+ return "90";
+
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ return "86";
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ return "88";
+ case LANGUAGE_JAPANESE:
+ return "81";
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ return "82";
+ case LANGUAGE_THAI:
+ return "66";
+ case LANGUAGE_HINDI:
+ return "91";
+
+ case LANGUAGE_ARABIC_PRIMARY_ONLY:
+ case LANGUAGE_ARABIC_IRAQ:
+ case LANGUAGE_ARABIC_EGYPT:
+ case LANGUAGE_ARABIC_LIBYA:
+ case LANGUAGE_ARABIC_ALGERIA:
+ case LANGUAGE_ARABIC_MOROCCO:
+ case LANGUAGE_ARABIC_TUNISIA:
+ case LANGUAGE_ARABIC_OMAN:
+ case LANGUAGE_ARABIC_YEMEN:
+ case LANGUAGE_ARABIC_SYRIA:
+ case LANGUAGE_ARABIC_JORDAN:
+ case LANGUAGE_ARABIC_LEBANON:
+ case LANGUAGE_ARABIC_KUWAIT:
+ case LANGUAGE_ARABIC_UAE:
+ case LANGUAGE_ARABIC_BAHRAIN:
+ case LANGUAGE_ARABIC_QATAR:
+ return "96";
+
+ case LANGUAGE_HEBREW:
+ return "97";
+
+ case LANGUAGE_CATALAN:
+ return "37";
+
+ default:
+ return "99";
+ }
+ }
+ else if ( nPrio == 1 )
+ {
+ switch ( nType )
+ {
+ case LANGUAGE_FRENCH_CANADIAN:
+ return "33";
+
+ case LANGUAGE_PORTUGUESE_BRAZILIAN:
+ return "03";
+
+ default:
+ return NULL;
+ }
+ }
+ else if ( nPrio == 2 )
+ return "01";
+ else if ( nPrio == 3 )
+ return "44";
+ else if ( nPrio == 4 )
+ return "49";
+ else
+ return "99";
+}
+
+// -----------------------------------------------------------------------
+
+ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName,
+ com::sun::star::lang::Locale aLocale )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
+
+ if( ! aLocale.Language.getLength() )
+ aLocale = ResMgrContainer::get().getDefLocale();
+
+ InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, aLocale );
+ return pImp ? new ResMgr( pImp ) : NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ResMgr* ResMgr::SearchCreateResMgr(
+ const sal_Char* pPrefixName,
+ com::sun::star::lang::Locale& rLocale )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
+
+ if( ! rLocale.Language.getLength() )
+ rLocale = ResMgrContainer::get().getDefLocale();
+
+ InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, rLocale );
+ return pImp ? new ResMgr( pImp ) : NULL;
+}
+
+// -----------------------------------------------------------------------
+
+INT16 ResMgr::ReadShort()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->ReadShort();
+
+ INT16 n = GetShort( GetClass() );
+ Increment( sizeof( INT16 ) );
+ return n;
+}
+
+// -----------------------------------------------------------------------
+
+INT32 ResMgr::ReadLong()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->ReadLong();
+
+ INT32 n = GetLong( GetClass() );
+ Increment( sizeof( INT32 ) );
+ return n;
+}
+
+// -----------------------------------------------------------------------
+
+UniString ResMgr::ReadStringWithoutHook()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->ReadStringWithoutHook();
+
+ UniString aRet;
+
+ const ImpRCStack& rTop = aStack[nCurStack];
+ if( (rTop.Flags & RC_NOTFOUND) )
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ aRet = OUString( RTL_CONSTASCII_USTRINGPARAM( "<resource not found>" ) );
+ #endif
+ }
+ else
+ Increment( GetStringWithoutHook( aRet, (const BYTE*)GetClass() ) );
+
+ return aRet;
+}
+
+UniString ResMgr::ReadString()
+{
+ UniString aRet = ReadStringWithoutHook();
+ if ( pImplResHookProc )
+ pImplResHookProc( aRet );
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG ResMgr::GetAutoHelpId()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->GetAutoHelpId();
+
+ DBG_ASSERT( nCurStack, "resource stack empty in Auto help id generation" );
+ if( nCurStack < 1 || nCurStack > 2 )
+ return 0;
+
+ const ImpRCStack *pRC = StackTop( nCurStack==1 ? 0 : 1 );
+
+ DBG_ASSERT( pRC->pResource, "MM hat gesagt, dass der immer einen hat" );
+ ULONG nGID = pRC->pResource->GetId();
+
+ if( !nGID || nGID > 32767 )
+ return 0;
+
+ ULONG nHID = 0;
+
+ // GGGg gggg::gggg gggg::ggLL LLLl::llll llll
+ switch( pRC->pResource->GetRT() ) { // maximal 7
+ case RSC_DOCKINGWINDOW:
+ nHID += 0x20000000L;
+ case RSC_WORKWIN:
+ nHID += 0x20000000L;
+ case RSC_MODELESSDIALOG:
+ nHID += 0x20000000L;
+ case RSC_FLOATINGWINDOW:
+ nHID += 0x20000000L;
+ case RSC_MODALDIALOG:
+ nHID += 0x20000000L;
+ case RSC_TABPAGE:
+ nHID += 0x20000000L;
+
+ if( nCurStack == 2 ) {
+ pRC = StackTop();
+ ULONG nLID = pRC->pResource->GetId();
+
+ if( !nLID || nLID > 511 )
+ return 0;
+
+ switch( pRC->pResource->GetRT() ) { // maximal 32
+ case RSC_TABCONTROL: nHID |= 0x0000; break;
+ case RSC_RADIOBUTTON: nHID |= 0x0200; break;
+ case RSC_CHECKBOX: nHID |= 0x0400; break;
+ case RSC_TRISTATEBOX: nHID |= 0x0600; break;
+ case RSC_EDIT: nHID |= 0x0800; break;
+ case RSC_MULTILINEEDIT: nHID |= 0x0A00; break;
+ case RSC_MULTILISTBOX: nHID |= 0x0C00; break;
+ case RSC_LISTBOX: nHID |= 0x0E00; break;
+ case RSC_COMBOBOX: nHID |= 0x1000; break;
+ case RSC_PUSHBUTTON: nHID |= 0x1200; break;
+ case RSC_SPINFIELD: nHID |= 0x1400; break;
+ case RSC_PATTERNFIELD: nHID |= 0x1600; break;
+ case RSC_NUMERICFIELD: nHID |= 0x1800; break;
+ case RSC_METRICFIELD: nHID |= 0x1A00; break;
+ case RSC_CURRENCYFIELD: nHID |= 0x1C00; break;
+ case RSC_DATEFIELD: nHID |= 0x1E00; break;
+ case RSC_TIMEFIELD: nHID |= 0x2000; break;
+ case RSC_IMAGERADIOBUTTON: nHID |= 0x2200; break;
+ case RSC_NUMERICBOX: nHID |= 0x2400; break;
+ case RSC_METRICBOX: nHID |= 0x2600; break;
+ case RSC_CURRENCYBOX: nHID |= 0x2800; break;
+ case RSC_DATEBOX: nHID |= 0x2A00; break;
+ case RSC_TIMEBOX: nHID |= 0x2C00; break;
+ case RSC_IMAGEBUTTON: nHID |= 0x2E00; break;
+ case RSC_MENUBUTTON: nHID |= 0x3000; break;
+ case RSC_MOREBUTTON: nHID |= 0x3200; break;
+ default:
+ return 0;
+ } // of switch
+ nHID |= nLID;
+ } // of if
+ break;
+ default:
+ return 0;
+ } // of switch
+ nHID |= nGID << 14;
+
+ return nHID;
+}
+
+// -----------------------------------------------------------------------
+
+void ResMgr::SetReadStringHook( ResHookProc pProc )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+ pImplResHookProc = pProc;
+}
+
+// -----------------------------------------------------------------------
+
+ResHookProc ResMgr::GetReadStringHook()
+{
+ return pImplResHookProc;
+}
+
+// -----------------------------------------------------------------------
+
+void ResMgr::SetDefaultLocale( const com::sun::star::lang::Locale& rLocale )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+ ResMgrContainer::get().setDefLocale( rLocale );
+}
+
+// -----------------------------------------------------------------------
+
+const OUString& ResMgr::GetFileName() const
+{
+ return pImpRes->aFileName;
+}
+
+// =======================================================================
+
+SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName,
+ const ::com::sun::star::lang::Locale& rLocale )
+{
+ OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
+ com::sun::star::lang::Locale aLocale( rLocale );
+
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+ if( ! aLocale.Language.getLength() )
+ aLocale = ResMgrContainer::get().getDefLocale();
+
+ m_pResImpl = ResMgrContainer::get().getResMgr( aPrefix, aLocale, true );
+ DBG_ASSERT( m_pResImpl, "SimpleResMgr::SimpleResMgr : have no impl class !" );
+}
+
+// -----------------------------------------------------------------------
+SimpleResMgr::SimpleResMgr( const ::rtl::OUString& _rPrefixName, ::com::sun::star::lang::Locale& _inout_Locale )
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+ m_pResImpl = ResMgrContainer::get().getResMgr( _rPrefixName, _inout_Locale, true );
+}
+
+// -----------------------------------------------------------------------
+SimpleResMgr::~SimpleResMgr()
+{
+ delete m_pResImpl;
+}
+
+// -----------------------------------------------------------------------
+SimpleResMgr* SimpleResMgr::Create( const sal_Char* pPrefixName, com::sun::star::lang::Locale aLocale )
+{
+ return new SimpleResMgr( pPrefixName, aLocale );
+}
+
+// -----------------------------------------------------------------------
+bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType, sal_uInt32 _resourceId )
+{
+ NAMESPACE_VOS(OGuard) aGuard(m_aAccessSafety);
+
+ if ( ( RSC_STRING != _resourceType ) && ( RSC_RESOURCE != _resourceType ) )
+ return false;
+
+ DBG_ASSERT( m_pResImpl, "SimpleResMgr::IsAvailable: have no impl class !" );
+ return m_pResImpl->IsGlobalAvailable( _resourceType, _resourceId );
+}
+
+// -----------------------------------------------------------------------
+UniString SimpleResMgr::ReadString( sal_uInt32 nId )
+{
+ NAMESPACE_VOS(OGuard) aGuard(m_aAccessSafety);
+
+ DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadString : have no impl class !" );
+ // perhaps constructed with an invalid filename ?
+
+ UniString sReturn;
+ if ( !m_pResImpl )
+ return sReturn;
+
+ void* pResHandle = NULL;
+ InternalResMgr* pFallback = m_pResImpl;
+ RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
+ if ( !pResHeader )
+ {
+ osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
+
+ // try fallback
+ while( ! pResHandle && pFallback )
+ {
+ InternalResMgr* pOldFallback = pFallback;
+ pFallback = ResMgrContainer::get().getNextFallback( pFallback );
+ if( pOldFallback != m_pResImpl )
+ ResMgrContainer::get().freeResMgr( pOldFallback );
+ if( pFallback )
+ {
+ // handle possible recursion
+ if( pFallback->aLocale.Language != m_pResImpl->aLocale.Language ||
+ pFallback->aLocale.Country != m_pResImpl->aLocale.Country ||
+ pFallback->aLocale.Variant != m_pResImpl->aLocale.Variant )
+ {
+ pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
+ }
+ else
+ {
+ ResMgrContainer::get().freeResMgr( pFallback );
+ pFallback = NULL;
+ }
+ }
+ }
+ if( ! pResHandle )
+ // no such resource
+ return sReturn;
+ }
+
+ // ULONG nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
+ ResMgr::GetString( sReturn, (const BYTE*)(pResHeader+1) );
+
+ // not neccessary with te current implementation which holds the string table permanently, but to be sure ....
+ // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl
+ pFallback->FreeGlobalRes( pResHeader, pResHandle );
+ if( m_pResImpl != pFallback )
+ {
+ osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
+
+ ResMgrContainer::get().freeResMgr( pFallback );
+ }
+ return sReturn;
+}
+
+// -----------------------------------------------------------------------
+
+const ::com::sun::star::lang::Locale& SimpleResMgr::GetLocale() const
+{
+ DBG_ASSERT( IsValid(), "SimpleResMgr::ReadBlob: invalid, this will crash!" );
+ return m_pResImpl->aLocale;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 SimpleResMgr::ReadBlob( sal_uInt32 nId, void** pBuffer )
+{
+ NAMESPACE_VOS(OGuard) aGuard(m_aAccessSafety);
+
+ DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadBlob : have no impl class !" );
+
+ // perhaps constructed with an invalid filename ?
+ DBG_ASSERT( pBuffer, "SimpleResMgr::ReadBlob : invalid argument !" );
+ *pBuffer = NULL;
+
+ void* pResHandle = NULL;
+ InternalResMgr* pFallback = m_pResImpl;
+ RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_RESOURCE, nId, &pResHandle );
+ DBG_ASSERT( pResHeader, "SimpleResMgr::ReadBlob : couldn't find the resource with the given id !" );
+
+ if ( !pResHeader )
+ {
+ osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
+
+ // try fallback
+ while( ! pResHandle && pFallback )
+ {
+ InternalResMgr* pOldFallback = pFallback;
+ pFallback = ResMgrContainer::get().getNextFallback( pFallback );
+ if( pOldFallback != m_pResImpl )
+ ResMgrContainer::get().freeResMgr( pOldFallback );
+ if( pFallback )
+ {
+ // handle possible recursion
+ if( pFallback->aLocale.Language != m_pResImpl->aLocale.Language ||
+ pFallback->aLocale.Country != m_pResImpl->aLocale.Country ||
+ pFallback->aLocale.Variant != m_pResImpl->aLocale.Variant )
+ {
+ pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_RESOURCE, nId, &pResHandle );
+ }
+ else
+ {
+ ResMgrContainer::get().freeResMgr( pFallback );
+ pFallback = NULL;
+ }
+ }
+ }
+ if( ! pResHandle )
+ // no exception handling, this would require the locking of the solar mutex which isn't allowed within this class
+ return 0;
+ }
+
+ DBG_ASSERT( pResHandle == NULL, "SimpleResMgr::ReadBlob : behaviour of LoadGlobalRes changed !" );
+ // if pResHandle is not NULL the FreeBlob wouldn't have to delete the pointer given as pBuffer, but
+ // FreeBlob doesn't know that so it would probably crash ....
+
+ sal_uInt32 nRemaining = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
+ *pBuffer = (void*)(((BYTE*)pResHeader) + sizeof(RSHEADER_TYPE));
+
+ // free an eventual fallback InternalResMgr
+ if( m_pResImpl != pFallback )
+ {
+ osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
+
+ ResMgrContainer::get().freeResMgr( pFallback );
+ }
+
+ return nRemaining;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleResMgr::FreeBlob( void* pBuffer )
+{
+ void* pCompleteBuffer = (void*)(((BYTE*)pBuffer) - sizeof(RSHEADER_TYPE));
+ rtl_freeMemory(pCompleteBuffer);
+}
diff --git a/tools/source/ref/errinf.cxx b/tools/source/ref/errinf.cxx
new file mode 100644
index 000000000000..2f9c75a4b71c
--- /dev/null
+++ b/tools/source/ref/errinf.cxx
@@ -0,0 +1,462 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <limits.h>
+#include <tools/shl.hxx>
+#include <tools/debug.hxx>
+#include <tools/errinf.hxx>
+#include <tools/string.hxx>
+
+class ErrorHandler;
+
+namespace {
+
+typedef void (* DisplayFnPtr)();
+
+}
+
+struct EDcrData
+{
+ public:
+
+ ErrorHandler *pFirstHdl;
+ ErrorContext *pFirstCtx;
+ DisplayFnPtr pDsp;
+ BOOL bIsWindowDsp;
+
+
+ DynamicErrorInfo *ppDcr[ERRCODE_DYNAMIC_COUNT];
+ USHORT nNextDcr;
+ EDcrData();
+
+static EDcrData *GetData();
+
+};
+
+class EDcr_Impl
+{
+ ULONG lErrId;
+ USHORT nMask;
+
+ void RegisterEDcr(DynamicErrorInfo *);
+ void UnRegisterEDcr(DynamicErrorInfo *);
+ static ErrorInfo *GetDynamicErrorInfo(ULONG lId);
+
+friend class DynamicErrorInfo;
+friend class ErrorInfo;
+};
+
+
+EDcrData::EDcrData()
+{
+ for(USHORT n=0;n<ERRCODE_DYNAMIC_COUNT;n++)
+ ppDcr[n]=0;
+ nNextDcr=0;
+ pFirstHdl=0;
+ pDsp=0;
+ pFirstCtx=0;
+}
+
+
+EDcrData *EDcrData::GetData()
+{
+#ifdef BOOTSTRAP
+ return 0x0;
+#else
+ EDcrData **ppDat=(EDcrData **)GetAppData(SHL_ERR);
+ if(!*ppDat)
+ {
+ return (*ppDat=new EDcrData);
+ }
+ else
+ return *ppDat;
+#endif
+}
+
+void EDcr_Impl::RegisterEDcr(DynamicErrorInfo *pDcr)
+{
+ //Vergibt eine dynamische Id
+
+ EDcrData* pData=EDcrData::GetData();
+ lErrId= (((ULONG)pData->nNextDcr + 1) << ERRCODE_DYNAMIC_SHIFT) +
+ pDcr->GetErrorCode();
+ DynamicErrorInfo **ppDcr=pData->ppDcr;
+ USHORT nNext=pData->nNextDcr;
+
+ // bei einem Ringbuffer koennen wir uns das ASSERT wohl sparen!
+ // DBG_ASSERT(ppDcr[nNext]==0,"ErrHdl: Alle Errors belegt");
+ if(ppDcr[nNext])
+ {
+ delete ppDcr[nNext];
+ }
+ ppDcr[nNext]=pDcr;
+ if(++pData->nNextDcr>=ERRCODE_DYNAMIC_COUNT)
+ pData->nNextDcr=0;
+}
+
+
+void EDcr_Impl::UnRegisterEDcr(DynamicErrorInfo *pDcr)
+{
+
+ EDcrData* pData=EDcrData::GetData();
+ DynamicErrorInfo **ppDcr=pData->ppDcr;
+ ULONG lIdx=(
+ ((ULONG)(*pDcr) & ERRCODE_DYNAMIC_MASK)>>ERRCODE_DYNAMIC_SHIFT)-1;
+ DBG_ASSERT(ppDcr[lIdx]==pDcr,"ErrHdl: Error nicht gefunden");
+ if(ppDcr[lIdx]==pDcr)
+ ppDcr[lIdx]=0;
+}
+
+TYPEINIT0(ErrorInfo);
+TYPEINIT1(DynamicErrorInfo, ErrorInfo);
+TYPEINIT1(StandardErrorInfo, DynamicErrorInfo);
+TYPEINIT1(StringErrorInfo, DynamicErrorInfo);
+TYPEINIT1(TwoStringErrorInfo, DynamicErrorInfo);
+TYPEINIT1(MessageInfo, DynamicErrorInfo);
+
+
+ErrorInfo *ErrorInfo::GetErrorInfo(ULONG lId)
+{
+ if(lId & ERRCODE_DYNAMIC_MASK)
+ return EDcr_Impl::GetDynamicErrorInfo(lId);
+ else
+ return new ErrorInfo(lId);
+}
+
+DynamicErrorInfo::operator ULONG() const
+{
+ return pImpl->lErrId;
+}
+
+DynamicErrorInfo::DynamicErrorInfo(ULONG lArgUserId, USHORT nMask)
+: ErrorInfo(lArgUserId)
+{
+ pImpl=new EDcr_Impl;
+ pImpl->RegisterEDcr(this);
+ pImpl->nMask=nMask;
+}
+
+DynamicErrorInfo::~DynamicErrorInfo()
+{
+ pImpl->UnRegisterEDcr(this);
+ delete pImpl;
+}
+
+ErrorInfo* EDcr_Impl::GetDynamicErrorInfo(ULONG lId)
+{
+ ULONG lIdx=((lId & ERRCODE_DYNAMIC_MASK)>>ERRCODE_DYNAMIC_SHIFT)-1;
+ DynamicErrorInfo* pDcr=EDcrData::GetData()->ppDcr[lIdx];
+ if(pDcr && (ULONG)(*pDcr)==lId)
+ return pDcr;
+ else
+ return new ErrorInfo(lId & ~ERRCODE_DYNAMIC_MASK);
+}
+
+
+USHORT DynamicErrorInfo::GetDialogMask() const
+{
+ return pImpl->nMask;
+}
+
+
+StandardErrorInfo::StandardErrorInfo(
+ ULONG UserId, ULONG lArgExtId, USHORT nFlags)
+: DynamicErrorInfo(UserId, nFlags), lExtId(lArgExtId)
+{
+}
+
+
+StringErrorInfo::StringErrorInfo(
+ ULONG UserId, const String& aStringP, USHORT nFlags)
+: DynamicErrorInfo(UserId, nFlags), aString(aStringP)
+{
+}
+
+
+class ErrHdl_Impl
+{
+ public:
+
+ ErrorHandler *pNext;
+ static BOOL CreateString(const ErrorHandler *pStart,
+ const ErrorInfo*, String&, USHORT&);
+};
+
+
+static void aDspFunc(const String &rErr, const String &rAction)
+{
+ ByteString aErr("Aktion: ");
+ aErr+= ByteString( rAction, RTL_TEXTENCODING_ASCII_US );
+ aErr+=" Fehler: ";
+ aErr+= ByteString( rErr, RTL_TEXTENCODING_ASCII_US );
+ DBG_ERROR(aErr.GetBuffer());
+}
+
+
+ErrorContext::ErrorContext(Window *pWinP)
+{
+ EDcrData *pData=EDcrData::GetData();
+ ErrorContext *&pHdl=pData->pFirstCtx;
+ pWin=pWinP;
+ pNext=pHdl;
+ pHdl=this;
+}
+
+ErrorContext::~ErrorContext()
+{
+ ErrorContext **ppCtx=&(EDcrData::GetData()->pFirstCtx);
+ while(*ppCtx && *ppCtx!=this)
+ ppCtx=&((*ppCtx)->pNext);
+ if(*ppCtx)
+ *ppCtx=(*ppCtx)->pNext;
+}
+
+ErrorContext *ErrorContext::GetContext()
+{
+ return EDcrData::GetData()->pFirstCtx;
+}
+
+ErrorHandler::ErrorHandler()
+{
+ pImpl=new ErrHdl_Impl;
+ EDcrData *pData=EDcrData::GetData();
+ ErrorHandler *&pHdl=pData->pFirstHdl;
+ pImpl->pNext=pHdl;
+ pHdl=this;
+ if(!pData->pDsp)
+ RegisterDisplay(&aDspFunc);
+}
+
+ErrorHandler::~ErrorHandler()
+{
+ ErrorHandler **ppHdl=&(EDcrData::GetData()->pFirstHdl);
+ while(*ppHdl && *ppHdl!=this)
+ ppHdl=&((*ppHdl)->pImpl->pNext);
+ if(*ppHdl)
+ *ppHdl=(*ppHdl)->pImpl->pNext;
+ delete pImpl;
+}
+
+void ErrorHandler::RegisterDisplay(WindowDisplayErrorFunc *aDsp)
+{
+ EDcrData *pData=EDcrData::GetData();
+ pData->bIsWindowDsp=TRUE;
+ pData->pDsp = reinterpret_cast< DisplayFnPtr >(aDsp);
+}
+
+void ErrorHandler::RegisterDisplay(BasicDisplayErrorFunc *aDsp)
+{
+ EDcrData *pData=EDcrData::GetData();
+ pData->bIsWindowDsp=FALSE;
+ pData->pDsp = reinterpret_cast< DisplayFnPtr >(aDsp);
+}
+
+USHORT ErrorHandler::HandleError_Impl(
+ ULONG lId, USHORT nFlags, BOOL bJustCreateString, String & rError)
+{
+
+/* [Beschreibung]
+ Handelt einen Fehler ab. lId ist die FehlerId, nFlags sind die
+ ErrorFlags. Werden nFlags nicht abgegeben, so werden die in
+ der DynamicErrorInfo angegebenen Flags bzw. die aus der Resource
+ verwendet.
+
+ Also:
+
+ 1. nFlags,
+ 2. Resource Flags
+ 3. Dynamic Flags
+ 4. Default ERRCODE_BUTTON_OK, ERRCODE_MSG_ERROR
+
+
+ */
+
+ String aErr;
+ String aAction;
+ if(!lId || lId == ERRCODE_ABORT)
+ return 0;
+ EDcrData *pData=EDcrData::GetData();
+ ErrorInfo *pInfo=ErrorInfo::GetErrorInfo(lId);
+ ErrorContext *pCtx=ErrorContext::GetContext();
+ if(pCtx)
+ pCtx->GetString(pInfo->GetErrorCode(), aAction);
+ Window *pParent=0;
+ //Nimm den Parent aus dem Konext
+ for(;pCtx;pCtx=pCtx->pNext)
+ if(pCtx->GetParent())
+ {
+ pParent=pCtx->GetParent();
+ break;
+ }
+
+ BOOL bWarning = ((lId & ERRCODE_WARNING_MASK) == ERRCODE_WARNING_MASK);
+ USHORT nErrFlags = ERRCODE_BUTTON_DEF_OK | ERRCODE_BUTTON_OK;
+ if (bWarning)
+ nErrFlags |= ERRCODE_MSG_WARNING;
+ else
+ nErrFlags |= ERRCODE_MSG_ERROR;
+
+ DynamicErrorInfo* pDynPtr=PTR_CAST(DynamicErrorInfo,pInfo);
+ if(pDynPtr)
+ {
+ USHORT nDynFlags = pDynPtr->GetDialogMask();
+ if( nDynFlags )
+ nErrFlags = nDynFlags;
+ }
+
+ if(ErrHdl_Impl::CreateString(pData->pFirstHdl,pInfo,aErr,nErrFlags))
+ {
+ if (bJustCreateString)
+ {
+ rError = aErr;
+ return 1;
+ }
+ else
+ {
+ if(!pData->pDsp)
+ {
+ ByteString aStr("Action: ");
+ aStr += ByteString( aAction, RTL_TEXTENCODING_ASCII_US );
+ aStr += ByteString("\nFehler: ");
+ aStr += ByteString( aErr, RTL_TEXTENCODING_ASCII_US );
+ DBG_ERROR( aStr.GetBuffer() );
+ }
+ else
+ {
+ delete pInfo;
+ if(!pData->bIsWindowDsp)
+ {
+ (*(BasicDisplayErrorFunc*)pData->pDsp)(aErr,aAction);
+ return 0;
+ }
+ else
+ {
+ if( nFlags != USHRT_MAX )
+ nErrFlags = nFlags;
+ return (*(WindowDisplayErrorFunc*)pData->pDsp)(
+ pParent, nErrFlags, aErr, aAction);
+ }
+ }
+ }
+ }
+ DBG_ERROR("Error nicht behandelt");
+ // Error 1 ist General Error im Sfx
+ if(pInfo->GetErrorCode()!=1) {
+ HandleError_Impl(1, USHRT_MAX, bJustCreateString, rError);
+ }
+ else {
+ DBG_ERROR("Error 1 nicht gehandeled");
+ }
+ delete pInfo;
+ return 0;
+}
+
+// static
+BOOL ErrorHandler::GetErrorString(ULONG lId, String& rStr)
+{
+ return (BOOL)HandleError_Impl( lId, USHRT_MAX, TRUE, rStr );
+}
+
+USHORT ErrorHandler::HandleError(ULONG lId, USHORT nFlags)
+{
+
+/* [Beschreibung]
+ Handelt einen Fehler ab. lId ist die FehlerId, nFlags sind die
+ ErrorFlags. Werden nFlags nicht abgegeben, so werden die in
+ der DynamicErrorInfo angegebenen Flags bzw. die aus der Resource
+ verwendet.
+
+ Also:
+
+ 1. nFlags,
+ 2. Resource Flags
+ 3. Dynamic Flags
+ 4. Default ERRCODE_BUTTON_OK, ERRCODE_MSG_ERROR
+
+
+ */
+
+ String aDummy;
+ return HandleError_Impl( lId, nFlags, FALSE, aDummy );
+}
+
+BOOL ErrorHandler::ForwCreateString(const ErrorInfo* pInfo, String& rStr, USHORT &rFlags) const
+{
+ return ErrHdl_Impl::CreateString(this->pImpl->pNext, pInfo, rStr, rFlags);
+}
+
+BOOL ErrHdl_Impl::CreateString( const ErrorHandler *pStart,
+ const ErrorInfo* pInfo, String& pStr,
+ USHORT &rFlags)
+{
+ for(const ErrorHandler *pHdl=pStart;pHdl;pHdl=pHdl->pImpl->pNext)
+ {
+ if(pHdl->CreateString( pInfo, pStr, rFlags))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL SimpleErrorHandler::CreateString(
+ const ErrorInfo *pInfo, String &rStr, USHORT &) const
+{
+ ULONG nId = pInfo->GetErrorCode();
+ ByteString aStr;
+ aStr="Id ";
+ aStr+=ByteString::CreateFromInt32(nId);
+ aStr+=" only handled by SimpleErrorHandler";
+ aStr+="\nErrorCode: ";
+ aStr+=ByteString::CreateFromInt32(nId & ((1L << ERRCODE_CLASS_SHIFT) - 1 ));
+ aStr+="\nErrorClass: ";
+ aStr+=ByteString::CreateFromInt32((nId & ERRCODE_CLASS_MASK) >> ERRCODE_CLASS_SHIFT);
+ aStr+="\nErrorArea: ";
+ aStr+=ByteString::CreateFromInt32((nId & ERRCODE_ERROR_MASK &
+ ~((1 << ERRCODE_AREA_SHIFT ) -1 ) ) >> ERRCODE_AREA_SHIFT);
+ DynamicErrorInfo *pDyn=PTR_CAST(DynamicErrorInfo,pInfo);
+ if(pDyn)
+ {
+ aStr+="\nDId ";
+ aStr+=ByteString::CreateFromInt32((ULONG)*pDyn);
+ }
+ StandardErrorInfo *pStd=PTR_CAST(StandardErrorInfo,pInfo);
+ if(pStd)
+ {
+ aStr+="\nXId ";
+ aStr+=ByteString::CreateFromInt32(pStd->GetExtendedErrorCode());
+ }
+ rStr = String( aStr, RTL_TEXTENCODING_ASCII_US );
+ return TRUE;
+}
+
+SimpleErrorHandler::SimpleErrorHandler()
+ : ErrorHandler()
+{
+}
+
diff --git a/tools/source/ref/globname.cxx b/tools/source/ref/globname.cxx
new file mode 100644
index 000000000000..2d45e470e688
--- /dev/null
+++ b/tools/source/ref/globname.cxx
@@ -0,0 +1,453 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <tools/stream.hxx>
+#include <tools/globname.hxx>
+
+/************** class ImpSvGlobalName ************************************/
+ImpSvGlobalName::ImpSvGlobalName( const ImpSvGlobalName & rObj )
+{
+ nRefCount = 0;
+ memcpy( szData, rObj.szData, sizeof( szData ) );
+}
+
+/************** class ImpSvGlobalName ************************************/
+ImpSvGlobalName::ImpSvGlobalName( int )
+{
+ nRefCount = 1;
+ memset( szData, 0, sizeof( szData ) );
+}
+
+/*************************************************************************
+|* ImpSvGlobalName::operator ==()
+*************************************************************************/
+BOOL ImpSvGlobalName::operator == ( const ImpSvGlobalName & rObj ) const
+{
+ return !memcmp( szData, rObj.szData, sizeof( szData ) );
+}
+
+/*************************************************************************
+|* SvGlobalName::SvGlobalName()
+*************************************************************************/
+SvGlobalName::SvGlobalName()
+{
+ static ImpSvGlobalName aNoName( 0 );
+
+ pImp = &aNoName;
+ pImp->nRefCount++;
+}
+
+// locker die Struktur von Windows kopiert
+#ifdef WNT
+struct _GUID
+#else
+struct GUID
+#endif
+{
+ UINT32 Data1;
+ UINT16 Data2;
+ UINT16 Data3;
+ BYTE Data4[8];
+};
+SvGlobalName::SvGlobalName( const CLSID & rId )
+{
+ pImp = new ImpSvGlobalName();
+ pImp->nRefCount++;
+ memcpy( pImp->szData, &rId, sizeof( pImp->szData ) );
+}
+
+SvGlobalName::SvGlobalName( UINT32 n1, USHORT n2, USHORT n3,
+ BYTE b8, BYTE b9, BYTE b10, BYTE b11,
+ BYTE b12, BYTE b13, BYTE b14, BYTE b15 )
+{
+ pImp = new ImpSvGlobalName();
+ pImp->nRefCount++;
+
+ *(UINT32 *)pImp->szData = n1;
+ *(USHORT *)&pImp->szData[ 4 ] = n2;
+ *(USHORT *)&pImp->szData[ 6 ] = n3;
+ pImp->szData[ 8 ] = b8;
+ pImp->szData[ 9 ] = b9;
+ pImp->szData[ 10 ] = b10;
+ pImp->szData[ 11 ] = b11;
+ pImp->szData[ 12 ] = b12;
+ pImp->szData[ 13 ] = b13;
+ pImp->szData[ 14 ] = b14;
+ pImp->szData[ 15 ] = b15;
+}
+
+/*************************************************************************
+|* SvGlobalName::~SvGlobalName()
+*************************************************************************/
+SvGlobalName::~SvGlobalName()
+{
+ pImp->nRefCount--;
+ if( !pImp->nRefCount )
+ delete pImp;
+}
+
+/*************************************************************************
+|* SvGlobalName::operator = ()
+*************************************************************************/
+SvGlobalName & SvGlobalName::operator = ( const SvGlobalName & rObj )
+{
+ rObj.pImp->nRefCount++;
+ pImp->nRefCount--;
+ if( !pImp->nRefCount )
+ delete pImp;
+ pImp = rObj.pImp;
+ return *this;
+}
+
+/*************************************************************************
+|* SvGlobalName::NewImp()
+*************************************************************************/
+void SvGlobalName::NewImp()
+{
+ if( pImp->nRefCount > 1 )
+ {
+ pImp->nRefCount--;
+ pImp = new ImpSvGlobalName( *pImp );
+ pImp->nRefCount++;
+ }
+}
+
+/*************************************************************************
+|* SvGlobalName::operator << ()
+|* SvGlobalName::operator >> ()
+*************************************************************************/
+SvStream& operator << ( SvStream& rOStr, const SvGlobalName & rObj )
+{
+ rOStr << *(UINT32 *)rObj.pImp->szData;
+ rOStr << *(USHORT *)&rObj.pImp->szData[ 4 ];
+ rOStr << *(USHORT *)&rObj.pImp->szData[ 6 ];
+ rOStr.Write( (sal_Char *)&rObj.pImp->szData[ 8 ], 8 );
+ return rOStr;
+}
+
+SvStream& operator >> ( SvStream& rStr, SvGlobalName & rObj )
+{
+ rObj.NewImp(); // kopieren, falls noetig
+ rStr >> *(UINT32 *)rObj.pImp->szData;
+ rStr >> *(USHORT *)&rObj.pImp->szData[ 4 ];
+ rStr >> *(USHORT *)&rObj.pImp->szData[ 6 ];
+ rStr.Read( (sal_Char *)&rObj.pImp->szData[ 8 ], 8 );
+ return rStr;
+}
+
+
+/*************************************************************************
+|* SvGlobalName::operator < ()
+*************************************************************************/
+BOOL SvGlobalName::operator < ( const SvGlobalName & rObj ) const
+{
+ int n = memcmp( pImp->szData +6, rObj.pImp->szData +6,
+ sizeof( pImp->szData ) -6);
+ if( n < 0 )
+ return TRUE;
+ else if( n > 0 )
+ return FALSE;
+ else if( *(USHORT *)&pImp->szData[ 4 ] < *(USHORT *)&rObj.pImp->szData[ 4 ] )
+ return TRUE;
+ else if( *(USHORT *)&pImp->szData[ 4 ] == *(USHORT *)&rObj.pImp->szData[ 4 ] )
+ return *(UINT32 *)pImp->szData < *(UINT32 *)rObj.pImp->szData;
+ else
+ return FALSE;
+
+}
+
+/*************************************************************************
+|* SvGlobalName::operator +=()
+*************************************************************************/
+SvGlobalName & SvGlobalName::operator += ( UINT32 n )
+{
+ NewImp();
+ UINT32 nOld = (*(UINT32 *)pImp->szData);
+ (*(UINT32 *)pImp->szData) += n;
+ if( nOld > *(UINT32 *)pImp->szData )
+ // ueberlauf
+ (*(USHORT *)&pImp->szData[ 4 ])++;
+ return *this;
+}
+
+/*************************************************************************
+|* SvGlobalName::operator ==()
+*************************************************************************/
+BOOL SvGlobalName::operator == ( const SvGlobalName & rObj ) const
+{
+ return *pImp == *rObj.pImp;
+}
+
+void SvGlobalName::MakeFromMemory( void * pData )
+{
+ NewImp();
+ memcpy( pImp->szData, pData, sizeof( pImp->szData ) );
+}
+
+/*************************************************************************
+|* SvGlobalName::MakeId()
+*************************************************************************/
+BOOL SvGlobalName::MakeId( const String & rIdStr )
+{
+ ByteString aStr( rIdStr, RTL_TEXTENCODING_ASCII_US );
+ sal_Char * pStr = (sal_Char *)aStr.GetBuffer();
+ if( rIdStr.Len() == 36
+ && '-' == pStr[ 8 ] && '-' == pStr[ 13 ]
+ && '-' == pStr[ 18 ] && '-' == pStr[ 23 ] )
+ {
+ UINT32 nFirst = 0;
+ int i = 0;
+ for( i = 0; i < 8; i++ )
+ {
+ if( isxdigit( *pStr ) )
+ if( isdigit( *pStr ) )
+ nFirst = nFirst * 16 + (*pStr - '0');
+ else
+ nFirst = nFirst * 16 + (toupper( *pStr ) - 'A' + 10 );
+ else
+ return FALSE;
+ pStr++;
+ }
+
+ UINT16 nSec = 0;
+ pStr++;
+ for( i = 0; i < 4; i++ )
+ {
+ if( isxdigit( *pStr ) )
+ if( isdigit( *pStr ) )
+ nSec = nSec * 16 + (*pStr - '0');
+ else
+ nSec = nSec * 16 + (UINT16)(toupper( *pStr ) - 'A' + 10 );
+ else
+ return FALSE;
+ pStr++;
+ }
+
+ UINT16 nThird = 0;
+ pStr++;
+ for( i = 0; i < 4; i++ )
+ {
+ if( isxdigit( *pStr ) )
+ if( isdigit( *pStr ) )
+ nThird = nThird * 16 + (*pStr - '0');
+ else
+ nThird = nThird * 16 + (UINT16)(toupper( *pStr ) - 'A' + 10 );
+ else
+ return FALSE;
+ pStr++;
+ }
+
+ BYTE szRemain[ 8 ];
+ memset( szRemain, 0, sizeof( szRemain ) );
+ pStr++;
+ for( i = 0; i < 16; i++ )
+ {
+ if( isxdigit( *pStr ) )
+ if( isdigit( *pStr ) )
+ szRemain[i/2] = szRemain[i/2] * 16 + (*pStr - '0');
+ else
+ szRemain[i/2] = szRemain[i/2] * 16 + (BYTE)(toupper( *pStr ) - 'A' + 10 );
+ else
+ return FALSE;
+ pStr++;
+ if( i == 3 )
+ pStr++;
+ }
+
+ NewImp();
+ *(UINT32 *)pImp->szData = nFirst;
+ *(USHORT *)&pImp->szData[ 4 ] = nSec;
+ *(USHORT *)&pImp->szData[ 6 ] = nThird;
+ memcpy( &pImp->szData[ 8 ], szRemain, 8 );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+|* SvGlobalName::GetctorName()
+*************************************************************************/
+String SvGlobalName::GetctorName() const
+{
+ ByteString aRet;
+
+ sal_Char buf[ 20 ];
+ sprintf( buf, "0x%8.8lX", (ULONG)*(UINT32 *)pImp->szData );
+ aRet += buf;
+ USHORT i;
+ for( i = 4; i < 8; i += 2 )
+ {
+ aRet += ',';
+ sprintf( buf, "0x%4.4X", *(USHORT *)&pImp->szData[ i ] );
+ aRet += buf;
+ }
+ for( i = 8; i < 16; i++ )
+ {
+ aRet += ',';
+ sprintf( buf, "0x%2.2x", pImp->szData[ i ] );
+ aRet += buf;
+ }
+ return String( aRet, RTL_TEXTENCODING_ASCII_US );
+}
+
+/*************************************************************************
+|* SvGlobalName::GetHexName()
+*************************************************************************/
+String SvGlobalName::GetHexName() const
+{
+ ByteString aRet;
+
+ sal_Char buf[ 10 ];
+ sprintf( buf, "%8.8lX", (ULONG)*(UINT32 *)pImp->szData );
+ aRet += buf;
+ aRet += '-';
+ USHORT i ;
+ for( i = 4; i < 8; i += 2 )
+ {
+ sprintf( buf, "%4.4X", *(USHORT *)&pImp->szData[ i ] );
+ aRet += buf;
+ aRet += '-';
+ }
+ for( i = 8; i < 10; i++ )
+ {
+ sprintf( buf, "%2.2x", pImp->szData[ i ] );
+ aRet += buf;
+ }
+ aRet += '-';
+ for( i = 10; i < 16; i++ )
+ {
+ sprintf( buf, "%2.2x", pImp->szData[ i ] );
+ aRet += buf;
+ }
+ return String( aRet, RTL_TEXTENCODING_ASCII_US );
+}
+
+/************** SvGlobalNameList ****************************************/
+/************************************************************************/
+/*************************************************************************
+|* SvGlobalNameList::SvGlobalNameList()
+*************************************************************************/
+SvGlobalNameList::SvGlobalNameList()
+ : aList( 1, 1 )
+{
+}
+
+/*************************************************************************
+|* SvGlobalNameList::~SvGlobalNameList()
+*************************************************************************/
+SvGlobalNameList::~SvGlobalNameList()
+{
+ for( ULONG i = Count(); i > 0; i-- )
+ {
+ ImpSvGlobalName * pImp = (ImpSvGlobalName *)aList.GetObject( i -1 );
+ pImp->nRefCount--;
+ if( !pImp->nRefCount )
+ delete pImp;
+ }
+}
+
+/*************************************************************************
+|* SvGlobalNameList::Append()
+*************************************************************************/
+void SvGlobalNameList::Append( const SvGlobalName & rName )
+{
+ rName.pImp->nRefCount++;
+ aList.Insert( rName.pImp, LIST_APPEND );
+}
+
+/*************************************************************************
+|* SvGlobalNameList::GetObject()
+*************************************************************************/
+SvGlobalName SvGlobalNameList::GetObject( ULONG nPos )
+{
+ return SvGlobalName( (ImpSvGlobalName *)aList.GetObject( nPos ) );
+}
+
+/*************************************************************************
+|* SvGlobalNameList::IsEntry()
+*************************************************************************/
+BOOL SvGlobalNameList::IsEntry( const SvGlobalName & rName )
+{
+ for( ULONG i = Count(); i > 0; i-- )
+ {
+ if( *rName.pImp == *(ImpSvGlobalName *)aList.GetObject( i -1 ) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+com::sun::star::uno::Sequence < sal_Int8 > SvGlobalName::GetByteSequence() const
+{
+ // platform independent representation of a "GlobalName"
+ // maybe transported remotely
+ com::sun::star::uno::Sequence< sal_Int8 > aResult( 16 );
+
+ aResult[0] = (sal_Int8) (*(UINT32 *)pImp->szData >> 24);
+ aResult[1] = (sal_Int8) ((*(UINT32 *)pImp->szData << 8 ) >> 24);
+ aResult[2] = (sal_Int8) ((*(UINT32 *)pImp->szData << 16 ) >> 24);
+ aResult[3] = (sal_Int8) ((*(UINT32 *)pImp->szData << 24 ) >> 24);
+ aResult[4] = (sal_Int8) (*(USHORT *)&pImp->szData[ 4 ] >> 8);
+ aResult[5] = (sal_Int8) ((*(USHORT *)&pImp->szData[ 4 ] << 8 ) >> 8);
+ aResult[6] = (sal_Int8) (*(USHORT *)&pImp->szData[ 6 ] >> 8);
+ aResult[7] = (sal_Int8) ((*(USHORT *)&pImp->szData[ 6 ] << 8 ) >> 8);
+ aResult[8] = pImp->szData[ 8 ];
+ aResult[9] = pImp->szData[ 9 ];
+ aResult[10] = pImp->szData[ 10 ];
+ aResult[11] = pImp->szData[ 11 ];
+ aResult[12] = pImp->szData[ 12 ];
+ aResult[13] = pImp->szData[ 13 ];
+ aResult[14] = pImp->szData[ 14 ];
+ aResult[15] = pImp->szData[ 15 ];
+
+ return aResult;
+}
+
+SvGlobalName::SvGlobalName( const com::sun::star::uno::Sequence < sal_Int8 >& aSeq )
+{
+ // create SvGlobalName from a platform independent representation
+ GUID aResult;
+ memset( &aResult, 0, sizeof( aResult ) );
+ if ( aSeq.getLength() == 16 )
+ {
+ aResult.Data1 = ( ( ( ( ( ( sal_uInt8 )aSeq[0] << 8 ) + ( sal_uInt8 )aSeq[1] ) << 8 ) + ( sal_uInt8 )aSeq[2] ) << 8 ) + ( sal_uInt8 )aSeq[3];
+ aResult.Data2 = ( ( sal_uInt8 )aSeq[4] << 8 ) + ( sal_uInt8 )aSeq[5];
+ aResult.Data3 = ( ( sal_uInt8 )aSeq[6] << 8 ) + ( sal_uInt8 )aSeq[7];
+ for( int nInd = 0; nInd < 8; nInd++ )
+ aResult.Data4[nInd] = ( sal_uInt8 )aSeq[nInd+8];
+ }
+
+ pImp = new ImpSvGlobalName();
+ pImp->nRefCount++;
+ memcpy( pImp->szData, &aResult, sizeof( pImp->szData ) );
+}
diff --git a/tools/source/ref/makefile.mk b/tools/source/ref/makefile.mk
new file mode 100644
index 000000000000..c87f8a740a4f
--- /dev/null
+++ b/tools/source/ref/makefile.mk
@@ -0,0 +1,53 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=ref
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/ref.obj \
+ $(SLO)$/pstm.obj \
+ $(SLO)$/globname.obj \
+ $(SLO)$/errinf.obj
+
+OBJFILES= $(OBJ)$/ref.obj \
+ $(OBJ)$/pstm.obj \
+ $(OBJ)$/globname.obj \
+ $(OBJ)$/errinf.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/ref/pstm.cxx b/tools/source/ref/pstm.cxx
new file mode 100644
index 000000000000..e0412fd5d675
--- /dev/null
+++ b/tools/source/ref/pstm.cxx
@@ -0,0 +1,915 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/debug.hxx>
+#include <tools/pstm.hxx>
+
+#define STOR_NO_OPTIMIZE
+
+/***********************************************************************/
+/************************************************************************
+|* SvClassManager::Register()
+*************************************************************************/
+void SvClassManager::Register( USHORT nClassId, SvCreateInstancePersist pFunc )
+{
+#ifdef DBG_UTIL
+ SvCreateInstancePersist p;
+ p = Get( nClassId );
+ DBG_ASSERT( !p || p == pFunc, "register class with same id" );
+#endif
+ aAssocTable.insert(Map::value_type(nClassId, pFunc));
+}
+
+/************************************************************************
+|* SvClassManager::Get()
+*************************************************************************/
+SvCreateInstancePersist SvClassManager::Get( USHORT nClassId )
+{
+ Map::const_iterator i(aAssocTable.find(nClassId));
+ return i == aAssocTable.end() ? 0 : i->second;
+}
+
+/****************** SvRttiBase *******************************************/
+TYPEINIT0( SvRttiBase );
+
+/****************** SvPersistBaseMemberList ******************************/
+
+SvPersistBaseMemberList::SvPersistBaseMemberList(){}
+SvPersistBaseMemberList::SvPersistBaseMemberList(
+ USHORT nInitSz, USHORT nResize )
+ : SuperSvPersistBaseMemberList( nInitSz, nResize ){}
+
+#define PERSIST_LIST_VER (BYTE)0
+#define PERSIST_LIST_DBGUTIL (BYTE)0x80
+
+/************************************************************************
+|* SvPersistBaseMemberList::WriteOnlyStreamedObjects()
+*************************************************************************/
+void SvPersistBaseMemberList::WriteObjects( SvPersistStream & rStm,
+ BOOL bOnlyStreamed ) const
+{
+#ifdef STOR_NO_OPTIMIZE
+ rStm << (BYTE)(PERSIST_LIST_VER | PERSIST_LIST_DBGUTIL);
+ UINT32 nObjPos = rStm.WriteDummyLen();
+#else
+ BYTE bTmp = PERSIST_LIST_VER;
+ rStm << bTmp;
+#endif
+ UINT32 nCountMember = Count();
+ ULONG nCountPos = rStm.Tell();
+ UINT32 nWriteCount = 0;
+ rStm << nCountMember;
+ //bloss die Liste nicht veraendern,
+ //wegen Seiteneffekten beim Save
+ for( ULONG n = 0; n < nCountMember; n++ )
+ {
+ SvPersistBase * pObj = GetObject( n );
+ if( !bOnlyStreamed || rStm.IsStreamed( pObj ) )
+ { // Objekt soll geschrieben werden
+ rStm << GetObject( n );
+ nWriteCount++;
+ }
+ }
+ if( nWriteCount != nCountMember )
+ {
+ // nicht alle Objekte geschrieben, Count anpassen
+ ULONG nPos = rStm.Tell();
+ rStm.Seek( nCountPos );
+ rStm << nWriteCount;
+ rStm.Seek( nPos );
+ }
+#ifdef STOR_NO_OPTIMIZE
+ rStm.WriteLen( nObjPos );
+#endif
+}
+
+/************************************************************************
+|* operator << ()
+*************************************************************************/
+SvPersistStream& operator << ( SvPersistStream & rStm,
+ const SvPersistBaseMemberList & rLst )
+{
+ rLst.WriteObjects( rStm );
+ return rStm;
+}
+
+/************************************************************************
+|* operator >> ()
+*************************************************************************/
+SvPersistStream& operator >> ( SvPersistStream & rStm,
+ SvPersistBaseMemberList & rLst )
+{
+ BYTE nVer;
+ rStm >> nVer;
+
+ if( (nVer & ~PERSIST_LIST_DBGUTIL) != PERSIST_LIST_VER )
+ {
+ rStm.SetError( SVSTREAM_GENERALERROR );
+ DBG_ERROR( "persist list, false version" );
+ }
+
+ UINT32 nObjLen(0), nObjPos(0);
+ if( nVer & PERSIST_LIST_DBGUTIL )
+ nObjLen = rStm.ReadLen( &nObjPos );
+
+ sal_uInt32 nCount;
+ rStm >> nCount;
+ for( ULONG n = 0; n < nCount && rStm.GetError() == SVSTREAM_OK; n++ )
+ {
+ SvPersistBase * pObj;
+ rStm >> pObj;
+ if( pObj )
+ rLst.Append( pObj );
+ }
+#ifdef DBG_UTIL
+ if( nObjLen + nObjPos != rStm.Tell() )
+ {
+ ByteString aStr( "false list len: read = " );
+ aStr += ByteString::CreateFromInt32( (long)(rStm.Tell() - nObjPos) );
+ aStr += ", should = ";
+ aStr += ByteString::CreateFromInt64(nObjLen);
+ DBG_ERROR( aStr.GetBuffer() );
+ }
+#endif
+ return rStm;
+}
+
+//=========================================================================
+SvPersistStream::SvPersistStream
+(
+ SvClassManager & rMgr, /* Alle Factorys, deren Objekt geladen und
+ gespeichert werdn k"onnen */
+ SvStream * pStream, /* Dieser Stream wird als Medium genommen, auf
+ dem der PersistStream arbeitet */
+ UINT32 nStartIdxP /* Ab diesem Index werden die Id's f"ur
+ die Objekte vergeben, er muss gr"osser
+ als Null sein. */
+)
+ : rClassMgr( rMgr )
+ , pStm( pStream )
+ , aPUIdx( nStartIdxP )
+ , nStartIdx( nStartIdxP )
+ , pRefStm( NULL )
+ , nFlags( 0 )
+/* [Beschreibung]
+
+ Der Konstruktor der Klasse SvPersistStream. Die Objekte rMgr und
+ pStream d"urfen nicht ver"andert werden, solange sie in einem
+ SvPersistStream eingesetzt sind. Eine Aussnahme gibt es f"ur
+ pStream (siehe <SvPersistStream::SetStream>).
+*/
+{
+ DBG_ASSERT( nStartIdx != 0, "zero index not allowed" );
+ bIsWritable = TRUE;
+ if( pStm )
+ {
+ SetVersion( pStm->GetVersion() );
+ SetError( pStm->GetError() );
+ SyncSvStream( pStm->Tell() );
+ }
+}
+
+//=========================================================================
+SvPersistStream::SvPersistStream
+(
+ SvClassManager & rMgr, /* Alle Factorys, deren Objekt geladen und
+ gespeichert werdn k"onnen */
+ SvStream * pStream, /* Dieser Stream wird als Medium genommen, auf
+ dem der PersistStream arbeitet */
+ const SvPersistStream & rPersStm
+ /* Wenn PersistStream's verschachtelt werden,
+ dann ist dies der Parent-Stream. */
+)
+ : rClassMgr( rMgr )
+ , pStm( pStream )
+ // Bereiche nicht ueberschneiden, deshalb nur groessere Indexe
+ , aPUIdx( rPersStm.GetCurMaxIndex() +1 )
+ , nStartIdx( rPersStm.GetCurMaxIndex() +1 )
+ , pRefStm( &rPersStm )
+ , nFlags( 0 )
+/* [Beschreibung]
+
+ Der Konstruktor der Klasse SvPersistStream. Die Objekte rMgr und
+ pStream d"urfen nicht ver"andert werden, solange sie in einem
+ SvPersistStream eingesetzt sind. Eine Aussnahme gibt es f"ur
+ pStream (siehe <SvPersistStream::SetStream>).
+ Durch diesen Konstruktor wird eine Hierarchiebildung unterst"utzt.
+ Alle Objekte aus einer Hierarchie m"ussen erst geladen werden,
+ wenn das erste aus dieser Hierarchie benutzt werden soll.
+*/
+{
+ bIsWritable = TRUE;
+ if( pStm )
+ {
+ SetVersion( pStm->GetVersion() );
+ SetError( pStm->GetError() );
+ SyncSvStream( pStm->Tell() );
+ }
+}
+
+//=========================================================================
+SvPersistStream::~SvPersistStream()
+/* [Beschreibung]
+
+ Der Detruktor ruft die Methode <SvPersistStream::SetStream>
+ mit NULL.
+*/
+{
+ SetStream( NULL );
+}
+
+//=========================================================================
+void SvPersistStream::SetStream
+(
+ SvStream * pStream /* auf diesem Stream arbeitet der PersistStream */
+
+)
+/* [Beschreibung]
+
+ Es wird ein Medium (pStream) eingesetzt, auf dem PersistStream arbeitet.
+ Dieses darf nicht von aussen modifiziert werden, solange es
+ eingesetzt ist. Es sei denn, w"ahrend auf dem Medium gearbeitet
+ wird, wird keine Methode von SvPersistStream gerufen, bevor
+ nicht <SvPersistStream::SetStream> mit demselben Medium gerufen
+ wurde.
+*/
+{
+ if( pStm != pStream )
+ {
+ if( pStm )
+ {
+ SyncSysStream();
+ pStm->SetError( GetError() );
+ }
+ pStm = pStream;
+ }
+ if( pStm )
+ {
+ SetVersion( pStm->GetVersion() );
+ SetError( pStm->GetError() );
+ SyncSvStream( pStm->Tell() );
+ }
+}
+
+//=========================================================================
+USHORT SvPersistStream::IsA() const
+/* [Beschreibung]
+
+ Gibt den Identifier dieses Streamklasse zur"uck.
+
+ [R"uckgabewert]
+
+ USHORT ID_PERSISTSTREAM wird zur"uckgegeben.
+
+
+ [Querverweise]
+
+ <SvStream::IsA>
+*/
+{
+ return ID_PERSISTSTREAM;
+}
+
+
+/*************************************************************************
+|* SvPersistStream::ResetError()
+*************************************************************************/
+void SvPersistStream::ResetError()
+{
+ SvStream::ResetError();
+ DBG_ASSERT( pStm, "stream not set" );
+ pStm->ResetError();
+}
+
+/*************************************************************************
+|* SvPersistStream::GetData()
+*************************************************************************/
+ULONG SvPersistStream::GetData( void* pData, ULONG nSize )
+{
+ DBG_ASSERT( pStm, "stream not set" );
+ ULONG nRet = pStm->Read( pData, nSize );
+ SetError( pStm->GetError() );
+ return nRet;
+}
+
+/*************************************************************************
+|* SvPersistStream::PutData()
+*************************************************************************/
+ULONG SvPersistStream::PutData( const void* pData, ULONG nSize )
+{
+ DBG_ASSERT( pStm, "stream not set" );
+ ULONG nRet = pStm->Write( pData, nSize );
+ SetError( pStm->GetError() );
+ return nRet;
+}
+
+/*************************************************************************
+|* SvPersistStream::Seek()
+*************************************************************************/
+ULONG SvPersistStream::SeekPos( ULONG nPos )
+{
+ DBG_ASSERT( pStm, "stream not set" );
+ ULONG nRet = pStm->Seek( nPos );
+ SetError( pStm->GetError() );
+ return nRet;
+}
+
+/*************************************************************************
+|* SvPersistStream::FlushData()
+*************************************************************************/
+void SvPersistStream::FlushData()
+{
+}
+
+/*************************************************************************
+|* SvPersistStream::GetCurMaxIndex()
+*************************************************************************/
+ULONG SvPersistStream::GetCurMaxIndex( const SvPersistUIdx & rIdx ) const
+{
+ // const bekomme ich nicht den hoechsten Index
+ SvPersistUIdx * p = (SvPersistUIdx *)&rIdx;
+ // alten merken
+ ULONG nCurIdx = p->GetCurIndex();
+ p->Last();
+ // Bereiche nicht ueberschneiden, deshalb nur groessere Indexe
+ ULONG nMaxIdx = p->GetCurIndex();
+ // wieder herstellen
+ p->Seek( nCurIdx );
+ return nMaxIdx;
+}
+
+/*************************************************************************
+|* SvPersistStream::GetIndex()
+*************************************************************************/
+ULONG SvPersistStream::GetIndex( SvPersistBase * pObj ) const
+{
+ ULONG nId = (ULONG)aPTable.Get( (ULONG)pObj );
+ if( !nId && pRefStm )
+ return pRefStm->GetIndex( pObj );
+ return nId;
+}
+
+/*************************************************************************
+|* SvPersistStream::GetObject)
+*************************************************************************/
+SvPersistBase * SvPersistStream::GetObject( ULONG nIdx ) const
+{
+ if( nIdx >= nStartIdx )
+ return aPUIdx.Get( nIdx );
+ else if( pRefStm )
+ return pRefStm->GetObject( nIdx );
+ return NULL;
+}
+
+//=========================================================================
+#define LEN_1 0x80
+#define LEN_2 0x40
+#define LEN_4 0x20
+#define LEN_5 0x10
+UINT32 SvPersistStream::ReadCompressed
+(
+ SvStream & rStm /* Aus diesem Stream werden die komprimierten Daten
+ gelesen */
+)
+/* [Beschreibung]
+
+ Ein im Stream komprimiert abgelegtes Wort wird gelesen. In welchem
+ Format komprimiert wird, siehe <SvPersistStream::WriteCompressed>.
+
+ [R"uckgabewert]
+
+ UINT32 Das nicht komprimierte Wort wird zur"uckgegeben.
+
+ [Querverweise]
+
+*/
+{
+ UINT32 nRet(0);
+ BYTE nMask;
+ rStm >> nMask;
+ if( nMask & LEN_1 )
+ nRet = ~LEN_1 & nMask;
+ else if( nMask & LEN_2 )
+ {
+ nRet = ~LEN_2 & nMask;
+ nRet <<= 8;
+ rStm >> nMask;
+ nRet |= nMask;
+ }
+ else if( nMask & LEN_4 )
+ {
+ nRet = ~LEN_4 & nMask;
+ nRet <<= 8;
+ rStm >> nMask;
+ nRet |= nMask;
+ nRet <<= 16;
+ USHORT n;
+ rStm >> n;
+ nRet |= n;
+ }
+ else if( nMask & LEN_5 )
+ {
+ if( nMask & 0x0F )
+ {
+ rStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ DBG_ERROR( "format error" );
+ }
+ rStm >> nRet;
+ }
+ else
+ {
+ rStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ DBG_ERROR( "format error" );
+ }
+ return nRet;
+}
+
+//=========================================================================
+void SvPersistStream::WriteCompressed
+(
+ SvStream & rStm,/* Aus diesem Stream werden die komprimierten Daten
+ gelesen */
+ UINT32 nVal /* Dieser Wert wird komprimiert geschrieben */
+)
+/* [Beschreibung]
+
+ Das "ubergebene Wort wird komprimiert und in den Stream
+ geschrieben. Folgendermassen wir komprimiert.
+ nVal < 0x80 => 0x80 + nVal ist 1 Byte gross.
+ nVal < 0x4000 => 0x4000 + nVal ist 2 Byte gross.
+ nVal < 0x20000000 => 0x20000000 + nVal ist 4 Byte gross.
+ nVal > 0x1FFFFFFF => 0x1000000000+ nVal ist 5 Byte gross.
+
+ [Querverweise]
+
+ <SvPersistStream::ReadCompressed>
+*/
+{
+#ifdef STOR_NO_OPTIMIZE
+ if( nVal < 0x80 )
+ rStm << (BYTE)(LEN_1 | nVal);
+ else if( nVal < 0x4000 )
+ {
+ rStm << (BYTE)(LEN_2 | (nVal >> 8));
+ rStm << (BYTE)nVal;
+ }
+ else if( nVal < 0x20000000 )
+ {
+ // hoechstes BYTE
+ rStm << (BYTE)(LEN_4 | (nVal >> 24));
+ // 2. hoechstes BYTE
+ rStm << (BYTE)(nVal >> 16);
+ rStm << (USHORT)(nVal);
+ }
+ else
+#endif
+ {
+ rStm << (BYTE)LEN_5;
+ rStm << nVal;
+ }
+}
+
+//=========================================================================
+UINT32 SvPersistStream::WriteDummyLen()
+/* [Beschreibung]
+
+ Die Methode schreibt 4 Byte in den Stream und gibt die Streamposition
+ zur"uck.
+
+ [R"uckgabewert]
+
+ UINT32 Die Position hinter der L"angenangabe wird zur"uckgegeben.
+
+ [Beispiel]
+
+ UINT32 nObjPos = rStm.WriteDummyLen();
+ ...
+ // Daten schreiben
+ ...
+ rStm.WriteLen( nObjPos );
+
+ [Querverweise]
+
+ <SvPersistStream::ReadLen>, <SvPersistStream::WriteLen>
+
+*/
+{
+#ifdef DBG_UTIL
+ UINT32 nPos = Tell();
+#endif
+ UINT32 n0 = 0;
+ *this << n0; // wegen Sun sp
+ // keine Assertion bei Streamfehler
+ DBG_ASSERT( GetError() != SVSTREAM_OK
+ || (sizeof( UINT32 ) == Tell() -nPos),
+ "keine 4-Byte fuer Langenangabe" );
+ return Tell();
+}
+
+//=========================================================================
+void SvPersistStream::WriteLen
+(
+ UINT32 nObjPos /* die Position + 4, an der die L"ange geschrieben
+ wird. */
+)
+/* [Beschreibung]
+
+ Die Methode schreibt die Differenz zwischen der aktuellen und
+ nObjPos als UINT32 an die Position nObjPos -4 im Stream. Danach
+ wird der Stream wieder auf die alte Position gestellt.
+
+ [Beispiel]
+
+ Die Differenz enth"alt nicht die L"angenangabe.
+
+ UINT32 nObjPos = rStm.WriteDummyLen();
+ ...
+ // Daten schreiben
+ ...
+ rStm.WriteLen( nObjPos );
+ // weitere Daten schreiben
+
+ [Querverweise]
+
+ <SvPersistStream::ReadLen>, <SvPersistStream::WriteDummyLen>
+*/
+{
+ UINT32 nPos = Tell();
+ UINT32 nLen = nPos - nObjPos;
+ // die Laenge mu� im stream 4-Byte betragen
+ Seek( nObjPos - sizeof( UINT32 ) );
+ // Laenge schreiben
+ *this << nLen;
+ Seek( nPos );
+}
+
+//=========================================================================
+UINT32 SvPersistStream::ReadLen
+(
+ UINT32 * pTestPos /* Die Position des Streams, nach dem Lesen der
+ L"ange, wird zur"uckgegeben. Es darf auch NULL
+ "ubergeben werden. */
+)
+/* [Beschreibung]
+
+ Liest die L"ange die vorher mit <SvPersistStream::WriteDummyLen>
+ und <SvPersistStream::WriteLen> geschrieben wurde.
+*/
+{
+ UINT32 nLen;
+ *this >> nLen;
+ if( pTestPos )
+ *pTestPos = Tell();
+ return nLen;
+}
+
+//=========================================================================
+// Dateirormat abw"arts kompatibel
+#ifdef STOR_NO_OPTIMIZE
+#define P_VER (BYTE)0x00
+#else
+#define P_VER (BYTE)0x01
+#endif
+#define P_VER_MASK (BYTE)0x0F
+#define P_ID_0 (BYTE)0x80
+#define P_OBJ (BYTE)0x40
+#define P_DBGUTIL (BYTE)0x20
+#define P_ID (BYTE)0x10
+#ifdef STOR_NO_OPTIMIZE
+#define P_STD P_DBGUTIL
+#else
+#define P_STD 0
+#endif
+
+static void WriteId
+(
+ SvStream & rStm,
+ BYTE nHdr,
+ UINT32 nId,
+ USHORT nClassId
+)
+{
+#ifdef STOR_NO_OPTIMIZE
+ nHdr |= P_ID;
+#endif
+ nHdr |= P_VER;
+ if( nHdr & P_ID )
+ {
+ if( (nHdr & P_OBJ) || nId != 0 )
+ { // Id nur bei Zeiger, oder DBGUTIL
+ rStm << (BYTE)(nHdr);
+ SvPersistStream::WriteCompressed( rStm, nId );
+ }
+ else
+ { // NULL Pointer
+ rStm << (BYTE)(nHdr | P_ID_0);
+ return;
+ }
+ }
+ else
+ rStm << nHdr;
+
+ if( (nHdr & P_DBGUTIL) || (nHdr & P_OBJ) )
+ // Objekte haben immer eine Klasse,
+ // Pointer nur bei DBG_UTIL und != NULL
+ SvPersistStream::WriteCompressed( rStm, nClassId );
+}
+
+//=========================================================================
+static void ReadId
+(
+ SvStream & rStm,
+ BYTE & nHdr,
+ UINT32 & nId,
+ USHORT & nClassId
+)
+{
+ nClassId = 0;
+ rStm >> nHdr;
+ if( nHdr & P_ID_0 )
+ nId = 0;
+ else
+ {
+ if( (nHdr & P_VER_MASK) == 0 )
+ {
+ if( (nHdr & P_DBGUTIL) || !(nHdr & P_OBJ) )
+ nId = SvPersistStream::ReadCompressed( rStm );
+ else
+ nId = 0;
+ }
+ else if( nHdr & P_ID )
+ nId = SvPersistStream::ReadCompressed( rStm );
+
+ if( (nHdr & P_DBGUTIL) || (nHdr & P_OBJ) )
+ nClassId = (USHORT)SvPersistStream::ReadCompressed( rStm );
+ }
+}
+
+//=========================================================================
+void SvPersistStream::WriteObj
+(
+ BYTE nHdr,
+ SvPersistBase * pObj
+)
+{
+#ifdef STOR_NO_OPTIMIZE
+ UINT32 nObjPos = 0;
+ if( nHdr & P_DBGUTIL )
+ // Position fuer Laenge merken
+ nObjPos = WriteDummyLen();
+#endif
+ pObj->Save( *this );
+#ifdef STOR_NO_OPTIMIZE
+ if( nHdr & P_DBGUTIL )
+ WriteLen( nObjPos );
+#endif
+}
+
+//=========================================================================
+SvPersistStream& SvPersistStream::WritePointer
+(
+ SvPersistBase * pObj
+)
+{
+ BYTE nP = P_STD;
+
+ if( pObj )
+ {
+ ULONG nId = GetIndex( pObj );
+ if( nId )
+ nP |= P_ID;
+ else
+ {
+ nId = aPUIdx.Insert( pObj );
+ aPTable.Insert( (ULONG)pObj, (void *)nId );
+ nP |= P_OBJ;
+ }
+ WriteId( *this, nP, nId, pObj->GetClassId() );
+ if( nP & P_OBJ )
+ WriteObj( nP, pObj );
+ }
+ else
+ { // NULL Pointer
+ WriteId( *this, nP | P_ID, 0, 0 );
+ }
+ return *this;
+}
+
+//=========================================================================
+UINT32 SvPersistStream::ReadObj
+(
+ SvPersistBase * & rpObj,
+ BOOL bRegister
+)
+{
+ BYTE nHdr;
+ UINT32 nId = 0;
+ USHORT nClassId;
+
+ rpObj = NULL; // Spezifikation: Im Fehlerfall 0.
+ ReadId( *this, nHdr, nId, nClassId );
+
+ // reine Versionsnummer durch maskieren
+ if( P_VER < (nHdr & P_VER_MASK) )
+ {
+ SetError( SVSTREAM_FILEFORMAT_ERROR );
+ DBG_ERROR( "false version" );
+ }
+
+ if( !(nHdr & P_ID_0) && GetError() == SVSTREAM_OK )
+ {
+ if( P_OBJ & nHdr )
+ { // read object, nId nur bei P_DBGUTIL gesetzt
+ DBG_ASSERT( !(nHdr & P_DBGUTIL) || NULL == aPUIdx.Get( nId ),
+ "object already exist" );
+ SvCreateInstancePersist pFunc = rClassMgr.Get( nClassId );
+
+ UINT32 nObjLen(0), nObjPos(0);
+ if( nHdr & P_DBGUTIL )
+ nObjLen = ReadLen( &nObjPos );
+ if( !pFunc )
+ {
+#ifdef DBG_UTIL
+ ByteString aStr( "no class with id: " );
+ aStr += ByteString::CreateFromInt32( nClassId );
+ aStr += " registered";
+ DBG_WARNING( aStr.GetBuffer() );
+#endif
+ SetError( ERRCODE_IO_NOFACTORY );
+ return 0;
+ }
+ pFunc( &rpObj );
+ // Sichern
+ rpObj->AddRef();
+
+ if( bRegister )
+ {
+ // unbedingt erst in Tabelle eintragen
+ ULONG nNewId = aPUIdx.Insert( rpObj );
+ // um den gleichen Zustand, wie nach dem Speichern herzustellen
+ aPTable.Insert( (ULONG)rpObj, (void *)nNewId );
+ DBG_ASSERT( !(nHdr & P_DBGUTIL) || nId == nNewId,
+ "read write id conflict: not the same" );
+ }
+ // und dann Laden
+ rpObj->Load( *this );
+#ifdef DBG_UTIL
+ if( nObjLen + nObjPos != Tell() )
+ {
+ ByteString aStr( "false object len: read = " );
+ aStr += ByteString::CreateFromInt32( (long)(Tell() - nObjPos) );
+ aStr += ", should = ";
+ aStr += ByteString::CreateFromInt32( nObjLen );
+ DBG_ERROR( aStr.GetBuffer() );
+ }
+#endif
+ rpObj->RestoreNoDelete();
+ rpObj->ReleaseRef();
+ }
+ else
+ {
+ rpObj = GetObject( nId );
+ DBG_ASSERT( rpObj != NULL, "object does not exist" );
+ DBG_ASSERT( rpObj->GetClassId() == nClassId, "class mismatch" );
+ }
+ }
+ return nId;
+}
+
+//=========================================================================
+SvPersistStream& SvPersistStream::ReadPointer
+(
+ SvPersistBase * & rpObj
+)
+{
+ ReadObj( rpObj, TRUE );
+ return *this;
+}
+
+//=========================================================================
+SvPersistStream& operator <<
+(
+ SvPersistStream & rStm,
+ SvPersistBase * pObj
+)
+{
+ return rStm.WritePointer( pObj );
+}
+
+//=========================================================================
+SvPersistStream& operator >>
+(
+ SvPersistStream & rStm,
+ SvPersistBase * & rpObj
+)
+{
+ return rStm.ReadPointer( rpObj );
+}
+
+//=========================================================================
+SvStream& operator <<
+(
+ SvStream & rStm,
+ SvPersistStream & rThis
+)
+{
+ SvStream * pOldStm = rThis.GetStream();
+ rThis.SetStream( &rStm );
+
+ BYTE bTmp = 0;
+ rThis << bTmp; // Version
+ UINT32 nCount = (UINT32)rThis.aPUIdx.Count();
+ rThis << nCount;
+ SvPersistBase * pEle = rThis.aPUIdx.First();
+ for( UINT32 i = 0; i < nCount; i++ )
+ {
+ BYTE nP = P_OBJ | P_ID | P_STD;
+ WriteId( rThis, nP, rThis.aPUIdx.GetCurIndex(),
+ pEle->GetClassId() );
+ rThis.WriteObj( nP, pEle );
+ pEle = rThis.aPUIdx.Next();
+ }
+ rThis.SetStream( pOldStm );
+ return rStm;
+}
+
+//=========================================================================
+SvStream& operator >>
+(
+ SvStream & rStm,
+ SvPersistStream & rThis
+)
+{
+ SvStream * pOldStm = rThis.GetStream();
+ rThis.SetStream( &rStm );
+
+ BYTE nVers;
+ rThis >> nVers; // Version
+ if( 0 == nVers )
+ {
+ UINT32 nCount = 0;
+ rThis >> nCount;
+ for( UINT32 i = 0; i < nCount; i++ )
+ {
+ SvPersistBase * pEle;
+ // Lesen, ohne in die Tabellen einzutragen
+ UINT32 nId = rThis.ReadObj( pEle, FALSE );
+ if( rThis.GetError() )
+ break;
+
+ // Die Id eines Objektes wird nie modifiziert
+ rThis.aPUIdx.Insert( nId, pEle );
+ rThis.aPTable.Insert( (ULONG)pEle, (void *)nId );
+ }
+ }
+ else
+ rThis.SetError( SVSTREAM_FILEFORMAT_ERROR );
+
+ rThis.SetStream( pOldStm );
+ return rStm;
+}
+
+//=========================================================================
+ULONG SvPersistStream::InsertObj( SvPersistBase * pObj )
+{
+ ULONG nId = aPUIdx.Insert( pObj );
+ aPTable.Insert( (ULONG)pObj, (void *)nId );
+ return nId;
+}
+
+//=========================================================================
+ULONG SvPersistStream::RemoveObj( SvPersistBase * pObj )
+{
+ ULONG nIdx = GetIndex( pObj );
+ aPUIdx.Remove( nIdx );
+ aPTable.Remove( (ULONG)pObj );
+ return nIdx;
+}
+
diff --git a/tools/source/ref/ref.cxx b/tools/source/ref/ref.cxx
new file mode 100644
index 000000000000..eeee931f9182
--- /dev/null
+++ b/tools/source/ref/ref.cxx
@@ -0,0 +1,51 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/ref.hxx>
+
+/****************** SvRefBaseMemberList **********************************/
+SV_IMPL_REF_LIST( SvRefBase,SvRefBase* )
+
+/**************************************************************************
+#* SvRefBase::~SvRefBase()
+**************************************************************************/
+SvRefBase::~SvRefBase()
+{
+}
+
+/**************************************************************************
+#* SvRefBase::QueryDelete()
+**************************************************************************/
+void SvRefBase::QueryDelete()
+{
+ nRefCount = SV_NO_DELETE_REFCOUNT / 2;
+ delete this;
+}
+
diff --git a/tools/source/solar/makefile.mk b/tools/source/solar/makefile.mk
new file mode 100644
index 000000000000..6f5dd85c608b
--- /dev/null
+++ b/tools/source/solar/makefile.mk
@@ -0,0 +1,63 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=mksvconf
+TARGETTYPE=CUI
+
+LIBSALCPPRT=$(0)
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+CFILES= solar.c
+
+OBJFILES= $(OBJ)$/solar.obj
+
+APP1TARGET= $(TARGET)
+APP1OBJS= $(OBJFILES)
+APP1STDLIBS=
+APP1DEPN=
+APP1DEF=
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.IF "$(L10N-framework)"==""
+ALLTAR : $(INCCOM)$/svconf.h
+.ENDIF # "$(L10N-framework)"==""
+
+$(INCCOM)$/svconf.h : $(BIN)$/$(TARGET)
+ $(BIN)$/$(TARGET) $@
+
diff --git a/tools/source/solar/solar.c b/tools/source/solar/solar.c
new file mode 100644
index 000000000000..608f0baf5129
--- /dev/null
+++ b/tools/source/solar/solar.c
@@ -0,0 +1,562 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+/* POSIX defines that a program is undefined after a SIG_SEGV. The
+ * code stopped working on Linux Kernel 2.6 so I have moved this back to
+ * use FORK.
+ * If at a later time the signals work correctly with the Linux Kernel 2.6
+ * then this change may be reverted although not strictly posix safe. */
+#define USE_FORK_TO_CHECK 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#define I_STDARG
+#ifdef I_STDARG
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#define NO_USE_FORK_TO_CHECK
+#ifdef USE_FORK_TO_CHECK
+#include <sys/wait.h>
+#else
+#include <signal.h>
+#include <setjmp.h>
+#endif
+
+#define printTypeSize(Type,Name) printf( "sizeof(%s)\t= %d\n", Name, sizeof (Type) )
+
+#define isSignedType(Type) (((Type)-1) < 0)
+#define printTypeSign(Type,Name) printf( "%s\t= %s %s\n", Name, ( isSignedType(Type) ? "signed" : "unsigned" ), Name )
+
+
+/*************************************************************************
+|*
+|* IsBigEndian()
+|*
+|* Beschreibung True, wenn CPU BigEndian ist
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+int IsBigEndian()
+{
+ long l = 1;
+ return ! *(char*)&l;
+}
+
+/*************************************************************************
+|*
+|* IsStackGrowingDown()
+|*
+|* Beschreibung True, wenn der Stack nach unten waechst
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+int IsStackGrowingDown_2( int * pI )
+{
+ int i = 1;
+ return ((unsigned long)&i) < (unsigned long)pI;
+}
+
+int IsStackGrowingDown()
+{
+ int i = 1;
+ return IsStackGrowingDown_2(&i);
+}
+
+/*************************************************************************
+|*
+|* GetStackAlignment()
+|*
+|* Beschreibung Alignment von char Parametern, die (hoffentlich)
+|* ueber den Stack uebergeben werden
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+int GetStackAlignment_3( char*p, long l, int i, short s, char b, char c, ... )
+{
+ if ( IsStackGrowingDown() )
+ return &c - &b;
+ else
+ return &b - &c;
+}
+
+int GetStackAlignment_2( char*p, long l, int i, short s, char b, char c )
+{
+ if ( IsStackGrowingDown() )
+ return &c - &b;
+ else
+ return &b - &c;
+}
+
+int GetStackAlignment()
+{
+ int nStackAlignment = GetStackAlignment_3(0,1,2,3,4,5);
+ if ( nStackAlignment != GetStackAlignment_2(0,1,2,3,4,5) )
+ printf( "Pascal calling convention\n" );
+ return nStackAlignment;
+}
+
+
+/*************************************************************************
+|*
+|* Typdeclarations for memory access test functions
+|*
+*************************************************************************/
+typedef enum { t_char, t_short, t_int, t_long, t_double } Type;
+typedef int (*TestFunc)( Type, void* );
+
+
+/*************************************************************************
+|*
+|* PrintArgs()
+|*
+|* Beschreibung Testfunktion fuer variable Parameter
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+#ifdef I_STDARG
+void PrintArgs( int p, ... )
+#else
+void PrintArgs( p, va_alist )
+int p;
+va_dcl
+#endif
+{
+ int value;
+ va_list ap;
+
+#ifdef I_STDARG
+ va_start( ap, p );
+#else
+ va_start( ap );
+#endif
+
+ printf( "value = %d", p );
+
+ while ( ( value = va_arg(ap, int) ) != 0 )
+ printf( " %d", value );
+
+ printf( "\n" );
+ va_end(ap);
+}
+
+#ifndef USE_FORK_TO_CHECK
+/*************************************************************************
+|*
+|* SignalHdl()
+|*
+|* Beschreibung faengt SIGBUS und SIGSEGV in check() ab
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+static jmp_buf check_env;
+static int bSignal;
+void SignalHdl( int sig )
+{
+ bSignal = 1;
+
+ fprintf( stderr, "Signal %d caught\n", sig );
+ signal( SIGSEGV, SIG_DFL );
+ signal( SIGBUS, SIG_DFL );
+ siglongjmp( check_env, sig );
+}
+#endif
+
+/*************************************************************************
+|*
+|* check()
+|*
+|* Beschreibung Testet MemoryZugriff (read/write)
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+int check( TestFunc func, Type eT, void* p )
+{
+#ifdef USE_FORK_TO_CHECK
+ pid_t nChild = fork();
+ if ( nChild )
+ {
+ int exitVal;
+ wait( &exitVal );
+ if ( exitVal & 0xff )
+ return -1;
+ else
+ return exitVal >> 8;
+ }
+ else
+ {
+ exit( func( eT, p ) );
+ }
+#else
+ int result;
+
+ bSignal = 0;
+
+ if ( !sigsetjmp( check_env, 1 ) )
+ {
+ signal( SIGSEGV, SignalHdl );
+ signal( SIGBUS, SignalHdl );
+ result = func( eT, p );
+ signal( SIGSEGV, SIG_DFL );
+ signal( SIGBUS, SIG_DFL );
+ }
+
+ if ( bSignal )
+ return -1;
+ else
+ return 0;
+#endif
+}
+
+/*************************************************************************
+|*
+|* GetAtAddress()
+|*
+|* Beschreibung memory read access
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+int GetAtAddress( Type eT, void* p )
+{
+ switch ( eT )
+ {
+ case t_char: return *((char*)p);
+ case t_short: return *((short*)p);
+ case t_int: return *((int*)p);
+ case t_long: return *((long*)p);
+ case t_double: return *((double*)p);
+ }
+ abort();
+}
+
+/*************************************************************************
+|*
+|* SetAtAddress()
+|*
+|* Beschreibung memory write access
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+int SetAtAddress( Type eT, void* p )
+{
+ switch ( eT )
+ {
+ case t_char: return *((char*)p) = 0;
+ case t_short: return *((short*)p) = 0;
+ case t_int: return *((int*)p) = 0;
+ case t_long: return *((long*)p) = 0;
+ case t_double: return *((double*)p)= 0;
+ }
+ abort();
+}
+
+char* TypeName( Type eT )
+{
+ switch ( eT )
+ {
+ case t_char: return "char";
+ case t_short: return "short";
+ case t_int: return "int";
+ case t_long: return "long";
+ case t_double: return "double";
+ }
+ abort();
+}
+
+/*************************************************************************
+|*
+|* Check(Get|Set)Access()
+|*
+|* Beschreibung Testet MemoryZugriff (read/write)
+|* Zugriffsverletzungen werden abgefangen
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+int CheckGetAccess( Type eT, void* p )
+{
+ int b;
+ b = -1 != check( (TestFunc)GetAtAddress, eT, p );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,
+ "%s read %s at %p\n",
+ (b? "can" : "can not" ), TypeName(eT), p );
+#endif
+ return b;
+}
+int CheckSetAccess( Type eT, void* p )
+{
+ int b;
+
+ b = -1 != check( (TestFunc)SetAtAddress, eT, p );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,
+ "%s write %s at %p\n",
+ (b? "can" : "can not" ), TypeName(eT), p );
+#endif
+ return b;
+}
+
+/*************************************************************************
+|*
+|* GetAlignment()
+|*
+|* Beschreibung Bestimmt das Alignment verschiedener Typen
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+int GetAlignment( Type eT )
+{
+ char a[ 16*8 ];
+ long p = (long)(void*)a;
+ int i;
+
+ /* clear a[...] to set legal value for double access */
+ for ( i = 0; i < 16*8; i++ )
+ a[i] = 0;
+
+ p = ( p + 0xF ) & ~0xF;
+ for ( i = 1; i < 16; i++ )
+ if ( CheckGetAccess( eT, (void*)(p+i) ) )
+ return i;
+ return 0;
+}
+
+/*************************************************************************
+|*
+|* struct Description
+|*
+|* Beschreibung Beschreibt die Parameter der Architektur
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+struct Description
+{
+ int bBigEndian;
+ int bStackGrowsDown;
+ int nStackAlignment;
+ int nAlignment[3]; /* 2,4,8 */
+};
+
+/*************************************************************************
+|*
+|* Description_Ctor()
+|*
+|* Beschreibung Bestimmt die Parameter der Architektur
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+void Description_Ctor( struct Description* pThis )
+{
+ pThis->bBigEndian = IsBigEndian();
+ pThis->bStackGrowsDown = IsStackGrowingDown();
+ pThis->nStackAlignment = GetStackAlignment();
+
+ if ( sizeof(short) != 2 )
+ abort();
+ pThis->nAlignment[0] = GetAlignment( t_short );
+ if ( sizeof(int) != 4 )
+ abort();
+ pThis->nAlignment[1] = GetAlignment( t_int );
+
+ if ( sizeof(long) == 8 )
+ pThis->nAlignment[2] = GetAlignment( t_long );
+ else if ( sizeof(double) == 8 )
+ pThis->nAlignment[2] = GetAlignment( t_double );
+ else
+ abort();
+}
+
+/*************************************************************************
+|*
+|* Description_Print()
+|*
+|* Beschreibung Schreibt die Parameter der Architektur als Header
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+void Description_Print( struct Description* pThis, char* name )
+{
+ int i;
+ FILE* f = fopen( name, "w" );
+ if( ! f ) {
+ fprintf( stderr, "Unable to open file %s: %s\n", name, strerror( errno ) );
+ exit( 99 );
+ }
+ fprintf( f, "#define __%s\n",
+ pThis->bBigEndian ? "BIGENDIAN" : "LITTLEENDIAN" );
+ for ( i = 0; i < 3; i++ )
+ fprintf( f, "#define __ALIGNMENT%d\t%d\n",
+ 1 << (i+1), pThis->nAlignment[i] );
+ fprintf( f, "/* Stack alignment is not used... */\n" );
+ fprintf( f, "#define __STACKALIGNMENT\t%d\n", pThis->nStackAlignment );
+ fprintf( f, "#define __STACKDIRECTION\t%d\n",
+ pThis->bStackGrowsDown ? -1 : 1 );
+ fprintf( f, "#define __SIZEOFCHAR\t%d\n", sizeof( char ) );
+ fprintf( f, "#define __SIZEOFSHORT\t%d\n", sizeof( short ) );
+ fprintf( f, "#define __SIZEOFINT\t%d\n", sizeof( int ) );
+ fprintf( f, "#define __SIZEOFLONG\t%d\n", sizeof( long ) );
+ fprintf( f, "#define __SIZEOFPOINTER\t%d\n", sizeof( void* ) );
+ fprintf( f, "#define __SIZEOFDOUBLE\t%d\n", sizeof( double ) );
+ fprintf( f, "#define __IEEEDOUBLE\n" );
+ fclose( f );
+}
+
+/*************************************************************************
+|*
+|* InfoMemoryAccess()
+|*
+|* Beschreibung Informeller Bytezugriffstest
+|*
+|* Ersterstellung EG 26.06.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+void InfoMemoryAccess( char* p )
+{
+ if ( CheckGetAccess( t_char, p ) )
+ printf( "can read address %p\n", p );
+ else
+ printf( "can not read address %p\n", p );
+
+ if ( CheckSetAccess( t_char, p ) )
+ printf( "can write address %p\n", p );
+ else
+ printf( "can not write address %p\n", p );
+}
+
+/*************************************************************************
+|*
+|* InfoMemoryTypeAccess()
+|*
+|* Beschreibung Informeller Zugriffstest verschiedener Typen
+|*
+|* Ersterstellung EG 15.08.96
+|* Letzte Aenderung
+|*
+*************************************************************************/
+void InfoMemoryTypeAccess( Type eT )
+{
+ char a[64];
+ int i;
+
+ /* clear a[...] to set legal value for double access */
+ for ( i = 0; i < 64; i++ )
+ a[i] = 0;
+
+ for ( i = 56; i >= 7; i >>= 1 )
+ {
+ printf( "Zugriff %s auf %i-Aligned Adresse : ", TypeName( eT ), i / 7 );
+ printf( ( CheckGetAccess( eT, (long*)&a[i] ) ? "OK\n" : "ERROR\n" ) );
+ }
+}
+/************************************************************************
+ *
+ * Use C code to determine the characteristics of the building platform.
+ *
+ ************************************************************************/
+int main( int argc, char* argv[] )
+{
+ printTypeSign( char, "char" );
+ printTypeSign( short, "short" );
+ printTypeSign( int, "int" );
+ printTypeSign( long, "long" );
+
+ printTypeSize( char, "char" );
+ printTypeSize( short, "short" );
+ printTypeSize( int, "int" );
+ printTypeSize( long, "long" );
+ printTypeSize( float, "float" );
+ printTypeSize( double, "double" );
+ printTypeSize( void *, "void *" );
+
+ if ( IsBigEndian() )
+ printf( "BIGENDIAN (Sparc, MC680x0, RS6000, IP22, IP32, g3)\n" );
+ else
+ printf( "LITTLEENDIAN (Intel, VAX, PowerPC)\n" );
+
+ if( IsStackGrowingDown() )
+ printf( "Stack waechst nach unten\n" );
+ else
+ printf( "Stack waechst nach oben\n" );
+
+ printf( "STACKALIGNMENT : %d\n", GetStackAlignment() );
+
+ /* PrintArgs( 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ); */
+
+ if ( argc > 1 )
+ {
+ struct Description description;
+ Description_Ctor( &description );
+ Description_Print( &description, argv[1] );
+ }
+ {
+ char* p = NULL;
+ InfoMemoryAccess( p );
+ p = (char*)&p;
+ InfoMemoryAccess( p );
+ InfoMemoryTypeAccess( t_short );
+ InfoMemoryTypeAccess( t_int );
+ InfoMemoryTypeAccess( t_long );
+ InfoMemoryTypeAccess( t_double );
+ }
+
+ exit( 0 );
+}
diff --git a/tools/source/stream/cachestr.cxx b/tools/source/stream/cachestr.cxx
new file mode 100644
index 000000000000..0233dc25fb52
--- /dev/null
+++ b/tools/source/stream/cachestr.cxx
@@ -0,0 +1,290 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <tools/cachestr.hxx>
+#include <tools/tempfile.hxx>
+
+/*************************************************************************
+|*
+|* SvCacheStream::SvCacheStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+SvCacheStream::SvCacheStream( ULONG nMaxMemSize )
+{
+ if( !nMaxMemSize )
+ nMaxMemSize = 20480;
+ SvStream::bIsWritable = TRUE;
+ nMaxSize = nMaxMemSize;
+ bPersistent = FALSE;
+ pSwapStream = 0;
+ pCurrentStream = new SvMemoryStream( nMaxMemSize );
+ pTempFile = 0;
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::SvCacheStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+SvCacheStream::SvCacheStream( const String &rFileName,
+ ULONG nExpectedSize,
+ ULONG nMaxMemSize )
+{
+ if( !nMaxMemSize )
+ nMaxMemSize = 20480;
+
+ if( nExpectedSize > nMaxMemSize )
+ nExpectedSize = nMaxMemSize; // oder gleich in File schreiben
+ else if( !nExpectedSize )
+ nExpectedSize = 4096;
+
+ SvStream::bIsWritable = TRUE;
+ nMaxSize = nMaxMemSize;
+ bPersistent = TRUE;
+ aFileName = rFileName;
+ pSwapStream = 0;
+ pCurrentStream = new SvMemoryStream( nExpectedSize );
+ pTempFile = 0;
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::~SvCacheStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+SvCacheStream::~SvCacheStream()
+{
+ if( pCurrentStream != pSwapStream )
+ delete pSwapStream;
+ delete pCurrentStream;
+
+ if( pSwapStream && !bPersistent && pTempFile )
+ {
+ // temporaeres File loeschen
+ pTempFile->EnableKillingFile( TRUE );
+ }
+
+ delete pTempFile;
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::SwapOut()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+void SvCacheStream::SwapOut()
+{
+ if( pCurrentStream != pSwapStream )
+ {
+ if( !pSwapStream && !aFileName.Len() )
+ {
+ if (aFilenameLinkHdl.IsSet())
+ {
+ // pSwapStream wird zum Schutz gegen Reentranz genutzt
+ pSwapStream = pCurrentStream;
+ Link aLink( aFilenameLinkHdl );
+ aFilenameLinkHdl = Link();
+ aLink.Call(this);
+ // pSwapStream nur zuruecksetzen, wenn nicht ueber
+ // SetSwapStream geaendert
+ if( pSwapStream == pCurrentStream ) pSwapStream = 0;
+ }
+ else
+ {
+ pTempFile = new TempFile;
+ aFileName = pTempFile->GetName();
+ }
+ }
+
+ ULONG nPos = pCurrentStream->Tell();
+ pCurrentStream->Seek( 0 );
+ if( !pSwapStream )
+ pSwapStream = new SvFileStream( aFileName, STREAM_READWRITE | STREAM_TRUNC );
+ *pSwapStream << *pCurrentStream;
+ pSwapStream->Flush();
+ delete pCurrentStream;
+ pCurrentStream = pSwapStream;
+ pCurrentStream->Seek( nPos );
+ }
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::GetData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+ULONG SvCacheStream::GetData( void* pData, ULONG nSize )
+{
+ return pCurrentStream->Read( pData, nSize );
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::PutData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+ULONG SvCacheStream::PutData( const void* pData, ULONG nSize )
+{
+ // lieber unnoetig auslagern als unnoetig umkopieren
+ if( pCurrentStream != pSwapStream
+ && pCurrentStream->Tell() + nSize > nMaxSize )
+ SwapOut();
+ return pCurrentStream->Write( pData, nSize );
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::SeekPos()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+ULONG SvCacheStream::SeekPos( ULONG nPos )
+{
+ return pCurrentStream->Seek( nPos );
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::FlushData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+void SvCacheStream::FlushData()
+{
+ pCurrentStream->Flush();
+ if( pCurrentStream != pSwapStream
+ && ((SvMemoryStream*)pCurrentStream)->GetSize() > nMaxSize )
+ SwapOut();
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::GetStr()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+const void* SvCacheStream::GetBuffer()
+{
+ Flush();
+ if( pCurrentStream != pSwapStream )
+ return ((SvMemoryStream*)pCurrentStream)->GetData();
+ else
+ return 0;
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::SetSize()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+void SvCacheStream::SetSize( ULONG nSize )
+{
+ pCurrentStream->SetStreamSize( nSize );
+}
+
+/*************************************************************************
+|*
+|* SvCacheStream::GetSize()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 27.09.94
+|* Letzte Aenderung OV 27.09.94
+|*
+*************************************************************************/
+
+ULONG SvCacheStream::GetSize()
+{
+ // ACHTUNG: SvMemoryStream::GetSize() gibt Groesse
+ // des allozierten Buffers zurueck
+ Flush();
+ ULONG nTemp = Tell();
+ ULONG nLength = Seek( STREAM_SEEK_TO_END );
+ Seek( nTemp );
+ return nLength;
+}
+
+void SvCacheStream::SetFilenameHdl( const Link& rLink)
+{
+ aFilenameLinkHdl = rLink;
+}
+
+const Link& SvCacheStream::GetFilenameHdl() const
+{
+ return aFilenameLinkHdl;
+}
diff --git a/tools/source/stream/makefile.mk b/tools/source/stream/makefile.mk
new file mode 100644
index 000000000000..ee548934c6c6
--- /dev/null
+++ b/tools/source/stream/makefile.mk
@@ -0,0 +1,58 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=stream
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/stream.obj \
+ $(SLO)$/strmsys.obj \
+ $(SLO)$/cachestr.obj \
+ $(SLO)$/vcompat.obj
+
+OBJFILES+= $(OBJ)$/stream.obj \
+ $(OBJ)$/strmsys.obj \
+ $(OBJ)$/cachestr.obj \
+ $(OBJ)$/vcompat.obj
+
+# --- Targets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
+$(SLO)$/strmsys.obj : \
+ strmwnt.cxx \
+ strmos2.cxx \
+ strmunx.cxx
+
diff --git a/tools/source/stream/stream.cxx b/tools/source/stream/stream.cxx
new file mode 100644
index 000000000000..9fdef8436f1a
--- /dev/null
+++ b/tools/source/stream/stream.cxx
@@ -0,0 +1,2841 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+// ToDo:
+// - Read->RefreshBuffer->Auf Aenderungen von nBufActualLen reagieren
+
+#include <cstddef>
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h> // isspace
+#include <stdlib.h> // strtol, _crotl
+
+#include "boost/static_assert.hpp"
+
+/*
+#if defined( DBG_UTIL ) && (OSL_DEBUG_LEVEL > 1)
+// prueft Synchronisation des Buffers nach allen Read, Write, Seek
+#define OV_DEBUG
+#endif
+*/
+
+#include <tools/solar.h>
+
+#if defined(BLC)
+#define SWAPNIBBLES(c) c=_crotl(c,4);
+#else
+#define SWAPNIBBLES(c) \
+unsigned char nSwapTmp=c; \
+nSwapTmp <<= 4; \
+c >>= 4; \
+c |= nSwapTmp;
+#endif
+
+#include <tools/debug.hxx>
+#define ENABLE_BYTESTRING_STREAM_OPERATORS
+#include <tools/stream.hxx>
+#include <osl/thread.h>
+#include <algorithm>
+
+// -----------------------------------------------------------------------
+
+DBG_NAME( Stream )
+
+// -----------------------------------------------------------------------
+
+// sprintf Param-Mode
+#define SPECIAL_PARAM_NONE 0 // Format-Str, Number
+#define SPECIAL_PARAM_WIDTH 1 // Format-Str, Width, Number
+#define SPECIAL_PARAM_PRECISION 2 // Format-Str, Precision, Number
+#define SPECIAL_PARAM_BOTH 3 // Format-Str, Width, Precision, Number
+
+// -----------------------------------------------------------------------
+
+// !!! Nicht inline, wenn Operatoren <<,>> inline sind
+inline static void SwapUShort( sal_uInt16& r )
+ { r = SWAPSHORT(r); }
+inline static void SwapShort( short& r )
+ { r = SWAPSHORT(r); }
+inline static void SwapLong( long& r )
+ { r = SWAPLONG(r); }
+inline static void SwapULong( sal_uInt32& r )
+ { r = SWAPLONG(r); }
+inline static void SwapLongInt( int& r )
+ { r = SWAPLONG(r); }
+inline static void SwapLongUInt( unsigned int& r )
+ { r = SWAPLONG(r); }
+#ifdef UNX
+inline static void SwapFloat( float& r )
+ {
+ *((sal_uInt32*)(void*)&r) = SWAPLONG( *((sal_uInt32*)(void*)&r) );
+ }
+inline static void SwapDouble( double& r )
+ {
+ if( sizeof(double) != 8 )
+ {
+ DBG_ASSERT( FALSE, "Can only swap 8-Byte-doubles\n" );
+ }
+ else
+ {
+ sal_uInt32* c = (sal_uInt32*)(void*)&r;
+ c[0] ^= c[1]; // zwei 32-Bit-Werte in situ vertauschen
+ c[1] ^= c[0];
+ c[0] ^= c[1];
+ c[0] = SWAPLONG(c[0]); // und die beiden 32-Bit-Werte selbst in situ drehen
+ c[1] = SWAPLONG(c[1]);
+ }
+ }
+#endif
+
+//SDO
+
+#define READNUMBER_WITHOUT_SWAP(datatype,value) \
+{\
+int tmp = eIOMode; \
+if( (tmp == STREAM_IO_READ) && sizeof(datatype)<=nBufFree) \
+{\
+ for (std::size_t i = 0; i < sizeof(datatype); i++)\
+ ((char *)&value)[i] = pBufPos[i];\
+ nBufActualPos += sizeof(datatype);\
+ pBufPos += sizeof(datatype);\
+ nBufFree -= sizeof(datatype);\
+}\
+else\
+ Read( (char*)&value, sizeof(datatype) );\
+}
+
+#define WRITENUMBER_WITHOUT_SWAP(datatype,value) \
+{\
+int tmp = eIOMode; \
+if( (tmp==STREAM_IO_WRITE) && sizeof(datatype) <= nBufFree)\
+{\
+ for (std::size_t i = 0; i < sizeof(datatype); i++)\
+ pBufPos[i] = ((char *)&value)[i];\
+ nBufFree -= sizeof(datatype);\
+ nBufActualPos += sizeof(datatype);\
+ if( nBufActualPos > nBufActualLen )\
+ nBufActualLen = nBufActualPos;\
+ pBufPos += sizeof(datatype);\
+ bIsDirty = TRUE;\
+}\
+else\
+ Write( (char*)&value, sizeof(datatype) );\
+}
+
+//============================================================================
+//
+// class SvLockBytes
+//
+//============================================================================
+
+void SvLockBytes::close()
+{
+ if (m_bOwner)
+ delete m_pStream;
+ m_pStream = 0;
+}
+
+//============================================================================
+TYPEINIT0(SvLockBytes);
+
+//============================================================================
+// virtual
+ErrCode SvLockBytes::ReadAt(sal_Size nPos, void * pBuffer, sal_Size nCount,
+ sal_Size * pRead) const
+{
+ if (!m_pStream)
+ {
+ DBG_ERROR("SvLockBytes::ReadAt(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ m_pStream->Seek(nPos);
+ sal_Size nTheRead = m_pStream->Read(pBuffer, nCount);
+ if (pRead)
+ *pRead = nTheRead;
+ return m_pStream->GetErrorCode();
+}
+
+//============================================================================
+// virtual
+ErrCode SvLockBytes::WriteAt(sal_Size nPos, const void * pBuffer, sal_Size nCount,
+ sal_Size * pWritten)
+{
+ if (!m_pStream)
+ {
+ DBG_ERROR("SvLockBytes::WriteAt(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ m_pStream->Seek(nPos);
+ sal_Size nTheWritten = m_pStream->Write(pBuffer, nCount);
+ if (pWritten)
+ *pWritten = nTheWritten;
+ return m_pStream->GetErrorCode();
+}
+
+//============================================================================
+// virtual
+ErrCode SvLockBytes::Flush() const
+{
+ if (!m_pStream)
+ {
+ DBG_ERROR("SvLockBytes::Flush(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ m_pStream->Flush();
+ return m_pStream->GetErrorCode();
+}
+
+//============================================================================
+// virtual
+ErrCode SvLockBytes::SetSize(sal_Size nSize)
+{
+ if (!m_pStream)
+ {
+ DBG_ERROR("SvLockBytes::SetSize(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ m_pStream->SetStreamSize(nSize);
+ return m_pStream->GetErrorCode();
+}
+
+//============================================================================
+ErrCode SvLockBytes::LockRegion(sal_Size, sal_Size, LockType)
+{
+ DBG_ERROR("SvLockBytes::LockRegion(): Not implemented");
+ return ERRCODE_NONE;
+}
+
+//============================================================================
+
+ErrCode SvLockBytes::UnlockRegion(sal_Size, sal_Size, LockType)
+{
+ DBG_ERROR("SvLockBytes::UnlockRegion(): Not implemented");
+ return ERRCODE_NONE;
+}
+
+//============================================================================
+ErrCode SvLockBytes::Stat(SvLockBytesStat * pStat, SvLockBytesStatFlag) const
+{
+ if (!m_pStream)
+ {
+ DBG_ERROR("SvLockBytes::Stat(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ if (pStat)
+ {
+ sal_Size nPos = m_pStream->Tell();
+ pStat->nSize = m_pStream->Seek(STREAM_SEEK_TO_END);
+ m_pStream->Seek(nPos);
+ }
+ return ERRCODE_NONE;
+}
+
+//============================================================================
+//
+// class SvOpenLockBytes
+//
+//============================================================================
+
+TYPEINIT1(SvOpenLockBytes, SvLockBytes);
+
+//============================================================================
+//
+// class SvAsyncLockBytes
+//
+//============================================================================
+
+TYPEINIT1(SvAsyncLockBytes, SvOpenLockBytes);
+
+//============================================================================
+// virtual
+ErrCode SvAsyncLockBytes::ReadAt(sal_Size nPos, void * pBuffer, sal_Size nCount,
+ sal_Size * pRead) const
+{
+ if (m_bTerminated)
+ return SvOpenLockBytes::ReadAt(nPos, pBuffer, nCount, pRead);
+ else
+ {
+ sal_Size nTheCount = std::min(nPos < m_nSize ? m_nSize - nPos : 0, nCount);
+ ErrCode nError = SvOpenLockBytes::ReadAt(nPos, pBuffer, nTheCount,
+ pRead);
+ return !nCount || nTheCount == nCount || nError ? nError :
+ ERRCODE_IO_PENDING;
+ }
+}
+
+//============================================================================
+// virtual
+ErrCode SvAsyncLockBytes::WriteAt(sal_Size nPos, const void * pBuffer,
+ sal_Size nCount, sal_Size * pWritten)
+{
+ if (m_bTerminated)
+ return SvOpenLockBytes::WriteAt(nPos, pBuffer, nCount, pWritten);
+ else
+ {
+ sal_Size nTheCount = std::min(nPos < m_nSize ? m_nSize - nPos : 0, nCount);
+ ErrCode nError = SvOpenLockBytes::WriteAt(nPos, pBuffer, nTheCount,
+ pWritten);
+ return !nCount || nTheCount == nCount || nError ? nError :
+ ERRCODE_IO_PENDING;
+ }
+}
+
+//============================================================================
+// virtual
+ErrCode SvAsyncLockBytes::FillAppend(const void * pBuffer, sal_Size nCount,
+ sal_Size * pWritten)
+{
+ sal_Size nTheWritten;
+ ErrCode nError = SvOpenLockBytes::WriteAt(m_nSize, pBuffer, nCount,
+ &nTheWritten);
+ if (!nError)
+ m_nSize += nTheWritten;
+ if (pWritten)
+ *pWritten = nTheWritten;
+ return nError;
+}
+
+//============================================================================
+// virtual
+sal_Size SvAsyncLockBytes::Seek(sal_Size nPos)
+{
+ if (nPos != STREAM_SEEK_TO_END)
+ m_nSize = nPos;
+ return m_nSize;
+}
+
+//============================================================================
+//
+// class SvStream
+//
+//============================================================================
+
+sal_Size SvStream::GetData( void* pData, sal_Size nSize )
+{
+ if( !GetError() )
+ {
+ DBG_ASSERT( xLockBytes.Is(), "pure virtual function" );
+ sal_Size nRet;
+ nError = xLockBytes->ReadAt( nActPos, pData, nSize, &nRet );
+ nActPos += nRet;
+ return nRet;
+ }
+ else return 0;
+}
+
+ErrCode SvStream::SetLockBytes( SvLockBytesRef& rLB )
+{
+ xLockBytes = rLB;
+ RefreshBuffer();
+ return ERRCODE_NONE;
+}
+
+//========================================================================
+
+sal_Size SvStream::PutData( const void* pData, sal_Size nSize )
+{
+ if( !GetError() )
+ {
+ DBG_ASSERT( xLockBytes.Is(), "pure virtual function" );
+ sal_Size nRet;
+ nError = xLockBytes->WriteAt( nActPos, pData, nSize, &nRet );
+ nActPos += nRet;
+ return nRet;
+ }
+ else return 0;
+}
+
+//========================================================================
+
+sal_Size SvStream::SeekPos( sal_Size nPos )
+{
+ if( !GetError() && nPos == STREAM_SEEK_TO_END )
+ {
+ DBG_ASSERT( xLockBytes.Is(), "pure virtual function" );
+ SvLockBytesStat aStat;
+ xLockBytes->Stat( &aStat, SVSTATFLAG_DEFAULT );
+ nActPos = aStat.nSize;
+ }
+ else
+ nActPos = nPos;
+ return nActPos;
+}
+
+//========================================================================
+
+void SvStream::FlushData()
+{
+ if( !GetError() )
+ {
+ DBG_ASSERT( xLockBytes.Is(), "pure virtual function" );
+ nError = xLockBytes->Flush();
+ }
+}
+
+//========================================================================
+
+void SvStream::SetSize( sal_Size nSize )
+{
+ DBG_ASSERT( xLockBytes.Is(), "pure virtual function" );
+ nError = xLockBytes->SetSize( nSize );
+}
+
+void SvStream::ImpInit()
+{
+ nActPos = 0;
+ nCompressMode = COMPRESSMODE_NONE;
+ eStreamCharSet = osl_getThreadTextEncoding();
+// eTargetCharSet = osl_getThreadTextEncoding();
+ nCryptMask = 0;
+ bIsEof = FALSE;
+#if defined UNX
+ eLineDelimiter = LINEEND_LF; // UNIX-Format
+#else
+ eLineDelimiter = LINEEND_CRLF; // DOS-Format
+#endif
+
+ SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ nBufFilePos = 0;
+ nBufActualPos = 0;
+ bIsDirty = FALSE;
+ bIsConsistent = TRUE;
+ bIsWritable = TRUE;
+
+ pRWBuf = 0;
+ pBufPos = 0;
+ nBufSize = 0;
+ nBufActualLen = 0;
+ eIOMode = STREAM_IO_DONTKNOW;
+ nBufFree = 0;
+
+ nRadix = 10;
+ nPrecision = 0; // all significant digits
+ nWidth = 0; // default width
+ cFiller = ' ';
+ nJustification = JUSTIFY_RIGHT;
+ eStreamMode = 0;
+ CreateFormatString();
+
+ nVersion = 0;
+
+ ClearError();
+}
+
+/*************************************************************************
+|*
+|* Stream::Stream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+SvStream::SvStream( SvLockBytes* pLockBytesP )
+{
+ DBG_CTOR( Stream, NULL );
+
+ ImpInit();
+ xLockBytes = pLockBytesP;
+ const SvStream* pStrm;
+ if( pLockBytesP ) {
+ pStrm = pLockBytesP->GetStream();
+ if( pStrm ) {
+ SetError( pStrm->GetErrorCode() );
+ }
+ }
+ SetBufferSize( 256 );
+}
+
+SvStream::SvStream()
+{
+ DBG_CTOR( Stream, NULL );
+
+ ImpInit();
+}
+
+/*************************************************************************
+|*
+|* Stream::~Stream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+SvStream::~SvStream()
+{
+ DBG_DTOR( Stream, NULL );
+
+ if ( xLockBytes.Is() )
+ Flush();
+
+ if( pRWBuf )
+ delete[] pRWBuf;
+}
+
+/*************************************************************************
+|*
+|* Stream::IsA()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_uInt16 SvStream::IsA() const
+{
+ return (sal_uInt16)ID_STREAM;
+}
+
+/*************************************************************************
+|*
+|* Stream::ClearError()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::ClearError()
+{
+ bIsEof = FALSE;
+ nError = SVSTREAM_OK;
+}
+
+/*************************************************************************
+|*
+|* Stream::SetError()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::SetError( sal_uInt32 nErrorCode )
+{
+ if ( nError == SVSTREAM_OK )
+ nError = nErrorCode;
+}
+
+
+/*************************************************************************
+|*
+|* Stream::SetNumberFormatInt()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::SetNumberFormatInt( sal_uInt16 nNewFormat )
+{
+ nNumberFormatInt = nNewFormat;
+ bSwap = FALSE;
+#ifdef OSL_BIGENDIAN
+ if( nNumberFormatInt == NUMBERFORMAT_INT_LITTLEENDIAN )
+ bSwap = TRUE;
+#else
+ if( nNumberFormatInt == NUMBERFORMAT_INT_BIGENDIAN )
+ bSwap = TRUE;
+#endif
+}
+
+/*************************************************************************
+|*
+|* Stream::SetBufferSize()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::SetBufferSize( sal_uInt16 nBufferSize )
+{
+ sal_Size nActualFilePos = Tell();
+ sal_Bool bDontSeek = (sal_Bool)(pRWBuf == 0);
+
+ if( bIsDirty && bIsConsistent && bIsWritable ) // wg. Windows NT: Access denied
+ Flush();
+
+ if( nBufSize )
+ {
+ delete[] pRWBuf;
+ nBufFilePos += nBufActualPos;
+ }
+
+ pRWBuf = 0;
+ nBufActualLen = 0;
+ nBufActualPos = 0;
+ nBufSize = nBufferSize;
+ if( nBufSize )
+ pRWBuf = new BYTE[ nBufSize ];
+ bIsConsistent = TRUE;
+ pBufPos = pRWBuf;
+ eIOMode = STREAM_IO_DONTKNOW;
+ if( !bDontSeek )
+ SeekPos( nActualFilePos );
+}
+
+/*************************************************************************
+|*
+|* Stream::ClearBuffer()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::ClearBuffer()
+{
+ nBufActualLen = 0;
+ nBufActualPos = 0;
+ nBufFilePos = 0;
+ pBufPos = pRWBuf;
+ bIsDirty = FALSE;
+ bIsConsistent = TRUE;
+ eIOMode = STREAM_IO_DONTKNOW;
+
+ bIsEof = FALSE;
+}
+
+/*************************************************************************
+|*
+|* Stream::ResetError()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::ResetError()
+{
+ ClearError();
+}
+
+/*************************************************************************
+|*
+|* Stream::ReadLine()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvStream::ReadByteStringLine( String& rStr, rtl_TextEncoding eSrcCharSet )
+{
+ sal_Bool bRet;
+ ByteString aStr;
+
+ bRet = ReadLine(aStr);
+ rStr = UniString( aStr, eSrcCharSet );
+ return bRet;
+}
+
+sal_Bool SvStream::ReadLine( ByteString& rStr )
+{
+ sal_Char buf[256+1];
+ sal_Bool bEnd = FALSE;
+ sal_Size nOldFilePos = Tell();
+ sal_Char c = 0;
+ sal_Size nTotalLen = 0;
+
+ rStr.Erase();
+ while( !bEnd && !GetError() ) // !!! nicht auf EOF testen,
+ // !!! weil wir blockweise
+ // !!! lesen
+ {
+ sal_uInt16 nLen = (sal_uInt16)Read( buf, sizeof(buf)-1 );
+ if ( !nLen )
+ {
+ if ( rStr.Len() == 0 )
+ {
+ // der allererste Blockread hat fehlgeschlagen -> Abflug
+ bIsEof = TRUE;
+ return FALSE;
+ }
+ else
+ break;
+ }
+
+ sal_uInt16 j, n;
+ for( j = n = 0; j < nLen ; ++j )
+ {
+ c = buf[j];
+ if ( c == '\n' || c == '\r' )
+ {
+ bEnd = TRUE;
+ break;
+ }
+ // erAck 26.02.01: Old behavior was no special treatment of '\0'
+ // character here, but a following rStr+=c did ignore it. Is this
+ // really intended? Or should a '\0' better terminate a line?
+ // The nOldFilePos stuff wasn't correct then anyways.
+ if ( c )
+ {
+ if ( n < j )
+ buf[n] = c;
+ ++n;
+ }
+ }
+ if ( n )
+ rStr.Append( buf, n );
+ nTotalLen += j;
+ }
+
+ if ( !bEnd && !GetError() && rStr.Len() )
+ bEnd = TRUE;
+
+ nOldFilePos += nTotalLen;
+ if( Tell() > nOldFilePos )
+ nOldFilePos++;
+ Seek( nOldFilePos ); // seeken wg. obigem BlockRead!
+
+ if ( bEnd && (c=='\r' || c=='\n') ) // Sonderbehandlung DOS-Dateien
+ {
+ char cTemp;
+ sal_Size nLen = Read((char*)&cTemp , sizeof(cTemp) );
+ if ( nLen ) {
+ if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
+ Seek( nOldFilePos );
+ }
+ }
+
+ if ( bEnd )
+ bIsEof = FALSE;
+ return bEnd;
+}
+
+sal_Bool SvStream::ReadUniStringLine( String& rStr )
+{
+ sal_Unicode buf[256+1];
+ sal_Bool bEnd = FALSE;
+ sal_Size nOldFilePos = Tell();
+ sal_Unicode c = 0;
+ sal_Size nTotalLen = 0;
+
+ DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "ReadUniStringLine: swapping sizeof(sal_Unicode) not implemented" );
+
+ rStr.Erase();
+ while( !bEnd && !GetError() ) // !!! nicht auf EOF testen,
+ // !!! weil wir blockweise
+ // !!! lesen
+ {
+ sal_uInt16 nLen = (sal_uInt16)Read( (char*)buf, sizeof(buf)-sizeof(sal_Unicode) );
+ nLen /= sizeof(sal_Unicode);
+ if ( !nLen )
+ {
+ if ( rStr.Len() == 0 )
+ {
+ // der allererste Blockread hat fehlgeschlagen -> Abflug
+ bIsEof = TRUE;
+ return FALSE;
+ }
+ else
+ break;
+ }
+
+ sal_uInt16 j, n;
+ for( j = n = 0; j < nLen ; ++j )
+ {
+ if ( bSwap )
+ SwapUShort( buf[n] );
+ c = buf[j];
+ if ( c == '\n' || c == '\r' )
+ {
+ bEnd = TRUE;
+ break;
+ }
+ // erAck 26.02.01: Old behavior was no special treatment of '\0'
+ // character here, but a following rStr+=c did ignore it. Is this
+ // really intended? Or should a '\0' better terminate a line?
+ // The nOldFilePos stuff wasn't correct then anyways.
+ if ( c )
+ {
+ if ( n < j )
+ buf[n] = c;
+ ++n;
+ }
+ }
+ if ( n )
+ rStr.Append( buf, n );
+ nTotalLen += j;
+ }
+
+ if ( !bEnd && !GetError() && rStr.Len() )
+ bEnd = TRUE;
+
+ nOldFilePos += nTotalLen * sizeof(sal_Unicode);
+ if( Tell() > nOldFilePos )
+ nOldFilePos += sizeof(sal_Unicode);
+ Seek( nOldFilePos ); // seeken wg. obigem BlockRead!
+
+ if ( bEnd && (c=='\r' || c=='\n') ) // Sonderbehandlung DOS-Dateien
+ {
+ sal_Unicode cTemp;
+ Read( (char*)&cTemp, sizeof(cTemp) );
+ if ( bSwap )
+ SwapUShort( cTemp );
+ if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
+ Seek( nOldFilePos );
+ }
+
+ if ( bEnd )
+ bIsEof = FALSE;
+ return bEnd;
+}
+
+sal_Bool SvStream::ReadUniOrByteStringLine( String& rStr, rtl_TextEncoding eSrcCharSet )
+{
+ if ( eSrcCharSet == RTL_TEXTENCODING_UNICODE )
+ return ReadUniStringLine( rStr );
+ else
+ return ReadByteStringLine( rStr, eSrcCharSet );
+}
+
+/*************************************************************************
+|*
+|* Stream::ReadCString
+|*
+*************************************************************************/
+
+sal_Bool SvStream::ReadCString( ByteString& rStr )
+{
+ if( rStr.Len() )
+ rStr.Erase();
+
+ sal_Char buf[ 256 + 1 ];
+ sal_Bool bEnd = FALSE;
+ sal_Size nFilePos = Tell();
+
+ while( !bEnd && !GetError() )
+ {
+ sal_uInt16 nLen = (sal_uInt16)Read( buf, sizeof(buf)-1 );
+ sal_uInt16 nReallyRead = nLen;
+ if( !nLen )
+ break;
+
+ const sal_Char* pPtr = buf;
+ while( *pPtr && nLen )
+ ++pPtr, --nLen;
+
+ bEnd = ( nReallyRead < sizeof(buf)-1 ) // read less than attempted to read
+ || ( ( nLen > 0 ) // OR it is inside the block we read
+ && ( 0 == *pPtr ) // AND found a string terminator
+ );
+
+ rStr.Append( buf, ::sal::static_int_cast< xub_StrLen >( pPtr - buf ) );
+ }
+
+ nFilePos += rStr.Len();
+ if( Tell() > nFilePos )
+ nFilePos++;
+ Seek( nFilePos ); // seeken wg. obigem BlockRead!
+ return bEnd;
+}
+
+sal_Bool SvStream::ReadCString( String& rStr, rtl_TextEncoding eToEncode )
+{
+ ByteString sStr;
+ sal_Bool bRet = ReadCString( sStr );
+ rStr = String( sStr, eToEncode );
+ return bRet;
+}
+
+
+/*************************************************************************
+|*
+|* Stream::WriteUnicodeText()
+|*
+*************************************************************************/
+
+sal_Bool SvStream::WriteUnicodeText( const String& rStr )
+{
+ DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "WriteUnicodeText: swapping sizeof(sal_Unicode) not implemented" );
+ if ( bSwap )
+ {
+ xub_StrLen nLen = rStr.Len();
+ sal_Unicode aBuf[384];
+ sal_Unicode* const pTmp = ( nLen > 384 ? new sal_Unicode[nLen] : aBuf);
+ memcpy( pTmp, rStr.GetBuffer(), nLen * sizeof(sal_Unicode) );
+ sal_Unicode* p = pTmp;
+ const sal_Unicode* const pStop = pTmp + nLen;
+ while ( p < pStop )
+ {
+ SwapUShort( *p );
+ p++;
+ }
+ Write( (char*)pTmp, nLen * sizeof(sal_Unicode) );
+ if ( pTmp != aBuf )
+ delete [] pTmp;
+ }
+ else
+ Write( (char*)rStr.GetBuffer(), rStr.Len() * sizeof(sal_Unicode) );
+ return nError == SVSTREAM_OK;
+}
+
+sal_Bool SvStream::WriteUnicodeOrByteText( const String& rStr, rtl_TextEncoding eDestCharSet )
+{
+ if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
+ return WriteUnicodeText( rStr );
+ else
+ {
+ ByteString aStr( rStr, eDestCharSet );
+ Write( aStr.GetBuffer(), aStr.Len() );
+ return nError == SVSTREAM_OK;
+ }
+}
+
+/*************************************************************************
+|*
+|* Stream::WriteLine()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvStream::WriteByteStringLine( const String& rStr, rtl_TextEncoding eDestCharSet )
+{
+ return WriteLine( ByteString( rStr, eDestCharSet ) );
+}
+
+sal_Bool SvStream::WriteLine( const ByteString& rStr )
+{
+ Write( rStr.GetBuffer(), rStr.Len() );
+ endl(*this);
+ return nError == SVSTREAM_OK;
+}
+
+sal_Bool SvStream::WriteUniStringLine( const String& rStr )
+{
+ WriteUnicodeText( rStr );
+ endlu(*this);
+ return nError == SVSTREAM_OK;
+}
+
+sal_Bool SvStream::WriteUniOrByteStringLine( const String& rStr, rtl_TextEncoding eDestCharSet )
+{
+ if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
+ return WriteUniStringLine( rStr );
+ else
+ return WriteByteStringLine( rStr, eDestCharSet );
+}
+
+/*************************************************************************
+|*
+|* Stream::WriteLines()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 17.07.95
+|* Letzte Aenderung OV 17.07.95
+|*
+*************************************************************************/
+
+sal_Bool SvStream::WriteByteStringLines( const String& rStr, rtl_TextEncoding eDestCharSet )
+{
+ return WriteLines( ByteString( rStr, eDestCharSet ) );
+}
+
+sal_Bool SvStream::WriteLines( const ByteString& rStr )
+{
+ ByteString aStr( rStr );
+ aStr.ConvertLineEnd( eLineDelimiter );
+ Write( aStr.GetBuffer(), aStr.Len() );
+ endl( *this );
+ return (sal_Bool)(nError == SVSTREAM_OK);
+}
+
+sal_Bool SvStream::WriteUniStringLines( const String& rStr )
+{
+ String aStr( rStr );
+ aStr.ConvertLineEnd( eLineDelimiter );
+ WriteUniStringLine( aStr );
+ return nError == SVSTREAM_OK;
+}
+
+sal_Bool SvStream::WriteUniOrByteStringLines( const String& rStr, rtl_TextEncoding eDestCharSet )
+{
+ if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
+ return WriteUniStringLines( rStr );
+ else
+ return WriteByteStringLines( rStr, eDestCharSet );
+}
+
+/*************************************************************************
+|*
+|* Stream::WriteUniOrByteChar()
+|*
+*************************************************************************/
+
+sal_Bool SvStream::WriteUniOrByteChar( sal_Unicode ch, rtl_TextEncoding eDestCharSet )
+{
+ if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
+ *this << ch;
+ else
+ {
+ ByteString aStr( ch, eDestCharSet );
+ Write( aStr.GetBuffer(), aStr.Len() );
+ }
+ return nError == SVSTREAM_OK;
+}
+
+/*************************************************************************
+|*
+|* Stream::StartWritingUnicodeText()
+|*
+*************************************************************************/
+
+sal_Bool SvStream::StartWritingUnicodeText()
+{
+ SetEndianSwap( FALSE ); // write native format
+ // BOM, Byte Order Mark, U+FEFF, see
+ // http://www.unicode.org/faq/utf_bom.html#BOM
+ // Upon read: 0xfeff(-257) => no swap; 0xfffe(-2) => swap
+ *this << sal_uInt16( 0xfeff );
+ return nError == SVSTREAM_OK;
+}
+
+/*************************************************************************
+|*
+|* Stream::StartReadingUnicodeText()
+|*
+*************************************************************************/
+
+sal_Bool SvStream::StartReadingUnicodeText()
+{
+ sal_uInt16 nFlag;
+ *this >> nFlag;
+ switch ( nFlag )
+ {
+ case 0xfeff :
+ // native
+ break;
+ case 0xfffe :
+ SetEndianSwap( !bSwap );
+ break;
+ default:
+ SeekRel( -((sal_sSize)sizeof(nFlag)) ); // no BOM, pure data
+ }
+ return nError == SVSTREAM_OK;
+}
+
+/*************************************************************************
+|*
+|* Stream::ReadCsvLine()
+|*
+*************************************************************************/
+
+// Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
+// array.
+inline const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,
+ sal_Unicode c )
+{
+ while (*pStr)
+ {
+ if (*pStr == c)
+ return pStr;
+ ++pStr;
+ }
+ return 0;
+}
+
+sal_Bool SvStream::ReadCsvLine( String& rStr, sal_Bool bEmbeddedLineBreak,
+ const String& rFieldSeparators, sal_Unicode cFieldQuote,
+ sal_Bool bAllowBackslashEscape)
+{
+ ReadUniOrByteStringLine( rStr);
+
+ if (bEmbeddedLineBreak)
+ {
+ const sal_Unicode* pSeps = rFieldSeparators.GetBuffer();
+ xub_StrLen nLastOffset = 0;
+ xub_StrLen nQuotes = 0;
+ while (!IsEof() && rStr.Len() < STRING_MAXLEN)
+ {
+ bool bBackslashEscaped = false;
+ const sal_Unicode *p, *pStart;
+ p = pStart = rStr.GetBuffer();
+ p += nLastOffset;
+ while (*p)
+ {
+ if (nQuotes)
+ {
+ if (*p == cFieldQuote && !bBackslashEscaped)
+ ++nQuotes;
+ else if (bAllowBackslashEscape)
+ {
+ if (*p == '\\')
+ bBackslashEscaped = !bBackslashEscaped;
+ else
+ bBackslashEscaped = false;
+ }
+ }
+ else if (*p == cFieldQuote && (p == pStart ||
+ lcl_UnicodeStrChr( pSeps, p[-1])))
+ nQuotes = 1;
+ // A quote character inside a field content does not start
+ // a quote.
+ ++p;
+ }
+
+ if (nQuotes % 2 == 0)
+ break;
+ else
+ {
+ nLastOffset = rStr.Len();
+ String aNext;
+ ReadUniOrByteStringLine( aNext);
+ rStr += sal_Unicode(_LF);
+ rStr += aNext;
+ }
+ }
+ }
+ return nError == SVSTREAM_OK;
+}
+
+/*************************************************************************
+|*
+|* Stream::SeekRel()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_Size SvStream::SeekRel( sal_sSize nPos )
+{
+ sal_Size nActualPos = Tell();
+
+ if ( nPos >= 0 )
+ {
+ if ( SAL_MAX_SIZE - nActualPos > (sal_Size)nPos )
+ nActualPos += nPos;
+ }
+ else
+ {
+ sal_Size nAbsPos = (sal_Size)-nPos;
+ if ( nActualPos >= nAbsPos )
+ nActualPos -= nAbsPos;
+ }
+
+ pBufPos = pRWBuf + nActualPos;
+ return Seek( nActualPos );
+}
+
+/*************************************************************************
+|*
+|* Stream::operator>>()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+SvStream& SvStream::operator >> ( sal_uInt16& r )
+{
+ READNUMBER_WITHOUT_SWAP(sal_uInt16,r)
+ if( bSwap )
+ SwapUShort(r);
+ return *this;
+}
+
+SvStream& SvStream::operator>> ( sal_uInt32& r )
+{
+ READNUMBER_WITHOUT_SWAP(sal_uInt32,r)
+ if( bSwap )
+ SwapULong(r);
+ return *this;
+}
+
+SvStream& SvStream::operator >> ( long& r )
+{
+#if(SAL_TYPES_SIZEOFLONG != 4)
+ int tmp = r;
+ *this >> tmp;
+ r = tmp;
+#else
+ READNUMBER_WITHOUT_SWAP(long,r)
+ if( bSwap )
+ SwapLong(r);
+#endif
+ return *this;
+}
+
+SvStream& SvStream::operator >> ( short& r )
+{
+ READNUMBER_WITHOUT_SWAP(short,r)
+ if( bSwap )
+ SwapShort(r);
+ return *this;
+}
+
+SvStream& SvStream::operator >> ( int& r )
+{
+ READNUMBER_WITHOUT_SWAP(int,r)
+ if( bSwap )
+ SwapLongInt(r);
+ return *this;
+}
+
+SvStream& SvStream::operator>>( signed char& r )
+{
+ if( (eIOMode == STREAM_IO_READ || !bIsConsistent) &&
+ sizeof(signed char) <= nBufFree )
+ {
+ r = *pBufPos;
+ nBufActualPos += sizeof(signed char);
+ pBufPos += sizeof(signed char);
+ nBufFree -= sizeof(signed char);
+ }
+ else
+ Read( (char*)&r, sizeof(signed char) );
+ return *this;
+}
+
+// Sonderbehandlung fuer Chars wegen PutBack
+
+SvStream& SvStream::operator>>( char& r )
+{
+ if( (eIOMode == STREAM_IO_READ || !bIsConsistent) &&
+ sizeof(char) <= nBufFree )
+ {
+ r = *pBufPos;
+ nBufActualPos += sizeof(char);
+ pBufPos += sizeof(char);
+ nBufFree -= sizeof(char);
+ }
+ else
+ Read( (char*)&r, sizeof(char) );
+ return *this;
+}
+
+SvStream& SvStream::operator>>( unsigned char& r )
+{
+ if( (eIOMode == STREAM_IO_READ || !bIsConsistent) &&
+ sizeof(char) <= nBufFree )
+ {
+ r = *pBufPos;
+ nBufActualPos += sizeof(char);
+ pBufPos += sizeof(char);
+ nBufFree -= sizeof(char);
+ }
+ else
+ Read( (char*)&r, sizeof(char) );
+ return *this;
+}
+
+SvStream& SvStream::operator>>( float& r )
+{
+ // Read( (char*)&r, sizeof(float) );
+ READNUMBER_WITHOUT_SWAP(float,r)
+#if defined UNX
+ if( bSwap )
+ SwapFloat(r);
+#endif
+ return *this;
+}
+
+SvStream& SvStream::operator>>( double& r )
+{
+ // Read( (char*)&r, sizeof(double) );
+ READNUMBER_WITHOUT_SWAP(double,r)
+#if defined UNX
+ if( bSwap )
+ SwapDouble(r);
+#endif
+ return *this;
+}
+
+SvStream& SvStream::operator>> ( SvStream& rStream )
+{
+ const sal_uInt32 cBufLen = 0x8000;
+ char* pBuf = new char[ cBufLen ];
+
+ sal_uInt32 nCount;
+ do {
+ nCount = Read( pBuf, cBufLen );
+ rStream.Write( pBuf, nCount );
+ } while( nCount == cBufLen );
+
+ delete[] pBuf;
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Stream::operator<<()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+SvStream& SvStream::operator<< ( sal_uInt16 v )
+{
+ if( bSwap )
+ SwapUShort(v);
+ WRITENUMBER_WITHOUT_SWAP(sal_uInt16,v)
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( sal_uInt32 v )
+{
+ if( bSwap )
+ SwapULong(v);
+ WRITENUMBER_WITHOUT_SWAP(sal_uInt32,v)
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( long v )
+{
+#if(SAL_TYPES_SIZEOFLONG != 4)
+ int tmp = v;
+ *this << tmp;
+#else
+ if( bSwap )
+ SwapLong(v);
+ WRITENUMBER_WITHOUT_SWAP(long,v)
+#endif
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( short v )
+{
+ if( bSwap )
+ SwapShort(v);
+ WRITENUMBER_WITHOUT_SWAP(short,v)
+ return *this;
+}
+
+SvStream& SvStream::operator<<( int v )
+{
+ if( bSwap )
+ SwapLongInt( v );
+ WRITENUMBER_WITHOUT_SWAP(int,v)
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( signed char v )
+{
+ //SDO
+ int tmp = eIOMode;
+ if(tmp == STREAM_IO_WRITE && sizeof(signed char) <= nBufFree )
+ {
+ *pBufPos = v;
+ pBufPos++; // sizeof(char);
+ nBufActualPos++;
+ if( nBufActualPos > nBufActualLen ) // Append ?
+ nBufActualLen = nBufActualPos;
+ nBufFree--; // = sizeof(char);
+ bIsDirty = TRUE;
+ }
+ else
+ Write( (char*)&v, sizeof(signed char) );
+ return *this;
+}
+
+// Sonderbehandlung fuer chars wegen PutBack
+
+SvStream& SvStream::operator<< ( char v )
+{
+ //SDO
+ int tmp = eIOMode;
+ if(tmp == STREAM_IO_WRITE && sizeof(char) <= nBufFree )
+ {
+ *pBufPos = v;
+ pBufPos++; // sizeof(char);
+ nBufActualPos++;
+ if( nBufActualPos > nBufActualLen ) // Append ?
+ nBufActualLen = nBufActualPos;
+ nBufFree--; // = sizeof(char);
+ bIsDirty = TRUE;
+ }
+ else
+ Write( (char*)&v, sizeof(char) );
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( unsigned char v )
+{
+//SDO
+ int tmp = eIOMode;
+ if(tmp == STREAM_IO_WRITE && sizeof(char) <= nBufFree )
+ {
+ *(unsigned char*)pBufPos = v;
+ pBufPos++; // = sizeof(char);
+ nBufActualPos++; // = sizeof(char);
+ if( nBufActualPos > nBufActualLen ) // Append ?
+ nBufActualLen = nBufActualPos;
+ nBufFree--;
+ bIsDirty = TRUE;
+ }
+ else
+ Write( (char*)&v, sizeof(char) );
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( float v )
+{
+#ifdef UNX
+ if( bSwap )
+ SwapFloat(v);
+#endif
+ WRITENUMBER_WITHOUT_SWAP(float,v)
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( const double& r )
+{
+// Write( (char*)&r, sizeof( double ) );
+#if defined UNX
+ if( bSwap )
+ {
+ double nHelp = r;
+ SwapDouble(nHelp);
+ WRITENUMBER_WITHOUT_SWAP(double,nHelp)
+ return *this;
+ }
+ else
+#endif
+ WRITENUMBER_WITHOUT_SWAP(double,r)
+
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( const char* pBuf )
+{
+ Write( pBuf, strlen( pBuf ) );
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( const unsigned char* pBuf )
+{
+ Write( (char*)pBuf, strlen( (char*)pBuf ) );
+ return *this;
+}
+
+SvStream& SvStream::operator<< ( SvStream& rStream )
+{
+ const sal_uInt32 cBufLen = 0x8000;
+ char* pBuf = new char[ cBufLen ];
+ sal_uInt32 nCount;
+ do {
+ nCount = rStream.Read( pBuf, cBufLen );
+ Write( pBuf, nCount );
+ } while( nCount == cBufLen );
+
+ delete[] pBuf;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& SvStream::ReadByteString( UniString& rStr, rtl_TextEncoding eSrcCharSet )
+{
+ // read UTF-16 string directly from stream ?
+ if (eSrcCharSet == RTL_TEXTENCODING_UNICODE)
+ {
+ sal_uInt32 nLen;
+ operator>> (nLen);
+ if (nLen)
+ {
+ if (nLen > STRING_MAXLEN) {
+ SetError(SVSTREAM_GENERALERROR);
+ return *this;
+ }
+ sal_Unicode *pStr = rStr.AllocBuffer(
+ static_cast< xub_StrLen >(nLen));
+ BOOST_STATIC_ASSERT(STRING_MAXLEN <= SAL_MAX_SIZE / 2);
+ Read( pStr, nLen << 1 );
+
+ if (bSwap)
+ for (sal_Unicode *pEnd = pStr + nLen; pStr < pEnd; pStr++)
+ SwapUShort(*pStr);
+ }
+ else
+ rStr.Erase();
+
+ return *this;
+ }
+
+ ByteString aStr;
+ ReadByteString( aStr );
+ rStr = UniString( aStr, eSrcCharSet );
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& SvStream::ReadByteString( ByteString& rStr )
+{
+ sal_uInt16 nLen = 0;
+ operator>>( nLen );
+ if( nLen )
+ {
+ char* pTmp = rStr.AllocBuffer( nLen );
+ nLen = (sal_uInt16)Read( pTmp, nLen );
+ }
+ else
+ rStr.Erase();
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& SvStream::WriteByteString( const UniString& rStr, rtl_TextEncoding eDestCharSet )
+{
+ // write UTF-16 string directly into stream ?
+ if (eDestCharSet == RTL_TEXTENCODING_UNICODE)
+ {
+ sal_uInt32 nLen = rStr.Len();
+ operator<< (nLen);
+ if (nLen)
+ {
+ if (bSwap)
+ {
+ const sal_Unicode *pStr = rStr.GetBuffer();
+ const sal_Unicode *pEnd = pStr + nLen;
+
+ for (; pStr < pEnd; pStr++)
+ {
+ sal_Unicode c = *pStr;
+ SwapUShort(c);
+ WRITENUMBER_WITHOUT_SWAP(sal_uInt16,c)
+ }
+ }
+ else
+ Write( rStr.GetBuffer(), nLen << 1 );
+ }
+
+ return *this;
+ }
+
+ return WriteByteString(ByteString( rStr, eDestCharSet ));
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& SvStream::WriteByteString( const ByteString& rStr)
+{
+ sal_uInt16 nLen = rStr.Len();
+ operator<< ( nLen );
+ if( nLen != 0 )
+ Write( rStr.GetBuffer(), nLen );
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Stream::Read()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_Size SvStream::Read( void* pData, sal_Size nCount )
+{
+ sal_Size nSaveCount = nCount;
+ if( !bIsConsistent )
+ RefreshBuffer();
+
+ if( !pRWBuf )
+ {
+ nCount = GetData( (char*)pData,nCount);
+ if( nCryptMask )
+ EncryptBuffer(pData, nCount);
+ nBufFilePos += nCount;
+ }
+ else
+ {
+ // ist Block komplett im Puffer
+ eIOMode = STREAM_IO_READ;
+ if( nCount <= (sal_Size)(nBufActualLen - nBufActualPos ) )
+ {
+ // Ja!
+ memcpy(pData, pBufPos, (size_t) nCount);
+ nBufActualPos = nBufActualPos + (sal_uInt16)nCount;
+ pBufPos += nCount;
+ nBufFree = nBufFree - (sal_uInt16)nCount;
+ }
+ else
+ {
+ if( bIsDirty ) // Flushen ?
+ {
+ SeekPos( nBufFilePos );
+ if( nCryptMask )
+ CryptAndWriteBuffer(pRWBuf, nBufActualLen);
+ else
+ PutData( pRWBuf, nBufActualLen );
+ bIsDirty = FALSE;
+ }
+
+ // passt der Datenblock in den Puffer ?
+ if( nCount > nBufSize )
+ {
+ // Nein! Deshalb ohne Umweg ueber den Puffer direkt
+ // in den Zielbereich einlesen
+
+ eIOMode = STREAM_IO_DONTKNOW;
+
+ SeekPos( nBufFilePos + nBufActualPos );
+ nBufActualLen = 0;
+ pBufPos = pRWBuf;
+ nCount = GetData( (char*)pData, nCount );
+ if( nCryptMask )
+ EncryptBuffer(pData, nCount);
+ nBufFilePos += nCount;
+ nBufFilePos += nBufActualPos;
+ nBufActualPos = 0;
+ }
+ else
+ {
+ // Der Datenblock passt komplett in den Puffer. Deshalb
+ // Puffer fuellen und dann die angeforderten Daten in den
+ // Zielbereich kopieren.
+
+ nBufFilePos += nBufActualPos;
+ SeekPos( nBufFilePos );
+
+ // TODO: Typecast vor GetData, sal_uInt16 nCountTmp
+ sal_Size nCountTmp = GetData( pRWBuf, nBufSize );
+ if( nCryptMask )
+ EncryptBuffer(pRWBuf, nCountTmp);
+ nBufActualLen = (sal_uInt16)nCountTmp;
+ if( nCount > nCountTmp )
+ {
+ nCount = nCountTmp; // zurueckstutzen, Eof siehe unten
+ }
+ memcpy( pData, pRWBuf, (size_t)nCount );
+ nBufActualPos = (sal_uInt16)nCount;
+ pBufPos = pRWBuf + nCount;
+ }
+ }
+ }
+ bIsEof = FALSE;
+ nBufFree = nBufActualLen - nBufActualPos;
+ if( nCount != nSaveCount && nError != ERRCODE_IO_PENDING )
+ bIsEof = TRUE;
+ if( nCount == nSaveCount && nError == ERRCODE_IO_PENDING )
+ nError = ERRCODE_NONE;
+ return nCount;
+}
+
+/*************************************************************************
+|*
+|* Stream::Write()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_Size SvStream::Write( const void* pData, sal_Size nCount )
+{
+ if( !nCount )
+ return 0;
+ if( !bIsWritable )
+ {
+ SetError( ERRCODE_IO_CANTWRITE );
+ return 0;
+ }
+ if( !bIsConsistent )
+ RefreshBuffer(); // Aenderungen des Puffers durch PutBack loeschen
+
+ if( !pRWBuf )
+ {
+ if( nCryptMask )
+ nCount = CryptAndWriteBuffer( pData, nCount );
+ else
+ nCount = PutData( (char*)pData, nCount );
+ nBufFilePos += nCount;
+ return nCount;
+ }
+
+ eIOMode = STREAM_IO_WRITE;
+ if( nCount <= (sal_Size)(nBufSize - nBufActualPos) )
+ {
+ memcpy( pBufPos, pData, (size_t)nCount );
+ nBufActualPos = nBufActualPos + (sal_uInt16)nCount;
+ // wurde der Puffer erweitert ?
+ if( nBufActualPos > nBufActualLen )
+ nBufActualLen = nBufActualPos;
+
+ pBufPos += nCount;
+ bIsDirty = TRUE;
+ }
+ else
+ {
+ // Flushen ?
+ if( bIsDirty )
+ {
+ SeekPos( nBufFilePos );
+ if( nCryptMask )
+ CryptAndWriteBuffer( pRWBuf, (sal_Size)nBufActualLen );
+ else
+ PutData( pRWBuf, nBufActualLen );
+ bIsDirty = FALSE;
+ }
+
+ // passt der Block in den Puffer ?
+ if( nCount > nBufSize )
+ {
+ eIOMode = STREAM_IO_DONTKNOW;
+ nBufFilePos += nBufActualPos;
+ nBufActualLen = 0;
+ nBufActualPos = 0;
+ pBufPos = pRWBuf;
+ SeekPos( nBufFilePos );
+ if( nCryptMask )
+ nCount = CryptAndWriteBuffer( pData, nCount );
+ else
+ nCount = PutData( (char*)pData, nCount );
+ nBufFilePos += nCount;
+ }
+ else
+ {
+ // Block in Puffer stellen
+ memcpy( pRWBuf, pData, (size_t)nCount );
+
+ // Reihenfolge!
+ nBufFilePos += nBufActualPos;
+ nBufActualPos = (sal_uInt16)nCount;
+ pBufPos = pRWBuf + nCount;
+ nBufActualLen = (sal_uInt16)nCount;
+ bIsDirty = TRUE;
+ }
+ }
+ nBufFree = nBufSize - nBufActualPos;
+ return nCount;
+}
+
+
+/*************************************************************************
+|*
+|* Stream::Seek()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_Size SvStream::Seek( sal_Size nFilePos )
+{
+ eIOMode = STREAM_IO_DONTKNOW;
+
+ bIsEof = FALSE;
+ if( !pRWBuf )
+ {
+ nBufFilePos = SeekPos( nFilePos );
+ DBG_ASSERT(Tell()==nBufFilePos,"Out Of Sync!");
+ return nBufFilePos;
+ }
+
+ // Ist Position im Puffer ?
+ if( nFilePos >= nBufFilePos && nFilePos <= (nBufFilePos + nBufActualLen))
+ {
+ nBufActualPos = (sal_uInt16)(nFilePos - nBufFilePos);
+ pBufPos = pRWBuf + nBufActualPos;
+ // nBufFree korrigieren, damit wir nicht von einem
+ // PutBack (ignoriert den StreamMode) getoetet werden
+ nBufFree = nBufActualLen - nBufActualPos;
+ }
+ else
+ {
+ if( bIsDirty && bIsConsistent)
+ {
+ SeekPos( nBufFilePos );
+ if( nCryptMask )
+ CryptAndWriteBuffer( pRWBuf, nBufActualLen );
+ else
+ PutData( pRWBuf, nBufActualLen );
+ bIsDirty = FALSE;
+ }
+ nBufActualLen = 0;
+ nBufActualPos = 0;
+ pBufPos = pRWBuf;
+ nBufFilePos = SeekPos( nFilePos );
+ }
+#ifdef OV_DEBUG
+ {
+ sal_Size nDebugTemp = nBufFilePos + nBufActualPos;
+ DBG_ASSERT(Tell()==nDebugTemp,"Sync?");
+ }
+#endif
+ return nBufFilePos + nBufActualPos;
+}
+
+/*************************************************************************
+|*
+|* Stream::Flush()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::Flush()
+{
+ if( bIsDirty && bIsConsistent )
+ {
+ SeekPos( nBufFilePos );
+ if( nCryptMask )
+ CryptAndWriteBuffer( pRWBuf, (sal_Size)nBufActualLen );
+ else
+ if( PutData( pRWBuf, nBufActualLen ) != nBufActualLen )
+ SetError( SVSTREAM_WRITE_ERROR );
+ bIsDirty = FALSE;
+ }
+ if( bIsWritable )
+ FlushData();
+}
+
+
+/*************************************************************************
+|*
+|* Stream::PutBack()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 01.08.94
+|* Letzte Aenderung OV 01.08.94
+|*
+*************************************************************************/
+
+/*
+ 4 Faelle :
+
+ 1. Datenzeiger steht mitten im Puffer (nBufActualPos >= 1)
+ 2. Datenzeiger auf Position 0, Puffer ist voll
+ 3. Datenzeiger auf Position 0, Puffer ist teilweise gefuellt
+ 4. Datenzeiger auf Position 0, Puffer ist leer -> Fehler!
+*/
+
+SvStream& SvStream::PutBack( char aCh )
+{
+ // wenn kein Buffer oder Zurueckscrollen nicht moeglich -> Fehler
+ if( !pRWBuf || !nBufActualLen || ( !nBufActualPos && !nBufFilePos ) )
+ {
+ // 4. Fall
+ SetError( SVSTREAM_GENERALERROR );
+ return *this;
+ }
+
+ // Flush() (Phys. Flushen aber nicht notwendig, deshalb selbst schreiben)
+ if( bIsConsistent && bIsDirty )
+ {
+ SeekPos( nBufFilePos );
+ if( nCryptMask )
+ CryptAndWriteBuffer( pRWBuf, nBufActualLen );
+ else
+ PutData( pRWBuf, nBufActualLen );
+ bIsDirty = FALSE;
+ }
+ bIsConsistent = FALSE; // Puffer enthaelt jetzt TRASH
+ if( nBufActualPos )
+ {
+ // 1. Fall
+ nBufActualPos--;
+ pBufPos--;
+ *pBufPos = aCh;
+ nBufFree++;
+ }
+ else // Puffer muss verschoben werden
+ {
+ // Ist Puffer am Anschlag ?
+ if( nBufSize == nBufActualLen )
+ {
+ // 2. Fall
+ memmove( pRWBuf+1, pRWBuf, nBufSize-1 );
+ // nBufFree behaelt den Wert!
+ }
+ else
+ {
+ // 3. Fall -> Puffer vergroessern
+ memmove( pRWBuf+1, pRWBuf, (sal_uInt16)nBufActualLen );
+ nBufActualLen++;
+ nBufFree++;
+ }
+ nBufFilePos--;
+ *pRWBuf = aCh;
+ }
+ eIOMode = STREAM_IO_DONTKNOW;
+ bIsEof = FALSE;
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Stream::EatWhite()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 01.08.94
+|* Letzte Aenderung OV 01.08.94
+|*
+*************************************************************************/
+
+void SvStream::EatWhite()
+{
+ char aCh;
+ Read(&aCh, sizeof(char) );
+ while( !bIsEof && isspace((int)aCh) ) //( aCh == ' ' || aCh == '\t' ) )
+ Read(&aCh, sizeof(char) );
+ if( !bIsEof ) // konnte das letzte Char gelesen werden ?
+ SeekRel( -1L );
+}
+
+/*************************************************************************
+|*
+|* Stream::RefreshBuffer()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 01.08.94
+|* Letzte Aenderung OV 01.08.94
+|*
+*************************************************************************/
+
+void SvStream::RefreshBuffer()
+{
+ if( bIsDirty && bIsConsistent )
+ {
+ SeekPos( nBufFilePos );
+ if( nCryptMask )
+ CryptAndWriteBuffer( pRWBuf, (sal_Size)nBufActualLen );
+ else
+ PutData( pRWBuf, nBufActualLen );
+ bIsDirty = FALSE;
+ }
+ SeekPos( nBufFilePos );
+ nBufActualLen = (sal_uInt16)GetData( pRWBuf, nBufSize );
+ if( nBufActualLen && nError == ERRCODE_IO_PENDING )
+ nError = ERRCODE_NONE;
+ if( nCryptMask )
+ EncryptBuffer(pRWBuf, (sal_Size)nBufActualLen);
+ bIsConsistent = TRUE;
+ eIOMode = STREAM_IO_DONTKNOW;
+}
+
+
+/*************************************************************************
+|*
+|* Stream::CreateFormatString()
+|*
+|* Beschreibung Baut Formatstring zusammen
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::CreateFormatString()
+{
+ aFormatString = '%';
+ nPrintfParams = SPECIAL_PARAM_NONE;
+
+ if( nJustification )
+ {
+ aFormatString += '-';
+ }
+
+ if( nWidth )
+ {
+ if( cFiller != ' ' )
+ aFormatString += '0';
+ aFormatString += '*';
+ nPrintfParams = SPECIAL_PARAM_WIDTH;
+ }
+
+ if( nPrecision )
+ {
+ aFormatString += ".*";
+ if( nWidth )
+ nPrintfParams = SPECIAL_PARAM_BOTH;
+ else
+ nPrintfParams = SPECIAL_PARAM_PRECISION;
+ }
+}
+
+/*************************************************************************
+|*
+|* Stream::ReadNumber()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+#define BUFSIZE_LONG 21 // log( 2 hoch 64 ) + 1
+
+SvStream& SvStream::ReadNumber( long& rLong )
+{
+ EatWhite();
+ if( bIsEof || nError )
+ {
+ SetError( SVSTREAM_GENERALERROR );
+ return *this;
+ }
+ sal_Size nFPtr = Tell();
+ char buf[ BUFSIZE_LONG ];
+ memset( buf, 0, BUFSIZE_LONG );
+ sal_Size nTemp = Read( buf, BUFSIZE_LONG-1 );
+ if( !nTemp || nError )
+ {
+ SetError( SVSTREAM_GENERALERROR );
+ return *this;
+ }
+ char *pEndPtr;
+ rLong = strtol( buf, &pEndPtr, (int)nRadix );
+ nFPtr += ( (sal_Size)pEndPtr - (sal_Size)(&(buf[0])) );
+ Seek( nFPtr );
+ bIsEof = FALSE;
+ return *this;
+}
+
+SvStream& SvStream::ReadNumber( sal_uInt32& rUInt32 )
+{
+ EatWhite();
+ if( bIsEof || nError )
+ {
+ SetError( SVSTREAM_GENERALERROR );
+ return *this;
+ }
+ sal_Size nFPtr = Tell();
+ char buf[ BUFSIZE_LONG ];
+ memset( buf, 0, BUFSIZE_LONG );
+ sal_Size nTemp = Read( buf, BUFSIZE_LONG-1 );
+ if( !nTemp || nError )
+ {
+ SetError( SVSTREAM_GENERALERROR );
+ return *this;
+ }
+ char *pEndPtr;
+ rUInt32 = strtoul( buf, &pEndPtr, (int)nRadix );
+ nFPtr += ( (sal_uIntPtr)pEndPtr - (sal_uIntPtr)buf );
+ Seek( nFPtr );
+ bIsEof = FALSE;
+ return *this;
+}
+
+SvStream& SvStream::ReadNumber( double& rDouble )
+{
+ EatWhite();
+ if( bIsEof || nError )
+ {
+ SetError( SVSTREAM_GENERALERROR );
+ return *this;
+ }
+ sal_Size nFPtr = Tell();
+ char buf[ BUFSIZE_LONG ];
+ memset( buf, 0, BUFSIZE_LONG );
+ sal_Size nTemp = Read( buf, BUFSIZE_LONG-1 );
+ if( !nTemp || nError )
+ {
+ SetError( SVSTREAM_GENERALERROR );
+ return *this;
+ }
+ char *pEndPtr;
+ rDouble = strtod( buf, &pEndPtr );
+ nFPtr += ( (sal_Size)pEndPtr - (sal_Size)buf );
+ Seek( nFPtr );
+ bIsEof = FALSE;
+ return *this;
+}
+
+
+/*************************************************************************
+|*
+|* Stream::WriteNumber()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+SvStream& SvStream::WriteNumber( long nLong )
+{
+ char buffer[256+12];
+ char pType[] = "ld"; // Nicht static!
+ if( nRadix == 16 )
+ pType[1] = 'x';
+ else if( nRadix == 8 )
+ pType[1] = 'o';
+ ByteString aFStr( aFormatString);
+ aFStr += pType;
+ int nLen;
+ switch ( nPrintfParams )
+ {
+ case SPECIAL_PARAM_NONE :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), nLong );
+ break;
+ case SPECIAL_PARAM_WIDTH :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), nWidth, nLong );
+ break;
+ case SPECIAL_PARAM_PRECISION :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), nPrecision,nLong);
+ break;
+ default:
+ nLen=sprintf(buffer, aFStr.GetBuffer(),nWidth,nPrecision,nLong);
+ }
+ Write( buffer, (long)nLen );
+ return *this;
+}
+
+SvStream& SvStream::WriteNumber( sal_uInt32 nUInt32 )
+{
+ char buffer[256+12];
+ char pType[] = "lu"; // Nicht static!
+ if( nRadix == 16 )
+ pType[1] = 'x';
+ else if( nRadix == 8 )
+ pType[1] = 'o';
+ ByteString aFStr( aFormatString);
+ aFStr += pType;
+ int nLen;
+ switch ( nPrintfParams )
+ {
+ case SPECIAL_PARAM_NONE :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), nUInt32 );
+ break;
+ case SPECIAL_PARAM_WIDTH :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), nWidth, nUInt32 );
+ break;
+ case SPECIAL_PARAM_PRECISION :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), nPrecision, nUInt32 );
+ break;
+ default:
+ nLen=sprintf(buffer,aFStr.GetBuffer(),nWidth,nPrecision,nUInt32 );
+ }
+ Write( buffer, (long)nLen );
+ return *this;
+}
+
+
+SvStream& SvStream::WriteNumber( const double& rDouble )
+{
+ char buffer[256+24];
+ ByteString aFStr( aFormatString);
+ aFStr += "lf";
+ int nLen;
+ switch ( nPrintfParams )
+ {
+ case SPECIAL_PARAM_NONE :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), rDouble );
+ break;
+ case SPECIAL_PARAM_WIDTH :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), nWidth, rDouble );
+ break;
+ case SPECIAL_PARAM_PRECISION :
+ nLen = sprintf( buffer, aFStr.GetBuffer(), nPrecision, rDouble);
+ break;
+ default:
+ nLen=sprintf(buffer, aFStr.GetBuffer(),nWidth,nPrecision,rDouble);
+ }
+ Write( buffer, (long)nLen );
+ return *this;
+}
+
+/*************************************************************************
+|*
+|* Stream::CryptAndWriteBuffer()
+|*
+|* Beschreibung Verschluesseln und Schreiben
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+#define CRYPT_BUFSIZE 1024
+
+sal_Size SvStream::CryptAndWriteBuffer( const void* pStart, sal_Size nLen)
+{
+ unsigned char pTemp[CRYPT_BUFSIZE];
+ unsigned char* pDataPtr = (unsigned char*)pStart;
+ sal_Size nCount = 0;
+ sal_Size nBufCount;
+ unsigned char nMask = nCryptMask;
+ do
+ {
+ if( nLen >= CRYPT_BUFSIZE )
+ nBufCount = CRYPT_BUFSIZE;
+ else
+ nBufCount = nLen;
+ nLen -= nBufCount;
+ memcpy( pTemp, pDataPtr, (sal_uInt16)nBufCount );
+ // **** Verschluesseln *****
+ for ( sal_uInt16 n=0; n < CRYPT_BUFSIZE; n++ )
+ {
+ unsigned char aCh = pTemp[n];
+ aCh ^= nMask;
+ SWAPNIBBLES(aCh)
+ pTemp[n] = aCh;
+ }
+ // *************************
+ nCount += PutData( (char*)pTemp, nBufCount );
+ pDataPtr += nBufCount;
+ }
+ while ( nLen );
+ return nCount;
+}
+
+/*************************************************************************
+|*
+|* Stream::EncryptBuffer()
+|*
+|* Beschreibung Buffer entschluesseln
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvStream::EncryptBuffer(void* pStart, sal_Size nLen)
+{
+ unsigned char* pTemp = (unsigned char*)pStart;
+ unsigned char nMask = nCryptMask;
+
+ for ( sal_Size n=0; n < nLen; n++, pTemp++ )
+ {
+ unsigned char aCh = *pTemp;
+ SWAPNIBBLES(aCh)
+ aCh ^= nMask;
+ *pTemp = aCh;
+ }
+ return TRUE;
+}
+
+/*************************************************************************
+|*
+|* Stream::SetKey()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+unsigned char implGetCryptMask(const sal_Char* pStr, sal_Int32 nLen, long nVersion)
+{
+ unsigned char nCryptMask = 0;
+
+ if (!nLen)
+ return nCryptMask;
+
+ if( nVersion <= SOFFICE_FILEFORMAT_31 )
+ {
+ while( nLen )
+ {
+ nCryptMask ^= *pStr;
+ pStr++;
+ nLen--;
+ }
+ }
+ else // BugFix #25888#
+ {
+ for( sal_uInt16 i = 0; i < nLen; i++ ) {
+ nCryptMask ^= pStr[i];
+ if( nCryptMask & 0x80 ) {
+ nCryptMask <<= 1;
+ nCryptMask++;
+ }
+ else
+ nCryptMask <<= 1;
+ }
+ }
+
+ if( !nCryptMask )
+ nCryptMask = 67;
+
+ return nCryptMask;
+}
+
+void SvStream::SetKey( const ByteString& rKey )
+{
+ aKey = rKey;
+ nCryptMask = implGetCryptMask( aKey.GetBuffer(), aKey.Len(), GetVersion() );
+}
+
+/*************************************************************************
+|*
+|* Stream::SyncSvStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::SyncSvStream( sal_Size nNewStreamPos )
+{
+ ClearBuffer();
+ SvStream::nBufFilePos = nNewStreamPos;
+}
+
+/*************************************************************************
+|*
+|* Stream::SyncSysStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+void SvStream::SyncSysStream()
+{
+ Flush();
+ SeekPos( Tell() );
+}
+
+/*************************************************************************
+|*
+|* Stream::SetStreamSize()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvStream::SetStreamSize( sal_Size nSize )
+{
+#ifdef DBG_UTIL
+ sal_Size nFPos = Tell();
+#endif
+ sal_uInt16 nBuf = nBufSize;
+ SetBufferSize( 0 );
+ SetSize( nSize );
+ SetBufferSize( nBuf );
+ DBG_ASSERT(Tell()==nFPos,"SetStreamSize failed");
+ return (sal_Bool)(nError == 0);
+}
+
+//============================================================================
+
+void SvStream::AddMark( sal_Size )
+{
+}
+
+//============================================================================
+
+void SvStream::RemoveMark( sal_Size )
+{
+}
+
+/*************************************************************************
+|*
+|* endl()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung TH 13.11.96
+|*
+*************************************************************************/
+
+SvStream& endl( SvStream& rStr )
+{
+ LineEnd eDelim = rStr.GetLineDelimiter();
+ if ( eDelim == LINEEND_CR )
+ rStr << _CR;
+ else if( eDelim == LINEEND_LF )
+ rStr << _LF;
+ else
+ rStr << _CR << _LF;
+ return rStr;
+}
+
+SvStream& endlu( SvStream& rStrm )
+{
+ switch ( rStrm.GetLineDelimiter() )
+ {
+ case LINEEND_CR :
+ rStrm << sal_Unicode(_CR);
+ break;
+ case LINEEND_LF :
+ rStrm << sal_Unicode(_LF);
+ break;
+ default:
+ rStrm << sal_Unicode(_CR) << sal_Unicode(_LF);
+ }
+ return rStrm;
+}
+
+SvStream& endlub( SvStream& rStrm )
+{
+ if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
+ return endlu( rStrm );
+ else
+ return endl( rStrm );
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::SvMemoryStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+SvMemoryStream::SvMemoryStream( void* pBuffer, sal_Size bufSize,
+ StreamMode eMode )
+{
+ if( eMode & STREAM_WRITE )
+ bIsWritable = TRUE;
+ else
+ bIsWritable = FALSE;
+ nEndOfData = bufSize;
+ bOwnsData = FALSE;
+ pBuf = (BYTE *) pBuffer;
+ nResize = 0L;
+ nSize = bufSize;
+ nPos = 0L;
+ SetBufferSize( 0 );
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::SvMemoryStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+SvMemoryStream::SvMemoryStream( sal_Size nInitSize, sal_Size nResizeOffset )
+{
+ bIsWritable = TRUE;
+ bOwnsData = TRUE;
+ nEndOfData = 0L;
+ nResize = nResizeOffset;
+ nPos = 0;
+ pBuf = 0;
+ if( nResize != 0 && nResize < 16 )
+ nResize = 16;
+ if( nInitSize && !AllocateMemory( nInitSize ) )
+ {
+ SetError( SVSTREAM_OUTOFMEMORY );
+ nSize = 0;
+ }
+ else
+ nSize = nInitSize;
+ SetBufferSize( 64 );
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::~SvMemoryStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+SvMemoryStream::~SvMemoryStream()
+{
+ if( pBuf )
+ {
+ if( bOwnsData )
+ FreeMemory();
+ else
+ Flush();
+ }
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::IsA()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+sal_uInt16 SvMemoryStream::IsA() const
+{
+ return (sal_uInt16)ID_MEMORYSTREAM;
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::SetBuffer()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+void* SvMemoryStream::SetBuffer( void* pNewBuf, sal_Size nCount,
+ sal_Bool bOwnsDat, sal_Size nEOF )
+{
+ void* pResult;
+ SetBufferSize( 0 ); // Buffering in der Basisklasse initialisieren
+ Seek( 0 );
+ if( bOwnsData )
+ {
+ pResult = 0;
+ if( pNewBuf != pBuf )
+ FreeMemory();
+ }
+ else
+ pResult = pBuf;
+
+ pBuf = (BYTE *) pNewBuf;
+ nPos = 0;
+ nSize = nCount;
+ nResize = 0;
+ bOwnsData = bOwnsDat;
+
+ if( nEOF > nCount )
+ nEOF = nCount;
+ nEndOfData = nEOF;
+
+ ResetError();
+
+ DBG_ASSERT( nEndOfData<STREAM_SEEK_TO_END,"Invalid EOF");
+ return pResult;
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::GetData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+sal_Size SvMemoryStream::GetData( void* pData, sal_Size nCount )
+{
+ sal_Size nMaxCount = nEndOfData-nPos;
+ if( nCount > nMaxCount )
+ nCount = nMaxCount;
+ memcpy( pData, pBuf+nPos, (size_t)nCount );
+ nPos += nCount;
+ return nCount;
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::PutData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+sal_Size SvMemoryStream::PutData( const void* pData, sal_Size nCount )
+{
+ if( GetError() )
+ return 0L;
+
+ sal_Size nMaxCount = nSize-nPos;
+
+ // auf Ueberlauf testen
+ if( nCount > nMaxCount )
+ {
+ if( nResize == 0 )
+ {
+ // soviel wie moeglich rueberschaufeln
+ nCount = nMaxCount;
+ SetError( SVSTREAM_OUTOFMEMORY );
+ }
+ else
+ {
+ long nNewResize;
+ if( nSize && nSize > nResize )
+ nNewResize = nSize;
+ else
+ nNewResize = nResize;
+
+ if( (nCount-nMaxCount) < nResize )
+ {
+ // fehlender Speicher ist kleiner als Resize-Offset,
+ // deshalb um Resize-Offset vergroessern
+ if( !ReAllocateMemory( nNewResize) )
+ {
+ nCount = 0;
+ SetError( SVSTREAM_WRITE_ERROR );
+ }
+ }
+ else
+ {
+ // fehlender Speicher ist groesser als Resize-Offset
+ // deshalb um Differenz+ResizeOffset vergroessern
+ if( !ReAllocateMemory( nCount-nMaxCount+nNewResize ) )
+ {
+ nCount = 0;
+ SetError( SVSTREAM_WRITE_ERROR );
+ }
+ }
+ }
+ }
+ DBG_ASSERT(pBuf,"Possibly Reallocate failed");
+ memcpy( pBuf+nPos, pData, (size_t)nCount);
+
+ nPos += nCount;
+ if( nPos > nEndOfData )
+ nEndOfData = nPos;
+ return nCount;
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::SeekPos()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+// nEndOfData: Erste Position im Stream, die nicht gelesen werden darf
+// nSize: Groesse des allozierten Speichers
+
+sal_Size SvMemoryStream::SeekPos( sal_Size nNewPos )
+{
+ if( nNewPos < nEndOfData )
+ nPos = nNewPos;
+ else if( nNewPos == STREAM_SEEK_TO_END )
+ nPos = nEndOfData;
+ else
+ {
+ if( nNewPos >= nSize ) // muss Buffer vergroessert werden ?
+ {
+ if( nResize ) // ist vergroeseern erlaubt ?
+ {
+ long nDiff = (long)(nNewPos - nSize + 1);
+ nDiff += (long)nResize;
+ ReAllocateMemory( nDiff );
+ nPos = nNewPos;
+ nEndOfData = nNewPos;
+ }
+ else // vergroessern ist nicht erlaubt -> ans Ende setzen
+ {
+ // SetError( SVSTREAM_OUTOFMEMORY );
+ nPos = nEndOfData;
+ }
+ }
+ else // gueltigen Bereich innerhalb des Buffers vergroessern
+ {
+ nPos = nNewPos;
+ nEndOfData = nNewPos;
+ }
+ }
+ return nPos;
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::FlushData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+void SvMemoryStream::FlushData()
+{
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::ResetError()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+void SvMemoryStream::ResetError()
+{
+ SvStream::ClearError();
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::AllocateMemory()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvMemoryStream::AllocateMemory( sal_Size nNewSize )
+{
+ pBuf = new BYTE[nNewSize];
+ return( pBuf != 0 );
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::ReAllocateMemory() (Bozo-Algorithmus)
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 20.06.94
+|* Letzte Aenderung OV 20.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvMemoryStream::ReAllocateMemory( long nDiff )
+{
+ sal_Bool bRetVal = FALSE;
+ long nTemp = (long)nSize;
+ nTemp += nDiff;
+ sal_Size nNewSize = (sal_Size)nTemp;
+
+ if( nNewSize )
+ {
+ BYTE* pNewBuf = new BYTE[nNewSize];
+
+ if( pNewBuf )
+ {
+ bRetVal = TRUE; // Success!
+ if( nNewSize < nSize ) // Verkleinern ?
+ {
+ memcpy( pNewBuf, pBuf, (size_t)nNewSize );
+ if( nPos > nNewSize )
+ nPos = 0L;
+ if( nEndOfData >= nNewSize )
+ nEndOfData = nNewSize-1L;
+ }
+ else
+ {
+ memcpy( pNewBuf, pBuf, (size_t)nSize );
+ }
+
+ FreeMemory();
+
+ pBuf = pNewBuf;
+ nSize = nNewSize;
+ }
+ }
+ else
+ {
+ bRetVal = TRUE;
+ FreeMemory();
+ pBuf = 0;
+ nSize = 0;
+ nEndOfData = 0;
+ nPos = 0;
+ }
+
+ return bRetVal;
+}
+
+void SvMemoryStream::FreeMemory()
+{
+ delete[] pBuf;
+}
+
+/*************************************************************************
+|*
+|* SvMemoryStream::SwitchBuffer()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 26.07.94
+|* Letzte Aenderung OV 26.07.94
+|*
+*************************************************************************/
+
+void* SvMemoryStream::SwitchBuffer( sal_Size nInitSize, sal_Size nResizeOffset)
+{
+ Flush();
+ if( !bOwnsData )
+ return 0;
+ Seek( STREAM_SEEK_TO_BEGIN );
+
+ void* pRetVal = pBuf;
+ pBuf = 0;
+ nEndOfData = 0L;
+ nResize = nResizeOffset;
+ nPos = 0;
+
+ if( nResize != 0 && nResize < 16 )
+ nResize = 16;
+
+ ResetError();
+
+ if( nInitSize && !AllocateMemory(nInitSize) )
+ {
+ SetError( SVSTREAM_OUTOFMEMORY );
+ nSize = 0;
+ }
+ else
+ nSize = nInitSize;
+
+ SetBufferSize( 64 );
+ return pRetVal;
+}
+
+void SvMemoryStream::SetSize( sal_Size nNewSize )
+{
+ long nDiff = (long)nNewSize - (long)nSize;
+ ReAllocateMemory( nDiff );
+}
+
+TYPEINIT0 ( SvDataCopyStream )
+
+void SvDataCopyStream::Assign( const SvDataCopyStream& )
+{
+}
diff --git a/tools/source/stream/strmos2.cxx b/tools/source/stream/strmos2.cxx
new file mode 100644
index 000000000000..d211d7790b08
--- /dev/null
+++ b/tools/source/stream/strmos2.cxx
@@ -0,0 +1,864 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include <limits.h>
+
+#define INCL_PM
+#define INCL_DOS
+#define INCL_DOSERRORS
+#include <svpm.h>
+
+#include <tools/debug.hxx>
+#include <tools/fsys.hxx>
+#include <tools/stream.hxx>
+
+// class FileBase
+#include <osl/file.hxx>
+
+using namespace osl;
+
+// class FileBase
+#ifndef _OSL_FILE_HXX_
+#include <osl/file.hxx>
+#endif
+
+using namespace osl;
+
+// -----------------------------------------------------------------------
+
+// --------------
+// - StreamData -
+// --------------
+
+class StreamData
+{
+public:
+ HFILE hFile;
+ BOOL bIsEof;
+
+ StreamData()
+ {
+ hFile = 0;
+ bIsEof = TRUE;
+ }
+};
+
+// -----------------------------------------------------------------------
+
+ULONG GetSvError( APIRET nPMError )
+{
+ static struct { APIRET pm; ULONG sv; } errArr[] =
+ {
+ { ERROR_FILE_NOT_FOUND, SVSTREAM_FILE_NOT_FOUND },
+ { ERROR_PATH_NOT_FOUND, SVSTREAM_PATH_NOT_FOUND },
+ { ERROR_TOO_MANY_OPEN_FILES, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { ERROR_ACCESS_DENIED, SVSTREAM_ACCESS_DENIED },
+ { ERROR_INVALID_ACCESS, SVSTREAM_INVALID_ACCESS },
+ { ERROR_SHARING_VIOLATION, SVSTREAM_SHARING_VIOLATION },
+ { ERROR_SHARING_BUFFER_EXCEEDED,SVSTREAM_SHARE_BUFF_EXCEEDED },
+ { ERROR_CANNOT_MAKE, SVSTREAM_CANNOT_MAKE },
+ { ERROR_INVALID_PARAMETER, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_DRIVE_LOCKED, SVSTREAM_LOCKING_VIOLATION },
+ { ERROR_LOCK_VIOLATION, SVSTREAM_LOCKING_VIOLATION },
+ { ERROR_FILENAME_EXCED_RANGE, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_ATOMIC_LOCK_NOT_SUPPORTED, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_READ_LOCKS_NOT_SUPPORTED, SVSTREAM_INVALID_PARAMETER },
+
+
+ { 0xFFFF, SVSTREAM_GENERALERROR }
+ };
+
+ ULONG nRetVal = SVSTREAM_GENERALERROR; // Standardfehler
+ int i=0;
+ do
+ {
+ if( errArr[i].pm == nPMError )
+ {
+ nRetVal = errArr[i].sv;
+ break;
+ }
+ i++;
+ }
+ while( errArr[i].pm != 0xFFFF );
+ return nRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+SvFileStream::SvFileStream( const String& rFileName, StreamMode nOpenMode )
+{
+ bIsOpen = FALSE;
+ nLockCounter = 0;
+ bIsWritable = FALSE;
+ pInstanceData = new StreamData;
+
+ SetBufferSize( 8192 );
+ // convert URL to SystemPath, if necessary
+ ::rtl::OUString aFileName, aNormPath;
+
+ if ( FileBase::getSystemPathFromFileURL( rFileName, aFileName ) != FileBase::E_None )
+ aFileName = rFileName;
+ Open( aFileName, nOpenMode );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 22.11.94
+|* Letzte Aenderung OV 22.11.94
+|*
+*************************************************************************/
+
+SvFileStream::SvFileStream()
+{
+ bIsOpen = FALSE;
+ nLockCounter = 0;
+ bIsWritable = FALSE;
+ pInstanceData = new StreamData;
+ SetBufferSize( 8192 );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::~SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 14.06.94
+|* Letzte Aenderung OV 14.06.94
+|*
+*************************************************************************/
+
+SvFileStream::~SvFileStream()
+{
+ Close();
+ if( pInstanceData )
+ delete pInstanceData;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::GetFileHandle()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 14.06.94
+|* Letzte Aenderung OV 14.06.94
+|*
+*************************************************************************/
+
+ULONG SvFileStream::GetFileHandle() const
+{
+ return (ULONG)pInstanceData->hFile;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::IsA()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 14.06.94
+|* Letzte Aenderung OV 14.06.94
+|*
+*************************************************************************/
+
+USHORT SvFileStream::IsA() const
+{
+ return ID_FILESTREAM;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::GetData()
+|*
+|* Beschreibung STREAM.SDW, Prueft nicht Eof; IsEof danach rufbar
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+ULONG SvFileStream::GetData( void* pData, ULONG nSize )
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "SvFileStream::GetData(): " );
+ aTraceStr += ByteString::CreateFromInt64(nSize);
+ aTraceStr += " Bytes from ";
+ aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ ULONG nCount = 0L;
+ if( IsOpen() )
+ {
+ APIRET nResult;
+ nResult = DosRead( pInstanceData->hFile,(PVOID)pData,nSize,&nCount );
+ if( nResult )
+ SetError(::GetSvError(nResult) );
+ }
+ return nCount;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::PutData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+ULONG SvFileStream::PutData( const void* pData, ULONG nSize )
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "SvFileStrean::PutData: " );
+ aTraceStr += ByteString::CreateFromInt64(nSize);
+ aTraceStr += " Bytes to ";
+ aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ ULONG nCount = 0L;
+ if( IsOpen() )
+ {
+ APIRET nResult;
+ nResult = DosWrite( pInstanceData->hFile,(PVOID)pData,nSize,&nCount );
+ if( nResult )
+ SetError(::GetSvError(nResult) );
+ else if( !nCount )
+ SetError( SVSTREAM_DISK_FULL );
+ }
+ return nCount;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SeekPos()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+ULONG SvFileStream::SeekPos( ULONG nPos )
+{
+ ULONG nNewPos = 0L;
+ if( IsOpen() )
+ {
+ APIRET nResult;
+
+ if( nPos != STREAM_SEEK_TO_END )
+ nResult = DosSetFilePtr( pInstanceData->hFile,(long)nPos,
+ FILE_BEGIN, &nNewPos );
+ else
+ nResult = DosSetFilePtr( pInstanceData->hFile,0L,
+ FILE_END, &nNewPos );
+
+ if( nResult )
+ SetError(::GetSvError(nResult) );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return nNewPos;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::Tell()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+/*
+ULONG SvFileStream::Tell()
+{
+ ULONG nPos = 0L;
+
+ if( IsOpen() )
+ {
+ APIRET nResult;
+ nResult = DosSetFilePtr(pInstanceData->hFile,0L,FILE_CURRENT,&nPos);
+ if( nResult )
+ SetError(::GetSvError(nResult) );
+ }
+ return nPos;
+}
+*/
+
+/*************************************************************************
+|*
+|* SvFileStream::FlushData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::FlushData()
+{
+ if( IsOpen() )
+ {
+ APIRET nResult;
+ nResult = DosResetBuffer(pInstanceData->hFile );
+ if( nResult )
+ SetError(::GetSvError(nResult) );
+ }
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::LockRange()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvFileStream::LockRange( ULONG nByteOffset, ULONG nBytes )
+{
+ sal_Bool bRetVal = FALSE;
+ if( IsOpen() )
+ {
+ APIRET nResult;
+ FILELOCK aLockArea, aUnlockArea;
+ aUnlockArea.lOffset = 0L;
+ aUnlockArea.lRange = 0L;
+ aLockArea.lOffset = (long)nByteOffset;
+ aLockArea.lRange = (long)nBytes;
+
+ nResult = DosSetFileLocks(pInstanceData->hFile,
+ &aUnlockArea, &aLockArea,
+ 1000UL, // Zeit in ms bis Abbruch
+ 0L // kein Atomic-Lock
+ );
+
+ if( nResult )
+ SetError(::GetSvError(nResult) );
+ else
+ bRetVal = TRUE;
+ }
+ return bRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::UnlockRange()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvFileStream::UnlockRange( ULONG nByteOffset, ULONG nBytes )
+{
+ sal_Bool bRetVal = FALSE;
+ if( IsOpen() )
+ {
+ APIRET nResult;
+ FILELOCK aLockArea, aUnlockArea;
+ aLockArea.lOffset = 0L;
+ aLockArea.lRange = 0L;
+ aUnlockArea.lOffset = (long)nByteOffset;
+ aUnlockArea.lRange = (long)nBytes;
+
+ nResult = DosSetFileLocks(pInstanceData->hFile,
+ &aUnlockArea, &aLockArea,
+ 1000UL, // Zeit in ms bis Abbruch
+ 0L // kein Atomic-Lock
+ );
+
+ if( nResult )
+ SetError(::GetSvError(nResult) );
+ else
+ bRetVal = TRUE;
+ }
+ return bRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::LockFile()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvFileStream::LockFile()
+{
+ sal_Bool bRetVal = FALSE;
+ if( !nLockCounter )
+ {
+ if( LockRange( 0L, LONG_MAX ) )
+ {
+ nLockCounter = 1;
+ bRetVal = TRUE;
+ }
+ }
+ else
+ {
+ nLockCounter++;
+ bRetVal = TRUE;
+ }
+ return bRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::UnlockFile()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvFileStream::UnlockFile()
+{
+ sal_Bool bRetVal = FALSE;
+ if( nLockCounter > 0)
+ {
+ if( nLockCounter == 1)
+ {
+ if( UnlockRange( 0L, LONG_MAX ) )
+ {
+ nLockCounter = 0;
+ bRetVal = TRUE;
+ }
+ }
+ else
+ {
+ nLockCounter--;
+ bRetVal = TRUE;
+ }
+ }
+ return bRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::Open()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+#if 0
+BOOL createLongNameEA ( const PCSZ pszPath, ULONG ulAttributes, const String& aLongName );
+#endif
+
+void SvFileStream::Open( const String& rFilename, StreamMode nOpenMode )
+{
+ String aParsedFilename;
+
+#if 0
+ if ( Folder::IsAvailable() && (rFilename.Search('{') < 9) )
+ {
+ String aVirtualPart;
+ String aRealPart;
+ String aVirtualPath;
+ ItemIDPath aVirtualURL;
+ ULONG nDivider = 0;
+
+ String aVirtualString(rFilename);
+
+ for (int x=aVirtualString.Len(); x>0; x--)
+ {
+ if (aVirtualString.Copy(x,1).Compare("}")==COMPARE_EQUAL)
+ {
+ nDivider = x;
+ break;
+ }
+ }
+
+ aVirtualPart = aVirtualString.Copy(0,nDivider+1);
+ aRealPart = aVirtualString.Copy(nDivider+2);
+
+ aVirtualURL = aVirtualPart;
+ aVirtualPath = aVirtualURL.GetHostNotationPath();
+
+ DirEntry aTempDirEntry(aVirtualPath);
+
+ aTempDirEntry += aRealPart;
+
+ aParsedFilename = aTempDirEntry.GetFull();
+ }
+ else
+#endif // 0
+ {
+ aParsedFilename = rFilename;
+ }
+
+ Close();
+ SvStream::ClearBuffer();
+
+ ULONG nActionTaken;
+ ULONG nOpenAction = 0L;
+ ULONG nShareBits = 0L;
+ ULONG nReadWriteBits = 0L;
+
+ eStreamMode = nOpenMode;
+ eStreamMode &= ~STREAM_TRUNC; // beim ReOpen nicht cutten
+
+ nOpenMode |= STREAM_SHARE_DENYNONE; // definierten Zustand garantieren
+
+ // ********* Zugriffsflags ***********
+ if( nOpenMode & STREAM_SHARE_DENYNONE)
+ nShareBits = OPEN_SHARE_DENYNONE;
+
+ if( nOpenMode & STREAM_SHARE_DENYREAD)
+ nShareBits = OPEN_SHARE_DENYREAD;
+
+ if( nOpenMode & STREAM_SHARE_DENYWRITE)
+ nShareBits = OPEN_SHARE_DENYWRITE;
+
+ if( nOpenMode & STREAM_SHARE_DENYALL)
+ nShareBits = OPEN_SHARE_DENYREADWRITE;
+
+ if( (nOpenMode & STREAM_READ) )
+ {
+ if( nOpenMode & STREAM_WRITE )
+ nReadWriteBits |= OPEN_ACCESS_READWRITE;
+ else
+ {
+ nReadWriteBits |= OPEN_ACCESS_READONLY;
+ nOpenMode |= STREAM_NOCREATE;
+ }
+ }
+ else
+ nReadWriteBits |= OPEN_ACCESS_WRITEONLY;
+
+
+ if( nOpenMode & STREAM_NOCREATE )
+ {
+ // Datei nicht erzeugen
+ nOpenAction = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
+ }
+ else
+ {
+ // Datei erzeugen, wenn nicht vorhanden
+ nOpenAction = OPEN_ACTION_CREATE_IF_NEW;
+ if( nOpenMode & STREAM_TRUNC )
+ // Auf Nullaenge kuerzen, wenn existiert
+ nOpenAction |= OPEN_ACTION_REPLACE_IF_EXISTS;
+ else
+ // Inhalt der Datei nicht wegwerfen
+ nOpenAction |= OPEN_ACTION_OPEN_IF_EXISTS;
+ }
+
+#if 0 // YD
+ //
+ // resolves long FAT names used by OS2
+ //
+ BOOL bIsLongOS2=FALSE;
+ if (Folder::IsAvailable())
+ {
+ DirEntry aDirEntry(rFilename);
+ if (aDirEntry.IsLongNameOnFAT())
+ {
+ // in kurzen Pfad wandeln
+ ItemIDPath aItemIDPath(rFilename);
+ aParsedFilename = aItemIDPath.GetHostNotationPath();
+ bIsLongOS2 = TRUE;
+ }
+ }
+#endif
+
+ aFilename = aParsedFilename;
+ ByteString aFileNameA( aFilename, gsl_getSystemTextEncoding());
+ FSysRedirector::DoRedirect( aFilename );
+
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "SvFileStream::Open(): " );
+ aTraceStr += aFileNameA;
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ APIRET nRet = DosOpen( aFileNameA.GetBuffer(), &pInstanceData->hFile,
+ &nActionTaken, 0L, FILE_NORMAL, nOpenAction,
+ nReadWriteBits | nShareBits | OPEN_FLAGS_NOINHERIT, 0L);
+
+ if( nRet == ERROR_TOO_MANY_OPEN_FILES )
+ {
+ long nToAdd = 10;
+ ULONG nCurMaxFH;
+ nRet = DosSetRelMaxFH( &nToAdd, &nCurMaxFH );
+ nRet = DosOpen( aFileNameA.GetBuffer(), &pInstanceData->hFile,
+ &nActionTaken, 0L, FILE_NORMAL, nOpenAction,
+ nReadWriteBits | nShareBits | OPEN_FLAGS_NOINHERIT, 0L);
+ }
+
+ // Bei Fehler pruefen, ob wir lesen duerfen
+ if( nRet==ERROR_ACCESS_DENIED || nRet==ERROR_SHARING_VIOLATION )
+ {
+ nReadWriteBits = OPEN_ACCESS_READONLY;
+ nRet = DosOpen( aFileNameA.GetBuffer(), &pInstanceData->hFile,
+ &nActionTaken, 0L, FILE_NORMAL, nOpenAction,
+ nReadWriteBits | nShareBits | OPEN_FLAGS_NOINHERIT, 0L);
+ }
+
+ if( nRet )
+ {
+ bIsOpen = FALSE;
+ SetError(::GetSvError(nRet) );
+ }
+ else
+ {
+ bIsOpen = TRUE;
+ pInstanceData->bIsEof = FALSE;
+ if( nReadWriteBits != OPEN_ACCESS_READONLY )
+ bIsWritable = TRUE;
+ }
+
+#if 0
+ if (bIsOpen && bIsLongOS2)
+ {
+ //file schließen, da sonst createLongName u.U. nicht möglich
+ Close();
+
+ // erzeugtem File langen Namen geben
+ DirEntry aDirEntry(rFilename);
+ createLongNameEA(aFileNameA.GetBuffer(), FILE_NORMAL, aDirEntry.GetName());
+
+ // und wieder oeffnen
+ ReOpen();
+ }
+#endif
+
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::ReOpen()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::ReOpen()
+{
+ if( !bIsOpen && aFilename.Len() )
+ Open( aFilename, eStreamMode );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::Close()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::Close()
+{
+ if( IsOpen() )
+ {
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "SvFileStream::Close(): " );
+ aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ if( nLockCounter )
+ {
+ nLockCounter = 1;
+ UnlockFile();
+ }
+ Flush();
+ DosClose( pInstanceData->hFile );
+ }
+
+ bIsOpen = FALSE;
+ nLockCounter= 0;
+ bIsWritable = FALSE;
+ pInstanceData->bIsEof = TRUE;
+ SvStream::ClearBuffer();
+ SvStream::ClearError();
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::ResetError()
+|*
+|* Beschreibung STREAM.SDW; Setzt Filepointer auf Dateianfang
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::ResetError()
+{
+ SvStream::ClearError();
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SetSize()
+|*
+|* Beschreibung
+|* Ersterstellung OV 19.10.95
+|* Letzte Aenderung OV 19.10.95
+|*
+*************************************************************************/
+
+void SvFileStream::SetSize( ULONG nSize )
+{
+ if( IsOpen() )
+ {
+ APIRET nRet = DosSetFileSize( pInstanceData->hFile, nSize );
+ if( nRet )
+ SetError( ::GetSvError( nRet ) );
+ }
+}
+
+#if 0
+/*************************************************************************
+|*
+|* SvSharedMemoryStream::AllocateMemory()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung CL 05.05.95
+|* Letzte Aenderung CL 05.05.95
+|*
+*************************************************************************/
+
+sal_Bool SvSharedMemoryStream::AllocateMemory( ULONG nNewSize )
+{
+ DBG_ASSERT(aHandle==0,"Keine Handles unter OS/2");
+ DBG_ASSERT(nNewSize,"Cannot allocate zero Bytes");
+ APIRET nRet = DosAllocSharedMem( (void**)&pBuf, (PSZ)NULL, nNewSize,
+ PAG_READ | PAG_WRITE | PAG_COMMIT |
+ OBJ_GIVEABLE | OBJ_GETTABLE | OBJ_ANY);
+ return( nRet == 0 );
+}
+
+/*************************************************************************
+|*
+|* SvSharedMemoryStream::ReAllocateMemory() (Bozo-Algorithmus)
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung CL 05.05.95
+|* Letzte Aenderung CL 05.05.95
+|*
+*************************************************************************/
+
+sal_Bool SvSharedMemoryStream::ReAllocateMemory( long nDiff )
+{
+ DBG_ASSERT(aHandle==0,"Keine Handles unter OS/2");
+ sal_Bool bRetVal = FALSE;
+ ULONG nNewSize = nSize + nDiff;
+ if( nNewSize )
+ {
+ // neuen Speicher nicht ueber AllocateMemory holen, da wir den
+ // alten Speicher behalten wollen, falls nicht genuegend Platz
+ // fuer den neuen Block da ist
+ char* pNewBuf;
+ APIRET nRet = DosAllocSharedMem( (void**)&pNewBuf,(PSZ)NULL,nNewSize,
+ PAG_READ | PAG_WRITE | PAG_COMMIT |
+ OBJ_GIVEABLE | OBJ_GETTABLE | OBJ_ANY);
+ DBG_ASSERT(!nRet,"DosAllocSharedMem failed");
+
+ if( !nRet )
+ {
+ bRetVal = TRUE; // Success!
+ if( nNewSize < nSize ) // Verkleinern ?
+ {
+ memcpy( pNewBuf, pBuf, (size_t)nNewSize );
+ if( nPos > nNewSize )
+ nPos = 0L;
+ if( nEndOfData >= nNewSize )
+ nEndOfData = nNewSize-1L;
+ }
+ else
+ memcpy( pNewBuf, pBuf, (size_t)nSize );
+
+ FreeMemory(); // den alten Block loeschen ...
+
+ // und den neuen Block in Dienst stellen
+ pBuf = (sal_uInt8*)pNewBuf;
+ nSize = nNewSize;
+ }
+ }
+ else
+ {
+ bRetVal = TRUE;
+ FreeMemory();
+ pBuf = 0;
+ nSize = 0;
+ nEndOfData = 0;
+ }
+ return bRetVal;
+}
+
+void SvSharedMemoryStream::FreeMemory()
+{
+ DBG_ASSERT(aHandle==0,"Keine Handles unter OS/2");
+ DosFreeMem( pBuf );
+}
+
+/*************************************************************************
+|*
+|* SvSharedMemoryStream::SetHandle()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 05.10.95
+|* Letzte Aenderung OV 05.10.95
+|*
+*************************************************************************/
+
+void* SvSharedMemoryStream::SetHandle( void* aNewHandle, sal_Size nSize,
+ sal_Bool bOwnsData, sal_Size nEOF )
+{
+ DBG_ERROR("OS/2 does not support memory handles");
+ // return SetBuffer(aNewHandle, nSize, bOwnsData, nEOF );
+ return 0;
+}
+
+
+#endif // 0
diff --git a/tools/source/stream/strmsys.cxx b/tools/source/stream/strmsys.cxx
new file mode 100644
index 000000000000..a373ad985214
--- /dev/null
+++ b/tools/source/stream/strmsys.cxx
@@ -0,0 +1,37 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#if defined WNT
+#include "strmwnt.cxx"
+#elif defined UNX
+#include "strmunx.cxx"
+#elif defined OS2
+#include "strmos2.cxx"
+#endif
diff --git a/tools/source/stream/strmunx.cxx b/tools/source/stream/strmunx.cxx
new file mode 100644
index 000000000000..88ccb2113e0d
--- /dev/null
+++ b/tools/source/stream/strmunx.cxx
@@ -0,0 +1,920 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// no include "precompiled_tools.hxx" because this file is included in strmsys.cxx
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h> // fuer getenv()
+
+#include <tools/debug.hxx>
+#include <tools/fsys.hxx>
+#include <tools/stream.hxx>
+
+#include <vos/mutex.hxx>
+#include <osl/thread.h> // osl_getThreadTextEncoding
+
+// class FileBase
+#include <osl/file.hxx>
+#include <rtl/instance.hxx>
+
+using namespace osl;
+
+// -----------------------------------------------------------------------
+
+// ----------------
+// - InternalLock -
+// ----------------
+
+class InternalStreamLock;
+DECLARE_LIST( InternalStreamLockList, InternalStreamLock* )
+namespace { struct LockList : public rtl::Static< InternalStreamLockList, LockList > {}; }
+
+#ifndef BOOTSTRAP
+namespace { struct LockMutex : public rtl::Static< NAMESPACE_VOS(OMutex), LockMutex > {}; }
+#endif
+
+class InternalStreamLock
+{
+ sal_Size m_nStartPos;
+ sal_Size m_nEndPos;
+ SvFileStream* m_pStream;
+ struct stat m_aStat;
+
+ InternalStreamLock( sal_Size, sal_Size, SvFileStream* );
+ ~InternalStreamLock();
+public:
+ static sal_Bool LockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* );
+ static void UnlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* );
+};
+
+InternalStreamLock::InternalStreamLock(
+ sal_Size nStart,
+ sal_Size nEnd,
+ SvFileStream* pStream ) :
+ m_nStartPos( nStart ),
+ m_nEndPos( nEnd ),
+ m_pStream( pStream )
+{
+ ByteString aFileName(m_pStream->GetFileName(), osl_getThreadTextEncoding());
+ stat( aFileName.GetBuffer(), &m_aStat );
+ LockList::get().Insert( this, LIST_APPEND );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "locked %s", aFileName.GetBuffer() );
+ if( m_nStartPos || m_nEndPos )
+ fprintf(stderr, " [ %ld ... %ld ]", m_nStartPos, m_nEndPos );
+ fprintf( stderr, "\n" );
+#endif
+}
+
+InternalStreamLock::~InternalStreamLock()
+{
+ LockList::get().Remove( this );
+#if OSL_DEBUG_LEVEL > 1
+ ByteString aFileName(m_pStream->GetFileName(), osl_getThreadTextEncoding());
+ fprintf( stderr, "unlocked %s", aFileName.GetBuffer() );
+ if( m_nStartPos || m_nEndPos )
+ fprintf(stderr, " [ %ld ... %ld ]", m_nStartPos, m_nEndPos );
+ fprintf( stderr, "\n" );
+#endif
+}
+
+sal_Bool InternalStreamLock::LockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream )
+{
+#ifndef BOOTSTRAP
+ NAMESPACE_VOS( OGuard ) aGuard( LockMutex::get() );
+#endif
+ ByteString aFileName(pStream->GetFileName(), osl_getThreadTextEncoding());
+ struct stat aStat;
+ if( stat( aFileName.GetBuffer(), &aStat ) )
+ return sal_False;
+
+ if( S_ISDIR( aStat.st_mode ) )
+ return sal_True;
+
+ InternalStreamLock* pLock = NULL;
+ InternalStreamLockList &rLockList = LockList::get();
+ for( ULONG i = 0; i < rLockList.Count(); ++i )
+ {
+ pLock = rLockList.GetObject( i );
+ if( aStat.st_ino == pLock->m_aStat.st_ino )
+ {
+ sal_Bool bDenyByOptions = sal_False;
+ StreamMode nLockMode = pLock->m_pStream->GetStreamMode();
+ StreamMode nNewMode = pStream->GetStreamMode();
+
+ if( nLockMode & STREAM_SHARE_DENYALL )
+ bDenyByOptions = sal_True;
+ else if( ( nLockMode & STREAM_SHARE_DENYWRITE ) &&
+ ( nNewMode & STREAM_WRITE ) )
+ bDenyByOptions = sal_True;
+ else if( ( nLockMode & STREAM_SHARE_DENYREAD ) &&
+ ( nNewMode & STREAM_READ ) )
+ bDenyByOptions = sal_True;
+
+ if( bDenyByOptions )
+ {
+ if( pLock->m_nStartPos == 0 && pLock->m_nEndPos == 0 ) // whole file is already locked
+ return sal_False;
+ if( nStart == 0 && nEnd == 0) // cannot lock whole file
+ return sal_False;
+
+ if( ( nStart < pLock->m_nStartPos && nEnd > pLock->m_nStartPos ) ||
+ ( nStart < pLock->m_nEndPos && nEnd > pLock->m_nEndPos ) )
+ return sal_False;
+ }
+ }
+ }
+ pLock = new InternalStreamLock( nStart, nEnd, pStream );
+ return sal_True;
+}
+
+void InternalStreamLock::UnlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream )
+{
+#ifndef BOOTSTRAP
+ NAMESPACE_VOS( OGuard ) aGuard( LockMutex::get() );
+#endif
+ InternalStreamLock* pLock = NULL;
+ InternalStreamLockList &rLockList = LockList::get();
+ if( nStart == 0 && nEnd == 0 )
+ {
+ for( ULONG i = 0; i < rLockList.Count(); ++i )
+ {
+ if( ( pLock = rLockList.GetObject( i ) )->m_pStream == pStream )
+ {
+ delete pLock;
+ i--;
+ }
+ }
+ return;
+ }
+ for( ULONG i = 0; i < rLockList.Count(); ++i )
+ {
+ if( ( pLock = rLockList.GetObject( i ) )->m_pStream == pStream &&
+ nStart == pLock->m_nStartPos && nEnd == pLock->m_nEndPos )
+ {
+ delete pLock;
+ return;
+ }
+ }
+}
+
+// --------------
+// - StreamData -
+// --------------
+
+class StreamData
+{
+public:
+ int nHandle;
+
+ StreamData() { nHandle = 0; }
+};
+
+// -----------------------------------------------------------------------
+
+static sal_uInt32 GetSvError( int nErrno )
+{
+ static struct { int nErr; sal_uInt32 sv; } errArr[] =
+ {
+ { 0, SVSTREAM_OK },
+ { EACCES, SVSTREAM_ACCESS_DENIED },
+ { EBADF, SVSTREAM_INVALID_HANDLE },
+#if defined( RS6000 ) || defined( ALPHA ) || defined( HP9000 ) || defined( NETBSD ) || defined(FREEBSD) || defined(MACOSX) || defined(__FreeBSD_kernel__)
+ { EDEADLK, SVSTREAM_LOCKING_VIOLATION },
+#else
+ { EDEADLOCK, SVSTREAM_LOCKING_VIOLATION },
+#endif
+ { EINVAL, SVSTREAM_INVALID_PARAMETER },
+ { EMFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { ENFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { ENOENT, SVSTREAM_FILE_NOT_FOUND },
+ { EPERM, SVSTREAM_ACCESS_DENIED },
+ { EROFS, SVSTREAM_ACCESS_DENIED },
+ { EAGAIN, SVSTREAM_LOCKING_VIOLATION },
+ { EISDIR, SVSTREAM_PATH_NOT_FOUND },
+ { ELOOP, SVSTREAM_PATH_NOT_FOUND },
+#if ! defined( RS6000 ) && ! defined( ALPHA ) && ! defined( NETBSD ) && ! defined (FREEBSD) && ! defined (MACOSX) && ! defined(__FreeBSD_kernel__)
+ { EMULTIHOP, SVSTREAM_PATH_NOT_FOUND },
+ { ENOLINK, SVSTREAM_PATH_NOT_FOUND },
+#endif
+ { ENOTDIR, SVSTREAM_PATH_NOT_FOUND },
+ { ETXTBSY, SVSTREAM_ACCESS_DENIED },
+ { EEXIST, SVSTREAM_CANNOT_MAKE },
+ { ENOSPC, SVSTREAM_DISK_FULL },
+ { (int)0xFFFF, SVSTREAM_GENERALERROR }
+ };
+
+ sal_uInt32 nRetVal = SVSTREAM_GENERALERROR; // Standardfehler
+ int i=0;
+ do
+ {
+ if ( errArr[i].nErr == nErrno )
+ {
+ nRetVal = errArr[i].sv;
+ break;
+ }
+ ++i;
+ }
+ while( errArr[i].nErr != 0xFFFF );
+ return nRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 08.06.94
+|* Letzte Aenderung OV 08.06.94
+|*
+*************************************************************************/
+
+SvFileStream::SvFileStream( const String& rFileName, StreamMode nOpenMode )
+{
+ bIsOpen = sal_False;
+ nLockCounter = 0;
+ bIsWritable = sal_False;
+ pInstanceData = new StreamData;
+
+ SetBufferSize( 1024 );
+ // convert URL to SystemPath, if necessary
+ ::rtl::OUString aSystemFileName;
+ if( FileBase::getSystemPathFromFileURL( rFileName , aSystemFileName )
+ != FileBase::E_None )
+ {
+ aSystemFileName = rFileName;
+ }
+ Open( aSystemFileName, nOpenMode );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 22.11.94
+|* Letzte Aenderung OV 22.11.94
+|*
+*************************************************************************/
+
+SvFileStream::SvFileStream()
+{
+ bIsOpen = sal_False;
+ nLockCounter = 0;
+ bIsWritable = sal_False;
+ pInstanceData = new StreamData;
+ SetBufferSize( 1024 );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::~SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 22.11.94
+|* Letzte Aenderung OV 22.11.94
+|*
+*************************************************************************/
+
+SvFileStream::~SvFileStream()
+{
+ Close();
+
+ InternalStreamLock::UnlockFile( 0, 0, this );
+
+ if (pInstanceData)
+ delete pInstanceData;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::GetFileHandle()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 22.11.94
+|* Letzte Aenderung OV 22.11.94
+|*
+*************************************************************************/
+
+sal_uInt32 SvFileStream::GetFileHandle() const
+{
+ return (sal_uInt32)pInstanceData->nHandle;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::IsA()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 14.06.94
+|* Letzte Aenderung OV 14.06.94
+|*
+*************************************************************************/
+
+sal_uInt16 SvFileStream::IsA() const
+{
+ return ID_FILESTREAM;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::GetData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Size SvFileStream::GetData( void* pData, sal_Size nSize )
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "SvFileStream::GetData(): " );
+ aTraceStr += ByteString::CreateFromInt64(nSize);
+ aTraceStr += " Bytes from ";
+ aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ int nRead = 0;
+ if ( IsOpen() )
+ {
+ nRead = read(pInstanceData->nHandle,pData,(unsigned)nSize);
+ if ( nRead == -1 )
+ SetError( ::GetSvError( errno ));
+ }
+ return (sal_Size)nRead;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::PutData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Size SvFileStream::PutData( const void* pData, sal_Size nSize )
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "SvFileStrean::PutData: " );
+ aTraceStr += ByteString::CreateFromInt64(nSize);
+ aTraceStr += " Bytes to ";
+ aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ int nWrite = 0;
+ if ( IsOpen() )
+ {
+ nWrite = write(pInstanceData->nHandle,pData,(unsigned)nSize);
+ if ( nWrite == -1 )
+ SetError( ::GetSvError( errno ) );
+ else if( !nWrite )
+ SetError( SVSTREAM_DISK_FULL );
+ }
+ return (sal_Size)nWrite;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SeekPos()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Size SvFileStream::SeekPos( sal_Size nPos )
+{
+ if ( IsOpen() )
+ {
+ long nNewPos;
+ if ( nPos != STREAM_SEEK_TO_END )
+ nNewPos = lseek( pInstanceData->nHandle, (long)nPos, SEEK_SET );
+ else
+ nNewPos = lseek( pInstanceData->nHandle, 0L, SEEK_END );
+
+ if ( nNewPos == -1 )
+ {
+ SetError( SVSTREAM_SEEK_ERROR );
+ return 0L;
+ }
+ // langsam aber sicherer als return nNewPos
+ return lseek(pInstanceData->nHandle,0L,SEEK_CUR);
+ // return nNewPos;
+ }
+ SetError( SVSTREAM_GENERALERROR );
+ return 0L;
+}
+
+
+/*************************************************************************
+|*
+|* SvFileStream::FlushData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::FlushData()
+{
+// lokal gibt es nicht
+}
+
+static char *pFileLockEnvVar = (char*)1;
+
+/*************************************************************************
+|*
+|* SvFileStream::LockRange()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvFileStream::LockRange( sal_Size nByteOffset, sal_Size nBytes )
+{
+ struct flock aflock;
+ aflock.l_start = nByteOffset;
+ aflock.l_whence = SEEK_SET;
+ aflock.l_len = nBytes;
+
+ int nLockMode = 0;
+
+ if ( ! IsOpen() )
+ return sal_False;
+
+ if ( eStreamMode & STREAM_SHARE_DENYALL )
+ {
+ if (bIsWritable)
+ nLockMode = F_WRLCK;
+ else
+ nLockMode = F_RDLCK;
+ }
+
+ if ( eStreamMode & STREAM_SHARE_DENYREAD )
+ {
+ if (bIsWritable)
+ nLockMode = F_WRLCK;
+ else
+ {
+ SetError(SVSTREAM_LOCKING_VIOLATION);
+ return sal_False;
+ }
+ }
+
+ if ( eStreamMode & STREAM_SHARE_DENYWRITE )
+ {
+ if (bIsWritable)
+ nLockMode = F_WRLCK;
+ else
+ nLockMode = F_RDLCK;
+ }
+
+ if (!nLockMode)
+ return sal_True;
+
+ if( ! InternalStreamLock::LockFile( nByteOffset, nByteOffset+nBytes, this ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "InternalLock on %s [ %ld ... %ld ] failed\n",
+ ByteString(aFilename, osl_getThreadTextEncoding()).GetBuffer(), nByteOffset, nByteOffset+nBytes );
+#endif
+ return sal_False;
+ }
+
+ // HACK: File-Locking nur via Environmentvariable einschalten
+ // um einen Haenger im Zusammenspiel mit einem Linux
+ // NFS-2-Server (kein Lockdaemon) zu verhindern.
+ // File-Locking ?ber NFS ist generell ein Performancekiller.
+ // HR, 22.10.1997 fuer SOLARIS
+ // CP, 30.11.1997 fuer HPUX
+ // ER, 18.12.1997 fuer IRIX
+ // HR, 18.05.1998 Environmentvariable
+
+ if ( pFileLockEnvVar == (char*)1 )
+ pFileLockEnvVar = getenv("STAR_ENABLE_FILE_LOCKING");
+ if ( ! pFileLockEnvVar )
+ return sal_True;
+
+ aflock.l_type = nLockMode;
+ if (fcntl(pInstanceData->nHandle, F_GETLK, &aflock) == -1)
+ {
+ #if ( defined HPUX && defined BAD_UNION )
+ #ifdef DBG_UTIL
+ fprintf( stderr, "***** FCNTL(lock):errno = %d\n", errno );
+ #endif
+ if ( errno == EINVAL || errno == ENOSYS )
+ return sal_True;
+ #endif
+ #if defined SINIX
+ if (errno == EINVAL)
+ return sal_True;
+ #endif
+ #if defined SOLARIS
+ if (errno == ENOSYS)
+ return sal_True;
+ #endif
+ SetError( ::GetSvError( errno ));
+ return sal_False;
+ }
+ if (aflock.l_type != F_UNLCK)
+ {
+ SetError(SVSTREAM_LOCKING_VIOLATION);
+ return sal_False;
+ }
+
+ aflock.l_type = nLockMode;
+ if (fcntl(pInstanceData->nHandle, F_SETLK, &aflock) == -1)
+ {
+ SetError( ::GetSvError( errno ));
+ return sal_False;
+ }
+ return sal_True;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::UnlockRange()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvFileStream::UnlockRange( sal_Size nByteOffset, sal_Size nBytes )
+{
+
+ struct flock aflock;
+ aflock.l_type = F_UNLCK;
+ aflock.l_start = nByteOffset;
+ aflock.l_whence = SEEK_SET;
+ aflock.l_len = nBytes;
+
+ if ( ! IsOpen() )
+ return sal_False;
+
+ InternalStreamLock::UnlockFile( nByteOffset, nByteOffset+nBytes, this );
+
+ if ( ! (eStreamMode &
+ (STREAM_SHARE_DENYALL | STREAM_SHARE_DENYREAD | STREAM_SHARE_DENYWRITE)))
+ return sal_True;
+
+ // wenn File Locking ausgeschaltet, siehe SvFileStream::LockRange
+ if ( ! pFileLockEnvVar )
+ return sal_True;
+
+ if (fcntl(pInstanceData->nHandle, F_SETLK, &aflock) != -1)
+ return sal_True;
+
+#if ( defined HPUX && defined BAD_UNION )
+#ifdef DBG_UTIL
+ fprintf( stderr, "***** FCNTL(unlock):errno = %d\n", errno );
+#endif
+ if ( errno == EINVAL || errno == ENOSYS )
+ return sal_True;
+#endif
+#if ( defined SINIX )
+ if (errno == EINVAL)
+ return sal_True;
+#endif
+
+ SetError( ::GetSvError( errno ));
+ return sal_False;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::LockFile()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvFileStream::LockFile()
+{
+ return LockRange( 0UL, 0UL );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::UnlockFile()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+sal_Bool SvFileStream::UnlockFile()
+{
+ return UnlockRange( 0UL, 0UL );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::Open()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::Open( const String& rFilename, StreamMode nOpenMode )
+{
+ int nAccess, nAccessRW;
+ int nMode;
+ int nHandleTmp;
+ struct stat buf;
+ sal_Bool bStatValid = sal_False;
+
+ Close();
+ errno = 0;
+ eStreamMode = nOpenMode;
+ eStreamMode &= ~STREAM_TRUNC; // beim ReOpen nicht cutten
+
+// !!! NoOp: Ansonsten ToAbs() verwendern
+// !!! DirEntry aDirEntry( rFilename );
+// !!! aFilename = aDirEntry.GetFull();
+ aFilename = rFilename;
+#ifndef BOOTSTRAP
+ FSysRedirector::DoRedirect( aFilename );
+#endif
+ ByteString aLocalFilename(aFilename, osl_getThreadTextEncoding());
+
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "SvFileStream::Open(): " );
+ aTraceStr += aLocalFilename;
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ if ( lstat( aLocalFilename.GetBuffer(), &buf ) == 0 )
+ {
+ bStatValid = sal_True;
+ // SvFileStream soll kein Directory oeffnen
+ if( S_ISDIR( buf.st_mode ) )
+ {
+ SetError( ::GetSvError( EISDIR ) );
+ return;
+ }
+ }
+
+
+ if ( !( nOpenMode & STREAM_WRITE ) )
+ nAccessRW = O_RDONLY;
+ else if ( !( nOpenMode & STREAM_READ ) )
+ nAccessRW = O_WRONLY;
+ else
+ nAccessRW = O_RDWR;
+
+ nAccess = 0;
+ // Fix (MDA, 18.01.95): Bei RD_ONLY nicht mit O_CREAT oeffnen
+ // Wichtig auf Read-Only-Dateisystemen (wie CDROM)
+ if ( (!( nOpenMode & STREAM_NOCREATE )) && ( nAccessRW != O_RDONLY ) )
+ nAccess |= O_CREAT;
+ if ( nOpenMode & STREAM_TRUNC )
+ nAccess |= O_TRUNC;
+
+ nMode = S_IREAD | S_IROTH | S_IRGRP;
+ if ( nOpenMode & STREAM_WRITE)
+ {
+ nMode |= (S_IWRITE | S_IWOTH | S_IWGRP);
+
+ if ( nOpenMode & STREAM_COPY_ON_SYMLINK )
+ {
+ if ( bStatValid && S_ISLNK( buf.st_mode ) < 0 )
+ {
+ char *pBuf = new char[ 1024+1 ];
+ if ( readlink( aLocalFilename.GetBuffer(), pBuf, 1024 ) > 0 )
+ {
+ if ( unlink(aLocalFilename.GetBuffer()) == 0 )
+ {
+#ifdef DBG_UTIL
+ fprintf( stderr,
+ "Copying file on symbolic link (%s).\n",
+ aLocalFilename.GetBuffer() );
+#endif
+ String aTmpString( pBuf, osl_getThreadTextEncoding() );
+ const DirEntry aSourceEntry( aTmpString );
+ const DirEntry aTargetEntry( aFilename );
+ FileCopier aFileCopier( aSourceEntry, aTargetEntry );
+ aFileCopier.Execute();
+ }
+ }
+ delete [] pBuf;
+ }
+ }
+ }
+
+
+ nHandleTmp = open(aLocalFilename.GetBuffer(),nAccessRW|nAccess, nMode );
+
+ if ( nHandleTmp == -1 )
+ {
+ if ( nAccessRW != O_RDONLY )
+ {
+ // auf Lesen runterschalten
+ nAccessRW = O_RDONLY;
+ nAccess = 0;
+ nMode = S_IREAD | S_IROTH | S_IRGRP;
+ nHandleTmp =open( aLocalFilename.GetBuffer(),
+ nAccessRW|nAccess,
+ nMode );
+ }
+ }
+ if ( nHandleTmp != -1 )
+ {
+ pInstanceData->nHandle = nHandleTmp;
+ bIsOpen = sal_True;
+ if ( nAccessRW != O_RDONLY )
+ bIsWritable = sal_True;
+
+ if ( !LockFile() ) // ganze Datei
+ {
+ close( nHandleTmp );
+ bIsOpen = sal_False;
+ bIsWritable = sal_False;
+ pInstanceData->nHandle = 0;
+ }
+ }
+ else
+ SetError( ::GetSvError( errno ) );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::ReOpen()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::ReOpen()
+{
+ if ( !bIsOpen && aFilename.Len() )
+ Open( aFilename, eStreamMode );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::Close()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::Close()
+{
+ InternalStreamLock::UnlockFile( 0, 0, this );
+
+ if ( IsOpen() )
+ {
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "SvFileStream::Close(): " );
+ aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ Flush();
+ close( pInstanceData->nHandle );
+ pInstanceData->nHandle = 0;
+ }
+
+ bIsOpen = sal_False;
+ bIsWritable = sal_False;
+ SvStream::ClearBuffer();
+ SvStream::ClearError();
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::ResetError()
+|*
+|* Beschreibung STREAM.SDW; Setzt Filepointer auf Dateianfang
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::ResetError()
+{
+ SvStream::ClearError();
+}
+
+
+/*************************************************************************
+|*
+|* SvFileStream::SetSize()
+|*
+|* Beschreibung STREAM.SDW;
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::SetSize (sal_Size nSize)
+{
+ if (IsOpen())
+ {
+ int fd = pInstanceData->nHandle;
+ if (::ftruncate (fd, (off_t)nSize) < 0)
+ {
+ // Save original error.
+ sal_uInt32 nErr = ::GetSvError (errno);
+
+ // Check against current size. Fail upon 'shrink'.
+ struct stat aStat;
+ if (::fstat (fd, &aStat) < 0)
+ {
+ SetError (nErr);
+ return;
+ }
+ if ((sal::static_int_cast< sal_sSize >(nSize) <= aStat.st_size))
+ {
+ // Failure upon 'shrink'. Return original error.
+ SetError (nErr);
+ return;
+ }
+
+ // Save current position.
+ sal_Size nCurPos = (sal_Size)::lseek (fd, (off_t)0, SEEK_CUR);
+ if (nCurPos == (sal_Size)(-1))
+ {
+ SetError (nErr);
+ return;
+ }
+
+ // Try 'expand' via 'lseek()' and 'write()'.
+ if (::lseek (fd, (off_t)(nSize - 1), SEEK_SET) < 0)
+ {
+ SetError (nErr);
+ return;
+ }
+ if (::write (fd, (char*)"", (size_t)1) < 0)
+ {
+ // Failure. Restore saved position.
+ if (::lseek (fd, (off_t)nCurPos, SEEK_SET) < 0)
+ {
+ // Double failure.
+ }
+
+ SetError (nErr);
+ return;
+ }
+
+ // Success. Restore saved position.
+ if (::lseek (fd, (off_t)nCurPos, SEEK_SET) < 0)
+ {
+ SetError (nErr);
+ return;
+ }
+ }
+ }
+}
+
+
diff --git a/tools/source/stream/strmwnt.cxx b/tools/source/stream/strmwnt.cxx
new file mode 100644
index 000000000000..d9e7da92296b
--- /dev/null
+++ b/tools/source/stream/strmwnt.cxx
@@ -0,0 +1,689 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// no include "precompiled_tools.hxx" because this file is included in strmsys.cxx
+
+/*
+ Todo: StreamMode <-> AllocateMemory
+*/
+
+#include <string.h>
+#include <limits.h>
+
+#include <tools/svwin.h>
+
+#include <tools/debug.hxx>
+#include <tools/fsys.hxx>
+#include <tools/stream.hxx>
+
+// class FileBase
+#include <osl/file.hxx>
+using namespace osl;
+
+// -----------------------------------------------------------------------
+
+// --------------
+// - StreamData -
+// --------------
+
+class StreamData
+{
+public:
+ HANDLE hFile;
+
+ StreamData()
+ {
+ hFile = 0;
+ }
+};
+
+// -----------------------------------------------------------------------
+
+static ULONG GetSvError( DWORD nWntError )
+{
+ static struct { DWORD wnt; ULONG sv; } errArr[] =
+ {
+ { ERROR_SUCCESS, SVSTREAM_OK },
+ { ERROR_ACCESS_DENIED, SVSTREAM_ACCESS_DENIED },
+ { ERROR_ACCOUNT_DISABLED, SVSTREAM_ACCESS_DENIED },
+ { ERROR_ACCOUNT_EXPIRED, SVSTREAM_ACCESS_DENIED },
+ { ERROR_ACCOUNT_RESTRICTION, SVSTREAM_ACCESS_DENIED },
+ { ERROR_ATOMIC_LOCKS_NOT_SUPPORTED, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_BAD_PATHNAME, SVSTREAM_PATH_NOT_FOUND },
+ // Filename too long
+ { ERROR_BUFFER_OVERFLOW, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_DIRECTORY, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_DRIVE_LOCKED, SVSTREAM_LOCKING_VIOLATION },
+ { ERROR_FILE_NOT_FOUND, SVSTREAM_FILE_NOT_FOUND },
+ { ERROR_FILENAME_EXCED_RANGE, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_INVALID_ACCESS, SVSTREAM_INVALID_ACCESS },
+ { ERROR_INVALID_DRIVE, SVSTREAM_PATH_NOT_FOUND },
+ { ERROR_INVALID_HANDLE, SVSTREAM_INVALID_HANDLE },
+ { ERROR_INVALID_NAME, SVSTREAM_PATH_NOT_FOUND },
+ { ERROR_INVALID_PARAMETER, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_IS_SUBST_PATH, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_IS_SUBST_TARGET, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_LOCK_FAILED, SVSTREAM_LOCKING_VIOLATION },
+ { ERROR_LOCK_VIOLATION, SVSTREAM_LOCKING_VIOLATION },
+ { ERROR_NEGATIVE_SEEK, SVSTREAM_SEEK_ERROR },
+ { ERROR_PATH_NOT_FOUND, SVSTREAM_PATH_NOT_FOUND },
+ { ERROR_READ_FAULT, SVSTREAM_READ_ERROR },
+ { ERROR_SEEK, SVSTREAM_SEEK_ERROR },
+ { ERROR_SEEK_ON_DEVICE, SVSTREAM_SEEK_ERROR },
+ { ERROR_SHARING_BUFFER_EXCEEDED,SVSTREAM_SHARE_BUFF_EXCEEDED },
+ { ERROR_SHARING_PAUSED, SVSTREAM_SHARING_VIOLATION },
+ { ERROR_SHARING_VIOLATION, SVSTREAM_SHARING_VIOLATION },
+ { ERROR_TOO_MANY_OPEN_FILES, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { ERROR_WRITE_FAULT, SVSTREAM_WRITE_ERROR },
+ { ERROR_WRITE_PROTECT, SVSTREAM_ACCESS_DENIED },
+ { ERROR_DISK_FULL, SVSTREAM_DISK_FULL },
+
+ { (DWORD)0xFFFFFFFF, SVSTREAM_GENERALERROR }
+ };
+
+ ULONG nRetVal = SVSTREAM_GENERALERROR; // Standardfehler
+ int i=0;
+ do
+ {
+ if( errArr[i].wnt == nWntError )
+ {
+ nRetVal = errArr[i].sv;
+ break;
+ }
+ i++;
+ } while( errArr[i].wnt != (DWORD)0xFFFFFFFF );
+ return nRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 17.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+SvFileStream::SvFileStream( const String& rFileName, StreamMode nMode )
+{
+ bIsOpen = FALSE;
+ nLockCounter = 0;
+ bIsWritable = FALSE;
+ pInstanceData = new StreamData;
+
+ SetBufferSize( 8192 );
+ // convert URL to SystemPath, if necessary
+ ::rtl::OUString aFileName, aNormPath;
+
+ if ( FileBase::getSystemPathFromFileURL( rFileName, aFileName ) != FileBase::E_None )
+ aFileName = rFileName;
+ Open( aFileName, nMode );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 22.11.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+SvFileStream::SvFileStream()
+{
+ bIsOpen = FALSE;
+ nLockCounter = 0;
+ bIsWritable = FALSE;
+ pInstanceData = new StreamData;
+
+ SetBufferSize( 8192 );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::~SvFileStream()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 14.06.94
+|* Letzte Aenderung OV 14.06.94
+|*
+*************************************************************************/
+
+SvFileStream::~SvFileStream()
+{
+ Close();
+ if (pInstanceData)
+ delete pInstanceData;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::GetFileHandle()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 14.06.94
+|* Letzte Aenderung OV 14.06.94
+|*
+*************************************************************************/
+
+ULONG SvFileStream::GetFileHandle() const
+{
+ return (ULONG)pInstanceData->hFile;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::IsA()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 14.06.94
+|* Letzte Aenderung OV 14.06.94
+|*
+*************************************************************************/
+
+USHORT SvFileStream::IsA() const
+{
+ return ID_FILESTREAM;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::GetData()
+|*
+|* Beschreibung STREAM.SDW, Prueft nicht Eof; IsEof danach rufbar
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+ULONG SvFileStream::GetData( void* pData, ULONG nSize )
+{
+ DWORD nCount = 0;
+ if( IsOpen() )
+ {
+ bool bResult = ReadFile(pInstanceData->hFile,(LPVOID)pData,nSize,&nCount,NULL);
+ if( !bResult )
+ {
+ ULONG nTestError = GetLastError();
+ SetError(::GetSvError( nTestError ) );
+ }
+ }
+ return (DWORD)nCount;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::PutData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+ULONG SvFileStream::PutData( const void* pData, ULONG nSize )
+{
+ DWORD nCount = 0;
+ if( IsOpen() )
+ {
+ if(!WriteFile(pInstanceData->hFile,(LPVOID)pData,nSize,&nCount,NULL))
+ SetError(::GetSvError( GetLastError() ) );
+ }
+ return nCount;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SeekPos()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+ULONG SvFileStream::SeekPos( ULONG nPos )
+{
+ DWORD nNewPos = 0;
+ if( IsOpen() )
+ {
+ if( nPos != STREAM_SEEK_TO_END )
+ // 64-Bit files werden nicht unterstuetzt
+ nNewPos=SetFilePointer(pInstanceData->hFile,nPos,NULL,FILE_BEGIN);
+ else
+ nNewPos=SetFilePointer(pInstanceData->hFile,0L,NULL,FILE_END);
+
+ if( nNewPos == 0xFFFFFFFF )
+ {
+ SetError(::GetSvError( GetLastError() ) );
+ nNewPos = 0L;
+ }
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return (ULONG)nNewPos;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::Tell()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+/*
+ULONG SvFileStream::Tell()
+{
+ ULONG nPos = 0L;
+
+ if( IsOpen() )
+ {
+ DWORD nPos;
+ nPos = SetFilePointer(pInstanceData->hFile,0L,NULL,FILE_CURRENT);
+ if( nPos = 0xFFFFFFFF )
+ {
+ SetError( ::GetSvError( GetLastError() ) );
+ nPos = 0L;
+ }
+ }
+ return nPos;
+}
+*/
+
+/*************************************************************************
+|*
+|* SvFileStream::FlushData()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+void SvFileStream::FlushData()
+{
+ if( IsOpen() )
+ {
+ if( !FlushFileBuffers(pInstanceData->hFile) )
+ SetError(::GetSvError(GetLastError()));
+ }
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::LockRange()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+BOOL SvFileStream::LockRange( ULONG nByteOffset, ULONG nBytes )
+{
+ bool bRetVal = false;
+ if( IsOpen() )
+ {
+ bRetVal = ::LockFile(pInstanceData->hFile,nByteOffset,0L,nBytes,0L );
+ if( !bRetVal )
+ SetError(::GetSvError(GetLastError()));
+ }
+ return bRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::UnlockRange()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+BOOL SvFileStream::UnlockRange( ULONG nByteOffset, ULONG nBytes )
+{
+ bool bRetVal = false;
+ if( IsOpen() )
+ {
+ bRetVal = ::UnlockFile(pInstanceData->hFile,nByteOffset,0L,nBytes,0L );
+ if( !bRetVal )
+ SetError(::GetSvError(GetLastError()));
+ }
+ return bRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::LockFile()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+BOOL SvFileStream::LockFile()
+{
+ BOOL bRetVal = FALSE;
+ if( !nLockCounter )
+ {
+ if( LockRange( 0L, LONG_MAX ) )
+ {
+ nLockCounter = 1;
+ bRetVal = TRUE;
+ }
+ }
+ else
+ {
+ nLockCounter++;
+ bRetVal = TRUE;
+ }
+ return bRetVal;
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::UnlockFile()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+BOOL SvFileStream::UnlockFile()
+{
+ BOOL bRetVal = FALSE;
+ if( nLockCounter > 0)
+ {
+ if( nLockCounter == 1)
+ {
+ if( UnlockRange( 0L, LONG_MAX ) )
+ {
+ nLockCounter = 0;
+ bRetVal = TRUE;
+ }
+ }
+ else
+ {
+ nLockCounter--;
+ bRetVal = TRUE;
+ }
+ }
+ return bRetVal;
+}
+
+
+/*************************************************************************
+|*
+|* SvFileStream::Open()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+/*
+ NOCREATE TRUNC NT-Action
+ ----------------------------------------------
+ 0 (Create) 0 OPEN_ALWAYS
+ 0 (Create) 1 CREATE_ALWAYS
+ 1 0 OPEN_EXISTING
+ 1 1 TRUNCATE_EXISTING
+*/
+
+void SvFileStream::Open( const String& rFilename, StreamMode nMode )
+{
+ String aParsedFilename(rFilename);
+
+ SetLastError( ERROR_SUCCESS );
+ Close();
+ SvStream::ClearBuffer();
+
+ eStreamMode = nMode;
+ eStreamMode &= ~STREAM_TRUNC; // beim ReOpen nicht cutten
+
+ // !!! NoOp: Ansonsten ToAbs() verwendern
+ // !!! DirEntry aDirEntry( rFilename );
+ // !!! aFilename = aDirEntry.GetFull();
+ aFilename = aParsedFilename;
+#ifdef BOOTSTRAP
+ ByteString aFileNameA( aFilename, gsl_getSystemTextEncoding());
+#else
+ ByteString aFileNameA( aFilename, osl_getThreadTextEncoding());
+ FSysRedirector::DoRedirect( aFilename );
+#endif
+ SetLastError( ERROR_SUCCESS ); // ggf. durch Redirector geaendert!
+
+ /*
+ #ifdef DBG_UTIL
+ String aTraceStr( "SvFileStream::Open(): " );
+ aTraceStr += aFilename;
+ DBG_TRACE( aTraceStr );
+ #endif
+ */
+
+ DWORD nOpenAction;
+ DWORD nShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ DWORD nAccessMode = 0L;
+ UINT nOldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX );
+
+ if( nMode & STREAM_SHARE_DENYREAD)
+ nShareMode &= ~FILE_SHARE_READ;
+
+ if( nMode & STREAM_SHARE_DENYWRITE)
+ nShareMode &= ~FILE_SHARE_WRITE;
+
+ if( nMode & STREAM_SHARE_DENYALL)
+ nShareMode = 0;
+
+ if( (nMode & STREAM_READ) )
+ nAccessMode |= GENERIC_READ;
+ if( (nMode & STREAM_WRITE) )
+ nAccessMode |= GENERIC_WRITE;
+
+ if( nAccessMode == GENERIC_READ ) // ReadOnly ?
+ nMode |= STREAM_NOCREATE; // wenn ja, nicht erzeugen
+
+ // Zuordnung siehe obige Wahrheitstafel
+ if( !(nMode & STREAM_NOCREATE) )
+ {
+ if( nMode & STREAM_TRUNC )
+ nOpenAction = CREATE_ALWAYS;
+ else
+ nOpenAction = OPEN_ALWAYS;
+ }
+ else
+ {
+ if( nMode & STREAM_TRUNC )
+ nOpenAction = TRUNCATE_EXISTING;
+ else
+ nOpenAction = OPEN_EXISTING;
+ }
+
+ pInstanceData->hFile = CreateFile(
+ aFileNameA.GetBuffer(),
+ nAccessMode,
+ nShareMode,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ nOpenAction,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+ (HANDLE) NULL
+ );
+
+ if( pInstanceData->hFile!=INVALID_HANDLE_VALUE && (
+ // Hat Create Always eine existierende Datei ueberschrieben ?
+ GetLastError() == ERROR_ALREADY_EXISTS ||
+ // Hat Open Always eine neue Datei angelegt ?
+ GetLastError() == ERROR_FILE_NOT_FOUND ))
+ {
+ // wenn ja, dann alles OK
+ if( nOpenAction == OPEN_ALWAYS || nOpenAction == CREATE_ALWAYS )
+ SetLastError( ERROR_SUCCESS );
+ }
+
+ // Bei Fehler pruefen, ob wir lesen duerfen
+ if( (pInstanceData->hFile==INVALID_HANDLE_VALUE) &&
+ (nAccessMode & GENERIC_WRITE))
+ {
+ ULONG nErr = ::GetSvError( GetLastError() );
+ if(nErr==SVSTREAM_ACCESS_DENIED || nErr==SVSTREAM_SHARING_VIOLATION)
+ {
+ nMode &= (~STREAM_WRITE);
+ nAccessMode = GENERIC_READ;
+ // OV, 28.1.97: Win32 setzt die Datei auf 0-Laenge, wenn
+ // die Openaction CREATE_ALWAYS ist!!!!
+ nOpenAction = OPEN_EXISTING;
+ SetLastError( ERROR_SUCCESS );
+ pInstanceData->hFile = CreateFile(
+ aFileNameA.GetBuffer(),
+ GENERIC_READ,
+ nShareMode,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ nOpenAction,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+ (HANDLE) NULL
+ );
+ if( GetLastError() == ERROR_ALREADY_EXISTS )
+ SetLastError( ERROR_SUCCESS );
+ }
+ }
+
+ if( GetLastError() != ERROR_SUCCESS )
+ {
+ bIsOpen = FALSE;
+ SetError(::GetSvError( GetLastError() ) );
+ }
+ else
+ {
+ bIsOpen = TRUE;
+ // pInstanceData->bIsEof = FALSE;
+ if( nAccessMode & GENERIC_WRITE )
+ bIsWritable = TRUE;
+ }
+ SetErrorMode( nOldErrorMode );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::ReOpen()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::ReOpen()
+{
+ if( !bIsOpen && aFilename.Len() )
+ Open( aFilename, eStreamMode );
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::Close()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+void SvFileStream::Close()
+{
+ if( IsOpen() )
+ {
+ if( nLockCounter )
+ {
+ nLockCounter = 1;
+ UnlockFile();
+ }
+ Flush();
+ CloseHandle( pInstanceData->hFile );
+ }
+ bIsOpen = FALSE;
+ nLockCounter= 0;
+ bIsWritable = FALSE;
+ SvStream::ClearBuffer();
+ SvStream::ClearError();
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::ResetError()
+|*
+|* Beschreibung STREAM.SDW; Setzt Filepointer auf Dateianfang
+|* Ersterstellung OV 15.06.94
+|* Letzte Aenderung OV 15.06.94
+|*
+*************************************************************************/
+
+void SvFileStream::ResetError()
+{
+ SvStream::ClearError();
+}
+
+/*************************************************************************
+|*
+|* SvFileStream::SetSize()
+|*
+|* Beschreibung STREAM.SDW
+|* Ersterstellung OV 19.10.95
+|* Letzte Aenderung TPF 15.07.98
+|*
+*************************************************************************/
+
+void SvFileStream::SetSize( ULONG nSize )
+{
+
+ if( IsOpen() )
+ {
+ int bError = FALSE;
+ HANDLE hFile = pInstanceData->hFile;
+ ULONG nOld = SetFilePointer( hFile, 0L, NULL, FILE_CURRENT );
+ if( nOld != 0xffffffff )
+ {
+ if( SetFilePointer(hFile,nSize,NULL,FILE_BEGIN ) != 0xffffffff)
+ {
+ bool bSucc = SetEndOfFile( hFile );
+ if( !bSucc )
+ bError = TRUE;
+ }
+ if( SetFilePointer( hFile,nOld,NULL,FILE_BEGIN ) == 0xffffffff)
+ bError = TRUE;
+ }
+ if( bError )
+ SetError(::GetSvError( GetLastError() ) );
+ }
+}
+
diff --git a/tools/source/stream/vcompat.cxx b/tools/source/stream/vcompat.cxx
new file mode 100644
index 000000000000..8430eb17659b
--- /dev/null
+++ b/tools/source/stream/vcompat.cxx
@@ -0,0 +1,80 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _VCOMPAT_CXX
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+
+// -----------------
+// - VersionCompat -
+// -----------------
+
+VersionCompat::VersionCompat( SvStream& rStm, USHORT nStreamMode, USHORT nVersion ) :
+ mpRWStm ( &rStm ),
+ mnStmMode ( nStreamMode ),
+ mnVersion ( nVersion )
+{
+ if( !mpRWStm->GetError() )
+ {
+ if( STREAM_WRITE == mnStmMode )
+ {
+ *mpRWStm << mnVersion;
+ mnTotalSize = ( mnCompatPos = mpRWStm->Tell() ) + 4UL;
+ mpRWStm->SeekRel( 4L );
+ }
+ else
+ {
+ *mpRWStm >> mnVersion;
+ *mpRWStm >> mnTotalSize;
+ mnCompatPos = mpRWStm->Tell();
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+VersionCompat::~VersionCompat()
+{
+ if( STREAM_WRITE == mnStmMode )
+ {
+ const UINT32 nEndPos = mpRWStm->Tell();
+
+ mpRWStm->Seek( mnCompatPos );
+ *mpRWStm << ( nEndPos - mnTotalSize );
+ mpRWStm->Seek( nEndPos );
+ }
+ else
+ {
+ const UINT32 nReadSize = mpRWStm->Tell() - mnCompatPos;
+
+ if( mnTotalSize > nReadSize )
+ mpRWStm->SeekRel( mnTotalSize - nReadSize );
+ }
+}
diff --git a/tools/source/string/debugprint.cxx b/tools/source/string/debugprint.cxx
new file mode 100644
index 000000000000..7acff963b1b9
--- /dev/null
+++ b/tools/source/string/debugprint.cxx
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+// =======================================================================
+
+#include <tools/string.hxx>
+
+const sal_Char *dbg_dump(const ByteString &rStr)
+{
+ static ByteString aStr;
+ aStr = rStr;
+ aStr.Append(static_cast<char>(0));
+ return aStr.GetBuffer();
+}
+
+const sal_Char *dbg_dump(const UniString &rStr)
+{
+ return dbg_dump(ByteString(rStr, RTL_TEXTENCODING_UTF8));
+}
+
+/* vi:set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/tools/source/string/makefile.mk b/tools/source/string/makefile.mk
new file mode 100644
index 000000000000..4caa31672472
--- /dev/null
+++ b/tools/source/string/makefile.mk
@@ -0,0 +1,79 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=str
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+ALWAYSDBGFILES = $(SLO)$/debugprint.obj
+
+.IF "$(ALWAYSDBGFILES)" != ""
+ALWAYSDBGTARGET=do_it_alwaysdebug
+.ENDIF
+
+SLOFILES= $(SLO)$/tstring.obj \
+ $(SLO)$/tustring.obj \
+ $(SLO)$/tenccvt.obj \
+ $(SLO)$/debugprint.obj
+
+OBJFILES= $(OBJ)$/tstring.obj \
+ $(OBJ)$/tustring.obj \
+ $(OBJ)$/tenccvt.obj \
+ $(OBJ)$/debugprint.obj
+
+# --- Targets ------------------------------------------------------
+
+.IF "$(ALWAYSDBG_FLAG)"==""
+TARGETDEPS+=$(ALWAYSDBGTARGET)
+.ENDIF
+
+.INCLUDE : target.mk
+
+.IF "$(ALWAYSDBGTARGET)" != ""
+.IF "$(ALWAYSDBG_FLAG)" == ""
+# --------------------------------------------------
+# - ALWAYSDBG - files always compiled with debugging
+# --------------------------------------------------
+$(ALWAYSDBGTARGET):
+ @echo --- ALWAYSDBGFILES ---
+ @dmake $(MFLAGS) $(MAKEFILE) debug=true $(ALWAYSDBGFILES) ALWAYSDBG_FLAG=TRUE $(CALLMACROS)
+ @echo --- ALWAYSDBGFILES OVER ---
+
+$(ALWAYSDBGFILES):
+ @echo --- ALWAYSDBG ---
+ @dmake $(MFLAGS) $(MAKEFILE) debug=true ALWAYSDBG_FLAG=TRUE $(CALLMACROS) $@
+ @echo --- ALWAYSDBG OVER ---
+.ENDIF
+.ENDIF
diff --git a/tools/source/string/strascii.cxx b/tools/source/string/strascii.cxx
new file mode 100644
index 000000000000..775e1ca7f142
--- /dev/null
+++ b/tools/source/string/strascii.cxx
@@ -0,0 +1,637 @@
+#/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// no include "precompiled_tools.hxx" because this is included in other cxx files.
+
+// =======================================================================
+
+#ifdef DBG_UTIL
+
+static BOOL ImplDbgCheckAsciiStr( const sal_Char* pAsciiStr, sal_Int32 nLen )
+{
+ while ( nLen && *pAsciiStr )
+ {
+ if ( ((unsigned char)*pAsciiStr) > 127 )
+ return FALSE;
+ ++pAsciiStr,
+ --nLen;
+ }
+
+ return TRUE;
+}
+
+#endif
+
+// =======================================================================
+
+static void ImplCopyAsciiStr( sal_Unicode* pDest, const sal_Char* pSrc,
+ sal_Int32 nLen )
+{
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pSrc, nLen ),
+ "UniString::CopyAsciiStr() - pAsciiStr include characters > 127" );
+
+ while ( nLen )
+ {
+ *pDest = (unsigned char)*pSrc;
+ ++pDest,
+ ++pSrc,
+ --nLen;
+ }
+}
+
+// =======================================================================
+
+static sal_Int32 ImplStringCompareAscii( const sal_Unicode* pStr1, const sal_Char* pStr2 )
+{
+ sal_Int32 nRet;
+ while ( ((nRet = ((sal_Int32)*pStr1)-((sal_Int32)((unsigned char)*pStr2))) == 0) &&
+ *pStr2 )
+ {
+ ++pStr1,
+ ++pStr2;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringCompareAscii( const sal_Unicode* pStr1, const sal_Char* pStr2,
+ xub_StrLen nCount )
+{
+ sal_Int32 nRet = 0;
+ while ( nCount &&
+ ((nRet = ((sal_Int32)*pStr1)-((sal_Int32)((unsigned char)*pStr2))) == 0) &&
+ *pStr2 )
+ {
+ ++pStr1,
+ ++pStr2,
+ --nCount;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringCompareWithoutZeroAscii( const sal_Unicode* pStr1, const sal_Char* pStr2,
+ xub_StrLen nCount )
+{
+ sal_Int32 nRet = 0;
+ while ( nCount &&
+ ((nRet = ((sal_Int32)*pStr1)-((sal_Int32)((unsigned char)*pStr2))) == 0) )
+ {
+ ++pStr1,
+ ++pStr2,
+ --nCount;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringICompareAscii( const sal_Unicode* pStr1, const sal_Char* pStr2 )
+{
+ sal_Int32 nRet;
+ sal_Unicode c1;
+ sal_Char c2;
+ do
+ {
+ // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
+ c1 = *pStr1;
+ c2 = *pStr2;
+ if ( (c1 >= 65) && (c1 <= 90) )
+ c1 += 32;
+ if ( (c2 >= 65) && (c2 <= 90) )
+ c2 += 32;
+ nRet = ((sal_Int32)c1)-((sal_Int32)((unsigned char)c2));
+ if ( nRet != 0 )
+ break;
+
+ ++pStr1,
+ ++pStr2;
+ }
+ while ( c2 );
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringICompareAscii( const sal_Unicode* pStr1, const sal_Char* pStr2,
+ xub_StrLen nCount )
+{
+ sal_Int32 nRet = 0;
+ sal_Unicode c1;
+ sal_Char c2;
+ do
+ {
+ if ( !nCount )
+ break;
+
+ // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
+ c1 = *pStr1;
+ c2 = *pStr2;
+ if ( (c1 >= 65) && (c1 <= 90) )
+ c1 += 32;
+ if ( (c2 >= 65) && (c2 <= 90) )
+ c2 += 32;
+ nRet = ((sal_Int32)c1)-((sal_Int32)((unsigned char)c2));
+ if ( nRet != 0 )
+ break;
+
+ ++pStr1,
+ ++pStr2,
+ --nCount;
+ }
+ while ( c2 );
+
+ return nRet;
+}
+
+// =======================================================================
+
+UniString UniString::CreateFromAscii( const sal_Char* pAsciiStr )
+{
+ DBG_ASSERT( pAsciiStr, "UniString::CreateFromAscii() - pAsciiStr is NULL" );
+
+ // Stringlaenge ermitteln
+ xub_StrLen nLen = ImplStringLen( pAsciiStr );
+
+ UniString aTempStr;
+ if ( nLen )
+ {
+ ImplCopyAsciiStr( aTempStr.AllocBuffer( nLen ), pAsciiStr, nLen );
+ }
+ return aTempStr;
+}
+
+// -----------------------------------------------------------------------
+
+UniString UniString::CreateFromAscii( const sal_Char* pAsciiStr, xub_StrLen nLen )
+{
+ DBG_ASSERT( pAsciiStr, "UniString::CreateFromAscii() - pAsciiStr is NULL" );
+
+ // Stringlaenge ermitteln
+ if ( nLen == STRING_LEN )
+ nLen = ImplStringLen( pAsciiStr );
+
+ UniString aTempStr;
+
+ if ( nLen )
+ {
+ ImplCopyAsciiStr( aTempStr.AllocBuffer( nLen ), pAsciiStr, nLen );
+ }
+ return aTempStr;
+}
+
+// -----------------------------------------------------------------------
+
+UniString& UniString::AssignAscii( const sal_Char* pAsciiStr )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( pAsciiStr, "UniString::AssignAscii() - pAsciiStr is NULL" );
+
+ // Stringlaenge ermitteln
+ xub_StrLen nLen = ImplStringLen( pAsciiStr );
+
+ if ( !nLen )
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+ else
+ {
+ // Wenn String genauso lang ist, wie der String, dann direkt kopieren
+ if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
+ ImplCopyAsciiStr( mpData->maStr, pAsciiStr, nLen );
+ else
+ {
+ // Alte Daten loeschen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+
+ // Daten initialisieren und String kopieren
+ mpData = ImplAllocData( nLen );
+ ImplCopyAsciiStr( mpData->maStr, pAsciiStr, nLen );
+ }
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+UniString& UniString::AssignAscii( const sal_Char* pAsciiStr, xub_StrLen nLen )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( pAsciiStr, "UniString::AssignAscii() - pAsciiStr is NULL" );
+
+ if ( nLen == STRING_LEN )
+ nLen = ImplStringLen( pAsciiStr );
+
+#ifdef DBG_UTIL
+ if ( DbgIsAssert() )
+ {
+ for ( xub_StrLen i = 0; i < nLen; ++i )
+ {
+ if ( !pAsciiStr[i] )
+ {
+ DBG_ERROR( "UniString::AssignAscii() : nLen is wrong" );
+ }
+ }
+ }
+#endif
+
+ if ( !nLen )
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+ else
+ {
+ // Wenn String genauso lang ist, wie der String, dann direkt kopieren
+ if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
+ ImplCopyAsciiStr( mpData->maStr, pAsciiStr, nLen );
+ else
+ {
+ // Alte Daten loeschen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+
+ // Daten initialisieren und String kopieren
+ mpData = ImplAllocData( nLen );
+ ImplCopyAsciiStr( mpData->maStr, pAsciiStr, nLen );
+ }
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+UniString& UniString::AppendAscii( const sal_Char* pAsciiStr )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( pAsciiStr, "UniString::AppendAscii() - pAsciiStr is NULL" );
+
+ // Stringlaenge ermitteln
+ sal_Int32 nCopyLen = ImplStringLen( pAsciiStr );
+
+ // Ueberlauf abfangen
+ nCopyLen = ImplGetCopyLen( mpData->mnLen, nCopyLen );
+
+ // Ist es kein leerer String
+ if ( nCopyLen )
+ {
+ // Neue Datenstruktur und neuen String erzeugen
+ UniStringData* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, mpData->mnLen*sizeof( sal_Unicode ) );
+ ImplCopyAsciiStr( pNewData->maStr+mpData->mnLen, pAsciiStr, nCopyLen );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+UniString& UniString::AppendAscii( const sal_Char* pAsciiStr, xub_StrLen nLen )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( pAsciiStr, "UniString::AppendAscii() - pAsciiStr is NULL" );
+
+ if ( nLen == STRING_LEN )
+ nLen = ImplStringLen( pAsciiStr );
+
+#ifdef DBG_UTIL
+ if ( DbgIsAssert() )
+ {
+ for ( xub_StrLen i = 0; i < nLen; ++i )
+ {
+ if ( !pAsciiStr[i] )
+ {
+ DBG_ERROR( "UniString::AppendAscii() : nLen is wrong" );
+ }
+ }
+ }
+#endif
+
+ // Ueberlauf abfangen
+ sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, nLen );
+
+ // Ist es kein leerer String
+ if ( nCopyLen )
+ {
+ // Neue Datenstruktur und neuen String erzeugen
+ UniStringData* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, mpData->mnLen*sizeof( sal_Unicode ) );
+ ImplCopyAsciiStr( pNewData->maStr+mpData->mnLen, pAsciiStr, nCopyLen );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+UniString& UniString::InsertAscii( const char* pAsciiStr, xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( pAsciiStr, "UniString::InsertAscii() - pAsciiStr is NULL" );
+
+ // Stringlaenge ermitteln
+ sal_Int32 nCopyLen = ImplStringLen( pAsciiStr );
+
+ // Ueberlauf abfangen
+ nCopyLen = ImplGetCopyLen( mpData->mnLen, nCopyLen );
+
+ // Ist der einzufuegende String ein Leerstring
+ if ( !nCopyLen )
+ return *this;
+
+ // Index groesser als Laenge
+ if ( nIndex > mpData->mnLen )
+ nIndex = static_cast< xub_StrLen >(mpData->mnLen);
+
+ // Neue Laenge ermitteln und neuen String anlegen
+ UniStringData* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( sal_Unicode ) );
+ ImplCopyAsciiStr( pNewData->maStr+nIndex, pAsciiStr, nCopyLen );
+ memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
+ (mpData->mnLen-nIndex)*sizeof( sal_Unicode ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+UniString& UniString::ReplaceAscii( xub_StrLen nIndex, xub_StrLen nCount,
+ const sal_Char* pAsciiStr, xub_StrLen nStrLen )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( pAsciiStr, "UniString::ReplaceAscii() - pAsciiStr is NULL" );
+
+ // Wenn Index groessergleich Laenge ist, dann ist es ein Append
+ if ( nIndex >= mpData->mnLen )
+ {
+ AppendAscii( pAsciiStr, nStrLen );
+ return *this;
+ }
+
+ // Ist es eine Zuweisung
+ if ( (nIndex == 0) && (nCount >= mpData->mnLen) )
+ {
+ AssignAscii( pAsciiStr, nStrLen );
+ return *this;
+ }
+
+ // Reicht ein Erase
+ if ( nStrLen == STRING_LEN )
+ nStrLen = ImplStringLen( pAsciiStr );
+ if ( !nStrLen )
+ return Erase( nIndex, nCount );
+
+ // nCount darf nicht ueber das Stringende hinnausgehen
+ if ( nCount > mpData->mnLen - nIndex )
+ nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
+
+ // Reicht eine zeichenweise Zuweisung
+ if ( nCount == nStrLen )
+ {
+ ImplCopyData();
+ ImplCopyAsciiStr( mpData->maStr+nIndex, pAsciiStr, nStrLen );
+ return *this;
+ }
+
+ // Ueberlauf abfangen
+ sal_Int32 n = ImplGetCopyLen( mpData->mnLen-nCount, nStrLen );
+
+ // Neue Daten anlegen
+ STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount+n );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
+ ImplCopyAsciiStr( pNewData->maStr+nIndex, pAsciiStr, n );
+ memcpy( pNewData->maStr+nIndex+n, mpData->maStr+nIndex+nCount,
+ (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+StringCompare UniString::CompareToAscii( const sal_Char* pAsciiStr,
+ xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, nLen ),
+ "UniString::CompareToAscii() - pAsciiStr include characters > 127" );
+
+ // String vergleichen
+ sal_Int32 nCompare = ImplStringCompareAscii( mpData->maStr, pAsciiStr, nLen );
+
+ // Rueckgabewert anpassen
+ if ( nCompare == 0 )
+ return COMPARE_EQUAL;
+ else if ( nCompare < 0 )
+ return COMPARE_LESS;
+ else
+ return COMPARE_GREATER;
+}
+
+// -----------------------------------------------------------------------
+
+StringCompare UniString::CompareIgnoreCaseToAscii( const sal_Char* pAsciiStr,
+ xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, nLen ),
+ "UniString::CompareIgnoreCaseToAscii() - pAsciiStr include characters > 127" );
+
+ // String vergleichen
+ sal_Int32 nCompare = ImplStringICompareAscii( mpData->maStr, pAsciiStr, nLen );
+
+ // Rueckgabewert anpassen
+ if ( nCompare == 0 )
+ return COMPARE_EQUAL;
+ else if ( nCompare < 0 )
+ return COMPARE_LESS;
+ else
+ return COMPARE_GREATER;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL UniString::EqualsAscii( const sal_Char* pAsciiStr ) const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ),
+ "UniString::EqualsAscii() - pAsciiStr include characters > 127" );
+
+ return (ImplStringCompareAscii( mpData->maStr, pAsciiStr ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL UniString::EqualsIgnoreCaseAscii( const sal_Char* pAsciiStr ) const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ),
+ "UniString::EqualsIgnoreCaseAscii() - pAsciiStr include characters > 127" );
+
+ return (ImplStringICompareAscii( mpData->maStr, pAsciiStr ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL UniString::EqualsAscii( const sal_Char* pAsciiStr,
+ xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, nLen ),
+ "UniString::EqualsAscii() - pAsciiStr include characters > 127" );
+
+ // Are there enough codes for comparing?
+ if ( nIndex > mpData->mnLen )
+ return (*pAsciiStr == 0);
+
+ return (ImplStringCompareAscii( mpData->maStr+nIndex, pAsciiStr, nLen ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL UniString::EqualsIgnoreCaseAscii( const sal_Char* pAsciiStr,
+ xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, nLen ),
+ "UniString::EqualsIgnoreCaseAscii() - pAsciiStr include characters > 127" );
+
+ // Are there enough codes for comparing?
+ if ( nIndex > mpData->mnLen )
+ return (*pAsciiStr == 0);
+
+ return (ImplStringICompareAscii( mpData->maStr+nIndex, pAsciiStr, nLen ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen UniString::SearchAscii( const sal_Char* pAsciiStr, xub_StrLen nIndex ) const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ),
+ "UniString::SearchAscii() - pAsciiStr include characters > 127" );
+
+ sal_Int32 nLen = mpData->mnLen;
+ xub_StrLen nStrLen = ImplStringLen( pAsciiStr );
+
+ // Falls die Laenge des uebergebenen Strings 0 ist oder der Index
+ // hinter dem String liegt, dann wurde der String nicht gefunden
+ if ( !nStrLen || (nIndex >= nLen) )
+ return STRING_NOTFOUND;
+
+ const sal_Unicode* pStr = mpData->maStr;
+ pStr += nIndex;
+
+ if ( nStrLen == 1 )
+ {
+ sal_Unicode cSearch = (unsigned char)*pAsciiStr;
+ while ( nIndex < nLen )
+ {
+ if ( *pStr == cSearch )
+ return nIndex;
+ ++pStr,
+ ++nIndex;
+ }
+ }
+ else
+ {
+ // Nur innerhalb des Strings suchen
+ while ( nLen - nIndex >= nStrLen )
+ {
+ // Stimmt der String ueberein
+ if ( ImplStringCompareWithoutZeroAscii( pStr, pAsciiStr, nStrLen ) == 0 )
+ return nIndex;
+ ++pStr,
+ ++nIndex;
+ }
+ }
+
+ return STRING_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen UniString::SearchAndReplaceAscii( const sal_Char* pAsciiStr, const UniString& rRepStr,
+ xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ),
+ "UniString::SearchAndReplaceAscii() - pAsciiStr include characters > 127" );
+
+ xub_StrLen nSPos = SearchAscii( pAsciiStr, nIndex );
+ if ( nSPos != STRING_NOTFOUND )
+ Replace( nSPos, ImplStringLen( pAsciiStr ), rRepStr );
+
+ return nSPos;
+}
+
+// -----------------------------------------------------------------------
+
+void UniString::SearchAndReplaceAllAscii( const sal_Char* pAsciiStr, const UniString& rRepStr )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+ DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ),
+ "UniString::SearchAndReplaceAllAscii() - pAsciiStr include characters > 127" );
+
+ xub_StrLen nCharLen = ImplStringLen( pAsciiStr );
+ xub_StrLen nSPos = SearchAscii( pAsciiStr, 0 );
+ while ( nSPos != STRING_NOTFOUND )
+ {
+ Replace( nSPos, nCharLen, rRepStr );
+ nSPos = nSPos + rRepStr.Len();
+ nSPos = SearchAscii( pAsciiStr, nSPos );
+ }
+}
diff --git a/tools/source/string/strcvt.cxx b/tools/source/string/strcvt.cxx
new file mode 100644
index 000000000000..ef55dee5bfe2
--- /dev/null
+++ b/tools/source/string/strcvt.cxx
@@ -0,0 +1,613 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// no include "precompiled_tools.hxx" because this is included in other cxx files.
+
+// -----------------------------------------------------------------------
+
+void ByteString::ImplUpdateStringFromUniString(
+ const sal_Unicode* pUniStr, sal_Size nUniLen,
+ rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ ByteStringData* pNewStringData = NULL;
+ rtl_uString2String( (rtl_String **)(&pNewStringData),
+ pUniStr, nUniLen,
+ eTextEncoding, nCvtFlags );
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewStringData;
+}
+
+// =======================================================================
+
+ByteString::ByteString( const UniString& rUniStr, rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ DBG_CTOR( ByteString, DbgCheckByteString );
+ DBG_CHKOBJ( &rUniStr, UniString, DbgCheckUniString );
+
+ mpData = NULL;
+ rtl_uString2String( (rtl_String **)(&mpData),
+ rUniStr.mpData->maStr, rUniStr.mpData->mnLen,
+ eTextEncoding, nCvtFlags );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString::ByteString( const UniString& rUniStr, xub_StrLen nPos, xub_StrLen nLen,
+ rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ DBG_CTOR( ByteString, DbgCheckByteString );
+ DBG_CHKOBJ( &rUniStr, UniString, DbgCheckUniString );
+
+ // Stringlaenge ermitteln
+ if ( nPos > rUniStr.mpData->mnLen )
+ nLen = 0;
+ else
+ {
+ // Laenge korrigieren, wenn noetig
+ sal_Int32 nMaxLen = rUniStr.mpData->mnLen-nPos;
+ if ( nLen > nMaxLen )
+ nLen = static_cast< xub_StrLen >(nMaxLen);
+ }
+
+ mpData = NULL;
+ rtl_uString2String( (rtl_String **)(&mpData),
+ rUniStr.mpData->maStr+nPos, nLen,
+ eTextEncoding, nCvtFlags );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString::ByteString( const sal_Unicode* pUniStr,
+ rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ DBG_CTOR( ByteString, DbgCheckByteString );
+ DBG_ASSERT( pUniStr, "ByteString::ByteString() - pUniStr is NULL" );
+
+ mpData = NULL;
+ rtl_uString2String( (rtl_String **)(&mpData),
+ pUniStr, ImplStringLen( pUniStr ),
+ eTextEncoding, nCvtFlags );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString::ByteString( const sal_Unicode* pUniStr, xub_StrLen nLen,
+ rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ DBG_CTOR( ByteString, DbgCheckByteString );
+ DBG_ASSERT( pUniStr, "ByteString::ByteString() - pUniStr is NULL" );
+
+ if ( nLen == STRING_LEN )
+ nLen = ImplStringLen( pUniStr );
+
+ mpData = NULL;
+ rtl_uString2String( (rtl_String **)(&mpData),
+ pUniStr, nLen,
+ eTextEncoding, nCvtFlags );
+}
+
+// =======================================================================
+
+static sal_uChar aImplByteTab[256] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255
+};
+
+// =======================================================================
+
+struct Impl1ByteUnicodeTabData
+{
+ rtl_TextEncoding meTextEncoding;
+ sal_Unicode maUniTab[256];
+ Impl1ByteUnicodeTabData* mpNext;
+};
+
+// -----------------------------------------------------------------------
+
+struct Impl1ByteConvertTabData
+{
+ rtl_TextEncoding meSrcTextEncoding;
+ rtl_TextEncoding meDestTextEncoding;
+ sal_uChar maConvertTab[256];
+ sal_uChar maRepConvertTab[256];
+ Impl1ByteConvertTabData* mpNext;
+};
+
+// =======================================================================
+
+sal_Unicode* ImplGet1ByteUnicodeTab( rtl_TextEncoding eTextEncoding )
+{
+#ifndef BOOTSTRAP
+ TOOLSINDATA* pToolsData = ImplGetToolsInData();
+#else
+ TOOLSINDATA* pToolsData = 0x0;
+#endif
+ Impl1ByteUnicodeTabData* pTab = pToolsData->mpFirstUniTabData;
+
+ while ( pTab )
+ {
+ if ( pTab->meTextEncoding == eTextEncoding )
+ return pTab->maUniTab;
+ pTab = pTab->mpNext;
+ }
+
+ // get TextEncodingInfo
+ rtl_TextEncodingInfo aTextEncInfo;
+ aTextEncInfo.StructSize = sizeof( aTextEncInfo );
+ rtl_getTextEncodingInfo( eTextEncoding, &aTextEncInfo );
+
+ if ( aTextEncInfo.MaximumCharSize == 1 )
+ {
+ pTab = new Impl1ByteUnicodeTabData;
+ pTab->meTextEncoding = eTextEncoding;
+ pTab->mpNext = pToolsData->mpFirstUniTabData;
+
+ rtl_TextToUnicodeConverter hConverter;
+ sal_uInt32 nInfo;
+ sal_Size nSrcBytes;
+ sal_Size nDestChars;
+ hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
+ nDestChars = rtl_convertTextToUnicode( hConverter, 0,
+ (const sal_Char*)aImplByteTab, 256,
+ pTab->maUniTab, 256,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT,
+ &nInfo, &nSrcBytes );
+ rtl_destroyTextToUnicodeConverter( hConverter );
+
+ if ( (nSrcBytes != 256) || (nDestChars != 256) )
+ delete pTab;
+ else
+ {
+ pToolsData->mpFirstUniTabData = pTab;
+ return pTab->maUniTab;
+ }
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_uChar* ImplGet1ByteConvertTab( rtl_TextEncoding eSrcTextEncoding,
+ rtl_TextEncoding eDestTextEncoding,
+ BOOL bReplace )
+{
+#ifndef BOOTSTRAP
+ TOOLSINDATA* pToolsData = ImplGetToolsInData();
+#else
+ TOOLSINDATA* pToolsData = 0x0;
+#endif
+ Impl1ByteConvertTabData* pTab = pToolsData->mpFirstConvertTabData;
+
+ while ( pTab )
+ {
+ if ( (pTab->meSrcTextEncoding == eSrcTextEncoding) &&
+ (pTab->meDestTextEncoding == eDestTextEncoding) )
+ {
+ if ( bReplace )
+ return pTab->maRepConvertTab;
+ else
+ return pTab->maConvertTab;
+ }
+ pTab = pTab->mpNext;
+ }
+
+ // get TextEncodingInfo
+ rtl_TextEncodingInfo aTextEncInfo1;
+ aTextEncInfo1.StructSize = sizeof( aTextEncInfo1 );
+ rtl_getTextEncodingInfo( eSrcTextEncoding, &aTextEncInfo1 );
+ rtl_TextEncodingInfo aTextEncInfo2;
+ aTextEncInfo2.StructSize = sizeof( aTextEncInfo2 );
+ rtl_getTextEncodingInfo( eDestTextEncoding, &aTextEncInfo2 );
+
+ if ( (aTextEncInfo1.MaximumCharSize == 1) &&
+ (aTextEncInfo2.MaximumCharSize == 1) )
+ {
+ pTab = new Impl1ByteConvertTabData;
+ pTab->meSrcTextEncoding = eSrcTextEncoding;
+ pTab->meDestTextEncoding = eDestTextEncoding;
+ pTab->mpNext = pToolsData->mpFirstConvertTabData;
+
+ rtl_TextToUnicodeConverter hConverter;
+ rtl_UnicodeToTextConverter hConverter2;
+ sal_uInt32 nInfo;
+ sal_Size nSrcBytes;
+ sal_Size nDestChars;
+ sal_Size nSrcChars;
+ sal_Size nDestBytes;
+ sal_Unicode aTempBuf[256];
+ hConverter = rtl_createTextToUnicodeConverter( eSrcTextEncoding );
+ nDestChars = rtl_convertTextToUnicode( hConverter, 0,
+ (const sal_Char*)aImplByteTab, 256,
+ aTempBuf, 256,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT,
+ &nInfo, &nSrcBytes );
+ rtl_destroyTextToUnicodeConverter( hConverter );
+ if ( (nSrcBytes != 256) || (nDestChars != 256) )
+ delete pTab;
+ else
+ {
+ hConverter2 = rtl_createUnicodeToTextConverter( eDestTextEncoding );
+ nDestBytes = rtl_convertUnicodeToText( hConverter2, 0,
+ aTempBuf, 256,
+ (sal_Char*)pTab->maConvertTab, 256,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_0 |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT,
+ &nInfo, &nSrcChars );
+ if ( (nDestBytes == 256) || (nSrcChars == 256) )
+ {
+ nDestBytes = rtl_convertUnicodeToText( hConverter2, 0,
+ aTempBuf, 256,
+ (sal_Char*)pTab->maRepConvertTab, 256,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE,
+ &nInfo, &nSrcChars );
+ }
+ rtl_destroyUnicodeToTextConverter( hConverter2 );
+ if ( (nDestBytes != 256) || (nSrcChars != 256) )
+ delete pTab;
+ else
+ {
+ pToolsData->mpFirstConvertTabData = pTab;
+ if ( bReplace )
+ return pTab->maRepConvertTab;
+ else
+ return pTab->maConvertTab;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// =======================================================================
+
+void ImplDeleteCharTabData()
+{
+#ifndef BOOTSTRAP
+ TOOLSINDATA* pToolsData = ImplGetToolsInData();
+#else
+ TOOLSINDATA* pToolsData = 0x0;
+#endif
+ Impl1ByteUnicodeTabData* pTempUniTab;
+ Impl1ByteUnicodeTabData* pUniTab = pToolsData->mpFirstUniTabData;
+ while ( pUniTab )
+ {
+ pTempUniTab = pUniTab->mpNext;
+ delete pUniTab;
+ pUniTab = pTempUniTab;
+ }
+ pToolsData->mpFirstUniTabData = NULL;
+
+ Impl1ByteConvertTabData* pTempConvertTab;
+ Impl1ByteConvertTabData* pConvertTab = pToolsData->mpFirstConvertTabData;
+ while ( pConvertTab )
+ {
+ pTempConvertTab = pConvertTab->mpNext;
+ delete pConvertTab;
+ pConvertTab = pTempConvertTab;
+ }
+ pToolsData->mpFirstConvertTabData = NULL;
+}
+
+// =======================================================================
+
+void ByteString::ImplStringConvert(
+ rtl_TextEncoding eSource, rtl_TextEncoding eTarget, BOOL bReplace )
+{
+ sal_uChar* pConvertTab = ImplGet1ByteConvertTab( eSource, eTarget, bReplace );
+ if ( pConvertTab )
+ {
+ char* pStr = mpData->maStr;
+ while ( *pStr )
+ {
+ sal_uChar c = (sal_uChar)*pStr;
+ sal_uChar cConv = pConvertTab[c];
+ if ( c != cConv )
+ {
+ pStr = ImplCopyStringData( pStr );
+ *pStr = (char)cConv;
+ }
+
+ pStr++;
+ }
+ }
+ else
+ {
+ rtl_UnicodeToTextConverter hSrcConverter = rtl_createTextToUnicodeConverter( eSource );
+ sal_uInt32 nInfo;
+ sal_Size nSrcBytes;
+ sal_Size nDestChars;
+ sal_Size nTempLen;
+ sal_Unicode* pTempBuf;
+ nTempLen = mpData->mnLen;
+ pTempBuf = new sal_Unicode[nTempLen];
+ nDestChars = rtl_convertTextToUnicode( hSrcConverter, 0,
+ mpData->maStr, mpData->mnLen,
+ pTempBuf, nTempLen,
+ RTL_TEXTTOUNICODE_FLAGS_FLUSH |
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT,
+ &nInfo, &nSrcBytes );
+ rtl_destroyTextToUnicodeConverter( hSrcConverter );
+ // Hier werten wir bReplace nicht aus, da fuer MultiByte-Textencodings
+ // sowieso keine Ersatzdarstellung moeglich ist. Da sich der String
+ // sowieso in der Laenge aendern kann, nehmen wir auch sonst keine
+ // Ruecksicht darauf, das die Laenge erhalten bleibt.
+ ImplUpdateStringFromUniString( pTempBuf, nDestChars, eTarget,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR |
+ RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 |
+ RTL_UNICODETOTEXT_FLAGS_NONSPACING_IGNORE |
+ RTL_UNICODETOTEXT_FLAGS_CONTROL_IGNORE );
+ delete [] pTempBuf;
+ }
+}
+
+// =======================================================================
+
+ByteString& ByteString::Convert( rtl_TextEncoding eSource, rtl_TextEncoding eTarget, BOOL bReplace )
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ // rtl_TextEncoding Dontknow kann nicht konvertiert werden
+ if ( (eSource == RTL_TEXTENCODING_DONTKNOW) || (eTarget == RTL_TEXTENCODING_DONTKNOW) )
+ return *this;
+
+ // Wenn Source und Target gleich sind, muss nicht konvertiert werden
+ if ( eSource == eTarget )
+ return *this;
+
+ // rtl_TextEncoding Symbol nur nach Unicode oder von Unicode wandeln, ansonsten
+ // wollen wir die Zeichencodes beibehalten
+ if ( (eSource == RTL_TEXTENCODING_SYMBOL) &&
+ (eTarget != RTL_TEXTENCODING_UTF7) &&
+ (eTarget != RTL_TEXTENCODING_UTF8) )
+ return *this;
+ if ( (eTarget == RTL_TEXTENCODING_SYMBOL) &&
+ (eSource != RTL_TEXTENCODING_UTF7) &&
+ (eSource != RTL_TEXTENCODING_UTF8) )
+ return *this;
+
+ // Zeichensatz umwandeln
+ ImplStringConvert( eSource, eTarget, bReplace );
+
+ return *this;
+}
+
+// =======================================================================
+
+char ByteString::Convert( char c,
+ rtl_TextEncoding eSource, rtl_TextEncoding eTarget,
+ BOOL bReplace )
+{
+ // TextEncoding Dontknow kann nicht konvertiert werden
+ if ( (eSource == RTL_TEXTENCODING_DONTKNOW) || (eTarget == RTL_TEXTENCODING_DONTKNOW) )
+ return '\0';
+
+ // Wenn Source und Target gleich sind, muss nicht konvertiert werden
+ if ( eSource == eTarget )
+ return c;
+
+ // TextEncoding Symbol nur nach Unicode oder von Unicode wandeln, ansonsten
+ // wollen wir die Zeichencodes beibehalten
+ if ( (eSource == RTL_TEXTENCODING_SYMBOL) &&
+ (eTarget != RTL_TEXTENCODING_UTF7) &&
+ (eTarget != RTL_TEXTENCODING_UTF8) )
+ return '\0';
+ if ( (eTarget == RTL_TEXTENCODING_SYMBOL) &&
+ (eSource != RTL_TEXTENCODING_UTF7) &&
+ (eSource != RTL_TEXTENCODING_UTF8) )
+ return '\0';
+
+ sal_uChar* pConvertTab = ImplGet1ByteConvertTab( eSource, eTarget, bReplace );
+ if ( pConvertTab )
+ return (char)pConvertTab[(sal_uChar)c];
+ else
+ return '\0';
+}
+
+// =======================================================================
+
+sal_Unicode ByteString::ConvertToUnicode( char c, rtl_TextEncoding eTextEncoding )
+{
+ sal_Size nLen = 1;
+ return ConvertToUnicode( &c, &nLen, eTextEncoding );
+}
+
+// -----------------------------------------------------------------------
+
+char ByteString::ConvertFromUnicode( sal_Unicode c, rtl_TextEncoding eTextEncoding, BOOL bReplace )
+{
+ sal_Size nLen;
+ char aBuf[30];
+ nLen = ConvertFromUnicode( c, aBuf, sizeof( aBuf ), eTextEncoding, bReplace );
+ if ( nLen == 1 )
+ return aBuf[0];
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Unicode ByteString::ConvertToUnicode( const char* pChar, sal_Size* pLen, rtl_TextEncoding eTextEncoding )
+{
+ // TextEncoding Dontknow wird nicht konvertiert
+ if ( eTextEncoding == RTL_TEXTENCODING_DONTKNOW )
+ return 0;
+
+ rtl_TextToUnicodeConverter hConverter;
+ sal_uInt32 nInfo;
+ sal_Size nSrcBytes;
+ sal_Size nDestChars;
+ sal_Unicode nConvChar;
+ hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
+ nDestChars = rtl_convertTextToUnicode( hConverter, 0,
+ (const sal_Char*)pChar, *pLen,
+ &nConvChar, 1,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_FLUSH,
+ &nInfo, &nSrcBytes );
+ rtl_destroyTextToUnicodeConverter( hConverter );
+
+ if ( nDestChars == 1 )
+ {
+ *pLen = nSrcBytes;
+ return nConvChar;
+ }
+ else
+ {
+ *pLen = 0;
+ return 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_Size ByteString::ConvertFromUnicode( sal_Unicode c, char* pBuf, sal_Size nBufLen, rtl_TextEncoding eTextEncoding,
+ BOOL bReplace )
+{
+ // TextEncoding Dontknow wird nicht konvertiert
+ if ( eTextEncoding == RTL_TEXTENCODING_DONTKNOW )
+ return '\0';
+
+ rtl_UnicodeToTextConverter hConverter;
+ sal_uInt32 nInfo;
+ sal_Size nSrcChars;
+ sal_Size nDestBytes;
+ sal_Unicode cUni = c;
+ sal_uInt32 nFlags = RTL_UNICODETOTEXT_FLAGS_NONSPACING_IGNORE |
+ RTL_UNICODETOTEXT_FLAGS_CONTROL_IGNORE |
+ RTL_UNICODETOTEXT_FLAGS_FLUSH;
+ if ( bReplace )
+ {
+ nFlags |= RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT;
+ nFlags |= RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE;
+ if ( nBufLen > 1 )
+ nFlags |= RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR;
+ }
+ else
+ {
+ nFlags |= RTL_UNICODETOTEXT_FLAGS_UNDEFINED_0 |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_0;
+ }
+
+ hConverter = rtl_createUnicodeToTextConverter( eTextEncoding );
+ nDestBytes = rtl_convertUnicodeToText( hConverter, 0,
+ &cUni, 1,
+ (sal_Char*)pBuf, nBufLen,
+ nFlags,
+ &nInfo, &nSrcChars );
+ rtl_destroyUnicodeToTextConverter( hConverter );
+ return nDestBytes;
+}
+
+// =======================================================================
+
+ByteString::ByteString( const rtl::OString& rStr )
+ : mpData(NULL)
+{
+ DBG_CTOR( ByteString, DbgCheckByteString );
+
+ OSL_ENSURE(rStr.pData->length < STRING_MAXLEN,
+ "Overflowing rtl::OString -> ByteString cut to zero length");
+
+ if (rStr.pData->length < STRING_MAXLEN)
+ {
+ mpData = reinterpret_cast< ByteStringData * >(const_cast< rtl::OString & >(rStr).pData);
+ STRING_ACQUIRE((STRING_TYPE *)mpData);
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ByteString& ByteString::Assign( const rtl::OString& rStr )
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ OSL_ENSURE(rStr.pData->length < STRING_MAXLEN,
+ "Overflowing rtl::OString -> ByteString cut to zero length");
+
+ if (rStr.pData->length < STRING_MAXLEN)
+ {
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = reinterpret_cast< ByteStringData * >(const_cast< rtl::OString & >(rStr).pData);
+ STRING_ACQUIRE((STRING_TYPE *)mpData);
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+
+ return *this;
+}
diff --git a/tools/source/string/strimp.cxx b/tools/source/string/strimp.cxx
new file mode 100644
index 000000000000..34038c576aa0
--- /dev/null
+++ b/tools/source/string/strimp.cxx
@@ -0,0 +1,2115 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// no include "precompiled_tools.hxx" because this is included in other cxx files.
+
+// =======================================================================
+
+static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2 )
+{
+ sal_Int32 nRet;
+ while ( ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) &&
+ *pStr2 )
+ {
+ ++pStr1,
+ ++pStr2;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2,
+ xub_StrLen nCount )
+{
+ sal_Int32 nRet = 0;
+ while ( nCount &&
+ ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) &&
+ *pStr2 )
+ {
+ ++pStr1,
+ ++pStr2,
+ --nCount;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringCompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
+ sal_Int32 nCount )
+{
+ sal_Int32 nRet = 0;
+ while ( nCount &&
+ ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) )
+ {
+ ++pStr1,
+ ++pStr2,
+ --nCount;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringICompare( const STRCODE* pStr1, const STRCODE* pStr2 )
+{
+ sal_Int32 nRet;
+ STRCODE c1;
+ STRCODE c2;
+ do
+ {
+ // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
+ c1 = *pStr1;
+ c2 = *pStr2;
+ if ( (c1 >= 65) && (c1 <= 90) )
+ c1 += 32;
+ if ( (c2 >= 65) && (c2 <= 90) )
+ c2 += 32;
+ nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
+ if ( nRet != 0 )
+ break;
+
+ ++pStr1,
+ ++pStr2;
+ }
+ while ( c2 );
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringICompare( const STRCODE* pStr1, const STRCODE* pStr2,
+ xub_StrLen nCount )
+{
+ sal_Int32 nRet = 0;
+ STRCODE c1;
+ STRCODE c2;
+ do
+ {
+ if ( !nCount )
+ break;
+
+ // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
+ c1 = *pStr1;
+ c2 = *pStr2;
+ if ( (c1 >= 65) && (c1 <= 90) )
+ c1 += 32;
+ if ( (c2 >= 65) && (c2 <= 90) )
+ c2 += 32;
+ nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
+ if ( nRet != 0 )
+ break;
+
+ ++pStr1,
+ ++pStr2,
+ --nCount;
+ }
+ while ( c2 );
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Int32 ImplStringICompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
+ sal_Int32 nCount )
+{
+ sal_Int32 nRet = 0;
+ STRCODE c1;
+ STRCODE c2;
+ do
+ {
+ if ( !nCount )
+ break;
+
+ // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
+ c1 = *pStr1;
+ c2 = *pStr2;
+ if ( (c1 >= 65) && (c1 <= 90) )
+ c1 += 32;
+ if ( (c2 >= 65) && (c2 <= 90) )
+ c2 += 32;
+ nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
+
+ ++pStr1,
+ ++pStr2,
+ --nCount;
+ }
+ while ( nRet == 0 );
+
+ return nRet;
+}
+
+// =======================================================================
+
+#ifdef DBG_UTIL
+const char* DBGCHECKSTRING( const void* pString )
+{
+ STRING* p = (STRING*)pString;
+
+ if ( p->GetBuffer()[p->Len()] != 0 )
+ return "String damaged: aStr[nLen] != 0";
+
+ return NULL;
+}
+#endif
+
+// =======================================================================
+
+static STRINGDATA* ImplAllocData( sal_Int32 nLen )
+{
+ // Dann kopiere die Daten
+ STRINGDATA* pData = (STRINGDATA*)rtl_allocateMemory( sizeof(STRINGDATA)+(nLen*sizeof( STRCODE )) );
+ pData->mnRefCount = 1;
+ pData->mnLen = nLen;
+ pData->maStr[nLen] = 0;
+ return pData;
+}
+
+// -----------------------------------------------------------------------
+
+static STRINGDATA* _ImplCopyData( STRINGDATA* pData )
+{
+ unsigned int nSize = sizeof(STRINGDATA)+(pData->mnLen*sizeof( STRCODE ));
+ STRINGDATA* pNewData = (STRINGDATA*)rtl_allocateMemory( nSize );
+ memcpy( pNewData, pData, nSize );
+ pNewData->mnRefCount = 1;
+ STRING_RELEASE((STRING_TYPE *)pData);
+ return pNewData;
+}
+
+// -----------------------------------------------------------------------
+
+inline void STRING::ImplCopyData()
+{
+ DBG_ASSERT( (mpData->mnRefCount != 0), "String::ImplCopyData() - RefCount == 0" );
+
+ // ist es ein referenzierter String, dann die Daten abkoppeln
+ if ( mpData->mnRefCount != 1 )
+ mpData = _ImplCopyData( mpData );
+}
+
+// -----------------------------------------------------------------------
+
+inline STRCODE* STRING::ImplCopyStringData( STRCODE* pStr )
+{
+ // Ist der Referenzzaehler groesser 0
+ if ( mpData->mnRefCount != 1 ) {
+ DBG_ASSERT( (pStr >= mpData->maStr) &&
+ ((pStr-mpData->maStr) < mpData->mnLen),
+ "ImplCopyStringData - pStr from other String-Instanz" );
+ unsigned int nIndex = (unsigned int)(pStr-mpData->maStr);
+ mpData = _ImplCopyData( mpData );
+ pStr = mpData->maStr + nIndex;
+ }
+ return pStr;
+}
+
+// -----------------------------------------------------------------------
+
+inline sal_Int32 ImplGetCopyLen( sal_Int32 nStrLen, sal_Int32 nCopyLen )
+{
+ OSL_ASSERT(nStrLen <= STRING_MAXLEN && nCopyLen <= STRING_MAXLEN);
+ if ( nCopyLen > STRING_MAXLEN-nStrLen )
+ nCopyLen = STRING_MAXLEN-nStrLen;
+ return nCopyLen;
+}
+
+// =======================================================================
+
+STRING::STRING()
+ : mpData(NULL)
+{
+ DBG_CTOR( STRING, DBGCHECKSTRING );
+
+ STRING_NEW((STRING_TYPE **)&mpData);
+}
+
+// -----------------------------------------------------------------------
+
+STRING::STRING( const STRING& rStr )
+{
+ DBG_CTOR( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Pointer auf die Daten des uebergebenen Strings setzen und
+ // Referenzzaehler erhoehen
+ STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
+ mpData = rStr.mpData;
+}
+
+// -----------------------------------------------------------------------
+
+STRING::STRING( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen )
+: mpData( NULL )
+{
+ DBG_CTOR( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Stringlaenge ermitteln
+ if ( nPos > rStr.mpData->mnLen )
+ nLen = 0;
+ else
+ {
+ // Laenge korrigieren, wenn noetig
+ sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
+ if ( nLen > nMaxLen )
+ nLen = static_cast< xub_StrLen >(nMaxLen);
+ }
+
+ // Ist es kein leerer String
+ if ( nLen )
+ {
+ // Reicht ein einfaches erhoehen des Referenzcounters
+ if ( (nPos == 0) && (nLen == rStr.mpData->mnLen) )
+ {
+ STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
+ mpData = rStr.mpData;
+ }
+ else
+ {
+ // Verwaltungsdaten anlegen und String kopieren
+ mpData = ImplAllocData( nLen );
+ memcpy( mpData->maStr, rStr.mpData->maStr+nPos, nLen*sizeof( STRCODE ) );
+ }
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+STRING::STRING( const STRCODE* pCharStr )
+ : mpData(NULL)
+{
+ DBG_CTOR( STRING, DBGCHECKSTRING );
+
+ // Stringlaenge ermitteln
+ // Bei diesem Ctor darf NULL uebergeben werden
+ xub_StrLen nLen;
+ if ( pCharStr )
+ nLen = ImplStringLen( pCharStr );
+ else
+ nLen = 0;
+
+ // Ist es kein leerer String
+ if ( nLen )
+ {
+ // Verwaltungsdaten anlegen und String kopieren
+ mpData = ImplAllocData( nLen );
+ memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+STRING::STRING( const STRCODE* pCharStr, xub_StrLen nLen )
+: mpData(NULL)
+{
+ DBG_CTOR( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( pCharStr, "String::String() - pCharStr is NULL" );
+
+ if ( nLen == STRING_LEN )
+ nLen = ImplStringLen( pCharStr );
+
+#ifdef DBG_UTIL
+ if ( DbgIsAssert() )
+ {
+ for ( xub_StrLen i = 0; i < nLen; i++ )
+ {
+ if ( !pCharStr[i] )
+ {
+ DBG_ERROR( "String::String() : nLen is wrong" );
+ }
+ }
+ }
+#endif
+
+ // Ist es kein leerer String
+ if ( nLen )
+ {
+ // Verwaltungsdaten anlegen und String kopieren
+ mpData = ImplAllocData( nLen );
+ memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+STRING::STRING( STRCODE c )
+{
+ DBG_CTOR( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( c, "String::String() - c is 0" );
+
+ // Verwaltungsdaten anlegen und initialisieren
+ mpData = ImplAllocData( 1 );
+ mpData->maStr[0] = c;
+}
+
+// -----------------------------------------------------------------------
+
+STRING::~STRING()
+{
+ DBG_DTOR( STRING, DBGCHECKSTRING );
+
+ // Daten loeschen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Assign( const STRING& rStr )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = rStr.mpData;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Assign( const STRCODE* pCharStr )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
+
+ // Stringlaenge ermitteln
+ xub_StrLen nLen = ImplStringLen( pCharStr );
+
+ if ( !nLen )
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+ else
+ {
+ // Wenn String genauso lang ist, wie der String, dann direkt kopieren
+ if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
+ memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
+ else
+ {
+ // Alte Daten loeschen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+
+ // Daten initialisieren und String kopieren
+ mpData = ImplAllocData( nLen );
+ memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
+ }
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Assign( const STRCODE* pCharStr, xub_StrLen nLen )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
+
+ if ( nLen == STRING_LEN )
+ nLen = ImplStringLen( pCharStr );
+
+#ifdef DBG_UTIL
+ if ( DbgIsAssert() )
+ {
+ for ( xub_StrLen i = 0; i < nLen; i++ )
+ {
+ if ( !pCharStr[i] )
+ {
+ DBG_ERROR( "String::Assign() : nLen is wrong" );
+ }
+ }
+ }
+#endif
+
+ if ( !nLen )
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+ else
+ {
+ // Wenn String genauso lang ist, wie der String, dann direkt kopieren
+ if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
+ memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
+ else
+ {
+ // Alte Daten loeschen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+
+ // Daten initialisieren und String kopieren
+ mpData = ImplAllocData( nLen );
+ memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
+ }
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Assign( STRCODE c )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( c, "String::Assign() - c is 0" );
+
+ // Verwaltungsdaten anlegen und initialisieren
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = ImplAllocData( 1 );
+ mpData->maStr[0] = c;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Append( const STRING& rStr )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Wenn String leer, dann reicht eine Zuweisung
+ sal_Int32 nLen = mpData->mnLen;
+ if ( !nLen )
+ {
+ STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = rStr.mpData;
+ }
+ else
+ {
+ // Ueberlauf abfangen
+ sal_Int32 nCopyLen = ImplGetCopyLen( nLen, rStr.mpData->mnLen );
+
+ // Ist der uebergebene String kein Leerstring
+ if ( nCopyLen )
+ {
+ // Neue Datenstruktur und neuen String erzeugen
+ STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nLen, rStr.mpData->maStr, nCopyLen*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Append( const STRCODE* pCharStr )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
+
+ // Stringlaenge ermitteln
+ sal_Int32 nLen = mpData->mnLen;
+ sal_Int32 nCopyLen = ImplStringLen( pCharStr );
+
+ // Ueberlauf abfangen
+ nCopyLen = ImplGetCopyLen( nLen, nCopyLen );
+
+ // Ist es kein leerer String
+ if ( nCopyLen )
+ {
+ // Neue Datenstruktur und neuen String erzeugen
+ STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Append( const STRCODE* pCharStr, xub_StrLen nCharLen )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
+
+ if ( nCharLen == STRING_LEN )
+ nCharLen = ImplStringLen( pCharStr );
+
+#ifdef DBG_UTIL
+ if ( DbgIsAssert() )
+ {
+ for ( xub_StrLen i = 0; i < nCharLen; i++ )
+ {
+ if ( !pCharStr[i] )
+ {
+ DBG_ERROR( "String::Append() : nLen is wrong" );
+ }
+ }
+ }
+#endif
+
+ // Ueberlauf abfangen
+ sal_Int32 nLen = mpData->mnLen;
+ sal_Int32 nCopyLen = ImplGetCopyLen( nLen, nCharLen );
+
+ // Ist es kein leerer String
+ if ( nCopyLen )
+ {
+ // Neue Datenstruktur und neuen String erzeugen
+ STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Append( STRCODE c )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // kein 0-Character und maximale Stringlaenge nicht ueberschreiten
+ sal_Int32 nLen = mpData->mnLen;
+ if ( c && (nLen < STRING_MAXLEN) )
+ {
+ // Neue Datenstruktur und neuen String erzeugen
+ STRINGDATA* pNewData = ImplAllocData( nLen+1 );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
+ pNewData->maStr[nLen] = c;
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void STRING::SetChar( xub_StrLen nIndex, STRCODE c )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( nIndex < mpData->mnLen, "String::SetChar() - nIndex > String.Len()" );
+
+ // Daten kopieren, wenn noetig und Character zuweisen
+ ImplCopyData();
+ mpData->maStr[nIndex] = c;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Insert( const STRING& rStr, xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Ueberlauf abfangen
+ sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, rStr.mpData->mnLen );
+
+ // Ist der einzufuegende String ein Leerstring
+ if ( !nCopyLen )
+ return *this;
+
+ // Index groesser als Laenge
+ if ( nIndex > mpData->mnLen )
+ nIndex = static_cast< xub_StrLen >(mpData->mnLen);
+
+ // Neue Laenge ermitteln und neuen String anlegen
+ STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr, nCopyLen*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
+ (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Insert( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen,
+ xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Stringlaenge ermitteln
+ if ( nPos > rStr.mpData->mnLen )
+ nLen = 0;
+ else
+ {
+ // Laenge korrigieren, wenn noetig
+ sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
+ if ( nLen > nMaxLen )
+ nLen = static_cast< xub_StrLen >(nMaxLen);
+ }
+
+ // Ueberlauf abfangen
+ sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, nLen );
+
+ // Ist der einzufuegende String ein Leerstring
+ if ( !nCopyLen )
+ return *this;
+
+ // Index groesser als Laenge
+ if ( nIndex > mpData->mnLen )
+ nIndex = static_cast< xub_StrLen >(mpData->mnLen);
+
+ // Neue Laenge ermitteln und neuen String anlegen
+ STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr+nPos, nCopyLen*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
+ (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Insert( const STRCODE* pCharStr, xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_ASSERT( pCharStr, "String::Insert() - pCharStr is NULL" );
+
+ // Stringlaenge ermitteln
+ sal_Int32 nCopyLen = ImplStringLen( pCharStr );
+
+ // Ueberlauf abfangen
+ nCopyLen = ImplGetCopyLen( mpData->mnLen, nCopyLen );
+
+ // Ist der einzufuegende String ein Leerstring
+ if ( !nCopyLen )
+ return *this;
+
+ // Index groesser als Laenge
+ if ( nIndex > mpData->mnLen )
+ nIndex = static_cast< xub_StrLen >(mpData->mnLen);
+
+ // Neue Laenge ermitteln und neuen String anlegen
+ STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex, pCharStr, nCopyLen*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
+ (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Insert( STRCODE c, xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Ist es kein 0-Character
+ if ( !c || (mpData->mnLen == STRING_MAXLEN) )
+ return *this;
+
+ // Index groesser als Laenge
+ if ( nIndex > mpData->mnLen )
+ nIndex = static_cast< xub_StrLen >(mpData->mnLen);
+
+ // Neue Laenge ermitteln und neuen String anlegen
+ STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+1 );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
+ pNewData->maStr[nIndex] = c;
+ memcpy( pNewData->maStr+nIndex+1, mpData->maStr+nIndex,
+ (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Replace( xub_StrLen nIndex, xub_StrLen nCount, const STRING& rStr )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Wenn Index groessergleich Laenge ist, dann ist es ein Append
+ if ( nIndex >= mpData->mnLen )
+ {
+ Append( rStr );
+ return *this;
+ }
+
+ // Ist es eine Zuweisung
+ if ( (nIndex == 0) && (nCount >= mpData->mnLen) )
+ {
+ Assign( rStr );
+ return *this;
+ }
+
+ // Reicht ein Erase
+ sal_Int32 nStrLen = rStr.mpData->mnLen;
+ if ( !nStrLen )
+ return Erase( nIndex, nCount );
+
+ // nCount darf nicht ueber das Stringende hinnausgehen
+ if ( nCount > mpData->mnLen - nIndex )
+ nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
+
+ // Reicht ein Insert
+ if ( !nCount )
+ return Insert( rStr, nIndex );
+
+ // Reicht eine zeichenweise Zuweisung
+ if ( nCount == nStrLen )
+ {
+ ImplCopyData();
+ memcpy( mpData->maStr+nIndex, rStr.mpData->maStr, nCount*sizeof( STRCODE ) );
+ return *this;
+ }
+
+ // Ueberlauf abfangen
+ nStrLen = ImplGetCopyLen( mpData->mnLen-nCount, nStrLen );
+
+ // Neue Daten anlegen
+ STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount+nStrLen );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr, nStrLen*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex+nStrLen, mpData->maStr+nIndex+nCount,
+ (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Erase( xub_StrLen nIndex, xub_StrLen nCount )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Ist der Index ausserhalb des Strings oder ist nCount == 0
+ if ( (nIndex >= mpData->mnLen) || !nCount )
+ return *this;
+
+ // nCount darf nicht ueber das Stringende hinnausgehen
+ if ( nCount > mpData->mnLen - nIndex )
+ nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
+
+ // Ist das Ergebnis kein Leerstring
+ if ( mpData->mnLen - nCount )
+ {
+ // Neue Daten anlegen
+ STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount );
+
+ // String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
+ memcpy( pNewData->maStr+nIndex, mpData->maStr+nIndex+nCount,
+ (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Fill( xub_StrLen nCount, STRCODE cFillChar )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ if ( !nCount )
+ return *this;
+
+ // Ist nCount groesser wie der jetzige String, dann verlaengern
+ if ( nCount > mpData->mnLen )
+ {
+ // dann neuen String mit der neuen Laenge anlegen
+ STRINGDATA* pNewData = ImplAllocData( nCount );
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+ else
+ ImplCopyData();
+
+ STRCODE* pStr = mpData->maStr;
+ do
+ {
+ *pStr = cFillChar;
+ ++pStr,
+ --nCount;
+ }
+ while ( nCount );
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Expand( xub_StrLen nCount, STRCODE cExpandChar )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Muss der String erweitert werden
+ sal_Int32 nLen = mpData->mnLen;
+ if ( nCount <= nLen )
+ return *this;
+
+ // Neuen String anlegen
+ STRINGDATA* pNewData = ImplAllocData( nCount );
+
+ // Alten String kopieren
+ memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
+
+ // und initialisieren
+ STRCODE* pStr = pNewData->maStr;
+ pStr += nLen;
+ for (sal_Int32 i = nCount - nLen; i > 0; --i) {
+ *pStr++ = cExpandChar;
+ }
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::EraseLeadingChars( STRCODE c )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ if ( mpData->maStr[0] != c )
+ return *this;
+
+ xub_StrLen nStart = 0;
+ while ( mpData->maStr[nStart] == c )
+ ++nStart;
+
+ return Erase( 0, nStart );
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::EraseTrailingChars( STRCODE c )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nEnd = mpData->mnLen;
+ while ( nEnd && (mpData->maStr[nEnd-1] == c) )
+ nEnd--;
+
+ if ( nEnd != mpData->mnLen )
+ Erase( static_cast< xub_StrLen >(nEnd) );
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::EraseLeadingAndTrailingChars( STRCODE c )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ xub_StrLen nStart = 0;
+ while ( mpData->maStr[nStart] == c )
+ ++nStart;
+ if ( nStart )
+ Erase( 0, nStart );
+
+ sal_Int32 nEnd = mpData->mnLen;
+ while ( nEnd && (mpData->maStr[nEnd-1] == c) )
+ nEnd--;
+ if ( nEnd != mpData->mnLen )
+ Erase( static_cast< xub_StrLen >(nEnd) );
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::EraseAllChars( STRCODE c )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nCount = 0;
+ for (sal_Int32 i = 0; i < mpData->mnLen; ++i) {
+ if ( mpData->maStr[i] == c )
+ ++nCount;
+ }
+
+ if ( nCount )
+ {
+ if ( nCount == mpData->mnLen )
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+ else
+ {
+ // Neuen String anlegen
+ STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount );
+
+ // Alten String kopieren und initialisieren
+ nCount = 0;
+ for( xub_StrLen j = 0; j < mpData->mnLen; ++j )
+ {
+ if ( mpData->maStr[j] != c )
+ {
+ pNewData->maStr[nCount] = mpData->maStr[j];
+ ++nCount;
+ }
+ }
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::Reverse()
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ if ( !mpData->mnLen )
+ return *this;
+
+ // Daten kopieren, wenn noetig
+ ImplCopyData();
+
+ // Reverse
+ sal_Int32 nCount = mpData->mnLen / 2;
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ STRCODE cTemp = mpData->maStr[i];
+ mpData->maStr[i] = mpData->maStr[mpData->mnLen-i-1];
+ mpData->maStr[mpData->mnLen-i-1] = cTemp;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::ToLowerAscii()
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nIndex = 0;
+ sal_Int32 nLen = mpData->mnLen;
+ STRCODE* pStr = mpData->maStr;
+ while ( nIndex < nLen )
+ {
+ // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
+ if ( (*pStr >= 65) && (*pStr <= 90) )
+ {
+ // Daten kopieren, wenn noetig
+ pStr = ImplCopyStringData( pStr );
+ *pStr += 32;
+ }
+
+ ++pStr,
+ ++nIndex;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::ToUpperAscii()
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nIndex = 0;
+ sal_Int32 nLen = mpData->mnLen;
+ STRCODE* pStr = mpData->maStr;
+ while ( nIndex < nLen )
+ {
+ // Ist das Zeichen zwischen 'a' und 'z' dann umwandeln
+ if ( (*pStr >= 97) && (*pStr <= 122) )
+ {
+ // Daten kopieren, wenn noetig
+ pStr = ImplCopyStringData( pStr );
+ *pStr -= 32;
+ }
+
+ ++pStr,
+ ++nIndex;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+STRING& STRING::ConvertLineEnd( LineEnd eLineEnd )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Zeilenumbrueche ermitteln und neue Laenge berechnen
+ BOOL bConvert = FALSE; // Muss konvertiert werden
+ const STRCODE* pStr = mpData->maStr; // damit es schneller geht
+ xub_StrLen nLineEndLen = (eLineEnd == LINEEND_CRLF) ? 2 : 1;
+ xub_StrLen nLen = 0; // Ziel-Laenge
+ xub_StrLen i = 0; // Source-Zaehler
+
+ while ( i < mpData->mnLen )
+ {
+ // Bei \r oder \n gibt es neuen Zeilenumbruch
+ if ( (pStr[i] == _CR) || (pStr[i] == _LF) )
+ {
+ nLen = nLen + nLineEndLen;
+
+ // Wenn schon gesetzt, dann brauchen wir keine aufwendige Abfrage
+ if ( !bConvert )
+ {
+ // Muessen wir Konvertieren
+ if ( ((eLineEnd != LINEEND_LF) && (pStr[i] == _LF)) ||
+ ((eLineEnd == LINEEND_CRLF) && (pStr[i+1] != _LF)) ||
+ ((eLineEnd == LINEEND_LF) &&
+ ((pStr[i] == _CR) || (pStr[i+1] == _CR))) ||
+ ((eLineEnd == LINEEND_CR) &&
+ ((pStr[i] == _LF) || (pStr[i+1] == _LF))) )
+ bConvert = TRUE;
+ }
+
+ // \r\n oder \n\r, dann Zeichen ueberspringen
+ if ( ((pStr[i+1] == _CR) || (pStr[i+1] == _LF)) &&
+ (pStr[i] != pStr[i+1]) )
+ ++i;
+ }
+ else
+ ++nLen;
+ ++i;
+
+ // Wenn String zu lang, dann konvertieren wir nicht
+ if ( nLen >= STRING_MAXLEN )
+ return *this;
+ }
+
+ // Zeilenumbrueche konvertieren
+ if ( bConvert )
+ {
+ // Neuen String anlegen
+ STRINGDATA* pNewData = ImplAllocData( nLen );
+ xub_StrLen j = 0;
+ i = 0;
+ while ( i < mpData->mnLen )
+ {
+ // Bei \r oder \n gibt es neuen Zeilenumbruch
+ if ( (pStr[i] == _CR) || (pStr[i] == _LF) )
+ {
+ if ( eLineEnd == LINEEND_CRLF )
+ {
+ pNewData->maStr[j] = _CR;
+ pNewData->maStr[j+1] = _LF;
+ j += 2;
+ }
+ else
+ {
+ if ( eLineEnd == LINEEND_CR )
+ pNewData->maStr[j] = _CR;
+ else
+ pNewData->maStr[j] = _LF;
+ ++j;
+ }
+
+ if ( ((pStr[i+1] == _CR) || (pStr[i+1] == _LF)) &&
+ (pStr[i] != pStr[i+1]) )
+ ++i;
+ }
+ else
+ {
+ pNewData->maStr[j] = mpData->maStr[i];
+ ++j;
+ }
+
+ ++i;
+ }
+
+ // Alte Daten loeschen und Neue zuweisen
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+StringCompare STRING::CompareTo( const STRING& rStr, xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Auf Gleichheit der Pointer testen
+ if ( mpData == rStr.mpData )
+ return COMPARE_EQUAL;
+
+ // Maximale Laenge ermitteln
+ if ( mpData->mnLen < nLen )
+ nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
+ if ( rStr.mpData->mnLen < nLen )
+ nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
+
+ // String vergleichen
+ sal_Int32 nCompare = ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
+
+ // Rueckgabewert anpassen
+ if ( nCompare == 0 )
+ return COMPARE_EQUAL;
+ else if ( nCompare < 0 )
+ return COMPARE_LESS;
+ else
+ return COMPARE_GREATER;
+}
+
+// -----------------------------------------------------------------------
+
+StringCompare STRING::CompareTo( const STRCODE* pCharStr, xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // String vergleichen
+ sal_Int32 nCompare = ImplStringCompare( mpData->maStr, pCharStr, nLen );
+
+ // Rueckgabewert anpassen
+ if ( nCompare == 0 )
+ return COMPARE_EQUAL;
+ else if ( nCompare < 0 )
+ return COMPARE_LESS;
+ else
+ return COMPARE_GREATER;
+}
+
+// -----------------------------------------------------------------------
+
+StringCompare STRING::CompareIgnoreCaseToAscii( const STRING& rStr,
+ xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Auf Gleichheit der Pointer testen
+ if ( mpData == rStr.mpData )
+ return COMPARE_EQUAL;
+
+ // Maximale Laenge ermitteln
+ if ( mpData->mnLen < nLen )
+ nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
+ if ( rStr.mpData->mnLen < nLen )
+ nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
+
+ // String vergleichen
+ sal_Int32 nCompare = ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
+
+ // Rueckgabewert anpassen
+ if ( nCompare == 0 )
+ return COMPARE_EQUAL;
+ else if ( nCompare < 0 )
+ return COMPARE_LESS;
+ else
+ return COMPARE_GREATER;
+}
+
+// -----------------------------------------------------------------------
+
+StringCompare STRING::CompareIgnoreCaseToAscii( const STRCODE* pCharStr,
+ xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // String vergleichen
+ sal_Int32 nCompare = ImplStringICompare( mpData->maStr, pCharStr, nLen );
+
+ // Rueckgabewert anpassen
+ if ( nCompare == 0 )
+ return COMPARE_EQUAL;
+ else if ( nCompare < 0 )
+ return COMPARE_LESS;
+ else
+ return COMPARE_GREATER;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL STRING::Equals( const STRING& rStr ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Sind die Daten gleich
+ if ( mpData == rStr.mpData )
+ return TRUE;
+
+ // Gleiche Laenge
+ if ( mpData->mnLen != rStr.mpData->mnLen )
+ return FALSE;
+
+ // String vergleichen
+ return (ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL STRING::Equals( const STRCODE* pCharStr ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ return (ImplStringCompare( mpData->maStr, pCharStr ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL STRING::EqualsIgnoreCaseAscii( const STRING& rStr ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Sind die Daten gleich
+ if ( mpData == rStr.mpData )
+ return TRUE;
+
+ // Gleiche Laenge
+ if ( mpData->mnLen != rStr.mpData->mnLen )
+ return FALSE;
+
+ // String vergleichen
+ return (ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL STRING::EqualsIgnoreCaseAscii( const STRCODE* pCharStr ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ return (ImplStringICompare( mpData->maStr, pCharStr ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL STRING::Equals( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Are there enough codes for comparing?
+ if ( nIndex > mpData->mnLen )
+ return (rStr.mpData->mnLen == 0);
+ sal_Int32 nMaxLen = mpData->mnLen-nIndex;
+ if ( nMaxLen < nLen )
+ {
+ if ( rStr.mpData->mnLen != nMaxLen )
+ return FALSE;
+ nLen = static_cast< xub_StrLen >(nMaxLen);
+ }
+
+ // String vergleichen
+ return (ImplStringCompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL STRING::Equals( const STRCODE* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Are there enough codes for comparing?
+ if ( nIndex > mpData->mnLen )
+ return (*pCharStr == 0);
+
+ return (ImplStringCompare( mpData->maStr+nIndex, pCharStr, nLen ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL STRING::EqualsIgnoreCaseAscii( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Are there enough codes for comparing?
+ if ( nIndex > mpData->mnLen )
+ return (rStr.mpData->mnLen == 0);
+ sal_Int32 nMaxLen = mpData->mnLen-nIndex;
+ if ( nMaxLen < nLen )
+ {
+ if ( rStr.mpData->mnLen != nMaxLen )
+ return FALSE;
+ nLen = static_cast< xub_StrLen >(nMaxLen);
+ }
+
+ // String vergleichen
+ return (ImplStringICompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL STRING::EqualsIgnoreCaseAscii( const STRCODE* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Are there enough codes for comparing?
+ if ( nIndex > mpData->mnLen )
+ return (*pCharStr == 0);
+
+ return (ImplStringICompare( mpData->maStr+nIndex, pCharStr, nLen ) == 0);
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::Match( const STRING& rStr ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ // Ist dieser String leer
+ if ( !mpData->mnLen )
+ return STRING_MATCH;
+
+ // Suche bis Stringende nach dem ersten nicht uebereinstimmenden Zeichen
+ const STRCODE* pStr1 = mpData->maStr;
+ const STRCODE* pStr2 = rStr.mpData->maStr;
+ xub_StrLen i = 0;
+ while ( i < mpData->mnLen )
+ {
+ // Stimmt das Zeichen nicht ueberein, dann abbrechen
+ if ( *pStr1 != *pStr2 )
+ return i;
+ ++pStr1,
+ ++pStr2,
+ ++i;
+ }
+
+ return STRING_MATCH;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::Match( const STRCODE* pCharStr ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Ist dieser String leer
+ if ( !mpData->mnLen )
+ return STRING_MATCH;
+
+ // Suche bis Stringende nach dem ersten nicht uebereinstimmenden Zeichen
+ const STRCODE* pStr = mpData->maStr;
+ xub_StrLen i = 0;
+ while ( i < mpData->mnLen )
+ {
+ // Stimmt das Zeichen nicht ueberein, dann abbrechen
+ if ( *pStr != *pCharStr )
+ return i;
+ ++pStr,
+ ++pCharStr,
+ ++i;
+ }
+
+ return STRING_MATCH;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::Search( STRCODE c, xub_StrLen nIndex ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nLen = mpData->mnLen;
+ const STRCODE* pStr = mpData->maStr;
+ pStr += nIndex;
+ while ( nIndex < nLen )
+ {
+ if ( *pStr == c )
+ return nIndex;
+ ++pStr,
+ ++nIndex;
+ }
+
+ return STRING_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::Search( const STRING& rStr, xub_StrLen nIndex ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ sal_Int32 nLen = mpData->mnLen;
+ sal_Int32 nStrLen = rStr.mpData->mnLen;
+
+ // Falls die Laenge des uebergebenen Strings 0 ist oder der Index
+ // hinter dem String liegt, dann wurde der String nicht gefunden
+ if ( !nStrLen || (nIndex >= nLen) )
+ return STRING_NOTFOUND;
+
+ const STRCODE* pStr1 = mpData->maStr;
+ pStr1 += nIndex;
+
+ if ( nStrLen == 1 )
+ {
+ STRCODE cSearch = rStr.mpData->maStr[0];
+ while ( nIndex < nLen )
+ {
+ if ( *pStr1 == cSearch )
+ return nIndex;
+ ++pStr1,
+ ++nIndex;
+ }
+ }
+ else
+ {
+ const STRCODE* pStr2 = rStr.mpData->maStr;
+
+ // Nur innerhalb des Strings suchen
+ while ( nLen - nIndex >= nStrLen )
+ {
+ // Stimmt der String ueberein
+ if ( ImplStringCompareWithoutZero( pStr1, pStr2, nStrLen ) == 0 )
+ return nIndex;
+ ++pStr1,
+ ++nIndex;
+ }
+ }
+
+ return STRING_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::Search( const STRCODE* pCharStr, xub_StrLen nIndex ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nLen = mpData->mnLen;
+ xub_StrLen nStrLen = ImplStringLen( pCharStr );
+
+ // Falls die Laenge des uebergebenen Strings 0 ist oder der Index
+ // hinter dem String liegt, dann wurde der String nicht gefunden
+ if ( !nStrLen || (nIndex >= nLen) )
+ return STRING_NOTFOUND;
+
+ const STRCODE* pStr = mpData->maStr;
+ pStr += nIndex;
+
+ if ( nStrLen == 1 )
+ {
+ STRCODE cSearch = *pCharStr;
+ while ( nIndex < nLen )
+ {
+ if ( *pStr == cSearch )
+ return nIndex;
+ ++pStr,
+ ++nIndex;
+ }
+ }
+ else
+ {
+ // Nur innerhalb des Strings suchen
+ while ( nLen - nIndex >= nStrLen )
+ {
+ // Stimmt der String ueberein
+ if ( ImplStringCompareWithoutZero( pStr, pCharStr, nStrLen ) == 0 )
+ return nIndex;
+ ++pStr,
+ ++nIndex;
+ }
+ }
+
+ return STRING_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::SearchBackward( STRCODE c, xub_StrLen nIndex ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ if ( nIndex > mpData->mnLen )
+ nIndex = (xub_StrLen)mpData->mnLen;
+
+ const STRCODE* pStr = mpData->maStr;
+ pStr += nIndex;
+
+ while ( nIndex )
+ {
+ nIndex--;
+ pStr--;
+ if ( *pStr == c )
+ return nIndex;
+ }
+
+ return STRING_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::SearchChar( const STRCODE* pChars, xub_StrLen nIndex ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nLen = mpData->mnLen;
+ const STRCODE* pStr = mpData->maStr;
+ pStr += nIndex;
+ while ( nIndex < nLen )
+ {
+ STRCODE c = *pStr;
+ const STRCODE* pCompStr = pChars;
+ while ( *pCompStr )
+ {
+ if ( *pCompStr == c )
+ return nIndex;
+ ++pCompStr;
+ }
+ ++pStr,
+ ++nIndex;
+ }
+
+ return STRING_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::SearchCharBackward( const STRCODE* pChars, xub_StrLen nIndex ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ if ( nIndex > mpData->mnLen )
+ nIndex = (xub_StrLen)mpData->mnLen;
+
+ const STRCODE* pStr = mpData->maStr;
+ pStr += nIndex;
+
+ while ( nIndex )
+ {
+ nIndex--;
+ pStr--;
+
+ STRCODE c =*pStr;
+ const STRCODE* pCompStr = pChars;
+ while ( *pCompStr )
+ {
+ if ( *pCompStr == c )
+ return nIndex;
+ ++pCompStr;
+ }
+ }
+
+ return STRING_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::SearchAndReplace( STRCODE c, STRCODE cRep, xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nLen = mpData->mnLen;
+ const STRCODE* pStr = mpData->maStr;
+ pStr += nIndex;
+ while ( nIndex < nLen )
+ {
+ if ( *pStr == c )
+ {
+ ImplCopyData();
+ mpData->maStr[nIndex] = cRep;
+ return nIndex;
+ }
+ ++pStr,
+ ++nIndex;
+ }
+
+ return STRING_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::SearchAndReplace( const STRING& rStr, const STRING& rRepStr,
+ xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
+
+ xub_StrLen nSPos = Search( rStr, nIndex );
+ if ( nSPos != STRING_NOTFOUND )
+ Replace( nSPos, rStr.Len(), rRepStr );
+
+ return nSPos;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::SearchAndReplace( const STRCODE* pCharStr, const STRING& rRepStr,
+ xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
+
+ xub_StrLen nSPos = Search( pCharStr, nIndex );
+ if ( nSPos != STRING_NOTFOUND )
+ Replace( nSPos, ImplStringLen( pCharStr ), rRepStr );
+
+ return nSPos;
+}
+
+// -----------------------------------------------------------------------
+
+void STRING::SearchAndReplaceAll( STRCODE c, STRCODE cRep )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ sal_Int32 nLen = mpData->mnLen;
+ const STRCODE* pStr = mpData->maStr;
+ sal_Int32 nIndex = 0;
+ while ( nIndex < nLen )
+ {
+ if ( *pStr == c )
+ {
+ ImplCopyData();
+ mpData->maStr[nIndex] = cRep;
+ }
+ ++pStr,
+ ++nIndex;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void STRING::SearchAndReplaceAll( const STRCODE* pCharStr, const STRING& rRepStr )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
+
+ xub_StrLen nCharLen = ImplStringLen( pCharStr );
+ xub_StrLen nSPos = Search( pCharStr, 0 );
+ while ( nSPos != STRING_NOTFOUND )
+ {
+ Replace( nSPos, nCharLen, rRepStr );
+ nSPos = nSPos + rRepStr.Len();
+ nSPos = Search( pCharStr, nSPos );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void STRING::SearchAndReplaceAll( const STRING& rStr, const STRING& rRepStr )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
+
+ xub_StrLen nSPos = Search( rStr, 0 );
+ while ( nSPos != STRING_NOTFOUND )
+ {
+ Replace( nSPos, rStr.Len(), rRepStr );
+ nSPos = nSPos + rRepStr.Len();
+ nSPos = Search( rStr, nSPos );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::GetTokenCount( STRCODE cTok ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Leerer String: TokenCount per Definition 0
+ if ( !mpData->mnLen )
+ return 0;
+
+ xub_StrLen nTokCount = 1;
+ sal_Int32 nLen = mpData->mnLen;
+ const STRCODE* pStr = mpData->maStr;
+ sal_Int32 nIndex = 0;
+ while ( nIndex < nLen )
+ {
+ // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
+ if ( *pStr == cTok )
+ ++nTokCount;
+ ++pStr,
+ ++nIndex;
+ }
+
+ return nTokCount;
+}
+
+// -----------------------------------------------------------------------
+
+void STRING::SetToken( xub_StrLen nToken, STRCODE cTok, const STRING& rStr,
+ xub_StrLen nIndex )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
+
+ const STRCODE* pStr = mpData->maStr;
+ xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
+ xub_StrLen nTok = 0;
+ xub_StrLen nFirstChar = nIndex;
+ xub_StrLen i = nFirstChar;
+
+ // Bestimme die Token-Position und Laenge
+ pStr += i;
+ while ( i < nLen )
+ {
+ // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
+ if ( *pStr == cTok )
+ {
+ ++nTok;
+
+ if ( nTok == nToken )
+ nFirstChar = i+1;
+ else
+ {
+ if ( nTok > nToken )
+ break;
+ }
+ }
+
+ ++pStr,
+ ++i;
+ }
+
+ if ( nTok >= nToken )
+ Replace( nFirstChar, i-nFirstChar, rStr );
+}
+
+// -----------------------------------------------------------------------
+
+STRING STRING::GetToken( xub_StrLen nToken, STRCODE cTok, xub_StrLen& rIndex ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ const STRCODE* pStr = mpData->maStr;
+ xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
+ xub_StrLen nTok = 0;
+ xub_StrLen nFirstChar = rIndex;
+ xub_StrLen i = nFirstChar;
+
+ // Bestimme die Token-Position und Laenge
+ pStr += i;
+ while ( i < nLen )
+ {
+ // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
+ if ( *pStr == cTok )
+ {
+ ++nTok;
+
+ if ( nTok == nToken )
+ nFirstChar = i+1;
+ else
+ {
+ if ( nTok > nToken )
+ break;
+ }
+ }
+
+ ++pStr,
+ ++i;
+ }
+
+ if ( nTok >= nToken )
+ {
+ if ( i < nLen )
+ rIndex = i+1;
+ else
+ rIndex = STRING_NOTFOUND;
+ return Copy( nFirstChar, i-nFirstChar );
+ }
+ else
+ {
+ rIndex = STRING_NOTFOUND;
+ return STRING();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen STRING::GetQuotedTokenCount( const STRING& rQuotedPairs, STRCODE cTok ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rQuotedPairs, STRING, DBGCHECKSTRING );
+ DBG_ASSERT( !(rQuotedPairs.Len()%2), "String::GetQuotedTokenCount() - QuotedString%2 != 0" );
+ DBG_ASSERT( rQuotedPairs.Search(cTok) == STRING_NOTFOUND, "String::GetQuotedTokenCount() - cTok in QuotedString" );
+
+ // Leerer String: TokenCount per Definition 0
+ if ( !mpData->mnLen )
+ return 0;
+
+ xub_StrLen nTokCount = 1;
+ sal_Int32 nLen = mpData->mnLen;
+ xub_StrLen nQuotedLen = rQuotedPairs.Len();
+ STRCODE cQuotedEndChar = 0;
+ const STRCODE* pQuotedStr = rQuotedPairs.mpData->maStr;
+ const STRCODE* pStr = mpData->maStr;
+ sal_Int32 nIndex = 0;
+ while ( nIndex < nLen )
+ {
+ STRCODE c = *pStr;
+ if ( cQuotedEndChar )
+ {
+ // Ende des Quotes erreicht ?
+ if ( c == cQuotedEndChar )
+ cQuotedEndChar = 0;
+ }
+ else
+ {
+ // Ist das Zeichen ein Quote-Anfang-Zeichen ?
+ xub_StrLen nQuoteIndex = 0;
+ while ( nQuoteIndex < nQuotedLen )
+ {
+ if ( pQuotedStr[nQuoteIndex] == c )
+ {
+ cQuotedEndChar = pQuotedStr[nQuoteIndex+1];
+ break;
+ }
+ else
+ nQuoteIndex += 2;
+ }
+
+ // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
+ if ( c == cTok )
+ ++nTokCount;
+ }
+
+ ++pStr,
+ ++nIndex;
+ }
+
+ return nTokCount;
+}
+
+// -----------------------------------------------------------------------
+
+STRING STRING::GetQuotedToken( xub_StrLen nToken, const STRING& rQuotedPairs,
+ STRCODE cTok, xub_StrLen& rIndex ) const
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+ DBG_CHKOBJ( &rQuotedPairs, STRING, DBGCHECKSTRING );
+ DBG_ASSERT( !(rQuotedPairs.Len()%2), "String::GetQuotedToken() - QuotedString%2 != 0" );
+ DBG_ASSERT( rQuotedPairs.Search(cTok) == STRING_NOTFOUND, "String::GetQuotedToken() - cTok in QuotedString" );
+
+ const STRCODE* pStr = mpData->maStr;
+ const STRCODE* pQuotedStr = rQuotedPairs.mpData->maStr;
+ STRCODE cQuotedEndChar = 0;
+ xub_StrLen nQuotedLen = rQuotedPairs.Len();
+ xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
+ xub_StrLen nTok = 0;
+ xub_StrLen nFirstChar = rIndex;
+ xub_StrLen i = nFirstChar;
+
+ // Bestimme die Token-Position und Laenge
+ pStr += i;
+ while ( i < nLen )
+ {
+ STRCODE c = *pStr;
+ if ( cQuotedEndChar )
+ {
+ // Ende des Quotes erreicht ?
+ if ( c == cQuotedEndChar )
+ cQuotedEndChar = 0;
+ }
+ else
+ {
+ // Ist das Zeichen ein Quote-Anfang-Zeichen ?
+ xub_StrLen nQuoteIndex = 0;
+ while ( nQuoteIndex < nQuotedLen )
+ {
+ if ( pQuotedStr[nQuoteIndex] == c )
+ {
+ cQuotedEndChar = pQuotedStr[nQuoteIndex+1];
+ break;
+ }
+ else
+ nQuoteIndex += 2;
+ }
+
+ // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
+ if ( c == cTok )
+ {
+ ++nTok;
+
+ if ( nTok == nToken )
+ nFirstChar = i+1;
+ else
+ {
+ if ( nTok > nToken )
+ break;
+ }
+ }
+ }
+
+ ++pStr,
+ ++i;
+ }
+
+ if ( nTok >= nToken )
+ {
+ if ( i < nLen )
+ rIndex = i+1;
+ else
+ rIndex = STRING_NOTFOUND;
+ return Copy( nFirstChar, i-nFirstChar );
+ }
+ else
+ {
+ rIndex = STRING_NOTFOUND;
+ return STRING();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+STRCODE* STRING::GetBufferAccess()
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ // Daten kopieren, wenn noetig
+ if ( mpData->mnLen )
+ ImplCopyData();
+
+ // Pointer auf den String zurueckgeben
+ return mpData->maStr;
+}
+
+// -----------------------------------------------------------------------
+
+void STRING::ReleaseBufferAccess( xub_StrLen nLen )
+{
+ // Hier ohne Funktionstest, da String nicht konsistent
+ DBG_CHKTHIS( STRING, NULL );
+ DBG_ASSERT( mpData->mnRefCount == 1, "String::ReleaseCharStr() called for String with RefCount" );
+
+ if ( nLen > mpData->mnLen )
+ nLen = ImplStringLen( mpData->maStr );
+ OSL_ASSERT(nLen <= mpData->mnLen);
+ if ( !nLen )
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+ // Bei mehr als 8 Zeichen unterschied, kuerzen wir den Buffer
+ else if ( mpData->mnLen - nLen > 8 )
+ {
+ STRINGDATA* pNewData = ImplAllocData( nLen );
+ memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = pNewData;
+ }
+ else
+ mpData->mnLen = nLen;
+}
+
+// -----------------------------------------------------------------------
+
+STRCODE* STRING::AllocBuffer( xub_StrLen nLen )
+{
+ DBG_CHKTHIS( STRING, DBGCHECKSTRING );
+
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ if ( nLen )
+ mpData = ImplAllocData( nLen );
+ else
+ {
+ mpData = NULL;
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+
+ return mpData->maStr;
+}
diff --git a/tools/source/string/strucvt.cxx b/tools/source/string/strucvt.cxx
new file mode 100644
index 000000000000..9c9ef1dc4b5a
--- /dev/null
+++ b/tools/source/string/strucvt.cxx
@@ -0,0 +1,213 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// no include "precompiled_tools.hxx" because this is included in other cxx files.
+
+// =======================================================================
+
+void UniString::InitStringRes( const char* pUTF8Str, sal_Int32 nLen )
+{
+ DBG_CTOR( UniString, DbgCheckUniString );
+ OSL_ENSURE(nLen <= STRING_MAXLEN, "Overflowing UniString");
+
+ mpData = NULL;
+ rtl_string2UString( (rtl_uString **)(&mpData),
+ pUTF8Str, nLen,
+ RTL_TEXTENCODING_UTF8,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
+}
+
+// =======================================================================
+
+UniString::UniString( const ByteString& rByteStr, rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ DBG_CTOR( UniString, DbgCheckUniString );
+ DBG_CHKOBJ( &rByteStr, ByteString, DbgCheckByteString );
+
+ mpData = NULL;
+ rtl_string2UString( (rtl_uString **)(&mpData),
+ rByteStr.mpData->maStr, rByteStr.mpData->mnLen,
+ eTextEncoding, nCvtFlags );
+}
+
+// -----------------------------------------------------------------------
+
+UniString::UniString( const ByteString& rByteStr, xub_StrLen nPos, xub_StrLen nLen,
+ rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ DBG_CTOR( UniString, DbgCheckUniString );
+ DBG_CHKOBJ( &rByteStr, ByteString, DbgCheckByteString );
+
+ // Stringlaenge ermitteln
+ if ( nPos > rByteStr.mpData->mnLen )
+ nLen = 0;
+ else
+ {
+ // Laenge korrigieren, wenn noetig
+ sal_Int32 nMaxLen = rByteStr.mpData->mnLen-nPos;
+ if ( nLen > nMaxLen )
+ nLen = static_cast< xub_StrLen >(nMaxLen);
+ }
+
+ mpData = NULL;
+ rtl_string2UString( (rtl_uString **)(&mpData),
+ rByteStr.mpData->maStr+nPos, nLen,
+ eTextEncoding, nCvtFlags );
+}
+
+// -----------------------------------------------------------------------
+
+UniString::UniString( const char* pByteStr,
+ rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ DBG_CTOR( UniString, DbgCheckUniString );
+ DBG_ASSERT( pByteStr, "UniString::UniString() - pByteStr is NULL" );
+
+ mpData = NULL;
+ rtl_string2UString( (rtl_uString **)(&mpData),
+ pByteStr, ImplStringLen( pByteStr ),
+ eTextEncoding, nCvtFlags );
+}
+
+// -----------------------------------------------------------------------
+
+UniString::UniString( const char* pByteStr, xub_StrLen nLen,
+ rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags )
+{
+ DBG_CTOR( UniString, DbgCheckUniString );
+ DBG_ASSERT( pByteStr, "UniString::UniString() - pByteStr is NULL" );
+
+ if ( nLen == STRING_LEN )
+ nLen = ImplStringLen( pByteStr );
+
+ mpData = NULL;
+ rtl_string2UString( (rtl_uString **)(&mpData),
+ pByteStr, nLen,
+ eTextEncoding, nCvtFlags );
+}
+
+// =======================================================================
+
+UniString::UniString( const rtl::OUString& rStr )
+ : mpData(NULL)
+{
+ DBG_CTOR( UniString, DbgCheckUniString );
+
+ OSL_ENSURE(rStr.pData->length < STRING_MAXLEN,
+ "Overflowing rtl::OUString -> UniString cut to zero length");
+
+
+ if (rStr.pData->length < STRING_MAXLEN)
+ {
+ mpData = reinterpret_cast< UniStringData * >(const_cast< rtl::OUString & >(rStr).pData);
+ STRING_ACQUIRE((STRING_TYPE *)mpData);
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+UniString& UniString::Assign( const rtl::OUString& rStr )
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+
+ OSL_ENSURE(rStr.pData->length < STRING_MAXLEN,
+ "Overflowing rtl::OUString -> UniString cut to zero length");
+
+
+ if (rStr.pData->length < STRING_MAXLEN)
+ {
+ STRING_RELEASE((STRING_TYPE *)mpData);
+ mpData = reinterpret_cast< UniStringData * >(const_cast< rtl::OUString & >(rStr).pData);
+ STRING_ACQUIRE((STRING_TYPE *)mpData);
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+ }
+
+ return *this;
+}
+
+UniString UniString::intern() const
+{
+ UniString aStr;
+
+ rtl_uString_intern( reinterpret_cast<rtl_uString **>(&aStr.mpData),
+ (rtl_uString *)(mpData) );
+
+ return aStr;
+}
+
+// =======================================================================
+
+#include <tools/rc.hxx>
+#include <tools/rcid.h>
+
+UniString::UniString( const ResId& rResId )
+{
+ rResId.SetRT( RSC_STRING );
+ ResMgr* pResMgr = rResId.GetResMgr();
+ mpData = NULL;
+ if ( pResMgr && pResMgr->GetResource( rResId ) )
+ {
+ // String laden
+ RSHEADER_TYPE * pResHdr = (RSHEADER_TYPE*)pResMgr->GetClass();
+ //sal_uInt32 nLen = pResHdr->GetLocalOff() - sizeof( RSHEADER_TYPE );
+
+ sal_Int32 nStringLen = rtl_str_getLength( (char*)(pResHdr+1) );
+ InitStringRes( (const char*)(pResHdr+1), nStringLen );
+
+ sal_uInt32 nSize = sizeof( RSHEADER_TYPE )
+ + sal::static_int_cast< sal_uInt32 >(nStringLen) + 1;
+ nSize += nSize % 2;
+ pResMgr->Increment( nSize );
+ }
+ else
+ {
+ STRING_NEW((STRING_TYPE **)&mpData);
+
+#if OSL_DEBUG_LEVEL > 0
+ *this = UniString::CreateFromAscii( "<resource id " );
+ Append( UniString::CreateFromInt32( rResId.GetId() ) );
+ AppendAscii( " not found>" );
+#endif
+ if( pResMgr )
+ pResMgr->PopContext();
+ }
+
+
+ ResHookProc pImplResHookProc = ResMgr::GetReadStringHook();
+ if ( pImplResHookProc )
+ pImplResHookProc( *this );
+}
+
diff --git a/tools/source/string/tenccvt.cxx b/tools/source/string/tenccvt.cxx
new file mode 100644
index 000000000000..5237b24948a7
--- /dev/null
+++ b/tools/source/string/tenccvt.cxx
@@ -0,0 +1,97 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <rtl/tencinfo.h>
+#include <tools/tenccvt.hxx>
+
+// =======================================================================
+
+rtl_TextEncoding GetExtendedCompatibilityTextEncoding( rtl_TextEncoding eEncoding )
+{
+ // Latin1
+ if ( eEncoding == RTL_TEXTENCODING_ISO_8859_1 )
+ return RTL_TEXTENCODING_MS_1252;
+ // Turkey
+ else if ( eEncoding == RTL_TEXTENCODING_ISO_8859_9 )
+ return RTL_TEXTENCODING_MS_1254;
+ else
+ return eEncoding;
+}
+
+// -----------------------------------------------------------------------
+
+rtl_TextEncoding GetExtendedTextEncoding( rtl_TextEncoding eEncoding )
+{
+ // Cyr
+ if ( eEncoding == RTL_TEXTENCODING_ISO_8859_5 )
+ return RTL_TEXTENCODING_MS_1251;
+ // Greek (2 Characters different: A1 (0x2018/0x0385), A2 (0x2019/0x0386) -
+ // so it is handled in this function and not in GetExtendedCompatibilityTextEncoding)
+ else if ( eEncoding == RTL_TEXTENCODING_ISO_8859_7 )
+ return RTL_TEXTENCODING_MS_1253;
+ // East-Europe - Latin2
+ else if ( eEncoding == RTL_TEXTENCODING_ISO_8859_2 )
+ return RTL_TEXTENCODING_MS_1250;
+ // Latin-15 - Latin 1 mit Euro-Sign
+ else if ( eEncoding == RTL_TEXTENCODING_ISO_8859_15 )
+ return RTL_TEXTENCODING_MS_1252;
+ else
+ return GetExtendedCompatibilityTextEncoding( eEncoding );
+}
+
+// -----------------------------------------------------------------------
+
+rtl_TextEncoding GetOneByteTextEncoding( rtl_TextEncoding eEncoding )
+{
+ rtl_TextEncodingInfo aTextEncInfo;
+ aTextEncInfo.StructSize = sizeof( aTextEncInfo );
+ if ( rtl_getTextEncodingInfo( eEncoding, &aTextEncInfo ) )
+ {
+ if ( aTextEncInfo.MaximumCharSize > 1 )
+ return RTL_TEXTENCODING_MS_1252;
+ else
+ return eEncoding;
+ }
+ else
+ return RTL_TEXTENCODING_MS_1252;
+}
+
+// -----------------------------------------------------------------------
+
+rtl_TextEncoding GetSOLoadTextEncoding( rtl_TextEncoding eEncoding, USHORT /* nVersion = SOFFICE_FILEFORMAT_50 */ )
+{
+ return GetExtendedCompatibilityTextEncoding( GetOneByteTextEncoding( eEncoding ) );
+}
+
+// -----------------------------------------------------------------------
+
+rtl_TextEncoding GetSOStoreTextEncoding( rtl_TextEncoding eEncoding, USHORT /* nVersion = SOFFICE_FILEFORMAT_50 */ )
+{
+ return GetExtendedTextEncoding( GetOneByteTextEncoding( eEncoding ) );
+}
diff --git a/tools/source/string/tstring.cxx b/tools/source/string/tstring.cxx
new file mode 100644
index 000000000000..f2525e3bca84
--- /dev/null
+++ b/tools/source/string/tstring.cxx
@@ -0,0 +1,295 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <string.h>
+
+#include "boost/static_assert.hpp"
+
+#include "osl/diagnose.h"
+#ifndef _OSL_INTERLCK_H
+#include <osl/interlck.h>
+#endif
+#ifndef _RTL_ALLOC_H
+#include <rtl/alloc.h>
+#endif
+#ifndef _RTL_MEMORY_H
+#include <rtl/memory.h>
+#endif
+#include <rtl/tencinfo.h>
+#include <rtl/instance.hxx>
+
+#include <tools/string.hxx>
+#include <impstrg.hxx>
+
+// For shared byte convert tables
+#ifndef _TOOLS_TOOLSIN_HXX
+#include <toolsin.hxx>
+#endif
+
+#include <tools/debug.hxx>
+
+// =======================================================================
+
+DBG_NAME( ByteString )
+DBG_NAMEEX( UniString )
+
+// -----------------------------------------------------------------------
+
+#define STRCODE sal_Char
+#define STRCODEU unsigned char
+#define STRING ByteString
+#define STRINGDATA ByteStringData
+#define DBGCHECKSTRING DbgCheckByteString
+#define STRING_TYPE rtl_String
+#define STRING_ACQUIRE rtl_string_acquire
+#define STRING_RELEASE rtl_string_release
+#define STRING_NEW rtl_string_new
+
+
+// -----------------------------------------------------------------------
+
+xub_StrLen ImplStringLen( const sal_Char* pStr )
+{
+ const sal_Char* pTempStr = pStr;
+ while( *pTempStr )
+ ++pTempStr;
+ return (xub_StrLen)(pTempStr-pStr);
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen ImplStringLen( const sal_Unicode* pStr )
+{
+ const sal_Unicode* pTempStr = pStr;
+ while( *pTempStr )
+ ++pTempStr;
+ return (xub_StrLen)(pTempStr-pStr);
+}
+
+// -----------------------------------------------------------------------
+
+#include <strimp.cxx>
+#include <strcvt.cxx>
+
+// -----------------------------------------------------------------------
+
+ByteString ByteString::CreateFromInt32( sal_Int32 n, sal_Int16 nRadix )
+{
+ sal_Char aBuf[RTL_STR_MAX_VALUEOFINT32];
+ BOOST_STATIC_ASSERT(RTL_STR_MAX_VALUEOFINT32 <= STRING_MAXLEN);
+ return ByteString(
+ aBuf,
+ static_cast< xub_StrLen >(rtl_str_valueOfInt32( aBuf, n, nRadix )) );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString ByteString::CreateFromInt64( sal_Int64 n, sal_Int16 nRadix )
+{
+ sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64];
+ BOOST_STATIC_ASSERT(RTL_STR_MAX_VALUEOFINT64 <= STRING_MAXLEN);
+ return ByteString(
+ aBuf,
+ static_cast< xub_StrLen >(rtl_str_valueOfInt64( aBuf, n, nRadix )) );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString ByteString::CreateFromFloat( float f )
+{
+ sal_Char aBuf[RTL_STR_MAX_VALUEOFFLOAT];
+ BOOST_STATIC_ASSERT(RTL_STR_MAX_VALUEOFFLOAT <= STRING_MAXLEN);
+ return ByteString(
+ aBuf, static_cast< xub_StrLen >(rtl_str_valueOfFloat( aBuf, f )) );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString ByteString::CreateFromDouble( double d )
+{
+ sal_Char aBuf[RTL_STR_MAX_VALUEOFDOUBLE];
+ BOOST_STATIC_ASSERT(RTL_STR_MAX_VALUEOFDOUBLE <= STRING_MAXLEN);
+ return ByteString(
+ aBuf, static_cast< xub_StrLen >(rtl_str_valueOfDouble( aBuf, d )) );
+}
+
+// -----------------------------------------------------------------------
+
+namespace { struct Empty : public rtl::Static< const ByteString, Empty> {}; }
+const ByteString& ByteString::EmptyString()
+{
+ return Empty::get();
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int32 ByteString::ToInt32() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ return atoi( mpData->maStr );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 ByteString::ToInt64() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ return atoi( mpData->maStr );
+}
+
+// -----------------------------------------------------------------------
+
+float ByteString::ToFloat() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ OSL_ENSURE(false, "ByteString::ToFloat unusable");
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+double ByteString::ToDouble() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ OSL_ENSURE(false, "ByteString::ToDouble unusable");
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ByteString::IsLowerAscii() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ sal_Int32 nIndex = 0;
+ sal_Int32 nLen = mpData->mnLen;
+ const sal_Char* pStr = mpData->maStr;
+ while ( nIndex < nLen )
+ {
+ if ( (*pStr >= 65) && (*pStr <= 90) )
+ return FALSE;
+
+ ++pStr,
+ ++nIndex;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ByteString::IsUpperAscii() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ sal_Int32 nIndex = 0;
+ sal_Int32 nLen = mpData->mnLen;
+ const sal_Char* pStr = mpData->maStr;
+ while ( nIndex < nLen )
+ {
+ if ( (*pStr >= 97) && (*pStr <= 122) )
+ return FALSE;
+
+ ++pStr,
+ ++nIndex;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ByteString::IsAlphaAscii() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ sal_Int32 nIndex = 0;
+ sal_Int32 nLen = mpData->mnLen;
+ const sal_Char* pStr = mpData->maStr;
+ while ( nIndex < nLen )
+ {
+ if ( !(((*pStr >= 97) && (*pStr <= 122)) ||
+ ((*pStr >= 65) && (*pStr <= 90))) )
+ return FALSE;
+
+ ++pStr,
+ ++nIndex;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ByteString::IsNumericAscii() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ sal_Int32 nIndex = 0;
+ sal_Int32 nLen = mpData->mnLen;
+ const sal_Char* pStr = mpData->maStr;
+ while ( nIndex < nLen )
+ {
+ if ( !((*pStr >= 48) && (*pStr <= 57)) )
+ return FALSE;
+
+ ++pStr,
+ ++nIndex;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ByteString::IsAlphaNumericAscii() const
+{
+ DBG_CHKTHIS( ByteString, DbgCheckByteString );
+
+ sal_Int32 nIndex = 0;
+ sal_Int32 nLen = mpData->mnLen;
+ const sal_Char* pStr = mpData->maStr;
+ while ( nIndex < nLen )
+ {
+ if ( !(((*pStr >= 97) && (*pStr <= 122)) ||
+ ((*pStr >= 65) && (*pStr <= 90)) ||
+ ((*pStr >= 48) && (*pStr <= 57))) )
+ return FALSE;
+
+ ++pStr,
+ ++nIndex;
+ }
+
+ return TRUE;
+}
diff --git a/tools/source/string/tustring.cxx b/tools/source/string/tustring.cxx
new file mode 100644
index 000000000000..27dab841124d
--- /dev/null
+++ b/tools/source/string/tustring.cxx
@@ -0,0 +1,162 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include <string.h>
+
+#include "boost/static_assert.hpp"
+
+#ifndef _OSL_INTERLCK_H
+#include <osl/interlck.h>
+#endif
+#ifndef _RTL_ALLOC_H
+#include <rtl/alloc.h>
+#endif
+#ifndef _RTL_MEMORY_H
+#include <rtl/memory.h>
+#endif
+#include <rtl/tencinfo.h>
+#include <rtl/instance.hxx>
+
+#include <tools/string.hxx>
+#include <impstrg.hxx>
+
+#include <tools/debug.hxx>
+
+// =======================================================================
+
+DBG_NAME( UniString )
+DBG_NAMEEX( ByteString )
+
+// -----------------------------------------------------------------------
+
+#define STRCODE sal_Unicode
+#define STRCODEU sal_Unicode
+#define STRING UniString
+#define STRINGDATA UniStringData
+#define DBGCHECKSTRING DbgCheckUniString
+#define STRING_TYPE rtl_uString
+#define STRING_ACQUIRE rtl_uString_acquire
+#define STRING_RELEASE rtl_uString_release
+#define STRING_NEW rtl_uString_new
+
+// -----------------------------------------------------------------------
+
+#include <strimp.cxx>
+#include <strucvt.cxx>
+#include <strascii.cxx>
+
+UniString::UniString(char c): mpData(ImplAllocData(1)) { mpData->maStr[0] = c; }
+
+// -----------------------------------------------------------------------
+
+UniString UniString::CreateFromInt32( sal_Int32 n, sal_Int16 nRadix )
+{
+ sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT32];
+ BOOST_STATIC_ASSERT(RTL_USTR_MAX_VALUEOFINT32 <= STRING_MAXLEN);
+ return UniString(
+ aBuf,
+ static_cast< xub_StrLen >(rtl_ustr_valueOfInt32( aBuf, n, nRadix )) );
+}
+
+// -----------------------------------------------------------------------
+
+UniString UniString::CreateFromInt64( sal_Int64 n, sal_Int16 nRadix )
+{
+ sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT64];
+ BOOST_STATIC_ASSERT(RTL_USTR_MAX_VALUEOFINT64 <= STRING_MAXLEN);
+ return UniString(
+ aBuf,
+ static_cast< xub_StrLen >(rtl_ustr_valueOfInt64( aBuf, n, nRadix )) );
+}
+
+// -----------------------------------------------------------------------
+
+UniString UniString::CreateFromFloat( float f )
+{
+ sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFFLOAT];
+ BOOST_STATIC_ASSERT(RTL_USTR_MAX_VALUEOFFLOAT <= STRING_MAXLEN);
+ return UniString(
+ aBuf, static_cast< xub_StrLen >(rtl_ustr_valueOfFloat( aBuf, f )) );
+}
+
+// -----------------------------------------------------------------------
+
+UniString UniString::CreateFromDouble( double d )
+{
+ sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFDOUBLE];
+ BOOST_STATIC_ASSERT(RTL_USTR_MAX_VALUEOFDOUBLE <= STRING_MAXLEN);
+ return UniString(
+ aBuf, static_cast< xub_StrLen >(rtl_ustr_valueOfDouble( aBuf, d )) );
+}
+
+// -----------------------------------------------------------------------
+
+namespace { struct Empty : public rtl::Static< const UniString, Empty> {}; }
+const UniString& UniString::EmptyString()
+{
+ return Empty::get();
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int32 UniString::ToInt32() const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+
+ return rtl_ustr_toInt32( mpData->maStr, 10 );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 UniString::ToInt64() const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+
+ return rtl_ustr_toInt64( mpData->maStr, 10 );
+}
+
+// -----------------------------------------------------------------------
+
+float UniString::ToFloat() const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+
+ return rtl_ustr_toFloat( mpData->maStr );
+}
+
+// -----------------------------------------------------------------------
+
+double UniString::ToDouble() const
+{
+ DBG_CHKTHIS( UniString, DbgCheckUniString );
+
+ return rtl_ustr_toDouble( mpData->maStr );
+}
+
diff --git a/tools/source/testtoolloader/makefile.mk b/tools/source/testtoolloader/makefile.mk
new file mode 100644
index 000000000000..3d5cb8223e3f
--- /dev/null
+++ b/tools/source/testtoolloader/makefile.mk
@@ -0,0 +1,45 @@
+#*************************************************************************
+#
+# 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=TOOLS
+TARGET=testtoolloader
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= \
+ $(SLO)$/testtoolloader.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/testtoolloader/testtoolloader.cxx b/tools/source/testtoolloader/testtoolloader.cxx
new file mode 100644
index 000000000000..ca269ef6eea2
--- /dev/null
+++ b/tools/source/testtoolloader/testtoolloader.cxx
@@ -0,0 +1,185 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#include "tools/testtoolloader.hxx"
+#include <osl/module.h>
+#include <rtl/logfile.hxx>
+#include <vos/process.hxx>
+#include "tools/solar.h"
+#include "tools/string.hxx"
+#include "tools/debug.hxx"
+
+#include <comphelper/uieventslogger.hxx>
+
+using namespace rtl;
+
+namespace tools
+{
+ typedef void ( *pfunc_CreateRemoteControl)();
+ typedef void ( *pfunc_DestroyRemoteControl)();
+
+ typedef void ( *pfunc_CreateEventLogger)();
+ typedef void ( *pfunc_DestroyEventLogger)();
+
+static oslModule aTestToolModule = 0;
+// are we to be automated at all?
+static bool bAutomate = false;
+static bool bLoggerStarted = false;
+
+
+sal_uInt32 GetCommandLineParamCount()
+{
+ NAMESPACE_VOS( OStartupInfo ) aStartInfo;
+ return aStartInfo.getCommandArgCount();
+}
+
+String GetCommandLineParam( sal_uInt32 nParam )
+{
+ NAMESPACE_VOS( OStartupInfo ) aStartInfo;
+ ::rtl::OUString aParam;
+ NAMESPACE_VOS( OStartupInfo )::TStartupError eError = aStartInfo.getCommandArg( nParam, aParam );
+ if ( eError == NAMESPACE_VOS( OStartupInfo )::E_None )
+ return String( aParam );
+ else
+ {
+ DBG_ERROR( "Unable to get CommandLineParam" );
+ return String();
+ }
+}
+
+extern "C" { static void SAL_CALL thisModule() {} }
+
+void LoadLib()
+{
+ if ( !aTestToolModule )
+ {
+ aTestToolModule = osl_loadModuleRelative(
+ &thisModule,
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SVLIBRARY("sts"))).pData,
+ SAL_LOADMODULE_GLOBAL );
+ }
+}
+
+void InitTestToolLib()
+{
+ RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) ::InitTestToolLib" );
+
+ sal_uInt32 i;
+
+ for ( i = 0 ; i < GetCommandLineParamCount() ; i++ )
+ {
+ if ( GetCommandLineParam( i ).EqualsIgnoreCaseAscii("/enableautomation")
+ || GetCommandLineParam( i ).EqualsIgnoreCaseAscii("-enableautomation"))
+ {
+ bAutomate = true;
+ break;
+ }
+ }
+
+ if ( bAutomate )
+ {
+ OUString aFuncName( RTL_CONSTASCII_USTRINGPARAM( "CreateRemoteControl" ));
+
+ LoadLib();
+ if ( aTestToolModule )
+ {
+ oslGenericFunction pInitFunc = osl_getFunctionSymbol(
+ aTestToolModule, aFuncName.pData );
+ if ( pInitFunc )
+ (reinterpret_cast< pfunc_CreateRemoteControl >(pInitFunc))();
+ else
+ {
+ DBG_ERROR1( "Unable to get Symbol 'CreateRemoteControl' from library %s while loading testtool support.", SVLIBRARY( "sts" ) );
+ }
+ }
+ else
+ {
+ DBG_ERROR1( "Unable to access library %s while loading testtool support.", SVLIBRARY( "sts" ) );
+ }
+ }
+
+ if ( ::comphelper::UiEventsLogger::isEnabled() )
+ {
+ OUString aFuncName( RTL_CONSTASCII_USTRINGPARAM( "CreateEventLogger" ));
+
+ LoadLib();
+ if ( aTestToolModule )
+ {
+ oslGenericFunction pInitFunc = osl_getFunctionSymbol(
+ aTestToolModule, aFuncName.pData );
+ if ( pInitFunc )
+ {
+ (reinterpret_cast< pfunc_CreateEventLogger >(pInitFunc))();
+ bLoggerStarted = TRUE;
+ }
+ else
+ {
+ DBG_ERROR1( "Unable to get Symbol 'CreateEventLogger' from library %s while loading testtool support.", SVLIBRARY( "sts" ) );
+ }
+ }
+ else
+ {
+ DBG_ERROR1( "Unable to access library %s while loading testtool support.", SVLIBRARY( "sts" ) );
+ }
+ }
+}
+
+void DeInitTestToolLib()
+{
+ if ( aTestToolModule )
+ {
+ if ( bAutomate )
+ {
+ OUString aFuncName( RTL_CONSTASCII_USTRINGPARAM( "DestroyRemoteControl" ));
+
+ oslGenericFunction pDeInitFunc = osl_getFunctionSymbol(
+ aTestToolModule, aFuncName.pData );
+ if ( pDeInitFunc )
+ (reinterpret_cast< pfunc_DestroyRemoteControl >(pDeInitFunc))();
+ }
+
+ if ( bLoggerStarted /*::comphelper::UiEventsLogger::isEnabled()*/ )
+ {
+ OUString aFuncName( RTL_CONSTASCII_USTRINGPARAM( "DestroyEventLogger" ));
+
+ oslGenericFunction pDeInitFunc = osl_getFunctionSymbol(
+ aTestToolModule, aFuncName.pData );
+ if ( pDeInitFunc )
+ {
+ (reinterpret_cast< pfunc_DestroyEventLogger >(pDeInitFunc))();
+ bLoggerStarted = FALSE;
+ }
+ }
+
+ osl_unloadModule( aTestToolModule );
+ }
+}
+
+} // namespace tools
diff --git a/tools/source/zcodec/makefile.mk b/tools/source/zcodec/makefile.mk
new file mode 100644
index 000000000000..9067b45c3b5d
--- /dev/null
+++ b/tools/source/zcodec/makefile.mk
@@ -0,0 +1,47 @@
+#*************************************************************************
+#
+# 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=tools
+TARGET=zcodec
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(SYSTEM_ZLIB)" == "YES"
+CFLAGS+=-DSYSTEM_ZLIB
+.ENDIF
+SLOFILES= $(SLO)$/zcodec.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/tools/source/zcodec/zcodec.cxx b/tools/source/zcodec/zcodec.cxx
new file mode 100644
index 000000000000..f4f62162854a
--- /dev/null
+++ b/tools/source/zcodec/zcodec.cxx
@@ -0,0 +1,488 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+#include <tools/stream.hxx>
+#ifndef _ZLIB_H
+#ifdef SYSTEM_ZLIB
+#include "zlib.h"
+#else
+#include "zlib/zlib.h"
+#endif
+#endif
+#include <tools/zcodec.hxx>
+#include <rtl/crc.h>
+#include <osl/endian.h>
+
+// -----------
+// - Defines -
+// -----------
+
+#define PZSTREAM ((z_stream*) mpsC_Stream)
+
+/* gzip flag byte */
+#define GZ_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define GZ_HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define GZ_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define GZ_ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define GZ_COMMENT 0x10 /* bit 4 set: file comment present */
+#define GZ_RESERVED 0xE0 /* bits 5..7: reserved */
+
+static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
+
+
+// ----------
+// - ZCodec -
+// ----------
+
+ZCodec::ZCodec( ULONG nInBufSize, ULONG nOutBufSize, ULONG nMemUsage )
+ : mnCRC(0)
+{
+ mnMemUsage = nMemUsage;
+ mnInBufSize = nInBufSize;
+ mnOutBufSize = nOutBufSize;
+ mpsC_Stream = new z_stream;
+}
+
+ZCodec::ZCodec( void )
+ : mnCRC(0)
+{
+ mnMemUsage = MAX_MEM_USAGE;
+ mnInBufSize = DEFAULT_IN_BUFSIZE;
+ mnOutBufSize = DEFAULT_OUT_BUFSIZE;
+ mpsC_Stream = new z_stream;
+}
+
+// ------------------------------------------------------------------------
+
+ZCodec::~ZCodec()
+{
+ delete (z_stream*) mpsC_Stream;
+}
+
+// ------------------------------------------------------------------------
+
+void ZCodec::BeginCompression( ULONG nCompressMethod )
+{
+ mbInit = 0;
+ mbStatus = TRUE;
+ mbFinish = FALSE;
+ mpIStm = mpOStm = NULL;
+ mnInToRead = 0xffffffff;
+ mpInBuf = mpOutBuf = NULL;
+ PZSTREAM->total_out = PZSTREAM->total_in = 0;
+ mnCompressMethod = nCompressMethod;
+ PZSTREAM->zalloc = ( alloc_func )0;
+ PZSTREAM->zfree = ( free_func )0;
+ PZSTREAM->opaque = ( voidpf )0;
+ PZSTREAM->avail_out = PZSTREAM->avail_in = 0;
+}
+
+// ------------------------------------------------------------------------
+
+long ZCodec::EndCompression()
+{
+ long retvalue = 0;
+
+ if ( mbInit != 0 )
+ {
+ if ( mbInit & 2 ) // 1->decompress, 3->compress
+ {
+ do
+ {
+ ImplWriteBack();
+ }
+ while ( deflate( PZSTREAM, Z_FINISH ) != Z_STREAM_END );
+
+ ImplWriteBack();
+
+ retvalue = PZSTREAM->total_in;
+ deflateEnd( PZSTREAM );
+ }
+ else
+ {
+ retvalue = PZSTREAM->total_out;
+ inflateEnd( PZSTREAM );
+ }
+ delete[] mpOutBuf;
+ delete[] mpInBuf;
+ }
+ return ( mbStatus ) ? retvalue : -1;
+}
+
+
+// ------------------------------------------------------------------------
+
+long ZCodec::Compress( SvStream& rIStm, SvStream& rOStm )
+{
+ long nOldTotal_In = PZSTREAM->total_in;
+
+ if ( mbInit == 0 )
+ {
+ mpIStm = &rIStm;
+ mpOStm = &rOStm;
+ ImplInitBuf( FALSE );
+ mpInBuf = new BYTE[ mnInBufSize ];
+ }
+ while (( PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, mnInBufSize )) != 0 )
+ {
+ if ( PZSTREAM->avail_out == 0 )
+ ImplWriteBack();
+ if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
+ {
+ mbStatus = FALSE;
+ break;
+ }
+ };
+ return ( mbStatus ) ? (long)(PZSTREAM->total_in - nOldTotal_In) : -1;
+}
+
+// ------------------------------------------------------------------------
+
+long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm )
+{
+ int err;
+ ULONG nInToRead;
+ long nOldTotal_Out = PZSTREAM->total_out;
+
+ if ( mbFinish )
+ return PZSTREAM->total_out - nOldTotal_Out;
+
+ if ( mbInit == 0 )
+ {
+ mpIStm = &rIStm;
+ mpOStm = &rOStm;
+ ImplInitBuf( TRUE );
+ PZSTREAM->next_out = mpOutBuf = new BYTE[ PZSTREAM->avail_out = mnOutBufSize ];
+ }
+ do
+ {
+ if ( PZSTREAM->avail_out == 0 ) ImplWriteBack();
+ if ( PZSTREAM->avail_in == 0 && mnInToRead )
+ {
+ nInToRead = ( mnInBufSize > mnInToRead ) ? mnInToRead : mnInBufSize;
+ PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, nInToRead );
+ mnInToRead -= nInToRead;
+
+ if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
+ mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
+
+ }
+ err = inflate( PZSTREAM, Z_NO_FLUSH );
+ if ( err < 0 )
+ {
+ mbStatus = FALSE;
+ break;
+ }
+
+ }
+ while ( ( err != Z_STREAM_END) && ( PZSTREAM->avail_in || mnInToRead ) );
+ ImplWriteBack();
+
+ if ( err == Z_STREAM_END )
+ mbFinish = TRUE;
+ return ( mbStatus ) ? (long)(PZSTREAM->total_out - nOldTotal_Out) : -1;
+}
+
+// ------------------------------------------------------------------------
+
+long ZCodec::Write( SvStream& rOStm, const BYTE* pData, ULONG nSize )
+{
+ if ( mbInit == 0 )
+ {
+ mpOStm = &rOStm;
+ ImplInitBuf( FALSE );
+ }
+
+ PZSTREAM->avail_in = nSize;
+ PZSTREAM->next_in = (unsigned char*)pData;
+
+ while ( PZSTREAM->avail_in || ( PZSTREAM->avail_out == 0 ) )
+ {
+ if ( PZSTREAM->avail_out == 0 )
+ ImplWriteBack();
+
+ if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
+ {
+ mbStatus = FALSE;
+ break;
+ }
+ }
+ return ( mbStatus ) ? (long)nSize : -1;
+}
+
+// ------------------------------------------------------------------------
+
+long ZCodec::Read( SvStream& rIStm, BYTE* pData, ULONG nSize )
+{
+ int err;
+ ULONG nInToRead;
+
+ if ( mbFinish )
+ return 0; // PZSTREAM->total_out;
+
+ mpIStm = &rIStm;
+ if ( mbInit == 0 )
+ {
+ ImplInitBuf( TRUE );
+ }
+ PZSTREAM->avail_out = nSize;
+ PZSTREAM->next_out = pData;
+ do
+ {
+ if ( PZSTREAM->avail_in == 0 && mnInToRead )
+ {
+ nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
+ PZSTREAM->avail_in = mpIStm->Read (
+ PZSTREAM->next_in = mpInBuf, nInToRead);
+ mnInToRead -= nInToRead;
+
+ if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
+ mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
+
+ }
+ err = inflate( PZSTREAM, Z_NO_FLUSH );
+ if ( err < 0 )
+ {
+ // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
+ mbStatus = (err == Z_BUF_ERROR);
+ break;
+ }
+ }
+ while ( (err != Z_STREAM_END) &&
+ (PZSTREAM->avail_out != 0) &&
+ (PZSTREAM->avail_in || mnInToRead) );
+ if ( err == Z_STREAM_END )
+ mbFinish = TRUE;
+
+ return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
+}
+
+// ------------------------------------------------------------------------
+
+long ZCodec::ReadAsynchron( SvStream& rIStm, BYTE* pData, ULONG nSize )
+{
+ int err = 0;
+ ULONG nInToRead;
+
+ if ( mbFinish )
+ return 0; // PZSTREAM->total_out;
+
+ if ( mbInit == 0 )
+ {
+ mpIStm = &rIStm;
+ ImplInitBuf( TRUE );
+ }
+ PZSTREAM->avail_out = nSize;
+ PZSTREAM->next_out = pData;
+ do
+ {
+ if ( PZSTREAM->avail_in == 0 && mnInToRead )
+ {
+ nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
+
+ ULONG nStreamPos = rIStm.Tell();
+ rIStm.Seek( STREAM_SEEK_TO_END );
+ ULONG nMaxPos = rIStm.Tell();
+ rIStm.Seek( nStreamPos );
+ if ( ( nMaxPos - nStreamPos ) < nInToRead )
+ {
+ rIStm.SetError( ERRCODE_IO_PENDING );
+ err= ! Z_STREAM_END; // TODO What is appropriate code for this?
+ break;
+ }
+
+ PZSTREAM->avail_in = mpIStm->Read (
+ PZSTREAM->next_in = mpInBuf, nInToRead);
+ mnInToRead -= nInToRead;
+
+ if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
+ mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
+
+ }
+ err = inflate( PZSTREAM, Z_NO_FLUSH );
+ if ( err < 0 )
+ {
+ // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
+ mbStatus = (err == Z_BUF_ERROR);
+ break;
+ }
+ }
+ while ( (err != Z_STREAM_END) &&
+ (PZSTREAM->avail_out != 0) &&
+ (PZSTREAM->avail_in || mnInToRead) );
+ if ( err == Z_STREAM_END )
+ mbFinish = TRUE;
+
+ return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
+}
+
+// ------------------------------------------------------------------------
+
+void ZCodec::ImplWriteBack()
+{
+ ULONG nAvail = mnOutBufSize - PZSTREAM->avail_out;
+
+ if ( nAvail )
+ {
+ if ( mbInit & 2 && ( mnCompressMethod & ZCODEC_UPDATE_CRC ) )
+ mnCRC = UpdateCRC( mnCRC, mpOutBuf, nAvail );
+ mpOStm->Write( PZSTREAM->next_out = mpOutBuf, nAvail );
+ PZSTREAM->avail_out = mnOutBufSize;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ZCodec::SetBreak( ULONG nInToRead )
+{
+ mnInToRead = nInToRead;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ZCodec::GetBreak( void )
+{
+ return ( mnInToRead + PZSTREAM->avail_in );
+}
+
+// ------------------------------------------------------------------------
+
+void ZCodec::SetCRC( ULONG nCRC )
+{
+ mnCRC = nCRC;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ZCodec::GetCRC()
+{
+ return mnCRC;
+}
+
+// ------------------------------------------------------------------------
+
+void ZCodec::ImplInitBuf ( BOOL nIOFlag )
+{
+ if ( mbInit == 0 )
+ {
+ if ( nIOFlag )
+ {
+ mbInit = 1;
+ if ( mbStatus && ( mnCompressMethod & ZCODEC_GZ_LIB ) )
+ {
+ BYTE n1, n2, j, nMethod, nFlags;
+ for ( int i = 0; i < 2; i++ ) // gz - magic number
+ {
+ *mpIStm >> j;
+ if ( j != gz_magic[ i ] )
+ mbStatus = FALSE;
+ }
+ *mpIStm >> nMethod;
+ *mpIStm >> nFlags;
+ if ( nMethod != Z_DEFLATED )
+ mbStatus = FALSE;
+ if ( ( nFlags & GZ_RESERVED ) != 0 )
+ mbStatus = FALSE;
+ /* Discard time, xflags and OS code: */
+ mpIStm->SeekRel( 6 );
+ /* skip the extra field */
+ if ( nFlags & GZ_EXTRA_FIELD )
+ {
+ *mpIStm >> n1 >> n2;
+ mpIStm->SeekRel( n1 + ( n2 << 8 ) );
+ }
+ /* skip the original file name */
+ if ( nFlags & GZ_ORIG_NAME)
+ {
+ do
+ {
+ *mpIStm >> j;
+ }
+ while ( j && !mpIStm->IsEof() );
+ }
+ /* skip the .gz file comment */
+ if ( nFlags & GZ_COMMENT )
+ {
+ do
+ {
+ *mpIStm >> j;
+ }
+ while ( j && !mpIStm->IsEof() );
+ }
+ /* skip the header crc */
+ if ( nFlags & GZ_HEAD_CRC )
+ mpIStm->SeekRel( 2 );
+ if ( mbStatus )
+ mbStatus = ( inflateInit2( PZSTREAM, -MAX_WBITS) != Z_OK ) ? FALSE : TRUE;
+ }
+ else
+ {
+ mbStatus = ( inflateInit( PZSTREAM ) >= 0 );
+ }
+ mpInBuf = new BYTE[ mnInBufSize ];
+ }
+ else
+ {
+ mbInit = 3;
+
+ mbStatus = ( deflateInit2_( PZSTREAM, mnCompressMethod & 0xff, Z_DEFLATED,
+ MAX_WBITS, mnMemUsage, ( mnCompressMethod >> 8 ) & 0xff,
+ ZLIB_VERSION, sizeof( z_stream ) ) >= 0 );
+
+ PZSTREAM->next_out = mpOutBuf = new BYTE[ PZSTREAM->avail_out = mnOutBufSize ];
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ZCodec::UpdateCRC ( ULONG nLatestCRC, ULONG nNumber )
+{
+
+#ifdef OSL_LITENDIAN
+ nNumber = SWAPLONG( nNumber );
+#endif
+ return rtl_crc32( nLatestCRC, &nNumber, 4 );
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ZCodec::UpdateCRC ( ULONG nLatestCRC, BYTE* pSource, long nDatSize)
+{
+ return rtl_crc32( nLatestCRC, pSource, nDatSize );
+}
+
+// ------------------------------------------------------------------------
+
+void GZCodec::BeginCompression( ULONG nCompressMethod )
+{
+ ZCodec::BeginCompression( nCompressMethod | ZCODEC_GZ_LIB );
+};
+
+