diff options
author | Jens-Heiner Rechtien <hr@openoffice.org> | 2000-09-18 16:07:07 +0000 |
---|---|---|
committer | Jens-Heiner Rechtien <hr@openoffice.org> | 2000-09-18 16:07:07 +0000 |
commit | 8ab086b6cc054501bfbf7ef6fa509c393691e860 (patch) | |
tree | 324d51845d7f1a2f4e02a14db22fb5947137c822 /tools/source | |
parent | 411e68cc54ae97eebd79ae3a9cb2971b74cb2a9e (diff) |
initial import
Diffstat (limited to 'tools/source')
71 files changed, 52531 insertions, 0 deletions
diff --git a/tools/source/communi/geninfo.cxx b/tools/source/communi/geninfo.cxx new file mode 100644 index 000000000000..f817b58b1dc3 --- /dev/null +++ b/tools/source/communi/geninfo.cxx @@ -0,0 +1,469 @@ +/************************************************************************* + * + * $RCSfile: geninfo.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#include "geninfo.hxx" +#include <stdio.h> + +// +// class GenericInformation +// + +/*****************************************************************************/ +GenericInformation::GenericInformation( const ByteString &rKey, + const ByteString &rValue, + GenericInformationList *pParentList, + GenericInformationList *pSubInfos ) +/*****************************************************************************/ + : ByteString( rKey ), + sValue( rValue ), + pParent( pParentList ), + pInfoList( pSubInfos ) +{ + // 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 ), + pParent(NULL), + pInfoList( 0L ) +{ + 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) +/*****************************************************************************/ +{ + 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 Hlfte der Eintrge gelscht +/* 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; + USHORT nTmp = 0; + 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; + } + +// ### GH: dieser Block schein berflssig zu sein + ByteString sKey( pInfo->GetBuffer()); + if ( Count() == 1 ) { + ByteString sCandidate( *GetObject( 0 )); + if ( sCandidate.ToUpperAscii() == sKey.ToUpperAscii()) { + // 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 berflssig zu sein + + ULONG nActPos = nStart + (( nEnd - nStart ) / 2 ); + ByteString sCandidate = ByteString( *GetObject( nActPos )); + + if ( sCandidate.ToUpperAscii() == sKey.ToUpperAscii()) { + // 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; +} + +/***************************************************************************** +BOOL GenericInformationList::InsertInfo( const String &rPathKey, + const String &rValue, + BOOL bNewPath = FALSE) +/***************************************************************************** +{ + GenericInformation *pInfo; + + if ( !pPathKey || '\0'==pPathKey[0] ) + return FALSE; + + char *pNextItem = strchr( pPathKey, '/' ); + if ( !pNextItem ) { // kein Token mehr gefunden + /* aus dem PathKey kann nun eine GenericInformation gebildet + * und eingefuegt werden * + pInfo = GetInfo( pPathKey, FALSE ); + // Object besteht nicht und soll auch nicht nachgebildet werden + if ( !pInfo && !bNewPath ) + return FALSE; + // erzeuge neue GI und stopfe sie in die Liste. Fertig ! + pInfo = new GenericInformation( String( pPathKey ), String( pValue ), 0, 0 ); + return InsertInfo( pInfo, TRUE ); + } + else { // noch nicht fertig, muss noch tiefer in den Baum gehen + // SuchString anfertigen + String sSearch ( pPathKey ); + sSearch.Erase ( USHORT(pNextItem - pPathKey)); + // suchen.. + pInfo = GetInfo( sSearch, FALSE ); + if ( !pInfo && ! bNewPath) // subinfo nicht vorhanden und + return FALSE; // ich darf keinen neuen Pfad anlegen + + if ( !pInfo ) + // neue Subinfo machen und einfuegen + pInfo = new GenericInformation ( sSearch , "", this, 0 ); + + pNextItem++; + return pInfo->InsertSubInfo( pNextItem, pValue, bNewPath ); + } + } +} +*/ + +/*****************************************************************************/ +void GenericInformationList::RemoveInfo( GenericInformation *pInfo, + BOOL bDelete ) +/*****************************************************************************/ +{ + Remove( pInfo ); + if ( bDelete ) + delete pInfo; + if ( Count() == 0 && pOwner ) // Leere Listen entfernen; + { + SetOwner( NULL ); + delete this; + } +} + +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..970f41a6121a --- /dev/null +++ b/tools/source/communi/makefile.mk @@ -0,0 +1,102 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=TOOLS +TARGET=communi + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +CXXFILES= simplecm.cxx bcst.cxx + +OBJFILES= $(OBJ)$/simplecm.obj \ + $(OBJ)$/bcst.obj \ + $(OBJ)$/persbcst.obj \ + $(OBJ)$/iiclient.obj \ + $(OBJ)$/siclient.obj \ + $(OBJ)$/infocom.obj \ + $(OBJ)$/bsockcon.obj \ + $(OBJ)$/ssockcon.obj \ + $(OBJ)$/parser.obj \ + $(OBJ)$/geninfo.obj \ + +SLOFILES= $(SLO)$/simplecm.obj \ + $(SLO)$/bcst.obj \ + $(SLO)$/persbcst.obj \ + $(SLO)$/iiclient.obj \ + $(SLO)$/siclient.obj \ + $(SLO)$/infocom.obj \ + $(SLO)$/bsockcon.obj \ + $(SLO)$/ssockcon.obj \ + $(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..99160560504a --- /dev/null +++ b/tools/source/communi/parser.cxx @@ -0,0 +1,438 @@ +/************************************************************************* + * + * $RCSfile: parser.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <stdio.h> +#include <stream.hxx> +#include <fsys.hxx> + +#include "iparser.hxx" +#include "geninfo.hxx" + + + +// +// class InformationParser +// + +const char InformationParser::cKeyLevelChars = '\t'; + +/*****************************************************************************/ +InformationParser::InformationParser( BOOL bReplace ) +/*****************************************************************************/ + : pActStream( NULL ), + nErrorCode( 0 ), + nErrorLine( 0 ), + nActLine( 0 ), + bRecover( FALSE ), + sOldLine( "" ), + sErrorText( "" ), + bReplaceVariables( bReplace ), + nLevel( 0 ), + sUPD( "" ), + sVersion( "" ) +{ +} + +/*****************************************************************************/ +InformationParser::~InformationParser() +/*****************************************************************************/ +{ +} + +/*****************************************************************************/ +ByteString &InformationParser::ReadLine() +/*****************************************************************************/ +{ + ByteString sLine; + if ( bRecover ) { + bRecover = FALSE; + } + else { + pActStream->ReadLine( sLine ); + sLine.EraseLeadingChars( 0x09 ); + sLine.EraseLeadingChars( ' ' ); + + if ( bReplaceVariables ) { + while( sLine.SearchAndReplace( "%UPD", sUPD ) != (USHORT)-1 ); + while( sLine.SearchAndReplace( "%VERSION", sVersion ) != (USHORT)-1 ); + } + + 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( "" ); + + // 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 ); + } + else { + Recover(); + pInfo = new GenericInformation( sKey, sValue, pExistingList ); + } + + return pInfo; +} + +/*****************************************************************************/ +void InformationParser::Recover() +/*****************************************************************************/ +{ + bRecover = TRUE; +} + +/*****************************************************************************/ +BOOL InformationParser::Save( SvStream &rOutStream, + const GenericInformationList *pSaveList, + USHORT nLevel ) +/*****************************************************************************/ +{ + USHORT i; + ULONG nInfoListCount; + ByteString sTmpStr; + GenericInformation *pGenericInfo; + GenericInformationList *pGenericInfoList; + + for ( nInfoListCount = 0; nInfoListCount < pSaveList->Count(); nInfoListCount++) { + // Key-Value Paare schreiben + pGenericInfo = pSaveList->GetObject( nInfoListCount ); + sTmpStr = ""; + for( i=0; i<nLevel; i++) + sTmpStr += cKeyLevelChars; + sTmpStr += pGenericInfo->GetBuffer(); + sTmpStr += ' '; + sTmpStr += pGenericInfo->GetValue(); + if ( !rOutStream.WriteLine( sTmpStr ) ) + return FALSE; + + // wenn vorhanden, bearbeite recursive die Sublisten + if (( pGenericInfoList = pGenericInfo->GetSubList() ) != 0) { + // oeffnende Klammer + sTmpStr = ""; + for( i=0; i<nLevel; i++) + sTmpStr += cKeyLevelChars; + sTmpStr += '{'; + if ( !rOutStream.WriteLine( sTmpStr ) ) + return FALSE; + // recursiv die sublist abarbeiten + if ( !Save( rOutStream, pGenericInfoList, nLevel+1 ) ) + return FALSE; + // schliessende Klammer + sTmpStr = ""; + for( i=0; i<nLevel; i++) + sTmpStr += cKeyLevelChars; + 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 ); + GenericInformation *pInfo = new GenericInformation( + sFileKey, + ByteString( "" ), + pList, pSubList ); + } + + return pList; +} + +/*****************************************************************************/ +BOOL InformationParser::Save( SvFileStream &rSourceStream, + const GenericInformationList *pSaveList ) +/*****************************************************************************/ +{ + if ( !rSourceStream.IsOpen() || !Save( (SvStream &)rSourceStream, pSaveList, 0 )) + return FALSE; + + return TRUE; +} + +/*****************************************************************************/ +BOOL InformationParser::Save( SvMemoryStream &rSourceStream, + const GenericInformationList *pSaveList ) +/*****************************************************************************/ +{ + return Save( (SvStream &)rSourceStream, pSaveList, 0 ); +} + +/*****************************************************************************/ +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( nErrorLine ); + sErrorText += ByteString( "): " ); + + switch ( nErrorCode ) { + case IP_NO_ERROR: + sErrorText += ByteString( "Keine Fehler aufgetereten" ); + break; + case IP_UNEXPECTED_EOF: + sErrorText += ByteString( "Ungltiges Dateiende!" ); + break; + } + + return sErrorText; +} + + diff --git a/tools/source/datetime/datetime.cxx b/tools/source/datetime/datetime.cxx new file mode 100644 index 000000000000..e3cf4a8895fe --- /dev/null +++ b/tools/source/datetime/datetime.cxx @@ -0,0 +1,349 @@ +/************************************************************************* + * + * $RCSfile: datetime.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <datetime.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 +|* +*************************************************************************/ + +ULONG DateTime::GetSecFromDateTime( const Date& rDate ) const +{ + if ( Date::operator<( rDate ) ) + return 0; + else + { + ULONG nSec = *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 = 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; +} diff --git a/tools/source/datetime/makefile.mk b/tools/source/datetime/makefile.mk new file mode 100644 index 000000000000..5a53e0a0039f --- /dev/null +++ b/tools/source/datetime/makefile.mk @@ -0,0 +1,88 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=datetime + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/tdate.obj \ + $(SLO)$/ttime.obj \ + $(SLO)$/datetime.obj + +.IF "$(UPDATER)"!="" +OBJFILES= $(OBJ)$/tdate.obj \ + $(OBJ)$/ttime.obj \ + $(OBJ)$/datetime.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/tools/source/datetime/tdate.cxx b/tools/source/datetime/tdate.cxx new file mode 100644 index 000000000000..72c188944096 --- /dev/null +++ b/tools/source/datetime/tdate.cxx @@ -0,0 +1,540 @@ +/************************************************************************* + * + * $RCSfile: tdate.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#if defined( OS2 ) +#include <svpm.h> +#elif defined( WNT ) +#include <svwin.h> +#elif defined( WIN ) || defined( DOS ) +#include <dos.h> +#elif defined( MAC ) +#include "mac_start.h" +#ifndef __OSUTILS__ +#include "OSUtils.h" +#endif +#include "mac_end.h" +#else +#include <time.h> +#endif + +#include <debug.hxx> +#include <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 ( ((nYear % 4) == 0) && ((nYear % 100) != 0) || + ((nYear % 400) == 0) ) + return aDaysInMonth[nMonth-1] + 1; + else + return aDaysInMonth[nMonth-1]; + } +} + +// ----------------------------------------------------------------------- + +static long 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); +#elif ( defined( WIN ) || defined( DOS )) && !defined( BLC ) + _dosdate_t aDate; + _dos_getdate( &aDate ); + + // Datum zusammenbauen + nDate = ((ULONG)aDate.day) + + (((ULONG)aDate.month)*100) + + (((ULONG)aDate.year)*10000); +#elif ( defined( WIN ) || defined( DOS )) && defined( BLC ) + dosdate_t aDate; + _dos_getdate( &aDate ); + + // Datum zusammenbauen + nDate = ((ULONG)aDate.day) + + (((ULONG)aDate.month)*100) + + (((ULONG)aDate.year)*10000); +#elif defined( MAC ) + DateTimeRec dt; + ::GetTime(&dt); + nDate = ((ULONG)dt.day) + + (((ULONG)dt.month)*100) + + (((ULONG)dt.year )*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 += ::DaysInMonth( i, GetYear() ); + return nDay; +} + +// ----------------------------------------------------------------------- + +USHORT Date::GetWeekOfYear( DayOfWeek eStartDay, + WeekCountStart eWeekStart ) 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 ( eWeekStart == WEEKCOUNT_FIRSTDAY ) + { + 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 ( eWeekStart == WEEKCOUNT_FIRSTFULLWEEK ) + { + 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, eWeekStart ); + } + } + else // ( eWeekStart == WEEKCOUNT_FIRST4DAYWEEK ) + { + // x_monday - thursday + if ( n1WDay < 4 ) + nWeek = 1; + // friday + else if ( n1WDay == 4 ) + nWeek = 53; + // saturday + else if ( n1WDay == 5 ) + { + // 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, eWeekStart ); + } + } + } + + 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 = DateToDays( rDate1.GetDay(), rDate1.GetMonth(), + rDate1.GetYear() ); + ULONG nTempDays2 = 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..af1f2ef267e1 --- /dev/null +++ b/tools/source/datetime/ttime.cxx @@ -0,0 +1,531 @@ +/************************************************************************* + * + * $RCSfile: ttime.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _TOOLS_TIME_CXX + +#if defined( OS2 ) +#define INCL_DOSMISC +#include <svpm.h> +#elif defined( WNT ) +#include <svwin.h> +#elif defined( WIN ) +#include <svwin.h> +#include <dos.h> +#elif defined( DOS ) +#include <dos.h> +#elif defined UNX +#include <limits.h> +#ifdef IRIX +#include <unistd.h> +#endif +#include <sys/times.h> +#elif defined( MAC ) +#include "mac_start.h" +#ifndef __OSUTILS__ +#include "OSUtils.h" +#include <MAC_Timer.h> +#include "mac_end.h" +#endif +#endif + +#include <time.h> +#include <time.hxx> + +#ifdef UNX +#include <math.h> +#endif + +#ifndef WNT +#ifndef localtime_r +extern "C" { +struct tm *localtime_r(const time_t *timep, struct tm *buffer); +} +#endif + +#ifndef gmtime_r +extern "C" { +struct tm *gmtime_r(const time_t *timep, struct tm *buffer); +} +#endif +#endif + +// ======================================================================= + +static long TimeToSec100( const Time& rTime ) +{ + short nSign = (rTime.GetTime() >= 0) ? +1 : -1; + long nHour = rTime.GetHour(); + long nMin = rTime.GetMin(); + long nSec = rTime.GetSec(); + long n100Sec = rTime.Get100Sec(); + +// Wegen Interal Compiler Error bei MSC, etwas komplizierter +// return (n100Sec + (nSec*100) + (nMin*60*100) + (nHour*60*60*100) * nSign); + + long nRet = n100Sec; + nRet += nSec*100; + nRet += nMin*60*100; + nRet += nHour*60*60*100; + + return (nRet * nSign); +} + +// ----------------------------------------------------------------------- + +static Time Sec100ToTime( long 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 = (((long)aDateTime.hours)*1000000) + + (((long)aDateTime.minutes)*10000) + + (((long)aDateTime.seconds)*100) + + ((long)aDateTime.hundredths); +#elif defined( WNT ) + SYSTEMTIME aDateTime; + GetLocalTime( &aDateTime ); + + // Zeit zusammenbauen + nTime = (((long)aDateTime.wHour)*1000000) + + (((long)aDateTime.wMinute)*10000) + + (((long)aDateTime.wSecond)*100) + + ((long)aDateTime.wMilliseconds/10); +#elif ( defined( WIN ) || defined( DOS ) ) && !defined ( BLC ) + _dostime_t aTime; + _dos_gettime( &aTime ); + + // Zeit zusammenbauen + nTime = (((long)aTime.hour)*1000000) + + (((long)aTime.minute)*10000) + + (((long)aTime.second)*100) + + ((long)aTime.hsecond); +#elif ( defined( WIN ) || defined( DOS ) ) && defined ( BLC ) + dostime_t aTime; + _dos_gettime( &aTime ); + + // Zeit zusammenbauen + nTime = (((long)aTime.hour)*1000000) + + (((long)aTime.minute)*10000) + + (((long)aTime.second)*100) + + ((long)aTime.hsecond); +#elif defined( MAC ) + DateTimeRec dt; + ::GetTime(&dt); + nTime = (((long)dt.hour)*1000000) + + (((long)dt.minute)*10000) + + (((long)dt.second)*100); +#else + time_t nTmpTime; + struct tm aTime; + + // Zeit ermitteln + nTmpTime = time( 0 ); + + // Zeit zusammenbauen + if ( localtime_r( &nTmpTime, &aTime ) ) + { + nTime = (((long)aTime.tm_hour)*1000000) + + (((long)aTime.tm_min)*10000) + + (((long)aTime.tm_sec)*100); + } + else + nTime = 0; +#endif +} + +// ----------------------------------------------------------------------- + +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 = (long)(n100Sec + (nSec*100) + (nMin*10000) + (nHour*1000000)); +} + +// ----------------------------------------------------------------------- + +void Time::SetHour( USHORT nNewHour ) +{ + short nSign = (nTime >= 0) ? +1 : -1; + long nMin = GetMin(); + long nSec = GetSec(); + long n100Sec = Get100Sec(); + + nTime = (n100Sec + (nSec*100) + (nMin*10000) + + (((long)nNewHour)*1000000)) * nSign; +} + +// ----------------------------------------------------------------------- + +void Time::SetMin( USHORT nNewMin ) +{ + short nSign = (nTime >= 0) ? +1 : -1; + long nHour = GetHour(); + long nSec = GetSec(); + long n100Sec = Get100Sec(); + + // kein Ueberlauf + nNewMin = nNewMin % 60; + + nTime = (n100Sec + (nSec*100) + (((long)nNewMin)*10000) + + (nHour*1000000)) * nSign; +} + +// ----------------------------------------------------------------------- + +void Time::SetSec( USHORT nNewSec ) +{ + short nSign = (nTime >= 0) ? +1 : -1; + long nHour = GetHour(); + long nMin = GetMin(); + long n100Sec = Get100Sec(); + + // kein Ueberlauf + nNewSec = nNewSec % 60; + + nTime = (n100Sec + (((long)nNewSec)*100) + (nMin*10000) + + (nHour*1000000)) * nSign; +} + +// ----------------------------------------------------------------------- + +void Time::Set100Sec( USHORT nNew100Sec ) +{ + short nSign = (nTime >= 0) ? +1 : -1; + long nHour = GetHour(); + long nMin = GetMin(); + long nSec = GetSec(); + + // kein Ueberlauf + nNew100Sec = nNew100Sec % 100; + + nTime = (((long)nNew100Sec) + (nSec*100) + (nMin*10000) + + (nHour*1000000)) * nSign; +} + +// ----------------------------------------------------------------------- + +long Time::GetMSFromTime() const +{ + short nSign = (nTime >= 0) ? +1 : -1; + long nHour = GetHour(); + long nMin = GetMin(); + long nSec = GetSec(); + long n100Sec = Get100Sec(); + + return (((nHour*3600000)+(nMin*60000)+(nSec*1000)+(n100Sec*10))*nSign); +} + +// ----------------------------------------------------------------------- + +void Time::MakeTimeFromMS( long nMS ) +{ + short nSign; + if ( nMS < 0 ) + { + nMS *= -1; + nSign = -1; + } + else + nSign = 1; + + Time aTime( 0, 0, 0, nMS/10 ); + SetTime( aTime.GetTime() * nSign ); +} + +// ----------------------------------------------------------------------- + +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 ) ); +} + +// ----------------------------------------------------------------------- + +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 ); + long 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; +#elif ( defined( WIN ) || defined( DOS ) ) && defined ( BLC ) + static ULONG nCacheTicks = 0; + static long nCacheSecOffset = -1; + ULONG nTicks = Time::GetSystemTicks(); + time_t nTime; + tm aTM; + long nLocalTime; + long nUTC; + short nTempTime; + + // Evt. Wert neu ermitteln + if ( (nCacheSecOffset == -1) || ((nTicks - nCacheTicks) > 360000) ) + { + nTime = time( 0 ); + tm aTMTmp; + aTM = *localtime_r( &nTime, &aTMTmp); + nLocalTime = mktime( &aTM ); + aTM = *gmtime_r( &nTime, &aTMTmp); + nUTC = mktime( &aTM ); + nCacheTicks = nTicks; + nCacheSecOffset = (nLocalTime-nUTC) / 60; + } + + nTempTime = (short)Abs( nCacheSecOffset ); + Time aTime( 0, (USHORT)nTempTime ); + if ( nCacheSecOffset < 0 ) + aTime = -aTime; + return aTime; +#else + static ULONG nCacheTicks = 0; + static long nCacheSecOffset = -1; + ULONG nTicks = Time::GetSystemTicks(); + time_t nTime; + tm aTM; + long nLocalTime; + long 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( WIN ) || defined( WNT ) + return (ULONG)GetTickCount(); +#elif defined( OS2 ) + PM_ULONG nClock; + DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) ); + return (ULONG)nClock; +#elif defined( MAC ) + long long millisec; + Microseconds((UnsignedWide *)&millisec); + millisec = ( millisec + 500L ) / 1000L; + return (ULONG)millisec; +#else + static ULONG nImplTicksPerSecond = 0; + static double dImplTicksPerSecond; + static double dImplTicksULONGMAX; + struct tms aTms; + ULONG nTicks = (ULONG)times( &aTms ); + + if ( !nImplTicksPerSecond ) + { + nImplTicksPerSecond = CLK_TCK; + dImplTicksPerSecond = nImplTicksPerSecond; + dImplTicksULONGMAX = (double)(ULONG)ULONG_MAX; + } + + double fTicks = nTicks; + fTicks *= 1000; + fTicks /= dImplTicksPerSecond; + fTicks = fmod (fTicks, dImplTicksULONGMAX); + + return (ULONG)fTicks; +#endif +} + +// ----------------------------------------------------------------------- + +ULONG Time::GetProcessTicks() +{ +#if defined( WIN ) || defined( WNT ) + return (ULONG)GetTickCount(); +#elif defined( OS2 ) + PM_ULONG nClock; + DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) ); + return (ULONG)nClock; +#elif defined( MAC ) + long long millisec; + Microseconds((UnsignedWide *)&millisec); + millisec = ( millisec + 500L ) / 1000L; + return (ULONG)millisec; +#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..cfa1ce5dfa1b --- /dev/null +++ b/tools/source/debug/debug.cxx @@ -0,0 +1,1581 @@ +/************************************************************************* + * + * $RCSfile: debug.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _TOOLS_DEBUG_CXX + +#ifndef MAC +#if defined (UNX) || defined (GCC) +#include <unistd.h> +#else +#include <direct.h> +#endif +#endif + +#include <time.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#ifdef OS2 +#define INCL_DOSSEMAPHORES +#define INCL_DOSMISC +#define INCL_WINDIALOGS +#include <svpm.h> +#endif + +#if defined ( WNT ) +#include <svwin.h> +#endif + +#include <debug.hxx> + +// ======================================================================= + +#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 pDbgPrintShell; + DbgPrintLine pDbgPrintTestTool; + PointerList* pProfList; + PointerList* pXtorList; + DbgTestSolarMutexProc pDbgTestSolarMutex; +}; + +#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 = +{ + { + DBG_TEST_RESOURCE | DBG_TEST_MEM_INIT, + TRUE, + DBG_OUT_NULL, + DBG_OUT_NULL, + DBG_OUT_MSGBOX, + 0x77, + 0x55, + 0x33, + "", + "", + "", + "", + "", + "", + }, + FALSE, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +#ifndef MAC +static sal_Char aCurPath[260]; +#endif + +static int bDbgImplInMain = FALSE; +static sal_Char aBuf[DBG_BUF_MAXLEN]; +static sal_Char aBufOut[DBG_BUF_MAXLEN]; + +// ======================================================================= + +#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 +} + +// ======================================================================= + +// Aus DBMEM.CXX +#if (defined( WNT ) || defined( OS2 ) || defined( MAC )) && !defined ( SVX_LIGHT ) +#define SV_MEMMGR +#endif +#ifdef SV_MEMMGR +void DbgImpCheckMemory( void* p = NULL ); +void DbgImpCheckMemoryDeInit(); +void DbgImpMemoryInfo( sal_Char* pBuf ); +#endif + +#if defined( OS2 ) +#define FILE_LINEEND "\r\n" +#else +#define FILE_LINEEND "\n" +#endif + +// ======================================================================= + +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; +#elif defined( MAC ) + debugstr( (sal_Char*)pLine ); + return TRUE; +#else + return FALSE; +#endif +} + +// ----------------------------------------------------------------------- + +static BOOL ImplCoreDump( const sal_Char* pMsg ) +{ +#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 ) + PM_ULONG nClock; + DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) ); + return (ULONG)nClock; +#elif defined( MAC ) + long long millisec; + Microseconds((UnsignedWide *)&millisec); + millisec = ( millisec + 500L ) / 1000L; + return (ULONG)millisec; +#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 +} + +// ----------------------------------------------------------------------- + +#if defined( OS2 ) + +typedef HFILE FILETYPE; + +static FILETYPE FileOpen( const sal_Char* pFileName, const sal_Char* pOpenMode ) +{ + HFILE hFile = 0; + ULONG lAction = 0; + ULONG nOpen1 = FILE_OPEN; + ULONG nOpen2 = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY; + + if ( *pOpenMode == 'w' ) + { + nOpen1 = OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW; + nOpen2 = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE; + } + else if ( *pOpenMode == 'a' ) + { + nOpen1 = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + nOpen2 = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE; + } + + APIRET nRet = DosOpen( pFileName, &hFile, &lAction, 0, + FILE_NORMAL, nOpen1, nOpen2, 0L ); + + if ( nRet ) + return NULL; + else + { + if ( *pOpenMode == 'a' ) + { + ULONG nTemp; + DosSetFilePtr( hFile, 0, FILE_END, &nTemp ); + } + + return hFile; + } +} + +static ULONG FileRead( void* pData, int n1, int n2, FILETYPE pFile ) +{ + ULONG nRead; + DosRead( pFile, pData, n1*n2, &nRead ); + return nRead; +} + +static ULONG FileWrite( void* pData, int n1, int n2, FILETYPE pFile ) +{ + ULONG nWritten; + DosWrite( pFile, pData, n1*n2, &nWritten ); + return nWritten; +} + +static void FilePrintF( FILETYPE pFile, const sal_Char* pFStr, ... ) +{ + static sal_Char aTempBuf[DBG_BUF_MAXLEN]; + + va_list pList; + + va_start( pList, pFStr ); + vsprintf( aTempBuf, pFStr, pList ); + va_end( pList ); + + FileWrite( aTempBuf, strlen( aTempBuf ), 1, pFile ); +} + +static void FileClose( FILETYPE pFile ) +{ + DosClose( pFile ); +} + +#else + +typedef FILE* FILETYPE; +#define FileOpen fopen +#define FileRead fread +#define FileWrite fwrite +#define FilePrintF fprintf +#define FileClose fclose + +#endif + +// ======================================================================= + +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 ) +{ +#if defined( UNX ) + const sal_Char* pName = getenv("DBGSV_INIT"); + if ( !pName ) + pName = ".dbgsv.init"; + strcpy( pStr, pName ); +#elif defined( WNT ) + const sal_Char* pName = getenv("DBGSV_INIT"); + if ( pName ) + strcpy( pStr, pName ); + else + GetProfileStringA( "sv", "dbgsv", "dbgsv.ini", pStr, 200 ); +#elif defined( OS2 ) + PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSV", + "dbgsv.ini", (PSZ)pStr, 200 ); +#else + strcpy( pStr, "dbgsv.ini" ); +#endif +} + +// ----------------------------------------------------------------------- + +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 int DbgImplIsAllErrorOut() +{ +#if defined( WNT ) + const sal_Char* pName = getenv("UPDATER"); + if ( pName && (strcmp( pName, "YES" ) == 0) ) + return TRUE; + if ( GetProfileInt( "sv", "dbgallerrorout", 0 ) ) + return TRUE; + else + return FALSE; +#elif defined( OS2 ) + const sal_Char* pName = getenv("UPDATER"); + if ( pName && (strcmp( pName, "YES" ) == 0) ) + return TRUE; + if ( PrfQueryProfileInt( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGALLERROROUT", 0 ) ) + return TRUE; + else + return FALSE; +#else + return TRUE; +#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 + FILETYPE pDbgFile; + DbgGetDbgFileName( aBuf ); + if ( (pDbgFile = FileOpen( aBuf, "r" )) != NULL ) + { + FileRead( &(aDebugData.aDbgData), sizeof( DbgData ), 1, pDbgFile ); + FileClose( pDbgFile ); + } + +#ifndef MAC + getcwd( aCurPath, sizeof( aCurPath ) ); +#endif + + // Daten initialisieren + if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_XTOR ) + aDebugData.pXtorList = new PointerList; + if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_PROFILING ) + aDebugData.pProfList = new PointerList; + if ( aDebugData.aDbgData.nErrorOut < DBG_OUT_MSGBOX ) + { + if ( !DbgImplIsAllErrorOut() ) + aDebugData.aDbgData.nErrorOut = DBG_OUT_MSGBOX; + } + } + + return &aDebugData; +} + +// ----------------------------------------------------------------------- + +inline DebugData* ImplGetDebugData() +{ + if ( !aDebugData.bInit ) + return GetDebugData(); + else + return &aDebugData; +} + +// ----------------------------------------------------------------------- + +static FILETYPE ImplDbgInitFile() +{ + static BOOL bFileInit = FALSE; + +#ifndef MAC + getcwd( aBuf, sizeof( aBuf ) ); + chdir( aCurPath ); +#endif + + 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" ); + +#ifndef MAC + chdir( aBuf ); +#endif + + 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; +} + +// ----------------------------------------------------------------------- + +static void DebugInit() +{ + bDbgImplInMain = TRUE; + ImplDbgInitLock(); +} + +// ----------------------------------------------------------------------- + +static void DebugDeInit() +{ + DebugData* pData = GetDebugData(); + ULONG i; + ULONG nCount; + ULONG nOldOut; + + // 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->pDbgPrintTestTool = NULL; + pData->pDbgPrintShell = NULL; + pData->pDbgPrintWindow = NULL; + pData->pDbgPrintShell = 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 ); + 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, "" ); + } +} + +// ----------------------------------------------------------------------- + +void* DbgFunc( USHORT nAction, void* pParam ) +{ + DebugData* pData = ImplGetDebugData(); + + if ( nAction == DBG_FUNC_GETDATA ) + return (void*)&(pData->aDbgData); + 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: + pData->pDbgPrintMsgBox = (DbgPrintLine)pParam; + break; + + case DBG_FUNC_SETPRINTWINDOW: + pData->pDbgPrintWindow = (DbgPrintLine)pParam; + break; + + case DBG_FUNC_SETPRINTSHELL: + pData->pDbgPrintShell = (DbgPrintLine)pParam; + break; + + case DBG_FUNC_SETPRINTTESTTOOL: + pData->pDbgPrintTestTool = (DbgPrintLine)pParam; + break; + + case DBG_FUNC_SAVEDATA: + { + FILETYPE pDbgFile; + DbgGetDbgFileName( aBuf ); + if ( (pDbgFile = FileOpen( aBuf, "w" )) != NULL ) + { + FileWrite( pParam, sizeof( DbgData ), 1, pDbgFile ); + FileClose( pDbgFile ); + } + } + 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( NULL ); + break; + + case DBG_FUNC_ALLERROROUT: + return (void*)(ULONG)DbgImplIsAllErrorOut(); + + case DBG_FUNC_SETTESTSOLARMUTEX: + pData->pDbgTestSolarMutex = (DbgTestSolarMutexProc)pParam; + break; + + case DBG_FUNC_TESTSOLARMUTEX: + if ( pData->pDbgTestSolarMutex ) + pData->pDbgTestSolarMutex(); + break; + + case DBG_FUNC_PRINTFILE: + ImplDbgPrintFile( (const sal_Char*)pParam ); + break; + } + + return NULL; + } +} + +// ----------------------------------------------------------------------- + +void DbgProf( USHORT nAction, DbgDataType* pDbgData ) +{ + // Ueberhaupt Profiling-Test an + DebugData* pData = ImplGetDebugData(); + ProfType* pProfData = (ProfType*)pDbgData->pData; + ULONG nTime; + + if ( !(pData->aDbgData.nTestFlags & DBG_TEST_PROFILING) ) + return; + + 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; + + 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; + DebugData* pData = GetDebugData(); + sal_Char* pStr; + ULONG nOut; + int nBufLen = 0; + + if ( bIn ) + return; + bIn = TRUE; + + 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 ( (nDbgOut != DBG_OUT_ERROR) || DbgImplIsAllErrorOut() ) + { + if ( !ImplDbgFilter( pData->aDbgData.aInclFilter, pMsg, TRUE ) ) + { + bIn = FALSE; + return; + } + if ( ImplDbgFilter( pData->aDbgData.aExclFilter, pMsg, FALSE ) ) + { + bIn = FALSE; + return; + } + } + + ImplDbgLock(); + + 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_COREDUMP ) + { + if ( !ImplCoreDump( aBufOut ) ) + 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_SHELL; + } + + if ( nOut == DBG_OUT_SHELL ) + { + if ( pData->pDbgPrintShell ) + pData->pDbgPrintShell( aBufOut ); + else + nOut = DBG_OUT_WINDOW; + } + + if ( nOut == DBG_OUT_WINDOW ) + { + if ( pData->pDbgPrintWindow ) + pData->pDbgPrintWindow( aBufOut ); + else + nOut = DBG_OUT_FILE; + } + + if ( nOut == DBG_OUT_FILE ) + ImplDbgPrintFile( aBufOut ); + + ImplDbgUnlock(); + + bIn = FALSE; +} + +// ----------------------------------------------------------------------- + +void DbgOutTypef( USHORT nDbgOut, const sal_Char* pFStr, ... ) +{ + va_list pList; + + va_start( pList, pFStr ); + vsprintf( aBuf, pFStr, pList ); + va_end( pList ); + + DbgOut( aBuf, nDbgOut ); +} + +// ----------------------------------------------------------------------- + +void DbgOutf( const sal_Char* pFStr, ... ) +{ + va_list pList; + + va_start( pList, pFStr ); + 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..c21005fd0331 --- /dev/null +++ b/tools/source/debug/makefile.mk @@ -0,0 +1,89 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=debug + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +CXXFILES= debug.cxx \ + stcktree.cxx + +SLOFILES= $(SLO)$/debug.obj \ + $(SLO)$/stcktree.obj + +.IF "$(UPDATER)"!="" +OBJFILES= $(OBJ)$/debug.obj \ + $(OBJ)$/stcktree.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/tools/source/debug/stcktree.cxx b/tools/source/debug/stcktree.cxx new file mode 100644 index 000000000000..3e58510312df --- /dev/null +++ b/tools/source/debug/stcktree.cxx @@ -0,0 +1,351 @@ +/************************************************************************* + * + * $RCSfile: stcktree.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string.h> + +#include <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 nAlloc ) {} +void DbgPrintStackTree( void* ) {} + +#endif diff --git a/tools/source/fsys/comdep.cxx b/tools/source/fsys/comdep.cxx new file mode 100644 index 000000000000..4bd8d1cc359a --- /dev/null +++ b/tools/source/fsys/comdep.cxx @@ -0,0 +1,116 @@ +/************************************************************************* + * + * $RCSfile: comdep.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifdef MAC +#define private public +#define protected public +#endif + +#include "comdep.hxx" + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _LIST_HXX +#include <list.hxx> +#endif +#ifndef _FSYS_HXX +#include <fsys.hxx> +#endif + +DBG_NAMEEX( DirEntry ); + +//-------------------------------------------------------------------- + +#if defined( DOS ) || defined( WIN ) + +#ifdef MSC +#include "dosmsc.cxx" +#endif + +#if defined( BLC ) || defined( TCPP ) +#include "dosblc.cxx" +#endif + +#ifdef ZTC +#include "dosztc.cxx" +#endif + +#else + +#if defined( WNT ) && !defined( WTC ) +#include "wntmsc.cxx" +#endif + +#ifdef UNX +#include "unx.cxx" +#endif + +#ifdef PM2 +#include "os2.cxx" +#endif + +#ifdef MAC +#include "mac.cxx" +#endif + +#endif + diff --git a/tools/source/fsys/comdep.hxx b/tools/source/fsys/comdep.hxx new file mode 100644 index 000000000000..702548429714 --- /dev/null +++ b/tools/source/fsys/comdep.hxx @@ -0,0 +1,224 @@ +/************************************************************************* + * + * $RCSfile: comdep.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _COMDEP_HXX +#define _COMDEP_HXX + +#include "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(DOS) || defined(WIN) + +#ifdef MSC +#include "dosmsc.hxx" +#endif + +#if defined(TCPP) || defined(BLC) +#include "dosblc.hxx" +#endif + +#ifdef ZTC +#include "dosztc.hxx" +#endif + +#else + +#if defined( WNT ) && !defined( WTC ) +#include "wntmsc.hxx" +#endif + +#ifdef UNX +#include "unx.hxx" +#endif + +#if defined(PM2) || defined(PM2) +#include "os2.hxx" +#endif + +#ifdef MAC +#include "mac.hxx" +#endif + +#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; +#ifdef MAC + union + { + DIR* pDosDir; + dirent* pDosEntry; + }; +#else + DIR* pDosDir; + dirent* pDosEntry; +#endif + DirEntry* pParent; + String aPath; + ByteString aBypass; + BOOL bReady; + BOOL bInUse; + + DirReader_Impl( Dir &rDir ) + : pDir( &rDir ), + aPath( GUI2FSYS(rDir.GetFull()) ), + pDosEntry( 0 ), + pParent( 0 ), + bReady ( FALSE ), + bInUse( FALSE ) + { +#ifndef BOOTSTRAP + // Redirection + FSysRedirector::DoRedirect( aPath ); +#endif + + // nur den String der Memer-Var nehmen! + +#ifdef UNX //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..996be942639e --- /dev/null +++ b/tools/source/fsys/dirent.cxx @@ -0,0 +1,3521 @@ +/************************************************************************* + * + * $RCSfile: dirent.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + + +#if !defined( MAC ) && !defined( UNX ) +#include <io.h> +#endif + +#if defined UNX +#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> + +#if defined (WIN) || defined (MAC) +#include <time.h> +#endif + +#ifdef PM2 +#include <os2.hxx> +#endif + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _LIST_HXX +#include <list.hxx> +#endif + +#ifndef _COMDEP_HXX +#include "comdep.hxx" +#endif +#ifndef _FSYS_HXX +#include "fsys.hxx" +#endif +#define _TOOLS_HXX +#ifndef _URLOBJ_HXX +#include <urlobj.hxx> +#endif + +#ifdef UNX +#define _MAX_PATH 260 +#endif + +#ifdef MAC_UNIVERSAL +#ifndef _UNISTD +#include <unistd.h> +#endif +#endif +#ifdef MAC +#ifndef __ERRORS__ +#include "Errors.h" +#endif +#endif + +#ifndef _STREAM_HXX +#include <stream.hxx> +#endif + +#ifndef _VOS_MUTEX_HXX +#include <vos/mutex.hxx> +#endif + +#include <osl/file.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 + +#if SUPD>=380 +FSysRedirector* FSysRedirector::_pRedirector = 0; +BOOL FSysRedirector::_bEnabled = TRUE; +#ifdef UNX +BOOL bInRedirection = TRUE; +#else +BOOL bInRedirection = FALSE; +#endif +static NAMESPACE_VOS( OMutex )* pRedirectMutex = 0; + +//======================================================================== + +FSysRedirector::~FSysRedirector() +{ +} + +//------------------------------------------------------------------------ +void FSysRedirector::Register( FSysRedirector *pRedirector ) +{ + if ( pRedirector ) + pRedirectMutex = new NAMESPACE_VOS( OMutex ); + else + DELETEZ( pRedirectMutex ); + _pRedirector = pRedirector; +} + +//------------------------------------------------------------------------ + +BOOL FSysRedirector::DoRedirect( String &rPath ) +{ + ByteString aURL(rPath, osl_getThreadTextEncoding()); + + // if redirection is disabled or not even registered do nothing + if ( !_bEnabled || !pRedirectMutex ) + return FALSE; + + // redirect only removable or remote volumes + if ( !IsRedirectable_Impl( aURL ) ) + return FALSE; + + // Redirection is acessible only by one thread per time + // dont move the guard behind the !bInRedirection return FALSE!!! + // think of nested calls (when called from callback) + NAMESPACE_VOS( OGuard ) aGuard( pRedirectMutex ); + + // if already in redirection, dont redirect + if ( bInRedirection ) + return FALSE; + + // dont redirect on nested calls + bInRedirection = TRUE; + + // convert to URL +#ifndef UNX + for ( char *p = (char *) aURL.GetBuffer(); *p; ++p ) +#ifndef MAC + if ( '\\' == *p ) *p = '/'; + else if ( ':' == *p ) *p = '|'; +#else + if ( ':' == *p ) *p = '/'; +#endif +#endif + + aURL.Insert( "file:///", 0 ); + + // do redirection + Redirector(); + BOOL bRedirected = Redirector()->Redirect( String(aURL, osl_getThreadTextEncoding()) ); + + // if redirected transform URL to file name + if ( bRedirected ) + { + rPath = String(aURL.Copy( 8 ), osl_getThreadTextEncoding()); + aURL = ByteString(rPath, osl_getThreadTextEncoding()); +#ifndef UNX + for ( char *p = (char *) aURL.GetBuffer(); *p; ++p ) +#ifndef MAC + if ( '/' == *p ) *p = '\\'; + else if ( '|' == *p ) *p = ':'; +#else + if ( '/' == *p ) *p = ':'; +#endif +#endif + } + + bInRedirection = FALSE; + return bRedirected; +} + +//------------------------------------------------------------------------ + +void FSysRedirector::EnableRedirection( BOOL bEnable ) +{ + if ( !bEnable && pRedirectMutex) + pRedirectMutex->acquire(); + _bEnabled = bEnable; + if ( bEnable && pRedirectMutex) + pRedirectMutex->release(); +} + +//------------------------------------------------------------------------ + +BOOL FSysRedirector::Redirect( String &rPath ) +{ +#ifdef DBG_MI + if ( rPath.Len() && rPath(1) == ':' && + ( rPath(0) == 'b' || rPath(0) == 'B' ) ) + { + rPath(0) = 'd'; + rPath.Insert( "\\mi", 2 ); + return TRUE; + } +#endif + return FALSE; +} + +//------------------------------------------------------------------------ + +FSysRedirector* FSysRedirector::Redirector() +{ + if ( !_pRedirector ) + Register( new FSysRedirector ); + return _pRedirector; +} +#endif + +#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 + ByteString aPfad( rPfad ); + 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 = aPfad.Copy( 2, nPos-2 ); + 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 = aPfad.Copy( 0, nPos + 1 ); + + // 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 = aPfad.Copy( 0, nPos ); + + // 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& rInitName, + FSysPathStyle eStyle ) +{ + if ( eStyle == FSYS_STYLE_HOST ) + eStyle = DEFSTYLE; + + // KI-Division of FSys + if ( eStyle == FSYS_STYLE_DETECT ) + { + char cFirst = rInitName.Copy(0,1).ToLowerAscii().GetChar(0); + if ( rInitName.Len() == 2 && rInitName.GetChar(1) == ':' && + 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( rInitName, eStyle ); + + case FSYS_STYLE_BSD: + case FSYS_STYLE_SYSV: + return ImpParseUnixName( rInitName, eStyle ); + + case FSYS_STYLE_MAC: + return ImpParseMacName( rInitName ); + + 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(INetURLObject( rInitName ).PathToFileName(), osl_getThreadTextEncoding()); + eStyle = FSYS_STYLE_HOST; +#endif // BOOTSTRAP + } + else + { + ::rtl::OUString aTmp; + ::rtl::OUString aOInitName; + if ( FileBase::normalizePath( OUString( rInitName ), aTmp ) == osl_File_E_None ) + { + FileBase::getSystemPathFromNormalizedPath( aTmp, aOInitName ); + 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(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(DOS) || defined(WIN) || 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(WIN) || defined(DOS) || defined(OS2) || defined(WNT) + 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( 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, 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 + { +#ifndef MAC + aRet.Insert( '/', 5 ); +#endif + } + 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; + + const DirEntry *pThis = this; + const DirEntry *pWith = &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( 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( 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 +|* +*************************************************************************/ +#if SUPD<=381 +BOOL DirEntry::Find( const String& rPfad ) +{ + return Find( rPfad, SEARCHDELIM(DEFSTYLE)[0] ); +} +#endif + +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; +#ifndef MAC + ByteString aThis = ACCESSDELIM(DEFSTYLE); + aThis += ByteString(GetFull(), osl_getThreadTextEncoding()); +#else + String aThis(GetFull(), osl_getThreadTextEncoding()); +#endif + for ( USHORT nToken = 0; nToken < nTokenCount; ++nToken ) + { + ByteString aPath = ByteString(rPfad, osl_getThreadTextEncoding()).GetToken( 0, cDelim, nIndex ); +#ifdef MAC + if (aPath[aPath.Len()-1] == ':') + aPath.Cut(aPath.Len()-1); +#endif + 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(); + ByteString aThisStr( aThis.GetFull( FSYS_STYLE_HPFS ), osl_getThreadTextEncoding()); + ByteString bCurStr( aCurStr, osl_getThreadTextEncoding()); + aThisStr = CMP_LOWER( aThisStr ); + bCurStr = CMP_LOWER( bCurStr ); + + // "Ubereinstimmung pr"ufen + USHORT nPos = aThisStr.Match( bCurStr ); + if ( nPos == STRING_MATCH && aThisStr.Len() != bCurStr.Len() ) + nPos = Min( aThisStr.Len(), bCurStr.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 ) ); + bCurStr.Erase( 0, nPos + ( ( bCurStr.GetChar(nPos) == '\\' ) ? 1 : 0 ) ); + + // und fuellen mit dem Level der Directories auf + for ( nPos = 0; nPos < bCurStr.Len(); ++nPos ) + if ( bCurStr.GetChar(nPos) == '\\' ) + aThisStr.Insert( "..\\", 0 ); + + // das ist dann unser relativer Pfad + *this = DirEntry( String(aThisStr, osl_getThreadTextEncoding()), 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, 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; + } + + return USHRT_MAX; +} + +/************************************************************************* +|* +|* DirEntry::TempName() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung VB 06.09.93 (im SWG) +|* Letzte Aenderung MI 06.02.98 +|* +*************************************************************************/ + +DirEntry aTempNameBase_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 ) ) + { + aTempDir.MakeDir(); + chmod( aName.GetBuffer(), S_IRWXU | S_IRWXG | S_IRWXO ); + } +#else + aTempDir.MakeDir(); +#endif + aTempNameBase_Impl = aTempDir.TempName( FSYS_KIND_DIR ); + return aTempNameBase_Impl; +} + +DirEntry DirEntry::TempName( DirEntryKind eKind ) const +{ + // ggf. Base-Temp-Dir verwenden (macht Remote keinen Sinn => vorher) + if ( !pParent && FSYS_FLAG_CURRENT != aTempNameBase_Impl.eFlag && FSYS_FLAG_ABSROOT != eFlag ) + + { + DirEntry aFactory( aTempNameBase_Impl ); + aFactory += GetName(); + return aFactory.TempName(); + } + +#ifdef OS2 + // + // resolves long FAT names used by OS2 + // + if (Folder::IsAvailable() && IsLongNameOnFAT()) + { + // in DirEntry mit kurzem Pfad wandeln + ItemIDPath aItemIDPath(GetFull()); + String aString(aItemIDPath.GetHostNotationPath()); + DirEntry aDirEntry(aString); + + // Aufruf der Methode + return aDirEntry.TempName(eKind); + } +#endif + + 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 + .ext + '\0' + // please note that number is of length 5 not 3 +# define TMPNAME_SIZE ( 1 + 5 + 5 + 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(DOS) || defined(PM2) || defined(WIN) || defined(WNT) + if ( i>0 && ret_val[i-1] != '\\' && ret_val[i-1] != '/' && + ret_val[i-1] != ':') + ret_val[i++] = '\\'; +#elif (UNX) + if (i>0 && ret_val[i-1] != '/') + ret_val[i++] = '/'; +#elif (MAC) + 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 + */ +#if (defined (MSC) || defined (BLC) || defined(ICC) ) && ( defined (WIN) || defined (WNT)) + static unsigned long u = GetTickCount(); +#else + static unsigned long u = clock(); +#endif + for ( unsigned long nOld = u; ++u != nOld; ) + { + u %= (26*26*26); + unsigned nTemp = (unsigned)u; +#if defined(OS2) || defined(WIN) || defined(WNT) || defined(DOS) + itoa(nTemp,ret_val + i,26); +#else + // the number needs length 5 not 3 !!!! + sprintf(ret_val+i, "%03u", nTemp); +#endif + 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(MAC) + OSErr nErr; + FSSpec aFSSpec; + FInfo dummyFInfo; + + nErr = FSMakeFSSpec( 0, 0, aRedirected.GetPascalStr(), &aFSSpec ); + if (nErr == noErr) + nErr = FSpGetFInfo(&aFSSpec,&dummyFInfo); + + if (nErr == fnfErr) // File Not Found, das ist was wir wollen ... + { + aRet = DirEntry( ret_val ); + break; + } + else if( nErr != noErr ) + { + DBG_ASSERT( nErr == noErr, "cannot generate TempName" ) + // keine Chance mehr, etwas zu finden + break; + } +#elif defined(PM2) +#ifdef POWERPC + // !!!!! DosQueryPathInfo liefert dezeit (Beta2) immer OK !!!!! + APIRET nRet; + HFILE hFile = 0; + PM_ULONG lAction = 0; + nRet = DosOpen( (PSZ)ret_val, &hFile, &lAction, 0, + FILE_NORMAL, FILE_OPEN, + OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, 0L ); + if ( !nRet ) + DosClose( hFile ); + else + { + aRet = DirEntry( ret_val ); + break; + } +#else + APIRET nRet; + ULONG nCount = 1; + HDIR hDirHandle = HDIR_SYSTEM; + FILEFINDBUF3 aDirEnt; + nRet = DosFindFirst( (PSZ) aRedirected.GetBuffer(), + &hDirHandle, 23, (PVOID) &aDirEnt, + sizeof( FILEFINDBUF3 ), + &nCount, FIL_STANDARD ); + if( nRet == ERROR_FILE_NOT_FOUND + || nRet == ERROR_NO_MORE_FILES ) + { + aRet = DirEntry( String( ret_val ) ); + break; + } + else if( nRet != NO_ERROR ) + { + DBG_ASSERT( nRet == NO_ERROR, "cannot generate TempName" ) + // keine Chance mehr, etwas zu finden + break; + } +#endif +#elif defined UNX + 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::ImpParseMacName() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MA 14.10.91 +|* Letzte Aenderung MI 26.05.93 +|* +*************************************************************************/ + +FSysError DirEntry::ImpParseMacName( const ByteString& rPfad ) +{ +#if 0 + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntryStack aStack; + ByteString aPfad( rPfad ); + + //If the Path starts with an ABSROOT ( Volume ) it has to be + //pushed. So the Tail can be easier evaluated + if ( ( aPfad.Search( ':' ) != STRING_NOTFOUND ) && ( aPfad.GetChar(0) != ':' ) ) { + aStack.Push( new DirEntry( aPfad.Cut( 0, aPfad.Search( ':' ) ), + FSYS_FLAG_ABSROOT, FSYS_STYLE_MAC ) ); + aPfad.Erase( 0, 1 ); + } + + //Purge Current-Directory + if ( aPfad(0) == ':' ) + aPfad.Erase( 0, 1 ); + + //Evaluate the Tail + while ( aPfad.Len() ) { + + if ( aPfad.GetChar(0) == ':' ) { + //PARENT detected + if ( aStack.Count() && (aStack.Top()->eFlag == FSYS_FLAG_ABSROOT) ) { + //an ABSROOT couldn't have a PARENT + return FSYS_ERR_NOTEXISTS; + } + else { + //Nothing or a Parent at the top? + if ( ( aStack.Count() == 0 ) || + ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) ) { + //put leading Parents on the Top + aStack.Push( new DirEntry( FSYS_FLAG_PARENT ) ); + aPfad.Erase( 0, 1 ); + } + else { + delete aStack.Pop(); + aPfad.Erase( 0, 1 ); + } + } + } + else + { + // Normal entry detected + USHORT nSepPos = aPfad.Search( ':' ); + if ( STRING_NOTFOUND == nSepPos ) + nSepPos = USHRT_MAX; + DirEntry *pNew = new DirEntry( aPfad.Cut( 0, nSepPos ), + FSYS_FLAG_NORMAL, FSYS_STYLE_MAC ); + if ( !pNew->IsValid() ) + { + aName = rPfad; + ErrCode eErr = pNew->GetError(); + delete pNew; + return eErr; + } + aStack.Push( pNew ); + if ( STRING_NOTFOUND == nSepPos ) + aPfad.Erase(); + else + aPfad.Erase( 0, 1 ); + } + } + + //assign *this + if ( aStack.Count() == 0 ) { + eFlag = FSYS_FLAG_CURRENT; + aName.Erase(); + } + else { + eFlag = aStack.Top()->eFlag; + aName = aStack.Top()->aName; + delete aStack.Pop(); + } + //assign the Parent-Entries + DirEntry** pTemp = &pParent; + while ( aStack.Count() ) { + *pTemp = aStack.Pop(); + pTemp = &( (*pTemp)->pParent ); + } +#endif + 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 defined(MAC) + if ( TRUE ) +#else + if ( FSYS_STYLE_MAC != eStyle ) +#endif + { + 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 += 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()); + link( aThis.GetBuffer(), aDest.GetBuffer() ); + return Sys2SolarError_Impl( errno ); + } +#else + return FSYS_ERR_NOTSUPPORTED; +#endif + + return FileCopier( *this, rDest ).Execute(nActions); +} + +/************************************************************************* +|* +|* DirEntry::MoveTo() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung HRO 24.03.99 +|* +*************************************************************************/ + +#if defined(WNT) || defined(DOS) || defined(WIN) || defined(UNX) + +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; + } + +#ifdef WIN + 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() ) ) ) +#ifndef UNX +#ifdef WIN + { // einfaches umbenennen ist fehlgeschlagen, kopieren versuchen + FILE *fpIN = fopen(aFrom.GetBuffer(), "rb"); + if (!fpIN) return Sys2SolarError_Impl(ENOENT); // Quelle kann nicht zum Lesen geoeffnet werden + FILE *fpOUT = fopen(aTo, "wb"); + if (!fpOUT) + { + fclose(fpIN); + return Sys2SolarError_Impl(EACCES); // Ziel kann nicht zum Schreiben geoeffnet werden + } + + char pBuf[16384]; + int nRead, nWrite, nError = 0; + while((nRead = fread(pBuf, 1, 16384, fpIN)) && (!nError)) + { + nWrite = fwrite(pBuf, 1, nRead, fpOUT); + if (nWrite != nRead) nError = ENOSPC; + } + fclose( fpIN ); + fclose( fpOUT ); + return Sys2SolarError_Impl(nError); + } +#else + return Sys2SolarError_Impl( GetLastError() ); +#endif +#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, nError = 0; + errno = 0; + while( ( nBytes = fread( pBuf, 1, sizeof(pBuf), fpIN ) ) && ! nError ) + { + nWritten = fwrite( pBuf, 1, nBytes, fpOUT ); + // Fehler im fwrite ? + if( nWritten < nBytes ) + { + nError = errno; + break; + } + } + fclose( fpIN ); + fclose( fpOUT ); + if ( nError ) + { + unlink( bTo.GetBuffer() ); + return Sys2SolarError_Impl( nError ); + } + 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 eFlag = rSubDir.GetFlag(); + if ( eFlag != FSYS_FLAG_CURRENT && eFlag != 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( (char*) pName ) ); +#else +#ifdef 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 +#endif + } + else + { +#ifdef OS2 + eError = ApiRet2ToSolarError_Impl( DosForceDelete( (PSZ) pName ) ); +#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; + } +#endif + } + } + + //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 ) +{ +#ifdef MAC + return ImpConvertNameToSystem( rName ); +#else + return rName; +#endif +} + +/************************************************************************* +|* +|* DirEntry::ConvertSystemToName() +|* +|* Beschreibung +|* Ersterstellung DV 29.03.96 +|* Letzte Aenderung DV 29.03.96 +|* +*************************************************************************/ + +String DirEntry::ConvertSystemToName( const String &rName ) +{ +#ifdef MAC + return ImpConvertSystemToName( rName ); +#else + return rName; +#endif +} + +/************************************************************************* +|* +|* 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( int 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..6be1822f8991 --- /dev/null +++ b/tools/source/fsys/filecopy.cxx @@ -0,0 +1,578 @@ +/************************************************************************* + * + * $RCSfile: filecopy.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#if defined(WIN) || defined(WNT) +#ifndef _SVWIN_H +#include <io.h> +#include <svwin.h> +#endif + +#elif defined(PM2) || defined(DOS) +#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> + +#elif defined MAC +#include <mac_start.h> +#include <fcntl.h> +#include <mac_end.h> +#endif + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#ifndef PM2 +#include <stdio.h> +#endif + +#ifndef _COMDEP_HXX +#include "comdep.hxx" +#endif + +#ifndef _FSYS_HXX +#include "fsys.hxx" +#endif + +#ifndef _STREAM_HXX +#ifdef UNX +#define private public +#endif +#include "stream.hxx" +#endif + +EA_Copier* EA_Copier::_pCopier = NULL; + +//======================================================================== + +EA_Copier::~EA_Copier() +{ +} + +//------------------------------------------------------------------------ +void EA_Copier::Register( EA_Copier* pCopier ) +{ + _pCopier = pCopier; +} + +//------------------------------------------------------------------------ + +EA_Copier* EA_Copier::Get() +{ + return _pCopier; +} + +/************************************************************************* +|* +|* FileCopier::FileCopier() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 13.04.94 +|* Letzte Aenderung MI 13.04.94 +|* +*************************************************************************/ + +FileCopier::FileCopier() : + + nBlockSize ( 4096 ), + nBytesTotal ( 0 ), + nBytesCopied( 0 ), + pImp ( new FileCopier_Impl ) + +{ +} + +// ----------------------------------------------------------------------- + +FileCopier::FileCopier( const DirEntry& rSource, const DirEntry& rTarget ) : + + aSource ( rSource ), + aTarget ( rTarget ), + nBlockSize ( 4096 ), + nBytesTotal ( 0 ), + nBytesCopied( 0 ), + pImp ( new FileCopier_Impl ) + +{ +} + +// ----------------------------------------------------------------------- + +FileCopier::FileCopier( const FileCopier& rCopier ) : + + aSource ( rCopier.aSource ), + aTarget ( rCopier.aTarget ), + nBlockSize ( 4096 ), + nBytesTotal ( 0 ), + nBytesCopied ( 0 ), + aProgressLink ( rCopier.aProgressLink ), + 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 +|* +*************************************************************************/ + +#ifndef MAC + +#ifdef OS2 +BOOL createLongNameEA ( const PCSZ pszPath, ULONG ulAttributes, const String& aLongName ); +#endif + +FSysError FileCopier::DoCopy_Impl( const DirEntry &rSource, const DirEntry &rTarget, + BOOL bTop ) +{ + 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 aTarget; + if ( bMakeShortNames ) + { + aTarget = rTarget.GetPath(); + aTarget.MakeShortName( rTarget.GetName() ); + } + else + aTarget = rTarget; + + // kein Move wenn Namen gekuerzt werden muessten + if ( bMakeShortNames && FSYS_ACTION_MOVE == ( pImp->nActions & FSYS_ACTION_MOVE ) && aTarget != 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, rSource.GetFull().GetStr()); + hSourceObject = WinQueryObject(szSource); + + if ( hSourceObject ) + { + PSZ pszSourceName; + PSZ pszTargetName; + CHAR szTarget[CCHMAXPATHCOMP]; + HOBJECT hTargetObject; + HOBJECT hReturn = NULLHANDLE; + + strcpy(szTarget, rTarget.GetFull().GetStr()); + 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( aTarget.MakeDir() ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN, 0, &aTarget ); + 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( aTarget ); + aSubTarget += rSubSource.GetName(); + eRet = DoCopy_Impl( rSubSource, aSubTarget, FALSE ); + if ( eRet && !eWarn ) + eWarn = eRet; + } + } + } + else if ( aSourceFileStat.IsKind(FSYS_KIND_FILE) ) + { + if ( ( FSYS_ACTION_KEEP_EXISTING == ( pImp->nActions & FSYS_ACTION_KEEP_EXISTING ) ) && + aTarget.Exists() ) + { + // Do not overwrite existing file in target folder. + return ERRCODE_NONE; + } + + // copy file + nBytesCopied = 0; + nBytesTotal = FileStat( rSource ).GetSize(); + + String aFileName( GUI2FSYS( rSource.GetFull() ).GetBuffer() ); + SvFileStream aSource( aFileName, STREAM_READ|STREAM_NOCREATE|STREAM_SHARE_DENYNONE ); + + if ( !aSource.GetError() ) + { +#ifdef UNX + struct stat buf; + if ( fstat( aSource.GetFileHandle(), &buf ) == -1 ) + eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTarget ); +#endif + SvFileStream aTargetStream( GUI2FSYS( aTarget.GetFull() ), + 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, &aTarget ); +#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 = aSource.Read( pBuf, nBlockSize ); + aTargetStream.Write( pBuf, nSize ); + if ( aTargetStream.GetError() ) + eRet = Error( aTargetStream.GetError(), 0, &aTarget ); + + // adjust counters + nBytesCopied += nSize; + if ( nBytesCopied > nBytesTotal ) + nBytesTotal = nBytesCopied; + } + delete pBuf; + } + else + eRet = Error( aTargetStream.GetError(), 0, &aTarget ); + + // ggf. EAs kopieren + if ( !eRet && EA_Copier::Get() && !EA_Copier::Get()->Copy( aSource, aTargetStream ) ) + eRet = FSYS_ERR_UNKNOWN | ERRCODE_WARNING_MASK; + + // unvollstaendiges File wieder loeschen + aTargetStream.Close(); + + if ( nBytesCopied != nBytesTotal ) + { + aTarget.Kill(); + } +#ifdef OS2 + else + { + // falls die Source-Target-Filenamen nicht gleich sind und der Target-Filename nicht + // 8.3 aber auf FAT ist, dann mu? das EA .longname korrekt gesetzt werden (TPF) + // (rSource.GetName()!=rTarget.GetName()) + + if ( rTarget.IsLongNameOnFAT() && Folder::IsAvailable() ) + { + createLongNameEA( (const char*)aTargetStream.GetFileName(), + FILE_NORMAL, rTarget.GetName() ); + } + } +#endif + } + else + eRet = Error( aSource.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(aTarget.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 + aTarget.Kill( pImp->nActions ); + if ( !eWarn ) + eWarn = eKillErr; + } + } + + return !eRet ? eWarn : eRet; +} + +#endif + +// ----------------------------------------------------------------------- + +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, TRUE ); +} + + diff --git a/tools/source/fsys/fstat.cxx b/tools/source/fsys/fstat.cxx new file mode 100644 index 000000000000..bbde14c83208 --- /dev/null +++ b/tools/source/fsys/fstat.cxx @@ -0,0 +1,516 @@ +/************************************************************************* + * + * $RCSfile: fstat.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#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 <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(OS2) || defined(UNX) + 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()); +#ifdef WNT + DWORD nRes = GetFileAttributes( (LPCTSTR) aFPath.GetBuffer() ); + return ULONG_MAX != nRes && + ( FILE_ATTRIBUTE_READONLY & nRes ) == FILE_ATTRIBUTE_READONLY; +#endif + +#ifdef 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 ); + + case ERROR_SHARING_VIOLATION: + return ERRCODE_IO_LOCKVIOLATION; + + default: + return ERRCODE_IO_NOTEXISTS; + } +#endif + +#ifdef 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); +#endif + return FALSE; +} + +/************************************************************************* +|* +|* 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()); + +#ifdef 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; +#endif + +#ifdef 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; + } +#endif + +#ifdef 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; +#endif + return ERRCODE_IO_NOTSUPPORTED; +} + +/************************************************************************* +|* +|* FileStat::SetDateTime +|* +|* Ersterstellung PB 27.06.97 +|* Letzte Aenderung +|* +*************************************************************************/ +#if defined(WIN) | 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(WIN) + unsigned date = 0; + unsigned time = 0; + + date = (unsigned) aNewDate.GetDay(); + date |= (unsigned)(aNewDate.GetMonth() << 5); + date |= (unsigned)((aNewDate.GetYear() - 1980) << 9); + time = (unsigned)(aNewTime.GetSec() / 2); + time |= (unsigned)(aNewTime.GetMin() << 5); + time |= (unsigned)(aNewTime.GetHour() << 11); + + + FILE* pFile = fopen( aFileName.GetBuffer(), "a" ); + + if ( pFile != NULL ) + { + _dos_setftime( fileno(pFile), date, time ); + fclose( pFile ); + } + +#elif defined( WNT ) + + TIME_ZONE_INFORMATION aTZI; + DWORD dwTZI = GetTimeZoneInformation( &aTZI ); + + if ( dwTZI != (DWORD)-1 && dwTZI != TIME_ZONE_ID_UNKNOWN ) + { + // 1. Korrektur der Zeitzone + short nDiff = (short)aTZI.Bias; + Time aOldTime = aNewTime; // alte Zeit merken + + // 2. evt. Korrektur Sommer-/Winterzeit + if ( dwTZI == TIME_ZONE_ID_DAYLIGHT ) + nDiff += (short)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 ); + } + +#endif +#ifdef 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 +/* +FileStatMembers *FileStat::GetAllMembers() +{ + FileStatMembers *members = new FileStatMembers; + members->nError = nError; + members->nKindFlags = nKindFlags; + members->nSize = nSize; + members->aCreator = aCreator; + members->aType = aType; + members->aDateCreated = aDateCreated.GetDate(); + members->aTimeCreated = aTimeCreated.GetTime(); + members->aDateAccessed = aDateAccessed.GetDate(); + members->aTimeAccessed = aTimeAccessed.GetTime(); + members->aDateModified = aDateModified.GetDate(); + members->aTimeModified = aTimeModified.GetTime(); + return members; +} + +void FileStat::InitMembers(FileStatMembers *members) +{ + nError = members->nError; + members->nKindFlags = nKindFlags; + members->nSize = nSize; + members->aCreator = aCreator; + members->aType = aType; + aDateCreated.SetDate(members->aDateCreated); + aTimeCreated.SetTime(members->aTimeCreated); + aDateAccessed.SetDate(members->aDateAccessed); + aTimeAccessed.SetTime(members->aTimeAccessed); + aDateModified.SetDate(members->aDateModified); + aTimeModified.SetTime(members->aTimeModified); +} +*/ + + diff --git a/tools/source/fsys/makefile.mk b/tools/source/fsys/makefile.mk new file mode 100644 index 000000000000..432ad2a1d8c4 --- /dev/null +++ b/tools/source/fsys/makefile.mk @@ -0,0 +1,98 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=fsys + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- 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 + +.IF "$(UPDATER)"!="" +OBJFILES= $(OBJ)$/wldcrd.obj \ + $(OBJ)$/fstat.obj \ + $(OBJ)$/comdep.obj \ + $(OBJ)$/filecopy.obj \ + $(OBJ)$/dirent.obj \ + $(OBJ)$/tdir.obj \ + $(OBJ)$/urlobj.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/tools/source/fsys/os2.cxx b/tools/source/fsys/os2.cxx new file mode 100644 index 000000000000..f65956b7926e --- /dev/null +++ b/tools/source/fsys/os2.cxx @@ -0,0 +1,1153 @@ +/************************************************************************* + * + * $RCSfile: os2.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define INCL_DOSEXCEPTIONS + +#ifdef __BORLANDC__ +#include <alloc.h> +#else +#include <malloc.h> +#endif + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _LIST_HXX +#include <list.hxx> +#endif +#ifndef _BIGINT_HXX +#include <bigint.hxx> +#endif +#ifndef _FSYS_HXX +#include <fsys.hxx> +#endif +#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 String sLastCaseSensitiveDir = ""; +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; +} + +//-------------------------------------------------------------------- + +DIR *opendir( const char* pPfad ) +{ + DIR *pDir = new DIR; + if ( pDir ) + pDir->p = (char*) pPfad; + return pDir; +} + +struct dirent *readdir( DIR *pDir ) +{ + APIRET nRet; + ULONG nCount = 1; + 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 ) == '\\' ) ); + pDir->aDirHdl = HDIR_SYSTEM; + nRet = DosFindFirst( (PSZ) pBuf, &pDir->aDirHdl, 23, + (PVOID) &pDir->aDirEnt, sizeof( FILEFINDBUF3 ), + &nCount, FIL_STANDARD ); + pDir->p = NULL; + delete pBuf; + } + else + nRet = 1; + } + else + { + nRet = DosFindNext( pDir->aDirHdl, + (PVOID) &pDir->aDirEnt, sizeof( pDir->aDirEnt ), + &nCount ); + } + + return !nRet ? &pDir->aDirEnt : NULL; +} + +int closedir( DIR *pDir ) +{ + if ( pDir ) + { + if ( !pDir->p ) + DosFindClose( pDir->aDirHdl ); + delete pDir; + } + return (pDir != NULL); +} + +typedef struct _FSInfo +{ + ULONG nSerial; + BYTE nNameLen; + UCHAR sName[40]; +} FSInfo; + +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.sName; + } + 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 (paVirtualURL) + { + return TRUE; + } + + if ( FSYS_FLAG_VOLUME == eFlag ) + { + eFlag = FSYS_FLAG_ABSROOT; + return TRUE; + } + + if ( IsAbs() ) + return TRUE; + + char sBuf[512]; + + // Device bestimmen + DirEntry* pTop = ImpGetTopPtr(); + ULONG nDev, nMap; + if ( ( pTop->eFlag == FSYS_FLAG_VOLUME || pTop->eFlag == FSYS_FLAG_RELROOT ) && + pTop->aName.Len() ) + nDev = tolower(aName(0)) - 'a' + 1; + else + DosQueryCurrentDisk( &nDev, &nMap ); + + // das dortige CWD ermitteln; + ULONG nLen = sizeof( sBuf ) - 1; + DirEntry *pCWD = 0; + DosQueryCurrentDir( nDev, (PSZ) sBuf, &nLen ); + if ( sBuf[0] == 0 ) + strcpy( sBuf, "\\" ); + else + pCWD = new DirEntry( String( sBuf ) ); + + // das Device voranstellen + String aTempStr( (char)(nDev + 'a' - 1) ); + aTempStr += ':'; + if ( pCWD ) + pCWD->ImpGetTopPtr()->pParent = + new DirEntry( aTempStr, FSYS_FLAG_ABSROOT, DEFSTYLE ); + else + pCWD = new DirEntry( aTempStr, FSYS_FLAG_ABSROOT, DEFSTYLE ); + + // die relative Root durch ihr aktuelles Verzeichnis ersetzen + if ( pTop == this && + ( pTop->eFlag == FSYS_FLAG_RELROOT || pTop->eFlag == FSYS_FLAG_VOLUME ) ) + { + *pTop = *pCWD; + delete pCWD; + } + else if ( pTop->eFlag == FSYS_FLAG_ABSROOT ) + { + pTop->aName = aTempStr; + delete pCWD; + } + else + { + // dir\\..-Sequenzen aufloesen + while ( (pTop = ImpGetTopPtr())->eFlag == FSYS_FLAG_PARENT && + pTop != this ) + { + pCWD->CutName(); + ImpGetPreTopPtr()->pParent = 0; + delete pTop; + } + + // Pfad davorhaengen + if ( pTop == this && eFlag == FSYS_FLAG_PARENT ) + { + *this = pCWD->GetPath(); + delete pCWD; + } + else + ImpGetTopPtr()->pParent = pCWD; + } + + 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 ); + + const DirEntry *pTop = ImpGetTopPtr(); + + if ( pTop->eFlag == FSYS_FLAG_ABSROOT || + pTop->eFlag == FSYS_FLAG_VOLUME ) + { + const char *pVol; + pVol = volumeid( (char*) pTop->aName.GetStr() ); + return FSYS2GUI( String( pVol ? pVol : "" ) ); + } + + return String(); +} + +/************************************************************************* +|* +|* DirEntry::SetCWD() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 21.05.92 +|* +*************************************************************************/ + +BOOL DirEntry::SetCWD( BOOL bSloppy ) +{ + if (paVirtualURL) + { + String aTempString(GetRealPathFromVirtualURL()); + if (aTempString.Len()==0) + { + return FALSE; + } + DirEntry aTempDirEntry(aTempString); + return aTempDirEntry.SetCWD(bSloppy); + } + + // is the device to be changed? + DirEntry *pTop = ImpGetTopPtr(); + if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT || + pTop->eFlag == FSYS_FLAG_RELROOT || pTop->eFlag == FSYS_FLAG_VOLUME ) + && pTop->aName.Len() ) + if ( DosSetDefaultDisk( pTop->aName.Lower()(0)-'a'+1 ) ) + return FALSE; + + APIRET nRet = DosSetCurrentDir( (PSZ) (const char *) GetFull() ); + if ( nRet && bSloppy ) + nRet = DosSetCurrentDir( (PSZ) (const char *) GetPath().GetFull() ); + return !nRet; +} + +/************************************************************************* +|* +|* DirEntry::MoveTo() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 14:07 +|* +*************************************************************************/ + +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 ); +} + +//------------------------------------------------------------------------- + +USHORT DirReader_Impl::Init() +{ + USHORT nRead = 0; + if ( pDir->eAttrMask & FSYS_KIND_BLOCK ) + { + CreateDriveMapImpl(); + DirEntry aCurrentDir; + aCurrentDir.ToAbs(); + char sDrive[3] = "?:"; + + for ( char c = START_DRV; c <= 'z'; c++ ) + { + sDrive[0] = c; + DirEntry* pDrive = new DirEntry( sDrive, + FSYS_FLAG_VOLUME, FSYS_STYLE_HOST ); + if ( aDriveMap[c-'a'].nKind != FSYS_KIND_UNKNOWN && + pDir->aNameMask.Matches( sDrive ) ) + { + 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; + } + + aCurrentDir.SetCWD(); + + } + +// OS2 ist beim Directory auslesen nicht threadfest +#ifdef OS2 + static NAMESPACE_VOS( OMutex )* pMutex = 0; + if( !pMutex ) pMutex = new NAMESPACE_VOS( OMutex ); + NAMESPACE_VOS( OGuard ) aGuard( pMutex ); +#endif + // Workaround: kein async-read, da OS/2 dann nix mehr liefert + for ( USHORT nLastRead; nLastRead = Read(); ) + nRead += nLastRead; + + return nRead; +} + +//------------------------------------------------------------------------- + +USHORT DirReader_Impl::Read() +{ + // Directories und Files auflisten? + if ( ( pDir->eAttrMask & FSYS_KIND_DIR || pDir->eAttrMask & FSYS_KIND_FILE ) && + ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) ) + { + if ( ( ( ( pDir->eAttrMask & FSYS_KIND_DIR ) && + ( pDosEntry->d_type & DOS_DIRECT ) ) || + ( ( pDir->eAttrMask & FSYS_KIND_FILE ) && + !( pDosEntry->d_type & DOS_DIRECT ) ) ) && + pDir->aNameMask.Matches( + ToLowerImpl( String( pDosEntry->d_name ) ) ) ) + { + String aName( FSYS2GUI( pDosEntry->d_name ) ); + DirEntryFlag eFlag = + aName == "." ? FSYS_FLAG_CURRENT + : aName == ".." ? FSYS_FLAG_PARENT + : FSYS_FLAG_NORMAL; + DirEntry *pTemp = new DirEntry( String( aName ), + eFlag, FSYS_STYLE_NTFS ); + 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; + } + } + 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) +{ + paVirtualURL = NULL; + + struct dirent *pDirent = (struct dirent*) pInfo; + + nSize = pDirent->d_size; + + aDateCreated = MsDos2Date( pDirent->d_date ); + aTimeCreated = MsDos2Time( 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 ) +{ + paVirtualURL = rDirEntry.paVirtualURL; + + 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 (paVirtualURL) + { + if (rDirEntry.GetRealPathFromVirtualURL().Len()==0) + { + // keine reale reprsentation fr VirtualURL, also alles setzen, + // lediglich dir/file unterscheidbar + nKindFlags = FSYS_KIND_ALL; + + if (Folder(ItemIDPath(rDirEntry.GetFull())).IsValid()) //ist dir? + { + nKindFlags &= ~FSYS_KIND_FILE; //ja, also kein file + } + else + { + nKindFlags &= ~FSYS_KIND_DIR; //nein, also kein dir + } + + nError = FSYS_ERR_OK; + return TRUE; + } + } + + nError = rDirEntry.IsValid() ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN; + if ( nError > FSYS_ERR_OK ) + return FALSE; + + // Sonderbehandlung falls es sich um eine Wildcard handelt + String aTempName( rDirEntry.GetName() ); + if ( strchr( (char*) (const char*) aTempName, '?' ) || + strchr( (char*) (const char*) aTempName, '*' ) || + strchr( (char*) (const char*) aTempName, ';' ) ) + { + 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(); + + DriveMapItem &rItem = aDriveMap[toupper(rDirEntry.aName[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; + String aFullName; + + aTempDirEntry.ToAbs(); + aFullName = aTempDirEntry.GetFull(); + + if (aTempDirEntry.paVirtualURL) + { + aFullName = rDirEntry.GetRealPathFromVirtualURL(); + } + + if (Folder::IsAvailable() && aTempDirEntry.IsLongNameOnFAT()) + { + // in String mit kurzem Pfad wandeln + ItemIDPath aItemIDPath(aTempDirEntry.GetFull()); + aFullName = aItemIDPath.GetHostNotationPath(); + } + + p = (char *) aFullName.GetStr(); + + 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; +} + +#if SUPD>364 +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 + +const char* TempDirImpl( char *pBuf ) +{ +#if defined( __BORLANDC__ ) && (__BORLANDC__ < 0x0460) + PSZ pVar; +#else + PCSZ pVar; +#endif + 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 ); + + // 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 + *--------------------------------------------------------------------*/ + +void CreateCaseMapImpl() +{ + // build a string starting with code 0 as first character upto 255 + char sTemp[256]; + for ( USHORT 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 + String aLower( rSource ); + for ( USHORT n = 0; n < aLower.Len(); ++n ) + aLower[n] = sCaseMap[ (unsigned char) aLower[n] ]; + return aLower; +} + +/*==================================================================== + * 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; + + // 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 ( 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; + } + } + + // 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, "HPFS" ) == 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 ) +{ + // UNC-Pathname? + if ( !rDevice || ( rDevice.Len() > 1 && rDevice[ (USHORT) 1] != ':' ) ) + return FSYS_STYLE_UNKNOWN; + + if ( !bDriveMap ) + CreateDriveMapImpl(); + return aDriveMap[toupper(rDevice[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; + String aVolume( DirEntry(rPath).ImpGetTopPtr()->GetName() ); + ULONG nDriveNumber = toupper( aVolume(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..bc03d0e21582 --- /dev/null +++ b/tools/source/fsys/os2.hxx @@ -0,0 +1,151 @@ +/************************************************************************* + * + * $RCSfile: os2.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _os2_hxx +#define _os2_hxx + +#include <string.h> + +#include <sys\types.h> +#include <sys\stat.h> +#include <stdio.h> +#include <ctype.h> + +#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 <string.hxx> + +#define FSYS_UNIX FALSE + +#define DOS_DIRECT 16 +#define setdrive(n,a) dos_setdrive(n,a) +#define GETDRIVE(n) dos_getdrive(&n) + +#define _mkdir(p) DosCreateDir( (PSZ)p, 0 ) +#define _rmdir(p) DosDeleteDir( (PSZ)p ) +#define _unlink(p) DosForceDelete( (PSZ)p ) +#define _chdir chdir +#define _getcwd getcwd +#define _access access + +const char* TempDirImpl( char *pBuf ); +String ToLowerImpl( const String& ); + +inline char *getcwd(char *p, ULONG nLen ) +{ + return DosQueryCurrentDir( 0, (PBYTE)p, &nLen ) ? p : 0; +} + +#define dirent _FILEFINDBUF3 +#define d_name achName +#define d_type attrFile +#define d_size cbFile +#define d_attr attrFile +#define d_date fdateLastWrite +#define d_time ftimeLastWrite + +typedef struct +{ + HDIR aDirHdl; + FILEFINDBUF3 aDirEnt; + char *p; +} DIR; + +#define DEFSTYLE FSYS_STYLE_OS2 +#define MKDIR( p ) mkdir( (unsigned char*) p ) +#define CMP_LOWER(aString) ToLowerImpl(aString) + +#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..021bed1f196e --- /dev/null +++ b/tools/source/fsys/tdir.cxx @@ -0,0 +1,808 @@ +/************************************************************************* + * + * $RCSfile: tdir.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _DIR_CXX + +#include <stdlib.h> +#include <stdarg.h> +#include <limits.h> + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _LIST_HXX +#include <list.hxx> +#endif + +#ifndef _COMPED_HXX +#include "comdep.hxx" +#endif +#ifndef _FSYS_HXX +#include <fsys.hxx> +#endif + + +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? +#ifndef UNX //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 += 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 ); + + 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( 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; + + // Ascending oder Descending? + BOOL bAscending = FSYS_SORT_ASCENDING == + ( *pSort & ( FSYS_SORT_ASCENDING | FSYS_SORT_DESCENDING ) ); + USHORT 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, ... ) +{ + 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 *pStat = NULL; + for ( USHORT nNr = 0; nNr < rDir.Count(); nNr++ ) { + if ( bStat ) + if ( rDir.pStatLst ) + { + pStat = new FileStat( *rDir.pStatLst->GetObject(nNr) ); + } + else + pStat = new FileStat( rDir[nNr] ); + ImpSortedInsert( new DirEntry( rDir[nNr] ), pStat ); + } + 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..f920d18dde0f --- /dev/null +++ b/tools/source/fsys/tempfile.cxx @@ -0,0 +1,337 @@ +/************************************************************************* + * + * $RCSfile: tempfile.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include "tempfile.hxx" +#include "comdep.hxx" + +#include <rtl/ustring.hxx> +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif +#ifndef _TOOLS_TIME_HXX +#include <time.hxx> +#endif +#include <debug.hxx> +#include <stdio.h> + +#ifdef UNX +#define _MAX_PATH 260 +#endif + +using namespace osl; + +static ::rtl::OUString aTempNameBase_Impl; + +struct TempFile_Impl +{ + String aName; + sal_Bool bIsDirectory; +}; + +String GetSystemTempDir_Impl() +{ + char sBuf[_MAX_PATH]; + const char *pDir = TempDirImpl(sBuf); + ::rtl::OUString aTmp = ::rtl::OUString::createFromAscii( pDir ); + rtl::OUString aRet; + FileBase::normalizePath( aTmp, aRet ); + String aName = aRet; + sal_Int32 i = aName.Len(); + if( aName.GetChar(i-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 + if ( FileBase::getNormalizedPathFromFileURL( aTmp, aRet ) == FileBase::E_None ) + { + ::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 + if ( !aTempNameBase_Impl.getLength() ) + aTempNameBase_Impl = GetSystemTempDir_Impl(); + aName = aTempNameBase_Impl; + } + + // Make sure that directory ends with a separator + sal_Int32 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" ); + sal_Int32 i = aName.Len(); + + 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() ) + FileBase::getFileURLFromNormalizedPath( aName, aTmp ); + 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; + FileBase::getFileURLFromNormalizedPath( pImp->aName, aTmp ); + return aTmp; +} + +String TempFile::SetTempNameBaseDirectory( const String &rBaseName ) +{ +// if ( !aTempNameBase_Impl.getLength() ) +// aTempNameBase_Impl = GetSystemTempDir_Impl(); +// String aName( aTempNameBase_Impl ); +// aName += rBaseName; + + String aName( rBaseName ); + + FileBase::RC err= Directory::create( aName ); + if ( err == FileBase::E_None || err == FileBase::E_EXIST ) + { + aTempNameBase_Impl = aName; + aTempNameBase_Impl += ::rtl::OUString( '/' ); + + TempFile aBase( NULL, sal_True ); + if ( aBase.IsValid() ) + aTempNameBase_Impl = aBase.pImp->aName; + } + + rtl::OUString aTmp; + FileBase::getFileURLFromNormalizedPath( aTempNameBase_Impl, aTmp ); + return aTmp; +} + +String TempFile::GetTempNameBaseDirectory() +{ + if ( !aTempNameBase_Impl.getLength() ) + aTempNameBase_Impl = GetSystemTempDir_Impl(); + + rtl::OUString aTmp; + FileBase::getFileURLFromNormalizedPath( aTempNameBase_Impl, aTmp ); + return aTmp; +} + diff --git a/tools/source/fsys/unx.cxx b/tools/source/fsys/unx.cxx new file mode 100644 index 000000000000..245ba9ebad4d --- /dev/null +++ b/tools/source/fsys/unx.cxx @@ -0,0 +1,694 @@ +/************************************************************************* + * + * $RCSfile: unx.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <utime.h> +#if defined HPUX || defined LINUX || defined IRIX +#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 S390 +#include <sys/mntent.h> +#define mnttab w_mntent +#elif defined(NETBSD) || 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 <debug.hxx> +#include <list.hxx> +#include <fsys.hxx> +#include "comdep.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 +#elif defined S390 +#define MOUNTSPECIAL mnt_fsname +#define MOUNTPOINT mnt_mountpoint +#else +#define MOUNTSPECIAL mnt_fsname +#define MOUNTPOINT mnt_dir +#define MOUNTFS mnt_type +#endif + +static ByteString sLastCaseSensitiveDir = ""; +static BOOL bLastCaseSensitive = FALSE; + +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 || defined S390 + 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 +|* +*************************************************************************/ + +static mymnttab mymnt; +static String aEmptyString; + +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 aEmptyString; + aPath = aPath [1]; + } + + return ((buf.st_dev == mymnt.mountdevice || + GetMountEntry(buf.st_dev, &mymnt)) ? String(mymnt.mountspecial, osl_getThreadTextEncoding()) : aEmptyString); +} + +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 aEmptyString; + aPath = aPath [1]; + } + return ((buf.st_dev == mymnt.mountdevice || + GetMountEntry(buf.st_dev, &mymnt)) ? String( mymnt.mountpoint, osl_getThreadTextEncoding()) : aEmptyString); +} + +/************************************************************************* +|* +|* DirEntry::SetCWD() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung DV 04.11.92 +|* +*************************************************************************/ + +BOOL DirEntry::SetCWD( BOOL bSloppy ) +{ + 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 +|* +*************************************************************************/ +#if SUPD < 345 +BOOL FileStat::Update( const DirEntry& rDirEntry ) +{ + return Update( rDirEntry, FALSE ); +} +#endif + +BOOL FileStat::Update( const DirEntry& rDirEntry, BOOL bAccessRemovableDevice ) +{ + + 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 ) +{ + 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" ); + return pBuf; +} + +/************************************************************************* +|* +|* DirEntry::GetPathStyle() const +|* +|* Beschreibung +|* Ersterstellung MI 11.05.95 +|* Letzte Aenderung MI 11.05.95 +|* +*************************************************************************/ + +FSysPathStyle DirEntry::GetPathStyle( const String &rDevice ) +{ + 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 (×); + + 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 &rPath, + BigInt &rFreeBytes, BigInt &rTotalBytes ) +{ + return ERRCODE_IO_NOTSUPPORTED; +} + +//========================================================================= + +void FSysEnableSysErrorBox( BOOL bEnable ) +{ +} + diff --git a/tools/source/fsys/unx.hxx b/tools/source/fsys/unx.hxx new file mode 100644 index 000000000000..2751289b7c2e --- /dev/null +++ b/tools/source/fsys/unx.hxx @@ -0,0 +1,139 @@ +/************************************************************************* + * + * $RCSfile: unx.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _unx_hxx +#define _unx_hxx + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifndef S390 +#include <sys/param.h> +#endif + +#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 <datetime.hxx> + +#ifndef localtime_r +extern "C" { +struct tm *localtime_r(const time_t *timep, struct tm *buffer); +} +#endif + +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..e3c937c5a7d4 --- /dev/null +++ b/tools/source/fsys/urlobj.cxx @@ -0,0 +1,5021 @@ +/************************************************************************* + * + * $RCSfile: urlobj.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define min min // fool <tools/solar.h>... +#define max max // fool <tools/solar.h>... + +#ifndef _URLOBJ_HXX +#include <urlobj.hxx> +#endif + +#include <limits> + +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif + +#ifndef _TOOLS_DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef TOOLS_INETMIME_HXX +#include <inetmime.hxx> +#endif +#ifndef _TOOLS_INTN_HXX +#include <intn.hxx> +#endif + +namespace unnamed_tools_urlobj {} using namespace unnamed_tools_urlobj; + // unnamed namespaces don't work well yet... + +//============================================================================ +// +// 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 / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~") + password = *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~") + hostport = host [":" port] + host = incomplete-hostname / hostname / IPv4address / IPv6reference + incomplete-hostname = *(domainlabel ".") domainlabel + hostname = *(domainlabel ".") toplabel ["."] + domainlabel = alphadigit [*(alphadigit / "-") alphadigit] + toplabel = ALPHA [*(alphadigit / "-") alphadigit] + alphadigit = ALPHA / DIGIT + 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 + file-url = "FILE://" [host / "LOCALHOST"] ["/" segment *("/" segment)] + segment = *pchar + + + ; RFC 2368, RFC 2396 + mailto-url = "MAILTO:" [to] [headers] + to = {RFC 822 <#mailbox> using *(escaped / ALPHA / DIGIT / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} + headers = "?" header *("&" header) + header = hname "=" hvalue + hname = {RFC 822 <field-name> using *(escaped / ALPHA / DIGIT / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} / "BODY" + hvalue = {RFC 822 <field-body> using *(escaped / ALPHA / DIGIT / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} + + + ; private (see RFC 1738) + news-url = "NEWS://" login ["/" (group / message)] + group = *uric + message = "<" *uric ">" + + + ; private + private-url = "PRIVATE:" path ["?" *uric] + path = *(escaped / ALPHA / DIGIT / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~" + + + ; private + https-url = "HTTPS://" hostport ["/" segment *("/" segment) ["?" *uric]] + segment = *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") + + + ; private + slot-url = "SLOT:" path ["?" *uric] + path = *(escaped / ALPHA / DIGIT / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~" + + + ; private + macro-url = "MACRO:" path ["?" *uric] + path = *(escaped / ALPHA / DIGIT / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~" + + + ; 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 / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "=" / "_" / "~")} + auth = {RFC 2060 <atom> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "+" / "," / "-" / "." / "=" / "_" / "~")} + segment = *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / "=" / "@" / "_" / "~") + 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 / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} + subtype = {RFC 2045 <subtype> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} + attribute = {RFC 2045 <subtype> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} + value = {RFC 2045 <subtype> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} + + + ; RFC 2392, RFC 2396 + cid-url = "CID:" {RFC 822 <addr-spec> using *uric} + + + ; private + out-url = "OUT:///~" name ["/" *uric] + name = *(escaped / ALPHA / DIGIT / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "?" / "@" / "_" / "~" + + + ; private + vim-url = "VIM://" +vimc [":" *vimc] ["/" [("INBOX" message) / ("NEWSGROUPS" ["/" [+vimc message]])]] + message = ["/" [+vimc [":" +DIGIT "." +DIGIT "." +DIGIT]]] + vimc = ("=" HEXDIG HEXDIG) / ALPHA / DIGIT + + + ; private + uno-url = ".UNO:" *uric + + + ; private + component-url = ".COMPONENT:" path ["?" *uric] + path = *(escaped / ALPHA / DIGIT / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~" + + + ; RFC 2255 + ldap-url = "LDAP://" [hostport] ["/" [dn ["?" [attrdesct *("," attrdesc)] ["?" ["base" / "one" / "sub"] ["?" [filter] ["?" extension *("," extension)]]]]]] + dn = {RFC 2253 <distinguishedName> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} + attrdesc = {RFC 2251 <AttributeDescription> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} + filter = {RFC 2254 <filter> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} + extension = ["!"] ["X-"] extoken ["=" exvalue] + extoken = {RFC 2252 <oid> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} + exvalue = {RFC 2251 <LDAPString> using *(escaped / ALPHA / DIGIT / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} + + + ; private + db-url = "DB:" *uric + */ + +//============================================================================ +inline sal_Int32 INetURLObject::SubString::clear() +{ + sal_Int32 nDelta = -m_nLength; + m_nBegin = STRING_NOTFOUND; + m_nLength = 0; + return nDelta; +} + +//============================================================================ +inline sal_Int32 INetURLObject::SubString::set(UniString & rString, + UniString const & rSubString) +{ + DBG_ASSERT(isPresent(), "INetURLObject::SubString::set(): Not present"); + sal_Int32 nDelta = rSubString.Len() - m_nLength; + rString.Replace(m_nBegin, m_nLength, rSubString); + m_nLength = rSubString.Len(); + return nDelta; +} + +//============================================================================ +inline sal_Int32 INetURLObject::SubString::set(UniString & rString, + UniString const & rSubString, + xub_StrLen nTheBegin) +{ + m_nBegin = nTheBegin; + return set(rString, rSubString); +} + +//============================================================================ +inline void INetURLObject::SubString::operator +=(sal_Int32 nDelta) +{ + if (isPresent()) + m_nBegin += nDelta; +} + +//============================================================================ +bool INetURLObject::SubString::equals(SubString const & rOther, + UniString const & rThisString, + UniString const & rOtherString) const +{ + if (m_nLength != rOther.m_nLength) + return true; + sal_Unicode const * p1 = rThisString.GetBuffer() + m_nBegin; + sal_Unicode const * p1End = p1 + m_nLength; + sal_Unicode const * p2 = rOtherString.GetBuffer() + rOther.m_nBegin; + while (p1 != p1End) + if (*p1++ != *p2++) + return false; + return true; +} + +//============================================================================ +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, EXTERNAL, INTERNAL }; + + sal_Char const * m_pPrefix; + sal_Char const * m_pTranslatedPrefix; + INetProtocol m_eScheme; + Kind m_eKind; +}; + +//============================================================================ +// static + +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 }, + { 0, 0, 0, false, false, false, false, false, false, false, + false }, + { "news", "news:", 119, true, true, false, true, true, true, + false, false }, + { "private", "private:", 0, false, false, false, false, false, + false, false, true }, + { 0, 0, 0, false, false, false, false, false, false, false, + false }, + { "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 }, + { 0, 0, 0, false, false, false, false, false, false, false, + false }, + { 0, 0, 0, false, false, false, false, false, false, false, + false }, + { "vim", "vim://", 0, true, true, false, true, false, false, true, + false }, + { ".uno", ".uno:", 0, false, false, false, false, false, false, + false, false }, + { ".component", ".component:", 0, false, false, false, false, + false, false, false, true }, + { 0, 0, 0, false, false, false, false, false, false, false, + false }, + { "ldap", "ldap://", 389, true, false, false, false, true, true, + false, true }, + { "db", "db:", 0, false, false, false, false, false, false, false, + false }, + { 0, 0, 0, false, false, false, false, false, false, false, + false } }; + +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(UniString & rTheText, + sal_Char cEscapePrefix, + sal_uInt32 nOctet) +{ + rTheText += cEscapePrefix; + rTheText += sal_Unicode(INetMIME::getHexDigit(int(nOctet >> 4))); + rTheText += sal_Unicode(INetMIME::getHexDigit(int(nOctet & 15))); +} + +//============================================================================ +// static +inline void INetURLObject::appendUTF32(UniString & rTheText, + sal_uInt32 nUTF32) +{ + DBG_ASSERT(nUTF32 <= 0x10FFFF, "INetURLObject::appendUTF32(): Bad char"); + if (nUTF32 < 0x10000) + rTheText += sal_Unicode(nUTF32); + else + { + nUTF32 -= 0x10000; + rTheText += sal_Unicode(0xD800 | nUTF32 >> 10); + rTheText += sal_Unicode(0xDC00 | nUTF32 & 0x3FF); + } +} + +//============================================================================ +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 +}; +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, +/* " */ 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, +/* % */ pU, +/* & */ pA+pB+pC+pD+pE+pH+pI+pJ+pK+pL+pM+pN+pO+pP+pR+pS+pT+pU+pV+pW+pX, +/* ' */ pD+pE+pG+pH+pI+pJ+pK+pL+pM+pN+pO+pP+pQ+pR+pS+pT+pU+pV+pW+pX+pY, +/* ( */ pD+pE+pG+pH+pI+pJ+pK+pL+pM+pN+pO+pP+pQ+pR+pS+pT+pU+pV+pW+pX+pY, +/* ) */ pD+pE+pG+pH+pI+pJ+pK+pL+pM+pN+pO+pP+pQ+pR+pS+pT+pU+pV+pW+pX+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, +/* + */ pA+pB+pC+pD+pE+pG+pH+pI+pJ+pK+pL+pM+pN+pO+pP+pQ+pR+pS+pT+pU+pV+pW+pX, +/* , */ pA+pB+pC+pD+pE+pG+pH+pI+pJ+pK+pL+pM+pN+pO+pP+pQ+pR+pS+pT+pU+pV+pW, +/* - */ pA+pB+pC+pD+pE+pG+pH+pI+pJ+pK+pL+pM+pN+pO+pP+pQ+pR+pS+pT+pU+pV+pW+pX+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, +/* / */ pA+pB+pC+pH+pJ+pL+pM+pP+pQ+pR+pT+pU+pV+pX, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* : */ pB+pC+pH+pI+pJ+pL+pM+pN+pO+pP+pQ+pR+pS+pT+pU+pV+pW+pX, +/* ; */ pC+pD+pI+pJ+pK+pL+pM+pO+pP+pQ+pR+pT+pU+pW, +/* < */ pC+pO+pP+pU+pV+pY, +/* = */ pA+pB+pC+pD+pE+pH+pI+pJ+pK+pL+pM+pN+pR+pS+pT+pU+pV+pW, +/* > */ pC+pO+pP+pU+pV+pY, +/* ? */ pC+pL+pT+pU+pW+pX, +/* @ */ pC+pH+pI+pJ+pK+pL+pM+pN+pO+pP+pQ+pR+pS+pT+pU+pV+pW+pX+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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* [ */ 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, +/* ` */ +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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* 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, +/* { */ +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, +/* */ 0 }; + +inline bool mustEncode(sal_uInt32 nUTF32, INetURLObject::Part ePart) +{ + return !INetMIME::isUSASCII(nUTF32) || !(aMustEncodeMap[nUTF32] & ePart); +} + +} + +//============================================================================ +void INetURLObject::setInvalid() +{ + m_aAbsURIRef.Erase(); + m_eScheme = INET_PROT_NOT_VALID; + 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; +} + +} + +bool INetURLObject::setAbsURIRef(UniString const & rTheAbsURIRef, + bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, + bool bSmart, + FSysStyle eStyle) +{ + sal_Unicode const * pPos = rTheAbsURIRef.GetBuffer(); + sal_Unicode const * pEnd = pPos + rTheAbsURIRef.Len(); + + setInvalid(); + + sal_uInt32 nFragmentDelimiter = '#'; + + UniString aSynAbsURIRef; + + // Parse <scheme>: + sal_Unicode const * p = pPos; + PrefixInfo const * pPrefix = getPrefix(p, pEnd); + if (pPrefix) + { + pPos = p; + m_eScheme = pPrefix->m_eScheme; + aSynAbsURIRef + = UniString::CreateFromAscii(pPrefix->m_eKind + == PrefixInfo::EXTERNAL ? + pPrefix->m_pTranslatedPrefix : + pPrefix->m_pPrefix); + } + 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 * p = pPos; + if (eStyle & FSYS_DOS + && pEnd - p >= 3 + && INetMIME::isAlpha(p[0]) + && p[1] == ':' + && (p[2] == '/' || p[2] == '\\')) + { + m_eScheme = INET_PROT_FILE; // 8th, 9th + eMechanism = ENCODE_ALL; + nFragmentDelimiter = 0x80000000; + } + else if (pEnd - p >= 2 && p[0] == '/' && p[1] == '/') + { + p += 2; + if ((scanDomain(p, pEnd) > 0 || scanIPv6reference(p, pEnd)) + && (p == pEnd || *p == '/')) + m_eScheme = INET_PROT_FILE; // 5th + } + else if (p != pEnd && *p == '/') + { + m_eScheme = INET_PROT_FILE; // 6th + eMechanism = ENCODE_ALL; + nFragmentDelimiter = 0x80000000; + } + else if (eStyle & FSYS_DOS + && pEnd - p >= 2 + && p[0] == '\\' + && p[1] == '\\') + { + p += 2; + if (scanDomain(p, pEnd) > 0 && (p == pEnd || *p == '\\')) + { + m_eScheme = INET_PROT_FILE; // 7th + eMechanism = ENCODE_ALL; + nFragmentDelimiter = 0x80000000; + } + } + else + { + sal_Unicode const * pDomainEnd = p; + 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 - p >= 4 + && p[0] == 'f' + && p[1] == 't' + && p[2] == 'p' + && p[3] == '.' ? + INET_PROT_FTP : INET_PROT_HTTP; // 3rd, 4th + } + + if (m_eScheme == INET_PROT_NOT_VALID && pPos != pEnd + && *pPos != nFragmentDelimiter) + m_eScheme = m_eSmartScheme; + } + + if (m_eScheme == INET_PROT_NOT_VALID) + { + setInvalid(); + return false; + } + + aSynAbsURIRef = UniString::CreateFromAscii(getSchemeInfo().m_pScheme); + aSynAbsURIRef += ':'; + } + + 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> + if (getSchemeInfo().m_bAuthority) + { + aSynAbsURIRef.AppendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + + 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_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 * p = pPos + 2; + if (p == pEnd || *p == nFragmentDelimiter || *p == '/' + || (scanDomain(p, pEnd) > 0 + || scanIPv6reference(p, pEnd)) + && (p == pEnd || *p == nFragmentDelimiter + || *p == '/')) + { + pHostPortBegin = pPos + 2; + pHostPortEnd = p; + pPos = p; + break; + } + } + + // 2nd Production (misscounted slashes): + // "//" *path ["#" *UCS4] + // becomes + // "file:///" *path ["#" *UCS4] + if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') + { + pPos += 2; + bSkippedInitialSlash = true; + break; + } + + // 3rd Production (Unix): + // "/" *path ["#" *UCS4] + // becomes + // "file:///" *path ["#" *UCS4] + if (pPos < pEnd && *pPos == '/') + break; + + // 4th 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 * p = pPos + 2; + if (scanDomain(p, pEnd) > 0 + && (p == pEnd || *p == nFragmentDelimiter + || *p == '\\')) + { + pHostPortBegin = pPos + 2; + pHostPortEnd = p; + pPos = p; + nSegmentDelimiter = '\\'; + break; + } + } + + // 5th Production (Unix-like DOS; FSYS_DOS only): + // ALPHA ":/" *path ["#" *UCS4] + // becomes + // "file:///" ALPHA ":/" *path ["#" *UCS4] + // replacing "\" by "/" within <*path> + // + // 6th Production (DOS; FSYS_DOS only): + // ALPHA ":\" *path ["#" *UCS4] + // becomes + // "file:///" ALPHA ":/" *path ["#" *UCS4] + // replacing "\" by "/" within <*path> + if (eStyle & FSYS_DOS + && pEnd - pPos >= 3 + && INetMIME::isAlpha(pPos[0]) + && pPos[1] == ':' + && (pPos[2] == '/' || pPos[2] == '\\')) + { + nAltSegmentDelimiter = '\\'; + bSkippedInitialSlash = true; + break; + } + + // 7th 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)) + { + 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: + { + if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') + pPos += 2; + else if (!bSmart) + { + setInvalid(); + return false; + } + + 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 * p = pAuthority; + while (p < pPos && *p != '@') + ++p; + if (p == pPos) + { + pHostPortBegin = pAuthority; + pHostPortEnd = pPos; + } + else + { + pUserInfoBegin = pAuthority; + pUserInfoEnd = p; + pHostPortBegin = p + 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; + UniString aSynUser; + sal_Unicode const * p = pUserInfoBegin; + while (p < pUserInfoEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(p, pUserInfoEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + if (eEscapeType == ESCAPE_NO) + if (nUTF32 == ':' && bSupportsPassword) + { + bHasAuth = true; + break; + } + else if (nUTF32 == ';' && bSupportsAuth + && pUserInfoEnd - p + > RTL_CONSTASCII_LENGTH("auth=") + && INetMIME::equalIgnoreCase( + p, + p + RTL_CONSTASCII_LENGTH("auth="), + "auth=")) + { + p += RTL_CONSTASCII_LENGTH("auth="); + bHasAuth = true; + break; + } + appendUCS4(aSynUser, nUTF32, eEscapeType, bOctets, ePart, + cEscapePrefix, eCharset, false); + } + m_aUser.set(aSynAbsURIRef, aSynUser, aSynAbsURIRef.Len()); + if (bHasAuth) + if (bSupportsPassword) + { + aSynAbsURIRef += ':'; + UniString aSynAuth; + while (p < pUserInfoEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(p, pUserInfoEnd, bOctets, + cEscapePrefix, + eMechanism, eCharset, + eEscapeType); + appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets, + ePart, cEscapePrefix, eCharset, false); + } + m_aAuth.set(aSynAbsURIRef, aSynAuth, aSynAbsURIRef.Len()); + } + else + { + aSynAbsURIRef. + AppendAscii(RTL_CONSTASCII_STRINGPARAM(";AUTH=")); + UniString aSynAuth; + while (p < pUserInfoEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(p, 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, aSynAbsURIRef.Len()); + } + if (pHostPortBegin) + aSynAbsURIRef += '@'; + } + + if (pHostPortBegin) + { + sal_Unicode const * pPort = pHostPortEnd; + if (getSchemeInfo().m_bPort && pHostPortBegin < pHostPortEnd) + { + sal_Unicode const * p = pHostPortEnd - 1; + while (p > pHostPortBegin && INetMIME::isDigit(*p)) + --p; + if (*p == ':') + pPort = p; + } + 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; + break; + + case INET_PROT_LDAP: + if (pHostPortBegin == pPort && pPort != pHostPortEnd) + { + setInvalid(); + return false; + } + break; + + default: + if (pHostPortBegin == pPort) + { + setInvalid(); + return false; + } + break; + } + UniString aSynHost; + if (pHostPortBegin != pPort + && (!parseHost(pHostPortBegin, pPort, bOctets, eMechanism, + eCharset, aSynHost) + || pHostPortBegin != pPort)) + { + setInvalid(); + return false; + } + m_aHost.set(aSynAbsURIRef, aSynHost, aSynAbsURIRef.Len()); + if (pPort != pHostPortEnd) + { + aSynAbsURIRef += ':'; + m_aPort.set(aSynAbsURIRef, + UniString(pPort + 1, pHostPortEnd - (pPort + 1)), + aSynAbsURIRef.Len()); + } + } + } + + // Parse <path> + UniString aSynPath; + if (!parsePath(&pPos, pEnd, bOctets, eMechanism, eCharset, + bSkippedInitialSlash, nSegmentDelimiter, + nAltSegmentDelimiter, + getSchemeInfo().m_bQuery ? '?' : 0x80000000, + nFragmentDelimiter, &aSynPath)) + { + setInvalid(); + return false; + } + m_aPath.set(aSynAbsURIRef, aSynPath, aSynAbsURIRef.Len()); + + // Parse ?<query> + if (getSchemeInfo().m_bQuery && pPos < pEnd && *pPos == '?') + { + aSynAbsURIRef += '?'; + UniString 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, aSynAbsURIRef.Len()); + } + + // Parse #<fragment> + if (pPos < pEnd && *pPos == nFragmentDelimiter) + { + aSynAbsURIRef += nFragmentDelimiter; + UniString 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, aSynAbsURIRef.Len()); + } + + if (pPos != pEnd) + { + setInvalid(); + return false; + } + + m_aAbsURIRef = aSynAbsURIRef; + + return true; +} + +//============================================================================ +// static +INetURLObject INetURLObject::m_aBaseURIRef; + +//============================================================================ +bool INetURLObject::convertRelToAbs(UniString 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.GetBuffer(); + sal_Unicode const * pEnd = p + rTheRelURIRef.Len(); + + sal_Unicode const * pPrefixBegin = p; + PrefixInfo const * pPrefix = getPrefix(pPrefixBegin, pEnd); + + sal_uInt32 nSegmentDelimiter = '/'; + sal_uInt32 nQueryDelimiter + = !bSmart || getSchemeInfo().m_bQuery ? '?' : 0x80000000; + sal_uInt32 nFragmentDelimiter = '#'; + Part ePart = PART_VISIBLE; + + if (!pPrefix && 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 >= 3 + && INetMIME::isAlpha(q[0]) + && q[1] == ':' + && (q[2] == '/' || q[2] == '\\')) + bFSys = true; // 2nd, 3rd + else if (pEnd - q >= 2 && q[0] == '\\' && q[1] == '\\') + { + q += 2; + if (scanDomain(q, pEnd) > 0 && (q == pEnd || *q == '\\')) + 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) + { + pPrefix = 0; + while (p != pEnd && *p++ != ':'); + } + rWasAbsolute = pPrefix != 0; + + // Fast solution for non-relative URIs: + if (pPrefix) + { + INetURLObject aNewURI(rTheRelURIRef, eMechanism, eCharset); + if (aNewURI.HasError()) + { + rWasAbsolute = false; + return false; + } + + if (bIgnoreFragment) + aNewURI.clearFragment(); + rTheAbsURIRef = aNewURI; + return true; + } + + UniString aSynAbsURIRef(UniString::CreateFromAscii(getSchemeInfo(). + m_pScheme)); + aSynAbsURIRef += ':'; + + sal_Char cEscapePrefix = getEscapePrefix(); + + enum State { STATE_AUTH, STATE_ABS_PATH, STATE_REL_PATH, STATE_FRAGMENT, + STATE_DONE }; + 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.GetBuffer() + + 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 += '/'; + 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) + { + rWasAbsolute = false; + return false; + } + + sal_Unicode const * pBasePathBegin + = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pBasePathEnd + = pBasePathBegin + m_aPath.getLength(); + while (pBasePathEnd != pBasePathBegin) + if (*(--pBasePathEnd) == '/') + { + ++pBasePathEnd; + break; + } + + xub_StrLen nPathBegin = aSynAbsURIRef.Len(); + aSynAbsURIRef.Append(pBasePathBegin, pBasePathEnd - pBasePathBegin); + DBG_ASSERT(aSynAbsURIRef.Len() > nPathBegin + && aSynAbsURIRef.GetChar(aSynAbsURIRef.Len() - 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.Len() - nPathBegin > 1) + { + p += 2; + if (p != pEnd && *p == nSegmentDelimiter) + ++p; + + xub_StrLen i = aSynAbsURIRef.Len() - 2; + while (i > nPathBegin && aSynAbsURIRef.GetChar(i) != '/') + --i; + aSynAbsURIRef.Erase(i + 1); + DBG_ASSERT( + aSynAbsURIRef.Len() > nPathBegin + && aSynAbsURIRef.GetChar(aSynAbsURIRef.Len() - 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 += '/'; + ++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.GetBuffer() + m_aPath.getBegin(), + m_aPath.getLength()); + if (m_aQuery.isPresent()) + aSynAbsURIRef.Append(m_aAbsURIRef.GetBuffer() + + m_aQuery.getBegin() - 1, + m_aQuery.getLength() + 1); + } + + if (eState == STATE_FRAGMENT && !bIgnoreFragment) + { + aSynAbsURIRef += '#'; + 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); + if (aNewURI.HasError()) + { + rWasAbsolute = false; + return false; + } + + rTheAbsURIRef = aNewURI; + return true; +} + +//============================================================================ +bool INetURLObject::convertAbsToRel(UniString const & rTheAbsURIRef, + bool bOctets, UniString & 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 URI ref, relative URI ref, file path) to an + // absolute URI ref: + INetURLObject aSubject; + bool bWasAbsolute; + if (!convertRelToAbs(rTheAbsURIRef, bOctets, aSubject, bWasAbsolute, + eEncodeMechanism, eCharset, false, true, false, + eStyle)) + { + rTheRelURIRef + = decode(rTheAbsURIRef, + getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)), + eDecodeMechanism, eCharset); + return false; + } + + // Check for differing scheme or authority parts: + if (m_eScheme != aSubject.m_eScheme + || !m_aUser.equals(aSubject.m_aUser, m_aAbsURIRef, + aSubject.m_aAbsURIRef) + || !m_aAuth.equals(aSubject.m_aAuth, m_aAbsURIRef, + aSubject.m_aAbsURIRef) + || !m_aHost.equals(aSubject.m_aHost, m_aAbsURIRef, + aSubject.m_aAbsURIRef) + || !m_aPort.equals(aSubject.m_aPort, m_aAbsURIRef, + aSubject.m_aAbsURIRef)) + { + rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset); + return false; + } + + sal_Unicode const * pBasePathBegin + = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pBasePathEnd = pBasePathBegin + m_aPath.getLength(); + sal_Unicode const * pSubjectPathBegin + = aSubject.m_aAbsURIRef.GetBuffer() + 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_uInt32 nMatch = pSlash - pBasePathBegin; + + // For file URLs, if the common prefix of the two paths is only "/" (which + // covers different DOS volumes like "/a:" and "/b:"), the subject is not + // made relative (it could be, but some people don't like that): + if (m_eScheme == INET_PROT_FILE && nMatch <= 1) + { + 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): + UniString 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.Len() == 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 += 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 += '?'; + aSynRelURIRef += aSubject.decode(aSubject.m_aQuery, cEscapePrefix, + eDecodeMechanism, eCharset); + } + if (aSubject.m_aFragment.isPresent()) + { + aSynRelURIRef += '#'; + aSynRelURIRef += aSubject.decode(aSubject.m_aFragment, cEscapePrefix, + eDecodeMechanism, eCharset); + } + + rTheRelURIRef = aSynRelURIRef; + return true; +} + +//============================================================================ +// static +bool INetURLObject::convertIntToExt(UniString const & rTheIntURIRef, + bool bOctets, UniString & rTheExtURIRef, + EncodeMechanism eEncodeMechanism, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset) +{ + sal_Char cEscapePrefix + = getEscapePrefix(CompareProtocolScheme(rTheIntURIRef)); + UniString aSynExtURIRef(encodeText(rTheIntURIRef, bOctets, PART_VISIBLE, + cEscapePrefix, NOT_CANONIC, eCharset, + true)); + sal_Unicode const * pBegin = aSynExtURIRef.GetBuffer(); + sal_Unicode const * pEnd = pBegin + aSynExtURIRef.Len(); + sal_Unicode const * p = pBegin; + PrefixInfo const * pPrefix = getPrefix(p, pEnd); + bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::INTERNAL; + if (bConvert) + aSynExtURIRef. + Replace(0, p - pBegin, + UniString::CreateFromAscii(pPrefix->m_pTranslatedPrefix)); + rTheExtURIRef = decode(aSynExtURIRef, cEscapePrefix, eDecodeMechanism, + eCharset); + return bConvert; +} + +//============================================================================ +// static +bool INetURLObject::convertExtToInt(UniString const & rTheExtURIRef, + bool bOctets, UniString & rTheIntURIRef, + EncodeMechanism eEncodeMechanism, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset) +{ + sal_Char cEscapePrefix + = getEscapePrefix(CompareProtocolScheme(rTheExtURIRef)); + UniString aSynIntURIRef(encodeText(rTheExtURIRef, bOctets, PART_VISIBLE, + cEscapePrefix, NOT_CANONIC, eCharset, + true)); + sal_Unicode const * pBegin = aSynIntURIRef.GetBuffer(); + sal_Unicode const * pEnd = pBegin + aSynIntURIRef.Len(); + sal_Unicode const * p = pBegin; + PrefixInfo const * pPrefix = getPrefix(p, pEnd); + bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::EXTERNAL; + if (bConvert) + aSynIntURIRef. + Replace(0, p - pBegin, + UniString::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 }, + { "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 }, + { "vim:", "staroffice.vim:", INET_PROT_VIM, + PrefixInfo::INTERNAL } }; + 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; + xub_StrLen 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 && pFirst->m_pPrefix[i] < nChar) + ++pFirst; + while (pFirst <= pLast && 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) == *q) + { + ++p; + ++q; + } + if (*q == '\0') + { + rBegin = p; + return pFirst; + } + } + rBegin = pMatched; + return pMatch; +} + +//============================================================================ +INetURLObject::SubString INetURLObject::getAuthority() const +{ + DBG_ASSERT(getSchemeInfo().m_bAuthority, + "INetURLObject::getAuthority(): Bad scheme"); + + xub_StrLen 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.GetChar(nBegin) == '/' + && m_aAbsURIRef.GetChar(nBegin + 1) == '/', + "INetURLObject::getAuthority(): Bad authority"); + + xub_StrLen 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(UniString const & rTheUser, + bool bOctets, EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (!getSchemeInfo().m_bUser + || m_eScheme == INET_PROT_IMAP && rTheUser.Len() == 0) + return false; + UniString 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()); + 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; +} + +//============================================================================ +bool INetURLObject::clearPassword() +{ + if (!getSchemeInfo().m_bPassword) + return false; + if (m_aAuth.isPresent()) + { + m_aAbsURIRef.Erase(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(UniString const & rThePassword, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (!getSchemeInfo().m_bPassword) + return false; + UniString 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()); + nDelta + = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aUser.getEnd() + 1) + 1; + } + else if (m_aHost.isPresent()) + { + m_aAbsURIRef.InsertAscii(":@", m_aHost.getBegin()); + m_aUser.set(m_aAbsURIRef, UniString(), 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()); + m_aUser.set(m_aAbsURIRef, UniString(), 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 +UniString INetURLObject::encodeHostPort(UniString const & rTheHostPort, + bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + xub_StrLen nPort = rTheHostPort.Len(); + if (rTheHostPort.Len() != 0) + { + xub_StrLen i = rTheHostPort.Len() - 1; + while (i != 0 && INetMIME::isDigit(rTheHostPort.GetChar(i))) + --i; + if (rTheHostPort.GetChar(i) == ':') + nPort = i; + } + UniString aResult(encodeText(rTheHostPort.Copy(0, nPort), bOctets, + PART_HOST_EXTRA, '%', eMechanism, eCharset, + true)); + aResult += rTheHostPort.Copy(nPort); + return aResult; +} + +//============================================================================ +bool INetURLObject::setHost(UniString const & rTheHost, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (!getSchemeInfo().m_bHost) + return false; + UniString aSynHost(rTheHost); + switch (m_eScheme) + { + case INET_PROT_FILE: + if (aSynHost.EqualsIgnoreCaseAscii("localhost")) + aSynHost.Erase(); + break; + + case INET_PROT_LDAP: + if (aSynHost.Len() == 0 && m_aPort.isPresent()) + return false; + break; + + default: + if (aSynHost.Len() == 0) + return false; + break; + } + if (aSynHost.Len() != 0) + { + sal_Unicode const * p = aSynHost.GetBuffer(); + sal_Unicode const * pEnd = p + aSynHost.Len(); + if (!parseHost(p, pEnd, bOctets, eMechanism, eCharset, aSynHost) + || p != pEnd) + return false; + } + sal_Int32 nDelta = m_aHost.set(m_aAbsURIRef, aSynHost); + m_aPort += nDelta; + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + return true; +} + +//============================================================================ +bool INetURLObject::parsePath(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, + UniString * pSynPath) +{ + DBG_ASSERT(pBegin && pSynPath, + "INetURLObject::parsePath(): Null output param"); + + sal_Char cEscapePrefix = getEscapePrefix(); + + sal_Unicode const * pPos = *pBegin; + UniString aTheSynPath; + + switch (m_eScheme) + { + case INET_PROT_NOT_VALID: + return false; + + case INET_PROT_FTP: + case INET_PROT_IMAP: + if (pPos < pEnd && *pPos != '/') + { + setInvalid(); + return false; + } + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_HTTP_PATH, cEscapePrefix, eCharset, true); + } + if (aTheSynPath.Len() == 0) + aTheSynPath = '/'; + break; + + case INET_PROT_HTTP: + case INET_PROT_HTTPS: + if (pPos < pEnd && *pPos != '/') + { + setInvalid(); + return false; + } + while (pPos < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_HTTP_PATH, cEscapePrefix, eCharset, true); + } + if (aTheSynPath.Len() == 0) + aTheSynPath = '/'; + break; + + case INET_PROT_FILE: + { + if (bSkippedInitialSlash) + aTheSynPath = '/'; + else if (pPos < pEnd + && *pPos != nSegmentDelimiter + && *pPos != nAltSegmentDelimiter) + { + setInvalid(); + return false; + } + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + if (eEscapeType == ESCAPE_NO) + if (nUTF32 == nSegmentDelimiter + || nUTF32 == nAltSegmentDelimiter) + { + aTheSynPath += '/'; + continue; + } + else if (nUTF32 == '|' + && (pPos == pEnd + || *pPos == nFragmentDelimiter + || *pPos == nSegmentDelimiter + || *pPos == nAltSegmentDelimiter) + && aTheSynPath.Len() == 2 + && INetMIME::isAlpha(aTheSynPath.GetChar(1))) + { + // A first segment of <ALPHA "|"> is translated to + // <ALPHA ":">: + aTheSynPath += ':'; + continue; + } + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_PCHAR, cEscapePrefix, eCharset, true); + } + if (aTheSynPath.Len() == 0) + aTheSynPath = '/'; + break; + } + + case INET_PROT_MAILTO: + while (pPos < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_MAILTO, cEscapePrefix, eCharset, true); + } + break; + + case INET_PROT_NEWS: + case INET_PROT_POP3: + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_MESSAGE_ID_PATH, cEscapePrefix, eCharset, + true); + } + break; + + case INET_PROT_PRIV_SOFFICE: + case INET_PROT_SLOT: + case INET_PROT_MACRO: + case INET_PROT_COMPONENT: + case INET_PROT_LDAP: + while (pPos < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_PATH_BEFORE_QUERY, cEscapePrefix, eCharset, + true); + } + break; + + case INET_PROT_JAVASCRIPT: + case INET_PROT_DATA: + case INET_PROT_CID: + case INET_PROT_UNO: + case INET_PROT_DB: + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_URIC, cEscapePrefix, eCharset, true); + } + break; + + case INET_PROT_OUT: + if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '~') + { + setInvalid(); + return false; + } + aTheSynPath.AssignAscii(RTL_CONSTASCII_STRINGPARAM("/~")); + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_URIC, cEscapePrefix, eCharset, true); + } + break; + + case INET_PROT_VIM: + { + if (m_aUser.isEmpty()) + { + setInvalid(); + return false; + } + sal_Unicode const * pPathEnd = pPos; + while (pPathEnd < pEnd && *pPathEnd != nFragmentDelimiter) + ++pPathEnd; + aTheSynPath = '/'; + if (pPos == pPathEnd) + break; + else if (*pPos++ != '/') + { + setInvalid(); + return false; + } + if (pPos == pPathEnd) + break; + while (pPos < pPathEnd && *pPos != '/') + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, + eEscapeType == ESCAPE_NO ? + INetMIME::toLowerCase(nUTF32) : nUTF32, + eEscapeType, bOctets, PART_VIM, cEscapePrefix, + eCharset, false); + } + bool bInbox; + if (aTheSynPath.EqualsAscii("/inbox")) + bInbox = true; + else if (aTheSynPath.EqualsAscii("/newsgroups")) + bInbox = false; + else + { + setInvalid(); + return false; + } + aTheSynPath += '/'; + if (pPos == pPathEnd) + break; + else if (*pPos++ != '/') + { + setInvalid(); + return false; + } + if (!bInbox) + { + bool bEmpty = true; + while (pPos < pPathEnd && *pPos != '/') + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_VIM, cEscapePrefix, eCharset, false); + bEmpty = false; + } + if (bEmpty) + { + setInvalid(); + return false; + } + aTheSynPath += '/'; + if (pPos == pPathEnd) + break; + else if (*pPos++ != '/') + { + setInvalid(); + return false; + } + } + bool bEmpty = true; + while (pPos < pPathEnd && *pPos != ':') + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_VIM, cEscapePrefix, eCharset, false); + bEmpty = false; + } + if (bEmpty) + { + setInvalid(); + return false; + } + if (pPos == pPathEnd) + break; + else if (*pPos++ != ':') + { + setInvalid(); + return false; + } + aTheSynPath += ':'; + for (int i = 0; i < 3; ++i) + { + if (i != 0) + { + if (pPos == pPathEnd || *pPos++ != '.') + { + setInvalid(); + return false; + } + aTheSynPath += '.'; + } + bool bEmpty = true; + while (pPos < pPathEnd && *pPos != '.') + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + if (!INetMIME::isDigit(nUTF32)) + { + setInvalid(); + return false; + } + aTheSynPath += sal_Unicode(nUTF32); + bEmpty = false; + } + if (bEmpty) + { + setInvalid(); + return false; + } + } + if (pPos != pPathEnd) + { + setInvalid(); + return false; + } + break; + } + } + + *pBegin = pPos; + *pSynPath = aTheSynPath; + return true; +} + +//============================================================================ +bool INetURLObject::setPath(UniString const & rThePath, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + UniString aSynPath; + sal_Unicode const * p = rThePath.GetBuffer(); + if (!parsePath(&p, p + rThePath.Len(), bOctets, eMechanism, eCharset, + false, '/', 0x80000000, 0x80000000, 0x80000000, &aSynPath)) + return false; + sal_Int32 nDelta = m_aPath.set(m_aAbsURIRef, aSynPath); + m_aQuery += nDelta; + m_aFragment += nDelta; + return true; +} + +//============================================================================ +bool INetURLObject::appendSegment(UniString 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 (!getSchemeInfo().m_bHierarchical) + return SubString(); + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + if (pPathBegin == pPathEnd || *pPathBegin != '/') + return SubString(); + + sal_Unicode const * pSegBegin; + sal_Unicode const * pSegEnd; + if (nIndex == LAST_SEGMENT) + { + pSegEnd = pPathEnd; + if (bIgnoreFinalSlash && pSegEnd[-1] == '/' + && pSegEnd != pPathBegin + 1) + --pSegEnd; + pSegBegin = pSegEnd - 1; + while (*pSegBegin != '/') + --pSegBegin; + } + else + { + pSegBegin = pPathBegin; + pSegEnd = pPathEnd; + if (bIgnoreFinalSlash && pSegEnd[-1] == '/') + --pSegEnd; + while (nIndex-- > 0) + do + { + ++pSegBegin; + if (pSegBegin >= pSegEnd) + return SubString(); + } + while (*pSegBegin != '/'); + pSegEnd = pSegBegin + 1; + while (pSegEnd != pPathEnd && *pSegEnd != '/') + ++pSegEnd; + } + + return SubString(pSegBegin - m_aAbsURIRef.GetBuffer(), + pSegEnd - pSegBegin); +} + +//============================================================================ +bool INetURLObject::insertName(UniString 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 (!getSchemeInfo().m_bHierarchical) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + if (pPathBegin == pPathEnd || *pPathBegin != '/') + return false; + + sal_Unicode const * pPrefixEnd; + sal_Unicode const * pSuffixBegin; + bool bPrefixSlash = true; + if (nIndex == LAST_SEGMENT) + { + pPrefixEnd = pPathEnd; + if (bIgnoreFinalSlash && pPrefixEnd[-1] == '/') + bPrefixSlash = false; + pSuffixBegin = bAppendFinalSlash ? 0 : pPathEnd; + } + else + { + pPrefixEnd = pPathBegin; + sal_Unicode const * pEnd = pPathEnd; + if (bIgnoreFinalSlash && pEnd[-1] == '/') + --pEnd; + while (nIndex-- > 0) + for (;;) + { + ++pPrefixEnd; + if (pPrefixEnd >= pEnd) + if (nIndex == 0) + { + pSuffixBegin = bAppendFinalSlash ? 0 : pPathEnd; + break; + } + else + return false; + if (*pPrefixEnd == '/') + { + pSuffixBegin = pPrefixEnd; + break; + } + } + } + + UniString aNewPath(pPathBegin, pPrefixEnd - pPathBegin); + if (bPrefixSlash) + aNewPath += '/'; + aNewPath += encodeText(rTheName, bOctets, PART_PCHAR, getEscapePrefix(), + eMechanism, eCharset, true); + if (pSuffixBegin) + aNewPath.Append(pSuffixBegin, pPathEnd - pSuffixBegin); + else + aNewPath += '/'; + + return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +bool INetURLObject::clearQuery() +{ + if (HasError()) + return false; + if (m_aQuery.isPresent()) + { + m_aAbsURIRef.Erase(m_aQuery.getBegin() - 1, m_aQuery.getLength() + 1); + m_aFragment += m_aQuery.clear() - 1; + } + return false; +} + +//============================================================================ +bool INetURLObject::setQuery(UniString const & rTheQuery, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (!getSchemeInfo().m_bQuery) + return false; + UniString 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()); + 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.Erase(m_aFragment.getBegin() - 1); + m_aFragment.clear(); + } + return true; +} + +//============================================================================ +bool INetURLObject::setFragment(UniString const & rTheFragment, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (HasError()) + return false; + UniString aNewFragment(encodeText(rTheFragment, bOctets, PART_URIC, + getEscapePrefix(), eMechanism, + eCharset, true)); + if (m_aFragment.isPresent()) + m_aFragment.set(m_aAbsURIRef, aNewFragment); + else + { + m_aAbsURIRef.Append('#'); + m_aFragment.set(m_aAbsURIRef, aNewFragment, m_aAbsURIRef.Len()); + } + return true; +} + +//============================================================================ +INetURLObject::FTPType INetURLObject::getFTPType() const +{ + if (m_eScheme == INET_PROT_FTP + && m_aPath.getLength() >= RTL_CONSTASCII_LENGTH(";type=") + 1 + && m_aAbsURIRef. + EqualsIgnoreCaseAscii(";type=", + m_aPath.getEnd() + - (RTL_CONSTASCII_LENGTH(";type=") + + 1), + RTL_CONSTASCII_LENGTH(";type="))) + switch (m_aAbsURIRef.GetChar(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; +} + +//============================================================================ +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.GetBuffer() + + 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' + && m_aAbsURIRef. + EqualsIgnoreCaseAscii("/;uid=", + p - RTL_CONSTASCII_LENGTH("/;uid=") + - m_aAbsURIRef.GetBuffer(), + RTL_CONSTASCII_LENGTH("/;uid="))) + { + sal_uInt32 nUID; + if (INetMIME::scanUnsigned(p, pEnd, false, nUID)) + return nUID; + } + } + return 0; +} + +//============================================================================ +// static +UniString INetURLObject::encodeText(sal_Unicode const * pBegin, + sal_Unicode const * pEnd, bool bOctets, + Part ePart, sal_Char cEscapePrefix, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, + bool bKeepVisibleEscapes) +{ + UniString 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; +} + +//============================================================================ +// static +UniString INetURLObject::decode(sal_Unicode const * pBegin, + sal_Unicode const * pEnd, + sal_Char cEscapePrefix, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + switch (eMechanism) + { + case NO_DECODE: + return UniString(pBegin, pEnd - pBegin); + + case DECODE_TO_IURI: + eCharset = RTL_TEXTENCODING_UTF8; + break; + } + UniString aResult; + while (pBegin < pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, false, cEscapePrefix, + WAS_ENCODED, eCharset, eEscapeType); + switch (eEscapeType) + { + case ESCAPE_NO: + aResult += 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 += sal_Unicode(nUTF32); + break; + } + } + return aResult; +} + +//============================================================================ +UniString INetURLObject::GetURLNoPass(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + INetURLObject aTemp(*this); + aTemp.clearPassword(); + return aTemp.GetMainURL(eMechanism, eCharset); +} + +//============================================================================ +UniString INetURLObject::GetURLNoMark(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + INetURLObject aTemp(*this); + aTemp.clearFragment(); + return aTemp.GetMainURL(eMechanism, eCharset); +} + +//============================================================================ +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 (GetUser(NO_DECODE) != rObject.GetUser(NO_DECODE) + || GetPass(NO_DECODE) != rObject.GetPass(NO_DECODE) + || !GetHost(NO_DECODE).EqualsIgnoreCaseAscii(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; + UniString aPath1(GetURLPath(NO_DECODE)); + UniString aPath2(rObject.GetURLPath(NO_DECODE)); + if (m_eScheme == 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): + xub_StrLen nLength = aPath1.Len(); + switch (sal_Int32(nLength) - sal_Int32(aPath2.Len())) + { + case -1: + if (aPath2.GetChar(nLength) != '/') + return false; + break; + + case 0: + break; + + case 1: + if (aPath1.GetChar(--nLength) != '/') + return false; + break; + + default: + return false; + } + return aPath1.CompareTo(aPath2, nLength) == COMPARE_EQUAL; + } + else + return (aPath1 == aPath2) != false; +} + +//============================================================================ +bool INetURLObject::operator <(INetURLObject const & rObject) const +{ + switch (GetScheme(m_eScheme).CompareTo(GetScheme(rObject.m_eScheme))) + { + case COMPARE_LESS: + return true; + + case COMPARE_GREATER: + return false; + } + sal_uInt32 nPort1 = GetPort(); + sal_uInt32 nPort2 = rObject.GetPort(); + if (nPort1 < nPort2) + return true; + else if (nPort1 > nPort2) + return false; + switch (GetUser(NO_DECODE).CompareTo(rObject.GetUser(NO_DECODE))) + { + case COMPARE_LESS: + return true; + + case COMPARE_GREATER: + return false; + } + switch (GetPass(NO_DECODE).CompareTo(rObject.GetPass(NO_DECODE))) + { + case COMPARE_LESS: + return true; + + case COMPARE_GREATER: + return false; + } + switch (GetHost(NO_DECODE).CompareTo(rObject.GetHost(NO_DECODE))) + { + case COMPARE_LESS: + return true; + + case COMPARE_GREATER: + return false; + } + UniString aPath1(GetURLPath(NO_DECODE)); + UniString aPath2(rObject.GetURLPath(NO_DECODE)); + switch (aPath1.CompareTo(aPath2)) + { + case COMPARE_LESS: + return true; + + case COMPARE_GREATER: + return false; + } + switch (GetParam(NO_DECODE).CompareTo(rObject.GetParam(NO_DECODE))) + { + case COMPARE_LESS: + return true; + + case COMPARE_GREATER: + return false; + } + return GetMsgId(NO_DECODE).CompareTo(rObject.GetMsgId(NO_DECODE)) + == COMPARE_LESS; +} + +//============================================================================ +bool INetURLObject::ConcatData(INetProtocol eTheScheme, + UniString const & rTheUser, + UniString const & rThePassword, + UniString const & rTheHost, + sal_uInt32 nThePort, + UniString const & rThePath, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + setInvalid(); + m_eScheme = eTheScheme; + if (HasError()) + return false; + m_aAbsURIRef.AssignAscii(getSchemeInfo().m_pScheme); + m_aAbsURIRef += ':'; + if (getSchemeInfo().m_bAuthority) + { + m_aAbsURIRef.AppendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + bool bUserInfo = false; + if (getSchemeInfo().m_bUser) + { + if (m_eScheme == INET_PROT_IMAP && rTheUser.Len() == 0) + { + setInvalid(); + return false; + } + if (rTheUser.Len() != 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.Len()); + bUserInfo = true; + } + } + else if (rTheUser.Len() != 0) + { + setInvalid(); + return false; + } + if (rThePassword.Len() != 0) + if (getSchemeInfo().m_bPassword) + { + m_aAbsURIRef += ':'; + m_aAuth.set(m_aAbsURIRef, + encodeText(rThePassword, false, + m_eScheme == INET_PROT_VIM ? + PART_VIM : PART_USER_PASSWORD, + getEscapePrefix(), eMechanism, + eCharset, false), + m_aAbsURIRef.Len()); + bUserInfo = true; + } + else + { + setInvalid(); + return false; + } + if (bUserInfo && getSchemeInfo().m_bHost) + m_aAbsURIRef += '@'; + if (getSchemeInfo().m_bHost) + { + UniString aSynHost(rTheHost); + switch (m_eScheme) + { + case INET_PROT_FILE: + if (aSynHost.EqualsIgnoreCaseAscii("localhost")) + aSynHost.Erase(); + break; + + case INET_PROT_LDAP: + if (aSynHost.Len() == 0 && nThePort != 0) + { + setInvalid(); + return false; + } + break; + + default: + if (aSynHost.Len() == 0) + { + setInvalid(); + return false; + } + break; + } + if (aSynHost.Len() != 0) + { + sal_Unicode const * p = aSynHost.GetBuffer(); + sal_Unicode const * pEnd = p + aSynHost.Len(); + if (!parseHost(p, pEnd, false, eMechanism, eCharset, aSynHost) + || p != pEnd) + { + setInvalid(); + return false; + } + } + m_aHost.set(m_aAbsURIRef, aSynHost, m_aAbsURIRef.Len()); + if (nThePort != 0) + if (getSchemeInfo().m_bPort) + { + m_aAbsURIRef += ':'; + m_aPort.set(m_aAbsURIRef, + UniString::CreateFromInt64(nThePort), + m_aAbsURIRef.Len()); + } + else + { + setInvalid(); + return false; + } + } + else if (rTheHost.Len() != 0 || nThePort != 0) + { + setInvalid(); + return false; + } + } + UniString aSynPath; + if (getSchemeInfo().m_bHierarchical + && rThePath.Len() == 0 || rThePath.GetChar(0) != '/') + aSynPath = '/'; + aSynPath += rThePath; + m_aPath.set(m_aAbsURIRef, + encodeText(aSynPath, false, + m_eScheme == INET_PROT_FILE ? + PART_PATH_SEGMENTS_EXTRA : + m_eScheme == INET_PROT_NEWS + || m_eScheme == INET_PROT_POP3 ? + PART_MESSAGE_ID_PATH : + PART_HTTP_PATH, + getEscapePrefix(), eMechanism, eCharset, true), + m_aAbsURIRef.Len()); + return true; +} + +//============================================================================ +namespace unnamed_tools_urlobj { + +inline bool isWLetter(International const & rInternational, sal_Unicode c) +{ + return rInternational.IsAlphaNumeric(c) || c == '$' || c == '%' + || c == '&' || c == '-' || c == '/' || c == '@' || c == '\\'; +} + +inline bool checkWChar(International const & rInternational, + sal_Unicode const * p, sal_Unicode const *& rEnd, + bool bBackslash = false, bool bPipe = false) +{ + sal_Unicode c = *p; + if (rInternational.IsAlphaNumeric(c) || c == '/' + || c == '\\' && bBackslash || c == '|' && bPipe) + { + rEnd = p + 1; + return true; + } + else + return !mustEncode(c, INetURLObject::PART_URIC) || c == '%'; +} + +} + +// static +UniString INetURLObject::FindFirstURLInText(UniString const & rText, + xub_StrLen & rBegin, + xub_StrLen & rEnd, + International const & + rInternational, + UniString const *, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (!(rBegin <= rEnd && rEnd <= rText.Len())) + return UniString(); + + sal_Unicode const * pBegin = rText.GetBuffer() + rBegin; + sal_Unicode const * pEnd = rText.GetBuffer() + rEnd; + + // Search for the first (longest possible) substring of [pBegin..pEnd[ + // that matches any of the following productions. "\W" stands for a word + // break, i.e., the begin or end of the block of text, or a character that + // is neither a letter nor a digit (according to rInternational). 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 + // wchar = <any uric character (ignoring the escaped rule), or "%", or + // a letter or digit (according to rInternational)> + // + // 1st Production (file): + // \W "file:" 1*(wchar / "\" / "|") ["#" 1*wchar] \W + // + // 2nd Production (known scheme): + // \W <one of the known schemes, ignoring case> ":" 1*wchar + // ["#" 1*wchar] \W + // + // 3rd Production (mailto): + // \W domain "@" domain \W + // + // 4th Production (ftp): + // \W "ftp" 2*("." label) ["/" *wchar] ["#" 1*wchar] \W + // + // 5th Production (http): + // \W label 2*("." label) ["/" *wchar] ["#" 1*wchar] \W + // + // 6th Production (file): + // \W "//" (domain / IPv6reference) ["/" *wchar] ["#" 1*wchar] \W + // + // 7th Production (Unix file): + // \W "/" 1*wchar \W + // + // 8th Production (UNC file): + // \W "\\" domain ["\" *(wchar / "\")] \W + // + // 9th Production (Unix-like DOS file): + // \W ALPHA ":/" *wchar \W + // + // 10th Production (DOS file): + // \W ALPHA ":\" *(wchar / "\") \W + + for (sal_Unicode const * pPos = pBegin; pPos != pEnd;) + if ((INetMIME::isAlpha(*pPos) || *pPos == '/' || *pPos == '\\') + && (pPos == pBegin || !isWLetter(rInternational, pPos[-1]))) + { + sal_Unicode const * pURIEnd = 0; + + if (INetMIME::isAlpha(*pPos)) + { + sal_Unicode const * p = pPos; + sal_Unicode const * pPrefixEnd = p; + PrefixInfo const * pPrefix = getPrefix(pPrefixEnd, pEnd); + if (pPrefix) // 1st, 2nd + { + while (*p++ != ':'); + pPrefixEnd = p; + if (pPrefix->m_eScheme == INET_PROT_FILE) + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd, true, + true)) + ++p; + else + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd)) + ++p; + if (p != pPrefixEnd && *p == '#') + { + ++p; + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd)) + ++p; + } + } + else if (pEnd - p >= 3 && p[1] == ':' && p[2] == '/') // 9th + { + p += 3; + pURIEnd = p; + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd)) + ++p; + } + else if (pEnd - p >= 3 && p[1] == ':' && p[2] == '\\') // 10th + { + p += 3; + pURIEnd = p; + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd, true)) + ++p; + } + else + { + sal_uInt32 nLabels = scanDomain(p, pEnd, false); + if (nLabels > 0 && p != pEnd && *p == '@') // 3rd + { + ++p; + if (scanDomain(p, pEnd, false) > 0) + pURIEnd = p; + } + else if (nLabels >= 3) // 4th, 5th + { + pURIEnd = p; + if (p != pEnd && *p == '/') + { + pURIEnd = ++p; + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd)) + ++p; + } + if (p != pEnd && *p == '#') + { + ++p; + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd)) + ++p; + } + } + } + } + else if (*pPos == '/') + { + sal_Unicode const * p = pPos; + if (pEnd - p >= 2) + if (p[1] == '/') // 6th + { + p += 2; + if (scanDomain(p, pEnd, false) > 0 + || scanIPv6reference(p, pEnd, false)) + { + pURIEnd = p; + if (p != pEnd && *p == '/') + { + pURIEnd = ++p; + while (p != pEnd + && checkWChar(rInternational, p, + pURIEnd)) + ++p; + } + if (p != pEnd && *p == '#') + { + ++p; + while (p != pEnd + && checkWChar(rInternational, p, + pURIEnd)) + ++p; + } + } + } + else // 7th + { + ++p; + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd)) + ++p; + } + } + else if (*pPos == '\\') // 8th + { + sal_Unicode const * p = pPos; + if (pEnd - p >= 2 && p[1] == '\\') + { + p += 2; + if (scanDomain(p, pEnd, false) > 0) + { + pURIEnd = p; + if (p != pEnd && *p == '\\') + { + pURIEnd = ++p; + while (p != pEnd + && checkWChar(rInternational, p, pURIEnd, + true)) + ++p; + } + } + } + } + + if (pURIEnd + && (pURIEnd == pEnd || !isWLetter(rInternational, *pURIEnd))) + { + INetURLObject aURI(UniString(pPos, pURIEnd - pPos), + INET_PROT_HTTP, eMechanism, eCharset); + if (!aURI.HasError()) + { + rBegin += pPos - pBegin; + rEnd -= pEnd - pURIEnd; + return aURI.GetMainURL(); + } + } + + ++pPos; + while (pPos != pEnd && isWLetter(rInternational, *pPos)) + ++pPos; + } + else + ++pPos; + + rBegin = rEnd; + return UniString(); +} + +//============================================================================ +UniString INetURLObject::getExternalURL(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + UniString aTheExtURIRef; + translateToExternal(m_aAbsURIRef, aTheExtURIRef, NOT_CANONIC, eMechanism, + eCharset); + return aTheExtURIRef; +} + +//============================================================================ +// static +UniString INetURLObject::GetScheme(INetProtocol eTheScheme) +{ + return UniString::CreateFromAscii(getSchemeInfo(eTheScheme).m_pPrefix); +} + +//============================================================================ +// static +INetProtocol INetURLObject::CompareProtocolScheme(UniString const & + rTheAbsURIRef) +{ + sal_Unicode const * p = rTheAbsURIRef.GetBuffer(); + PrefixInfo const * pPrefix = getPrefix(p, p + rTheAbsURIRef.Len()); + 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.GetChar(m_aAuth.getBegin()) == '*') + { + m_aAbsURIRef.Erase(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; + } +} + +//============================================================================ +UniString INetURLObject::GetHostPort(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + UniString aHostPort(decode(m_aHost, getEscapePrefix(), eMechanism, + eCharset)); + if (m_aPort.isPresent()) + { + aHostPort += ':'; + aHostPort += decode(m_aPort, getEscapePrefix(), eMechanism, eCharset); + } + return aHostPort; +} + +//============================================================================ +sal_uInt32 INetURLObject::GetPort() const +{ + if (m_aPort.isPresent()) + { + sal_Unicode const * p = m_aAbsURIRef.GetBuffer() + 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()) + { + UniString aNewPort(UniString::CreateFromInt64(nThePort)); + sal_Int32 nDelta; + if (m_aPort.isPresent()) + nDelta = m_aPort.set(m_aAbsURIRef, aNewPort); + else + { + m_aAbsURIRef.Insert(':', m_aHost.getEnd()); + 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.GetBuffer() + 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) + { + m_aAbsURIRef.Erase(m_aPort.getBegin() - 1, + m_aPort.getLength() + 1); + nDelta = m_aPort.clear() - 1; + } + else + nDelta = m_aPort.set(m_aAbsURIRef, + UniString::CreateFromInt64(nThePort)); + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + } + } +} + +//============================================================================ +// static +bool INetURLObject::parseHost(sal_Unicode const *& rBegin, + sal_Unicode const * pEnd, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, UniString & rCanonic) +{ + 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 }; + UniString aTheCanonic; + sal_uInt32 nNumber; + int nDigits; + int nOctets; + State eState = STATE_INITIAL; + sal_Unicode const * p = rBegin; + for (; p != pEnd; ++p) + switch (eState) + { + case STATE_INITIAL: + if (*p == '[') + { + aTheCanonic = '['; + eState = STATE_IP6; + } + else if (INetMIME::isAlpha(*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)) + goto done; + break; + + case STATE_LABEL_HYPHEN: + if (INetMIME::isAlphanumeric(*p)) + eState = STATE_LABEL; + else if (*p != '-') + goto done; + break; + + case STATE_LABEL_DOT: + if (INetMIME::isAlpha(*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)) + goto done; + break; + + case STATE_TOPLABEL_HYPHEN: + if (INetMIME::isAlphanumeric(*p)) + eState = STATE_TOPLABEL; + else if (*p != '-') + goto done; + break; + + case STATE_TOPLABEL_DOT: + if (INetMIME::isAlpha(*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 += UniString::CreateFromInt32(nNumber); + aTheCanonic += '.'; + ++nOctets; + eState = STATE_IP4_DOT; + } + else + eState = STATE_LABEL_DOT; + else if (*p == '-') + eState = STATE_LABEL_HYPHEN; + else if (INetMIME::isAlpha(*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)) + 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 += ':'; + eState = STATE_IP6_3COLON; + } + 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 += UniString::CreateFromInt32(nNumber, 16); + eState = STATE_IP6_DONE; + } + else if (*p == ':') + { + aTheCanonic += UniString::CreateFromInt32(nNumber, 16); + aTheCanonic += ':'; + 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.AppendAscii(RTL_CONSTASCII_STRINGPARAM("::")); + 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 += UniString::CreateFromInt32(nNumber, 16); + eState = STATE_IP6_DONE; + } + else if (*p == ':') + { + aTheCanonic += UniString::CreateFromInt32(nNumber, 16); + aTheCanonic += ':'; + eState = STATE_IP6_HEXSEQ1_COLON; + } + else if (*p == '.') + { + nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15) + + (nNumber & 15); + aTheCanonic += UniString::CreateFromInt32(nNumber); + aTheCanonic += '.'; + 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 += UniString::CreateFromInt32(nNumber, 16); + eState = STATE_IP6_DONE; + } + else if (*p == ':') + { + aTheCanonic += UniString::CreateFromInt32(nNumber, 16); + aTheCanonic += ':'; + 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 += UniString::CreateFromInt32(nNumber, 16); + eState = STATE_IP6_DONE; + } + else if (*p == ':') + { + aTheCanonic += UniString::CreateFromInt32(nNumber, 16); + aTheCanonic += ':'; + eState = STATE_IP6_HEXSEQ2_COLON; + } + else if (*p == '.') + { + nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15) + + (nNumber & 15); + aTheCanonic += UniString::CreateFromInt32(nNumber); + aTheCanonic += '.'; + 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 += UniString::CreateFromInt32(nNumber); + eState = STATE_IP6_DONE; + } + else + goto done; + else if (*p == '.') + if (nOctets < 4) + { + aTheCanonic += UniString::CreateFromInt32(nNumber); + aTheCanonic += '.'; + ++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; + } + done: + switch (eState) + { + case STATE_LABEL: + case STATE_TOPLABEL: + case STATE_TOPLABEL_DOT: + aTheCanonic.Assign(rBegin, p - rBegin); + rBegin = p; + rCanonic = aTheCanonic; + return true; + + case STATE_IP4: + if (nOctets == 4) + { + aTheCanonic += UniString::CreateFromInt32(nNumber); + rBegin = p; + rCanonic = aTheCanonic; + return true; + } + break; + + case STATE_IP6_DONE: + aTheCanonic += ']'; + rBegin = p; + rCanonic = aTheCanonic; + return true; + } + return false; +} + +//============================================================================ +sal_Int32 INetURLObject::getSegmentCount(bool bIgnoreFinalSlash) const +{ + if (!getSchemeInfo().m_bHierarchical) + return 0; + + sal_Unicode const * p = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pEnd = p + m_aPath.getLength(); + if (p == pEnd || *p != '/') + return 0; + + if (bIgnoreFinalSlash && pEnd[-1] == '/') + --pEnd; + + sal_Int32 n = 0; + 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; + + UniString aNewPath(m_aAbsURIRef, m_aPath.getBegin(), + aSegment.getBegin() - m_aPath.getBegin()); + if (bIgnoreFinalSlash && aSegment.getEnd() == m_aPath.getEnd()) + aNewPath += '/'; + else + aNewPath.Append(m_aAbsURIRef.GetBuffer() + aSegment.getEnd(), + m_aPath.getEnd() - aSegment.getEnd()); + if (aNewPath.Len() == 0) + aNewPath = '/'; + + return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +UniString INetURLObject::getName(sal_Int32 nIndex, bool bIgnoreFinalSlash, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return UniString(); + + sal_Unicode const * pSegBegin + = m_aAbsURIRef.GetBuffer() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + ++pSegBegin; + sal_Unicode const * p = pSegBegin; + while (p != pSegEnd && *p != ';') + ++p; + + return decode(pSegBegin, p, getEscapePrefix(), eMechanism, eCharset); +} + +//============================================================================ +bool INetURLObject::setName(UniString 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.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin + = m_aAbsURIRef.GetBuffer() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + ++pSegBegin; + sal_Unicode const * p = pSegBegin; + while (p != pSegEnd && *p != ';') + ++p; + + UniString aNewPath(pPathBegin, pSegBegin - pPathBegin); + aNewPath += encodeText(rTheName, false, PART_PCHAR, getEscapePrefix(), + eMechanism, eCharset, true); + aNewPath.Append(p, pPathEnd - p); + + return setPath(aNewPath, 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.GetBuffer() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + ++pSegBegin; + for (sal_Unicode const * p = pSegBegin; p != pSegEnd && *p != ';'; ++p) + if (*p == '.' && p != pSegBegin) + return true; + return false; +} + +//============================================================================ +UniString INetURLObject::getBase(sal_Int32 nIndex, bool bIgnoreFinalSlash, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return UniString(); + + sal_Unicode const * pSegBegin + = m_aAbsURIRef.GetBuffer() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + ++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(UniString 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.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin + = m_aAbsURIRef.GetBuffer() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + ++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; + + UniString aNewPath(pPathBegin, pSegBegin - pPathBegin); + aNewPath += encodeText(rTheBase, false, PART_PCHAR, getEscapePrefix(), + eMechanism, eCharset, true); + aNewPath.Append(pExtension, pPathEnd - pExtension); + + return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +UniString INetURLObject::getExtension(sal_Int32 nIndex, + bool bIgnoreFinalSlash, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return UniString(); + + sal_Unicode const * pSegBegin + = m_aAbsURIRef.GetBuffer() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + ++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 UniString(); + + return decode(pExtension + 1, p, getEscapePrefix(), eMechanism, eCharset); +} + +//============================================================================ +bool INetURLObject::setExtension(UniString 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.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin + = m_aAbsURIRef.GetBuffer() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + ++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; + + UniString aNewPath(pPathBegin, pExtension - pPathBegin); + aNewPath += '.'; + aNewPath += encodeText(rTheExtension, false, PART_PCHAR, + getEscapePrefix(), eMechanism, eCharset, true); + aNewPath.Append(p, pPathEnd - p); + + return setPath(aNewPath, 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.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin + = m_aAbsURIRef.GetBuffer() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + ++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; + + UniString aNewPath(pPathBegin, pExtension - pPathBegin); + aNewPath.Append(p, pPathEnd - p); + + return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +bool INetURLObject::hasFinalSlash() const +{ + if (!getSchemeInfo().m_bHierarchical) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + if (pPathBegin == pPathEnd || *pPathBegin != '/') + return false; + + return pPathEnd[-1] == '/'; +} + +//============================================================================ +bool INetURLObject::setFinalSlash() +{ + if (!getSchemeInfo().m_bHierarchical) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + if (pPathBegin == pPathEnd || *pPathBegin != '/') + return false; + + if (pPathEnd[-1] == '/') + return true; + + UniString aNewPath(pPathBegin, pPathEnd - pPathBegin); + aNewPath += '/'; + + return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +bool INetURLObject::removeFinalSlash() +{ + if (!getSchemeInfo().m_bHierarchical) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + if (pPathBegin == pPathEnd || *pPathBegin != '/') + return false; + + if (pPathEnd[-1] != '/') + return true; + + --pPathEnd; + if (pPathEnd == pPathBegin) + return false; + UniString aNewPath(pPathBegin, pPathEnd - pPathBegin); + + return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +// static +UniString INetURLObject::createFragment(UniString const & rText) +{ + UniString aFragment(rText); + for (xub_StrLen i = 0; i < aFragment.Len();) + { + sal_Unicode c = aFragment.GetChar(i); + if (mustEncode(aFragment.GetChar(i), PART_CREATEFRAGMENT)) + aFragment.Erase(i, 1); + else + ++i; + } + return aFragment; +} + +//============================================================================ +bool INetURLObject::setFSysPath(UniString const & rFSysPath, FSysStyle eStyle) +{ + sal_Unicode const * pFSysBegin = rFSysPath.GetBuffer(); + sal_Unicode const * pFSysEnd = pFSysBegin + rFSysPath.Len(); + + 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; + UniString aHost; + if (parseHost(p, pFSysEnd, false, ENCODE_ALL, + RTL_TEXTENCODING_UTF8, 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; + UniString aHost; + if (parseHost(p, pFSysEnd, false, ENCODE_ALL, + RTL_TEXTENCODING_UTF8, aHost) + && (p == pFSysEnd || *p == '\\')) + { + eStyle = FSYS_DOS; // Production T3 + break; + } + } + + if (eStyle & FSYS_DOS + && pFSysEnd - pFSysBegin >= 3 + && INetMIME::isAlpha(pFSysBegin[0]) + && pFSysBegin[1] == ':' + && (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; + } + + UniString aSynAbsURIRef(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 += *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 += *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 += '/'; + if (pFSysEnd - p >= 3 && INetMIME::isAlpha(p[0]) + && p[1] == ':' && (p[2] == '\\' || p[2] == '/')) + nAltDelimiter = '/'; + } + for (; p != pFSysEnd; ++p) + if (*p == '\\' || *p == nAltDelimiter) + aSynAbsURIRef += '/'; + else + switch (*p) + { + case '/': + case '#': + case '%': + appendEscape(aSynAbsURIRef, '%', *p); + break; + + default: + aSynAbsURIRef += *p; + break; + } + break; + } + + case FSYS_MAC: + aSynAbsURIRef += '/'; + {for (sal_Unicode const * p = pFSysBegin; p != pFSysEnd; ++p) + switch (*p) + { + case ':': + aSynAbsURIRef += '/'; + break; + + case '/': + case '|': + case '#': + case '%': + appendEscape(aSynAbsURIRef, '%', *p); + break; + + default: + aSynAbsURIRef += *p; + break; + } + } + break; + } + + INetURLObject aTemp(aSynAbsURIRef, WAS_ENCODED, RTL_TEXTENCODING_UTF8); + if (aTemp.HasError()) + return false; + + *this = aTemp; + return true; +} + +//============================================================================ +UniString INetURLObject::getFSysPath(FSysStyle eStyle, + sal_Unicode * pDelimiter) const +{ + if (m_eScheme != INET_PROT_FILE) + return UniString(); + + if ((eStyle & FSYS_VOS ? 1 : 0) + + (eStyle & FSYS_UNX ? 1 : 0) + + (eStyle & FSYS_DOS ? 1 : 0) + + (eStyle & FSYS_MAC ? 1 : 0) + > 1) + { + sal_Unicode const * p = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + eStyle = eStyle & FSYS_VOS + && m_aHost.isPresent() + && m_aHost.getLength() > 0 ? + FSYS_VOS : + eStyle & FSYS_DOS + && (!m_aHost.isPresent() || m_aHost.getLength() == 0) + && m_aPath.getLength() >= 3 + && p[0] == '/' + && INetMIME::isAlpha(p[1]) + && p[2] == ':' + && (m_aPath.getLength() == 3 || p[3] == '/') ? + FSYS_DOS : + eStyle & FSYS_UNX + && (!m_aHost.isPresent() || m_aHost.getLength() == 0) ? + FSYS_UNX : + FSysStyle(0); + } + + switch (eStyle) + { + case FSYS_VOS: + { + if (pDelimiter) + *pDelimiter = '/'; + + UniString aSynFSysPath(RTL_CONSTASCII_USTRINGPARAM("//")); + if (m_aHost.isPresent() && m_aHost.getLength() > 0) + aSynFSysPath += decode(m_aHost, '%', DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8); + else + aSynFSysPath += '.'; + aSynFSysPath += decode(m_aPath, '%', DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8); + return aSynFSysPath; + } + + case FSYS_UNX: + { + if (m_aHost.isPresent() && m_aHost.getLength() > 0) + return UniString(); + + if (pDelimiter) + *pDelimiter = '/'; + + return decode(m_aPath, '%', DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8); + } + + case FSYS_DOS: + { + if (pDelimiter) + *pDelimiter = '\\'; + + UniString aSynFSysPath; + if (m_aHost.isPresent() && m_aHost.getLength() > 0) + { + aSynFSysPath.AssignAscii(RTL_CONSTASCII_STRINGPARAM("\\\\")); + aSynFSysPath += decode(m_aHost, '%', DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8); + aSynFSysPath += '\\'; + } + sal_Unicode const * p + = m_aAbsURIRef.GetBuffer() + 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 += '\\'; + else + appendUTF32(aSynFSysPath, nUTF32); + } + return aSynFSysPath; + } + + case FSYS_MAC: + { + if (m_aHost.isPresent() && m_aHost.getLength() > 0) + return UniString(); + + if (pDelimiter) + *pDelimiter = ':'; + + UniString aSynFSysPath; + sal_Unicode const * p + = m_aAbsURIRef.GetBuffer() + 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 += ':'; + else + appendUTF32(aSynFSysPath, nUTF32); + } + return aSynFSysPath; + } + } + + return UniString(); +} + +//============================================================================ +bool INetURLObject::HasMsgId() const +{ + if (m_eScheme != INET_PROT_NEWS && m_eScheme != INET_PROT_POP3) + return false; + sal_Unicode const * p = m_aAbsURIRef.GetBuffer() + m_aPath.getBegin(); + sal_Unicode const * pEnd = p + m_aPath.getLength(); + for (; p < pEnd; ++p) + if (*p == '<') + return true; + return false; +} + +//============================================================================ +UniString INetURLObject::GetMsgId(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + if (m_eScheme != INET_PROT_NEWS && m_eScheme != INET_PROT_POP3) + return UniString(); + sal_Unicode const * p = m_aAbsURIRef.GetBuffer() + 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 UniString(); +} + +//============================================================================ +// static +void INetURLObject::appendUCS4Escape(UniString & 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(UniString & rTheText, sal_uInt32 nUCS4, + EscapeType eEscapeType, bool bOctets, + Part ePart, sal_Char cEscapePrefix, + rtl_TextEncoding eCharset, + bool bKeepVisibleEscapes) +{ + bool bEscape; + rtl_TextEncoding eTargetCharset; + 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; + } + 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 += 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 == 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 == 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; + xub_StrLen 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)) + { + ++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)) + 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)) + { + 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, + bool bEager) +{ + return false; //@@@ +} + +//============================================================================ +// static +UniString INetURLObject::RelToAbs(ByteString const & rTheRelURIRef, + bool bIgnoreFragment, + EncodeMechanism eEncodeMechanism, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset, + FSysStyle eStyle) +{ + // Backwards compatibility: + if (rTheRelURIRef.Len() == 0 || rTheRelURIRef.GetChar(0) == '#') + return extend(rTheRelURIRef); + + INetURLObject aTheAbsURIRef; + bool bWasAbsolute; + m_aBaseURIRef.convertRelToAbs(extend(rTheRelURIRef), true, aTheAbsURIRef, + bWasAbsolute, eEncodeMechanism, eCharset, + bIgnoreFragment, false, false, eStyle); + return aTheAbsURIRef.GetMainURL(eDecodeMechanism, eCharset); +} + +//============================================================================ +// static +UniString INetURLObject::RelToAbs(UniString const & rTheRelURIRef, + bool bIgnoreFragment, + EncodeMechanism eEncodeMechanism, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset, + FSysStyle eStyle) +{ + // Backwards compatibility: + if (rTheRelURIRef.Len() == 0 || rTheRelURIRef.GetChar(0) == '#') + return rTheRelURIRef; + + INetURLObject aTheAbsURIRef; + bool bWasAbsolute; + return m_aBaseURIRef.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; +} + +//============================================================================ +// static +UniString INetURLObject::AbsToRel(ByteString const & rTheAbsURIRef, + EncodeMechanism eEncodeMechanism, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset, + FSysStyle eStyle) +{ + UniString aTheRelURIRef; + m_aBaseURIRef.convertAbsToRel(extend(rTheAbsURIRef), true, aTheRelURIRef, + eEncodeMechanism, eDecodeMechanism, + eCharset, eStyle); + return aTheRelURIRef; +} + +//============================================================================ +// static +UniString INetURLObject::AbsToRel(UniString const & rTheAbsURIRef, + EncodeMechanism eEncodeMechanism, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset, + FSysStyle eStyle) +{ + UniString aTheRelURIRef; + m_aBaseURIRef.convertAbsToRel(rTheAbsURIRef, false, aTheRelURIRef, + eEncodeMechanism, eDecodeMechanism, + eCharset, eStyle); + return aTheRelURIRef; +} + +//============================================================================ +// static +bool INetURLObject::SetBaseURL(ByteString const & rTheBaseURIRef, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + return m_aBaseURIRef.SetURL(rTheBaseURIRef, eMechanism, eCharset); +} + +//============================================================================ +// static +bool INetURLObject::SetBaseURL(UniString const & rTheBaseURIRef, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + return m_aBaseURIRef.SetURL(rTheBaseURIRef, eMechanism, eCharset); +} + +//============================================================================ +// static +UniString INetURLObject::GetBaseURL(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + return m_aBaseURIRef.GetMainURL(eMechanism, eCharset); +} + +//============================================================================ +UniString INetURLObject::GetPartBeforeLastName(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) + const +{ + if (!getSchemeInfo().m_bHierarchical) + return UniString(); + INetURLObject aTemp(*this); + aTemp.clearFragment(); + aTemp.clearQuery(); + aTemp.removeSegment(LAST_SEGMENT, false); + aTemp.setFinalSlash(); + return aTemp.GetMainURL(eMechanism, eCharset); +} + +//============================================================================ +UniString INetURLObject::GetLastName(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + return getName(LAST_SEGMENT, true, eMechanism, eCharset); +} + +//============================================================================ +UniString 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; +} + +//============================================================================ +UniString INetURLObject::PathToFileName() const +{ + if (m_eScheme != INET_PROT_FILE) + return UniString(); + rtl::OUString aNormalizedPath; + if (osl::FileBase::getNormalizedPathFromFileURL( + decode(m_aAbsURIRef.GetBuffer(), + m_aAbsURIRef.GetBuffer() + m_aPath.getEnd(), + getEscapePrefix(), NO_DECODE, RTL_TEXTENCODING_UTF8), + aNormalizedPath) + != osl::FileBase::E_None) + return UniString(); + rtl::OUString aSystemPath; + if (osl::FileBase::getSystemPathFromNormalizedPath(aNormalizedPath, + aSystemPath) + != osl::FileBase::E_None) + return UniString(); + return aSystemPath; +} + +//============================================================================ +UniString INetURLObject::GetFull() const +{ + INetURLObject aTemp(*this); + aTemp.removeFinalSlash(); + return aTemp.PathToFileName(); +} + +//============================================================================ +UniString INetURLObject::GetPath() const +{ + INetURLObject aTemp(*this); + aTemp.removeSegment(LAST_SEGMENT, true); + aTemp.removeFinalSlash(); + return aTemp.PathToFileName(); +} + +//============================================================================ +void INetURLObject::SetBase(UniString const & rTheBase) +{ + setBase(rTheBase, LAST_SEGMENT, true, ENCODE_ALL); +} + +//============================================================================ +UniString INetURLObject::GetBase() const +{ + return getBase(LAST_SEGMENT, true, DECODE_WITH_CHARSET); +} + +//============================================================================ +void INetURLObject::SetName(UniString 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; +} + +//============================================================================ +UniString INetURLObject::CutName(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + UniString aTheName(getName(LAST_SEGMENT, true, eMechanism, eCharset)); + return removeSegment(LAST_SEGMENT, true) ? aTheName : UniString(); +} + +//============================================================================ +void INetURLObject::SetExtension(UniString const & rTheExtension, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + setExtension(rTheExtension, LAST_SEGMENT, false, eMechanism, eCharset); +} + +//============================================================================ +UniString INetURLObject::CutExtension(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + UniString aTheExtension(getExtension(LAST_SEGMENT, false, eMechanism, + eCharset)); + return removeExtension(LAST_SEGMENT, false) ? aTheExtension : UniString(); +} + +//============================================================================ +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..8b8bd7c5950b --- /dev/null +++ b/tools/source/fsys/wldcrd.cxx @@ -0,0 +1,177 @@ +/************************************************************************* + * + * $RCSfile: wldcrd.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _WLDCRD_HXX +#include <wldcrd.hxx> +#endif + +/************************************************************************* +|* +|* 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..b1ae509c6056 --- /dev/null +++ b/tools/source/fsys/wntmsc.cxx @@ -0,0 +1,1103 @@ +/************************************************************************* + * + * $RCSfile: wntmsc.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include <limits.h> + +#include "wntmsc.hxx" +#include "errinf.hxx" + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _LIST_HXX +#include <list.hxx> +#endif +#ifndef _WLDCRD_HXX +#include <wldcrd.hxx> +#endif +#ifndef _FSYS_HXX +#include <fsys.hxx> +#endif +#ifndef _BIGINT_HXX +#include "bigint.hxx" +#endif + +DECLARE_LIST( DirEntryList, DirEntry* ); +DECLARE_LIST( FSysSortList, FSysSort* ); +DECLARE_LIST( FileStatList, FileStat* ); + +int Sys2SolarError_Impl( int nSysErr ); + +static ByteString sLastCaseSensitiveDir = ""; +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 ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + FSysFailOnErrorImpl(); + + if ( eFlag == FSYS_FLAG_CURRENT && !aName.Len() ) + return TRUE; + + if ( SetCurrentDirectory(ByteString(GetFull(), osl_getThreadTextEncoding()).GetBuffer()) ) + { + nError = FSYS_ERR_OK; + return TRUE; + } + + if ( bSloppy && pParent && + SetCurrentDirectory(ByteString(pParent->GetFull(), osl_getThreadTextEncoding()).GetBuffer()) ) + { + nError = FSYS_ERR_OK; + return TRUE; + } + + nError = FSYS_ERR_NOTADIRECTORY; + 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; + 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; + + 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 ENABLEUNICODE +// #define UNICODE +#endif + +#include <prewin.h> +#include <shlobj.h> +#include <postwin.h> + +#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; + + // 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 + BOOL bRedirected = 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( "\\" ); + USHORT 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 ); + USHORT 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..e51931fc4173 --- /dev/null +++ b/tools/source/fsys/wntmsc.hxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * $RCSfile: wntmsc.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#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 <svwin.h> +#include <winbase.h> +#include <solar.h> +#include <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() ) + +#include <svwin.h> +#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/bigint.cxx b/tools/source/generic/bigint.cxx new file mode 100644 index 000000000000..352731311a6c --- /dev/null +++ b/tools/source/generic/bigint.cxx @@ -0,0 +1,1187 @@ +/************************************************************************* + * + * $RCSfile: bigint.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <math.h> +#include <tools.h> + +#define private public +#include <bigint.hxx> +#undef private + +#ifndef _STRING_HXX +#include <string.hxx> +#endif +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif + +#include <string.h> +#include <ctype.h> + +static void SubLong( BigInt& rA, BigInt& rB, BigInt& rErg ); + +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. + +// ----------------------------------------------------------------------- + +static void MakeBigInt( BigInt& rThis, const BigInt& rVal ) +{ + if ( rVal.bIsBig ) + { + memcpy( (void*)&rThis, (const void*)&rVal, sizeof( BigInt ) ); + while ( rThis.nLen > 1 && rThis.nNum[rThis.nLen-1] == 0 ) + rThis.nLen--; + } + else + { + long nTmp = rVal.nVal; + + rThis.nVal = rVal.nVal; + rThis.bIsBig = TRUE; + if ( nTmp < 0 ) + { + rThis.bIsNeg = TRUE; + nTmp = -nTmp; + } + else + rThis.bIsNeg = FALSE; + + rThis.nNum[0] = (USHORT)(nTmp & 0xffffL); + rThis.nNum[1] = (USHORT)(nTmp >> 16); +#ifndef _WIN16 + if ( nTmp & 0xffff0000L ) +#else + long l = 0xffff0000L; + if ( nTmp & l ) +#endif + rThis.nLen = 2; + else + rThis.nLen = 1; + } +} + +// ----------------------------------------------------------------------- + +static void Normalize( BigInt& rThis ) +{ + if ( rThis.bIsBig ) + { + while ( rThis.nLen > 1 && rThis.nNum[rThis.nLen-1] == 0 ) + rThis.nLen--; + + if ( rThis.nLen < 3 ) + { + if ( rThis.nLen < 2 ) + rThis.nVal = rThis.nNum[0]; + else if ( rThis.nNum[1] & 0x8000 ) + return; + else + rThis.nVal = ((long)rThis.nNum[1] << 16) + rThis.nNum[0]; + + rThis.bIsBig = FALSE; + + if ( rThis.bIsNeg ) + rThis.nVal = -rThis.nVal; + } + // else ist nVal undefiniert !!! W.P. + } + // wozu, nLen ist doch undefiniert ??? W.P. + else if ( rThis.nVal & 0xFFFF0000L ) + rThis.nLen = 2; + else + rThis.nLen = 1; +} + +// ----------------------------------------------------------------------- + +static void Mult( BigInt& rThis, const BigInt &rVal, USHORT nMul ) +{ + USHORT nK = 0; + for ( int i = 0; i < rVal.nLen; i++ ) + { + ULONG nTmp = (ULONG)rVal.nNum[i] * (ULONG)nMul + nK; + nK = (USHORT)(nTmp >> 16); + rThis.nNum[i] = (USHORT)nTmp; + } + + if ( nK ) + { + rThis.nNum[rVal.nLen] = nK; + rThis.nLen = rVal.nLen + 1; + } + else + rThis.nLen = rVal.nLen; + + rThis.bIsBig = TRUE; + rThis.bIsNeg = rVal.bIsNeg; +} + +// ----------------------------------------------------------------------- + +static void Div( BigInt& rThis, USHORT nDiv, USHORT& rRem ) +{ + ULONG nK = 0; + for ( int i = rThis.nLen - 1; i >= 0; i-- ) + { + ULONG nTmp = (ULONG)rThis.nNum[i] + (nK << 16); + rThis.nNum[i] = (USHORT)(nTmp / nDiv); + nK = nTmp % nDiv; + } + rRem = (USHORT)nK; + + if ( rThis.nNum[rThis.nLen-1] == 0 ) + rThis.nLen -= 1; +} + +// ----------------------------------------------------------------------- + +static BOOL IsLess( const BigInt& rThis, const BigInt& rVal ) +{ + if ( rVal.nLen < rThis.nLen) + return TRUE; + if ( rVal.nLen > rThis.nLen ) + return FALSE; + + int i; + for ( i = rThis.nLen - 1; i > 0 && rThis.nNum[i] == rVal.nNum[i]; i-- ) + { + } + return rVal.nNum[i] < rThis.nNum[i]; +} + +// ----------------------------------------------------------------------- + +static void AddLong( BigInt& rA, BigInt& rB, BigInt& rErg ) +{ + if ( rA.bIsNeg == rB.bIsNeg ) + { + int i; + char nLen; + + // wenn die Zahlen unterschiedlich lang sind, sollte zunaechst bei + // der kleineren Zahl die fehlenden Ziffern mit 0 initialisert werden + if (rA.nLen >= rB.nLen) + { + nLen = rA.nLen; + for (i = rB.nLen; i < nLen; i++) + rB.nNum[i] = 0; + } + else + { + nLen = rB.nLen; + for (i = rA.nLen; i < nLen; i++) + rA.nNum[i] = 0; + } + + // Die Ziffern werden von hinten nach vorne addiert + long k; + long nZ = 0; + for (i = 0, k = 0; i < nLen; i++) { + nZ = (long)rA.nNum[i] + (long)rB.nNum[i] + k; + if (nZ & 0xff0000L) + k = 1; + else + k = 0; + rErg.nNum[i] = (USHORT)(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; + nLen++; + } + // Die Laenge und das Vorzeichen setzen + rErg.nLen = nLen; + rErg.bIsNeg = rA.bIsNeg && rB.bIsNeg; + rErg.bIsBig = TRUE; + } + // Wenn nur einer der beiden Operanten negativ ist, wird aus der + // Addition eine Subtaktion + else if (rA.bIsNeg) + { + rA.bIsNeg = FALSE; + SubLong(rB, rA, rErg); + rA.bIsNeg = TRUE; + } + else + { + rB.bIsNeg = FALSE; + SubLong(rA, rB, rErg); + rB.bIsNeg = TRUE; + } +} + +// ----------------------------------------------------------------------- + +static void SubLong( BigInt& rA, BigInt& rB, BigInt& rErg ) +{ + if ( rA.bIsNeg == rB.bIsNeg ) + { + int i; + char nLen; + long nZ, k; + + // wenn die Zahlen unterschiedlich lang sind, sollte zunaechst bei + // der kleineren Zahl die fehlenden Ziffern mit 0 initialisert werden + if (rA.nLen >= rB.nLen) + { + nLen = rA.nLen; + for (i = rB.nLen; i < nLen; i++) + rB.nNum[i] = 0; + } + else + { + nLen = rB.nLen; + for (i = rA.nLen; i < nLen; i++) + rA.nNum[i] = 0; + } + + if ( IsLess(rA, rB) ) + { + for (i = 0, k = 0; i < nLen; i++) + { + nZ = (long)rA.nNum[i] - (long)rB.nNum[i] + k; + if (nZ < 0) + k = -1; + else + k = 0; + rErg.nNum[i] = (USHORT)(nZ & 0xffffL); + } + rErg.bIsNeg = rA.bIsNeg; + } + else + { + for (i = 0, k = 0; i < nLen; i++) + { + nZ = (long)rB.nNum[i] - (long)rA.nNum[i] + k; + if (nZ < 0) + k = -1; + else + k = 0; + rErg.nNum[i] = (USHORT)(nZ & 0xffffL); + } + // wenn a < b, dann Vorzeichen vom Ergebnis umdrehen + rErg.bIsNeg = !rA.bIsNeg; + } + rErg.nLen = nLen; + rErg.bIsBig = TRUE; + } + // Wenn nur einer der beiden Operanten negativ ist, wird aus der + // Subtaktion eine Addition + else if (rA.bIsNeg) + { + rA.bIsNeg = FALSE; + AddLong(rA, rB, rErg); + rA.bIsNeg = TRUE; + rErg.bIsNeg = TRUE; + } + else + { + rB.bIsNeg = FALSE; + AddLong(rA, rB, rErg); + rB.bIsNeg = TRUE; + rErg.bIsNeg = FALSE; + } +} + +// ----------------------------------------------------------------------- + +static void MultLong( const BigInt& rA, const BigInt& rB, BigInt& rErg ) +{ + int i, j; + ULONG nZ, k; + + rErg.bIsNeg = rA.bIsNeg != rB.bIsNeg; + rErg.bIsBig = TRUE; + rErg.nLen = rA.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 < rA.nLen; i++) + { + nZ = (ULONG)rA.nNum[i] * (ULONG)rB.nNum[j] + + (ULONG)rErg.nNum[i + j] + k; + rErg.nNum[i + j] = (USHORT)(nZ & 0xffffUL); + k = nZ >> 16; + } + rErg.nNum[i + j] = (USHORT)k; + } +} + +// ----------------------------------------------------------------------- + +static void DivLong( const BigInt& rA, const BigInt& rB, BigInt& rErg ) +{ + int i, j; + long nTmp; + USHORT nK, nQ, nMult; + short nLenB = rB.nLen; + short nLenB1 = rB.nLen - 1; + BigInt aTmpA, aTmpB; + + nMult = (USHORT)(0x10000L / ((long)rB.nNum[nLenB1] + 1)); + + Mult( aTmpA, rA, nMult ); + if ( aTmpA.nLen == rA.nLen ) + { + aTmpA.nNum[aTmpA.nLen] = 0; + aTmpA.nLen++; + } + + Mult( aTmpB, 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 = (USHORT)(((ULONG)nTmp) / aTmpB.nNum[nLenB1]); + + if ( ((ULONG)aTmpB.nNum[nLenB1 - 1] * nQ) > + ((((ULONG)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] = (USHORT)nTmp; + nK = (USHORT) (nTmp >> 16); + if ( nK ) + nK = (USHORT)(0x10000UL - nK); + } + aTmpA.nNum[j - nLenB + i] -= 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] = (USHORT)(nTmp & 0xFFFFL); + if (nTmp & 0xFFFF0000L) + nK = 1; + else + nK = 0; + } + } + } + + rErg.bIsNeg = rA.bIsNeg != rB.bIsNeg; + rErg.bIsBig = TRUE; + rErg.nLen = rA.nLen - rB.nLen + 1; +} + +// ----------------------------------------------------------------------- + +static void ModLong( const BigInt& rA, const BigInt& rB, BigInt& rErg ) +{ + short i, j; + long nTmp; + USHORT nK, nQ, nMult; + short nLenB = rB.nLen; + short nLenB1 = rB.nLen - 1; + BigInt aTmpA, aTmpB; + + nMult = (USHORT)(0x10000L / ((long)rB.nNum[nLenB1] + 1)); + + Mult( aTmpA, rA, nMult); + if ( aTmpA.nLen == rA.nLen ) + { + aTmpA.nNum[aTmpA.nLen] = 0; + aTmpA.nLen++; + } + + Mult( aTmpB, 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 = (USHORT)(((ULONG)nTmp) / aTmpB.nNum[nLenB1]); + + if ( ((ULONG)aTmpB.nNum[nLenB1 - 1] * nQ) > + ((((ULONG)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] = (USHORT)nTmp; + nK = (USHORT) (nTmp >> 16); + if ( nK ) + nK = (USHORT)(0x10000UL - nK); + } + aTmpA.nNum[j - nLenB + i] -= 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] = (USHORT)(nTmp & 0xFFFFL); + if (nTmp & 0xFFFF0000L) + nK = 1; + else + nK = 0; + } + } + } + + rErg = aTmpA; + Div( rErg, nMult, nQ ); +} + +// ----------------------------------------------------------------------- + +static BOOL ABS_IsLess( const BigInt& rA, const BigInt& rB ) +{ + if (rA.bIsBig || rB.bIsBig) + { + BigInt nA, nB; + MakeBigInt( nA, rA ); + MakeBigInt( nB, 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 ( rA.nVal < 0 ) + if ( rB.nVal < 0 ) + return rA.nVal > rB.nVal; + else + return rA.nVal > -rB.nVal; + else + if ( rB.nVal < 0 ) + return rA.nVal < -rB.nVal; + else + return rA.nVal < rB.nVal; +} + +// ----------------------------------------------------------------------- + +BigInt::BigInt( const BigInt& rBigInt ) +{ + if ( rBigInt.bIsBig ) + memcpy( (void*)this, (const void*)&rBigInt, sizeof( BigInt ) ); + else + { + bIsSet = rBigInt.bIsSet; + bIsBig = FALSE; + nVal = rBigInt.nVal; + } +} + +// ----------------------------------------------------------------------- + +BigInt::BigInt( const ByteString& rString ) +{ + bIsSet = TRUE; + bIsNeg = FALSE; + bIsBig = FALSE; + nVal = 0; + + BOOL bNeg = FALSE; + const sal_Char* p = rString.GetBuffer(); + if ( *p == '-' ) + { + bNeg = 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 = TRUE; + bIsNeg = FALSE; + bIsBig = FALSE; + nVal = 0; + + BOOL bNeg = FALSE; + const sal_Unicode* p = rString.GetBuffer(); + if ( *p == '-' ) + { + bNeg = 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 = TRUE; + + if ( nValue < 0 ) + { + nValue *= -1; + bIsNeg = TRUE; + } + else + { + bIsNeg = FALSE; + } + + if ( nValue < 1 ) + { + bIsBig = FALSE; + nVal = 0; + } + else + { + bIsBig = TRUE; + + int i=0; + + while ( ( nValue > 65536.0 ) && ( i < MAX_DIGITS ) ) + { + nNum[i] = (USHORT) fmod( nValue, 65536.0 ); + nValue -= nNum[i]; + nValue /= 65536.0; + i++; + } + if ( i < MAX_DIGITS ) + nNum[i++] = (USHORT) nValue; + + nLen = i; + + if ( i < 3 ) + Normalize( *this ); + } +} + +// ----------------------------------------------------------------------- + +BigInt::BigInt( ULONG nValue ) +{ +#if __SIZEOFLONG != 4 + #error sizeof (long) != 4: API auf INTxx umstellen +#else + bIsSet = TRUE; + if ( nValue & 0x80000000UL ) + { + bIsBig = TRUE; + bIsNeg = FALSE; + nNum[0] = (USHORT)(nValue & 0xffffUL); + nNum[1] = (USHORT)(nValue >> 16); + nLen = 2; + } + else + { + bIsBig = FALSE; + nVal = nValue; + } +#endif +} + +// ----------------------------------------------------------------------- + +BigInt::operator ULONG() const +{ + if ( !bIsBig ) + return (ULONG)nVal; + else if ( nLen == 2 ) + { + ULONG nRet; + nRet = ((ULONG)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) ((ULONG)nNum[i]); + + while ( i ) + { + nRet *= 65536.0; + i--; + nRet += (double) ((ULONG)nNum[i]); + } + + if ( bIsNeg ) + nRet *= -1; + + return nRet; + } +} + +// ----------------------------------------------------------------------- + +ByteString BigInt::GetByteString() const +{ + ByteString aString; + + if ( !bIsBig ) + aString = 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; +} + +// ----------------------------------------------------------------------- + +#ifdef ENABLEUNICODE + +UniString BigInt::GetString() const +{ + UniString aString; + + if ( !bIsBig ) + aString = 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; +} + +#endif + +// ----------------------------------------------------------------------- + +BigInt& BigInt::operator=( const BigInt& rBigInt ) +{ + if ( rBigInt.bIsBig ) + memcpy( (void*)this, (const void*)&rBigInt, sizeof( BigInt ) ); + else + { + bIsSet = rBigInt.bIsSet; + bIsBig = 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; + MakeBigInt( aTmp1, *this ); + MakeBigInt( aTmp2, rVal ); + AddLong( aTmp1, aTmp2, *this ); + Normalize( *this ); + 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; + MakeBigInt( aTmp1, *this ); + MakeBigInt( aTmp2, rVal ); + SubLong( aTmp1, aTmp2, *this ); + Normalize( *this ); + 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; + MakeBigInt( aTmp1, rVal ); + MakeBigInt( aTmp2, *this ); + MultLong(aTmp1, aTmp2, *this); + Normalize( *this ); + } + 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 USHORT teilen + USHORT nTmp; + if ( rVal.nVal < 0 ) + { + nTmp = (USHORT) -rVal.nVal; + bIsNeg = !bIsNeg; + } + else + nTmp = (USHORT) rVal.nVal; + + Div( *this, nTmp, nTmp ); + Normalize( *this ); + return *this; + } + } + + if ( ABS_IsLess( *this, rVal ) ) + { + *this = BigInt( (long)0 ); + return *this; + } + + // BigInt durch BigInt teilen + BigInt aTmp1, aTmp2; + MakeBigInt( aTmp1, *this ); + MakeBigInt( aTmp2, rVal ); + DivLong(aTmp1, aTmp2, *this); + Normalize( *this ); + 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 USHORT teilen + USHORT nTmp; + if ( rVal.nVal < 0 ) + { + nTmp = (USHORT) -rVal.nVal; + bIsNeg = !bIsNeg; + } + else + nTmp = (USHORT) rVal.nVal; + + Div( *this, nTmp, nTmp ); + rMod = BigInt( (long)nTmp ); + Normalize( *this ); + return; + } + } + + if ( ABS_IsLess( *this, rVal ) ) + { + rMod = *this; + *this = BigInt( (long)0 ); + return; + } + + // BigInt durch BigInt teilen + BigInt aTmp1, aTmp2; + MakeBigInt( aTmp1, *this ); + MakeBigInt( aTmp2, rVal ); + DivLong(aTmp1, aTmp2, *this); + Normalize( *this ); + ModLong(aTmp1, aTmp2, rMod); // nicht optimal + Normalize( rMod ); +} + +// ----------------------------------------------------------------------- + +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 + USHORT nTmp; + if ( rVal.nVal < 0 ) + { + nTmp = (USHORT) -rVal.nVal; + bIsNeg = !bIsNeg; + } + else + nTmp = (USHORT) rVal.nVal; + + Div( *this, nTmp, nTmp ); + *this = BigInt( (long)nTmp ); + return *this; + } + } + + if ( ABS_IsLess( *this, rVal ) ) + return *this; + + // BigInt durch BigInt teilen + BigInt aTmp1, aTmp2; + MakeBigInt( aTmp1, *this ); + MakeBigInt( aTmp2, rVal ); + ModLong(aTmp1, aTmp2, *this); + Normalize( *this ); + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL operator==( const BigInt& rVal1, const BigInt& rVal2 ) +{ + if ( rVal1.bIsBig || rVal2.bIsBig ) + { + BigInt nA, nB; + MakeBigInt( nA, rVal1 ); + MakeBigInt( nB, 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 FALSE; + } + return FALSE; + } + return rVal1.nVal == rVal2.nVal; +} + +// ----------------------------------------------------------------------- + +BOOL operator<( const BigInt& rVal1, const BigInt& rVal2 ) +{ + if ( rVal1.bIsBig || rVal2.bIsBig ) + { + BigInt nA, nB; + MakeBigInt( nA, rVal1 ); + MakeBigInt( nB, 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; +} + +// ----------------------------------------------------------------------- + +BOOL operator >(const BigInt& rVal1, const BigInt& rVal2 ) +{ + if ( rVal1.bIsBig || rVal2.bIsBig ) + { + BigInt nA, nB; + MakeBigInt( nA, rVal1 ); + MakeBigInt( nB, 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..f3ca447bffb5 --- /dev/null +++ b/tools/source/generic/color.cxx @@ -0,0 +1,403 @@ +/************************************************************************* + * + * $RCSfile: color.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <stdlib.h> + +#ifndef _VOS_MACROS_HXX_ +#include <vos/macros.hxx> +#endif + +#ifndef _TOOLS_COLOR_HXX +#include <color.hxx> +#endif +#ifndef _TOOLS_DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _STREAM_HXX +#include <stream.hxx> +#endif + +// ----------- +// - Inlines - +// ----------- + +static inline long _FRound( double fVal ) +{ + return( fVal > 0.0 ? (long) ( fVal + 0.5 ) : -(long) ( -fVal + 0.5 ) ); +} + +// --------- +// - Color - +// --------- + +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 ) ); +} + +// ----------------------------------------------------------------------- + +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/fract.cxx b/tools/source/generic/fract.cxx new file mode 100644 index 000000000000..6fc728df517f --- /dev/null +++ b/tools/source/generic/fract.cxx @@ -0,0 +1,720 @@ +/************************************************************************* + * + * $RCSfile: fract.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _LIMITS_H +#include <limits.h> +#endif + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif + +#ifndef _FRACT_HXX +#include <fract.hxx> +#endif + +#define private public +#define bIsLong bIsBig +#include <bigint.hxx> +#include <stream.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 zurckgegeben. 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.bIsLong || nD.bIsLong ) + { + 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.bIsLong || nD.bIsLong ) + { + 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.bIsLong || nD.bIsLong ) + { + 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.bIsLong || nD.bIsLong ) + { + 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.bIsLong || nD.bIsLong ) + { + 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 JOE 17.09.95 +|* +*************************************************************************/ + +// Funktioniert z.Zt. nur fuer 32-Bit Werte !!! +// Fehlerbehaftetes Kuerzen einer Fraction. +// nSignificantBits gibt an, wieviele signifikante Binaerstellen +// in Zaehler/Nenner mindestens erhalten bleiben sollen. +// Beispiel: ReduceInaccurate(8) hat einen Fehler <1% [1/2^(8-1)] +// dabei tritt der groesste Fehler bei folgendem Wertepaar auf: +// Binaer 1000000011111111111111111111111b/1000000000000000000000000000000b +// = 1082130431/1073741824 +// = ca. 1.007812499 +// Nach ReduceInaccurate( 8 ) wird daraus 1/1. + +void Fraction::ReduceInaccurate( unsigned nSignificantBits ) +{ + if ( !nNumerator || !nDenominator ) + return; + + // Zaehler und Nenner auf den Stack fuer schnelleren Zugriff + UINT32 nMul; + UINT32 nDiv; + BOOL bNeg; + if ( nNumerator >= 0 ) + { + nMul = (UINT32)nNumerator; + bNeg = FALSE; + } + else + { + nMul = (UINT32)(-nNumerator); + bNeg = TRUE; + } + nDiv=(UINT32)nDenominator; + + UINT32 a=nMul; unsigned nMulZ=0; // Fuehrende Nullen zaehlen + while (a<0x00800000) { nMulZ+=8; a<<=8; } + while (a<0x80000000) { nMulZ++; a<<=1; } + a=nDiv; unsigned nDivZ=0; // Fuehrende Nullen zaehlen + while (a<0x00800000) { nDivZ+=8; a<<=8; } + while (a<0x80000000) { nDivZ++; a<<=1; } + // Anzahl der verwendeten Digits bestimmen + // Auch hier gehe ich davon aus, dass es sich um 32Bit-Werte handelt + int nMulDigits=32-nMulZ; + int nDivDigits=32-nDivZ; + // Nun bestimmen, wieviele Stellen hinten weg koennen + // Hier koennte man das Ergebnis noch etwas optimieren... + int nMulWeg=nMulDigits-nSignificantBits; if (nMulWeg<0) nMulWeg=0; + int nDivWeg=nDivDigits-nSignificantBits; if (nDivWeg<0) nDivWeg=0; + int nWeg=Min(nMulWeg,nDivWeg); + nMul>>=nWeg; + nDiv>>=nWeg; + if ( !nMul || !nDiv ) + { + DBG_ERROR( "Oups, beim kuerzen einer Fraction hat sich Joe verrechnet." ); + return; + } + + // Nun noch kuerzen ueber GGT + long n1=GetGGT( nMul, nDiv ); + if ( n1!=1 ) + { + nMul/=n1; + nDiv/=n1; + } + if ( !bNeg ) + nNumerator = (long)nMul; + else + nNumerator = -(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..3b340a558a3d --- /dev/null +++ b/tools/source/generic/gen.cxx @@ -0,0 +1,699 @@ +/************************************************************************* + * + * $RCSfile: gen.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _TOOLS_DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _SV_GEN_HXX +#include <gen.hxx> +#endif +#ifndef _STREAM_HXX +#include <stream.hxx> +#endif + +// ======================================================================= + +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/link.cxx b/tools/source/generic/link.cxx new file mode 100644 index 000000000000..33248d3363cd --- /dev/null +++ b/tools/source/generic/link.cxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * $RCSfile: link.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _LINK_HXX +#include <link.hxx> +#endif + +/************************************************************************* +|* +|* 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..6b6ce0d86eef --- /dev/null +++ b/tools/source/generic/makefile.mk @@ -0,0 +1,98 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=gen + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/toolsin.obj \ + $(SLO)$/link.obj \ + $(SLO)$/bigint.obj \ + $(SLO)$/fract.obj \ + $(SLO)$/solmath.obj \ + $(SLO)$/color.obj \ + $(SLO)$/l2txtenc.obj \ + $(SLO)$/gen.obj + +.IF "$(UPDATER)"!="" +OBJFILES= $(OBJ)$/toolsin.obj \ + $(OBJ)$/link.obj \ + $(OBJ)$/bigint.obj \ + $(OBJ)$/fract.obj \ + $(OBJ)$/solmath.obj \ + $(OBJ)$/color.obj \ + $(OBJ)$/l2txtenc.obj \ + $(OBJ)$/gen.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/tools/source/generic/toolsin.cxx b/tools/source/generic/toolsin.cxx new file mode 100644 index 000000000000..b37e14321d9e --- /dev/null +++ b/tools/source/generic/toolsin.cxx @@ -0,0 +1,159 @@ +/************************************************************************* + * + * $RCSfile: toolsin.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _TOOLS_TOOLSIN_CXX + +#include <string.h> + +#ifndef _SHL_HXX +#include <shl.hxx> +#endif + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _INTNTAB_HXX +#include <intntab.hxx> +#endif +#ifndef _TOOLSIN_HXX +#include <toolsin.hxx> +#endif + +#if defined( WIN ) || defined( WNT ) || defined( OS2 ) +#include <dll.hxx> +#endif +#ifdef MAC +void ImpDeInitMemMgr(); +#endif + +void ImplDeleteCharTabData(); + +// ======================================================================= + +// Hier drin, da DOS bisher kein eigenes TOOLS-Verzeichnis hat + +#if defined( DOS ) + +static void* aAppData[SHL_COUNT]; + +void** GetAppData( USHORT nSharedLib ) +{ + return &(aAppData[nSharedLib]); +} + +#endif + +// ======================================================================= + +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 ) + { + ImplDeleteIntnListData(); + ImplDeleteCharTabData(); + delete pData; + *ppData = NULL; + } + + DBG_DEBUGEND(); +} + +// ----------------------------------------------------------------------- + +void GlobalDeInitTools() +{ + DBG_GLOBALDEBUGEND(); + +#if defined( WIN ) || defined( WNT ) + ImpDeInitWinTools(); +#endif +#ifdef OS2 + ImpDeInitOS2Tools(); +#endif +#ifdef MAC + ImpDeInitMemMgr(); +#endif +} diff --git a/tools/source/inet/inetmime.cxx b/tools/source/inet/inetmime.cxx new file mode 100644 index 000000000000..a1d70a045222 --- /dev/null +++ b/tools/source/inet/inetmime.cxx @@ -0,0 +1,4630 @@ +/************************************************************************* + * + * $RCSfile: inetmime.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <limits> + +#ifndef _DATETIME_HXX +#include <datetime.hxx> +#endif +#ifndef TOOLS_INETMIME_HXX +#include <inetmime.hxx> +#endif + +#undef max // defined by <tools/solar.h> +#undef min // defined by <tools/solar.h> + +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) +{ + sal_Size nLength = 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; + 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, 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_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; + for (const sal_Char * p = rBegin; 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; + for (const sal_Unicode * p = rBegin; 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; + for (const sal_Char * 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; + for (const sal_Unicode * 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 +const sal_Char * INetMIME::scanQuotedBlock(const sal_Char * pBegin, + const sal_Char * pEnd, + sal_uInt32 nOpening, + sal_uInt32 nClosing, + sal_uInt32 & 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 +const sal_Unicode * INetMIME::scanQuotedBlock(const sal_Unicode * pBegin, + const sal_Unicode * pEnd, + sal_uInt32 nOpening, + sal_uInt32 nClosing, + sal_uInt32 & 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); + sal_Char const * p = pAttributeBegin; + bool bDowncaseAttribute = false; + while (p != pEnd && isTokenChar(*p) && *p != '*') + { + bDowncaseAttribute = bDowncaseAttribute || isUpperCase(*p); + ++p; + } + if (p == pAttributeBegin) + break; + ByteString aAttribute(pAttributeBegin, 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, 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, + 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, 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); + sal_Unicode const * p = pAttributeBegin; + bool bDowncaseAttribute = false; + while (p != pEnd && isTokenChar(*p) && *p != '*') + { + bDowncaseAttribute = bDowncaseAttribute || isUpperCase(*p); + ++p; + } + if (p == pAttributeBegin) + break; + ByteString aAttribute = ByteString(pAttributeBegin, + 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, 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, 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, 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 (eEncoding < RTL_TEXTENCODING_STD_COUNT) + { + // 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: + static const sal_Char * aMap[RTL_TEXTENCODING_STD_COUNT] + = { 0, // RTL_TEXTENCODING_DONTKNOW + 0, // RTL_TEXTENCODING_MS_1252 + "macintosh", // RTL_TEXTENCODING_APPLE_ROMAN + "IBM437", // RTL_TEXTENCODING_IBM_437 + "IBM850", // RTL_TEXTENCODING_IBM_850 + "IBM860", // RTL_TEXTENCODING_IBM_860 + "IBM861", // RTL_TEXTENCODING_IBM_861 + "IBM863", // RTL_TEXTENCODING_IBM_863 + "IBM865", // RTL_TEXTENCODING_IBM_865 + 0, // CHARSET_SYSTEM + 0, // RTL_TEXTENCODING_SYMBOL + "US-ASCII", // RTL_TEXTENCODING_ASCII_US + "ISO-8859-1", // RTL_TEXTENCODING_ISO_8859_1 + "ISO-8859-2", // RTL_TEXTENCODING_ISO_8859_2 + "ISO-8859-3", // RTL_TEXTENCODING_ISO_8859_3 + "ISO-8859-4", // RTL_TEXTENCODING_ISO_8859_4 + "ISO-8859-5", // RTL_TEXTENCODING_ISO_8859_5 + "ISO-8859-6", // RTL_TEXTENCODING_ISO_8859_6 + "ISO-8859-7", // RTL_TEXTENCODING_ISO_8859_7 + "ISO-8859-8", // RTL_TEXTENCODING_ISO_8859_8 + "ISO-8859-9", // RTL_TEXTENCODING_ISO_8859_9 + "ISO-8859-14", // RTL_TEXTENCODING_ISO_8859_14, RFC 2047 + "ISO_8859-15", // RTL_TEXTENCODING_ISO_8859_15 + 0, // RTL_TEXTENCODING_IBM_737 + "IBM775", // RTL_TEXTENCODING_IBM_775 + "IBM852", // RTL_TEXTENCODING_IBM_852 + "IBM855", // RTL_TEXTENCODING_IBM_855 + "IBM857", // RTL_TEXTENCODING_IBM_857 + "IBM862", // RTL_TEXTENCODING_IBM_862 + "IBM864", // RTL_TEXTENCODING_IBM_864 + "IBM866", // RTL_TEXTENCODING_IBM_866 + "IBM869", // RTL_TEXTENCODING_IBM_869 + 0, // RTL_TEXTENCODING_MS_874 + "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 + 0, // RTL_TEXTENCODING_APPLE_ARABIC + 0, // RTL_TEXTENCODING_APPLE_CENTEURO + 0, // RTL_TEXTENCODING_APPLE_CROATIAN + 0, // RTL_TEXTENCODING_APPLE_CYRILLIC + 0, // RTL_TEXTENCODING_APPLE_DEVANAGARI + 0, // RTL_TEXTENCODING_APPLE_FARSI + 0, // RTL_TEXTENCODING_APPLE_GREEK + 0, // RTL_TEXTENCODING_APPLE_GUJARATI + 0, // RTL_TEXTENCODING_APPLE_GURMUKHI + 0, // RTL_TEXTENCODING_APPLE_HEBREW + 0, // RTL_TEXTENCODING_APPLE_ICELAND + 0, // RTL_TEXTENCODING_APPLE_ROMANIAN + 0, // RTL_TEXTENCODING_APPLE_THAI + 0, // RTL_TEXTENCODING_APPLE_TURKISH + 0, // RTL_TEXTENCODING_APPLE_UKRAINIAN + 0, // RTL_TEXTENCODING_APPLE_CHINSIMP + 0, // RTL_TEXTENCODING_APPLE_CHINTRAD + 0, // RTL_TEXTENCODING_APPLE_JAPANESE + 0, // RTL_TEXTENCODING_APPLE_KOREAN + 0, // RTL_TEXTENCODING_MS_932 + 0, // RTL_TEXTENCODING_MS_936 + 0, // RTL_TEXTENCODING_MS_949 + 0, // RTL_TEXTENCODING_MS_950 + "Shift_JIS", // RTL_TEXTENCODING_SHIFT_JIS + "GB2312", // RTL_TEXTENCODING_GB_2312 + 0, // RTL_TEXTENCODING_GBT_12345 + 0, // RTL_TEXTENCODING_GBK + "Big5", // RTL_TEXTENCODING_BIG5 + "EUC-JP", // RTL_TEXTENCODING_EUC_JP + 0, // RTL_TEXTENCODING_EUC_CN + 0, // RTL_TEXTENCODING_EUC_TW + "ISO-2022-JP", // RTL_TEXTENCODING_ISO_2022_JP + "ISO-2022-CN", // RTL_TEXTENCODING_ISO_2022_CN + "KOI8-R", // 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 + "ISO-2022-KR" }; // RTL_TEXTENCODING_ISO_2022_KR + DBG_ASSERT(aMap[eEncoding], + "INetMIME::getCharsetName(): Unsupported encoding"); + return aMap[eEncoding]; + } + 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 + + 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 + + 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); +} + +//============================================================================ +// 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; + 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; + } + } + + // 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_uInt32 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_uInt32 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 || *rBegin < 0x80 || *rBegin >= 0xFE) + return false; + + int nCount; + sal_uInt32 nMin; + sal_uInt32 nUCS4; + const sal_Char * p = rBegin; + if (*p < 0xE0) + { + nCount = 1; + nMin = 0x80; + nUCS4 = *p & 0x1F; + } + else if (*p < 0xF0) + { + nCount = 2; + nMin = 0x800; + nUCS4 = *p & 0xF; + } + else if (*p < 0xF8) + { + nCount = 3; + nMin = 0x10000; + nUCS4 = *p & 7; + } + else if (*p < 0xFC) + { + nCount = 4; + nMin = 0x200000; + nUCS4 = *p & 3; + } + else + { + nCount = 5; + nMin = 0x4000000; + nUCS4 = *p & 1; + } + ++p; + + for (; nCount-- > 0; ++p) + if ((*p & 0xC0) == 0x80) + nUCS4 = nUCS4 << 6 | *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; + if (bEncodedWord) + { + const sal_Char * pCharsetBegin = q; + const sal_Char * pLanguageBegin = 0; + int nAlphaCount; + 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; + 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 ? 2 : 1; + } + } + 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( + pEncodedTextCopyBegin + - pBegin, + q - 1 + - pEncodedTextCopyBegin); + sText += sal_Char(nDigit1 << 4 | nDigit2); + q += 2; + pEncodedTextCopyBegin = q; + break; + } + + case '?': + if (q - pEncodedTextBegin > 1) + sText + += rBody. + Copy( + pEncodedTextCopyBegin + - pBegin, + q - 1 + - pEncodedTextCopyBegin); + else + bEncodedWord = false; + bDone = true; + break; + + case '_': + sText + += rBody. + Copy( + pEncodedTextCopyBegin + - pBegin, + 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; + sal_Size nUnicodeSize; + 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, nUnicodeSize); + else if (nCommentLevel == 0) + { + sEncodedText.Append(pUnicodeBuffer, 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 = 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, 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, 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 if (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; + } + + 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; + } + 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; + } + 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; + sal_Size nTargetSize; + 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; + 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; + } + } + } + + 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; + } + + // 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..d34513f62b6c --- /dev/null +++ b/tools/source/inet/inetmsg.cxx @@ -0,0 +1,2945 @@ +/************************************************************************* + * + * $RCSfile: inetmsg.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SAL_TYPES_H_ +#include <sal/types.h> +#endif + +#ifndef _RTL_CHAR_H_ +#include <rtl/char.h> +#endif + +#ifndef _DATETIME_HXX +#include <datetime.hxx> +#endif +#ifndef _TOOLS_INETMIME_HXX +#include <inetmime.hxx> +#endif +#ifndef _TOOLS_INETMSG_HXX +#include <inetmsg.hxx> +#endif +#ifndef _TOOLS_INETSTRM_HXX +#include <inetstrm.hxx> +#endif + +#include <stdio.h> + +/*======================================================================= + * + * 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 << m_nDocSize; + rStrm.WriteByteString (m_aDocName, RTL_TEXTENCODING_UTF8); + + ULONG i, n = m_aHeaderList.Count(); + rStrm << 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(); + + // Copy. + rStrm >> m_nDocSize; + rStrm.ReadByteString (m_aDocName, RTL_TEXTENCODING_UTF8); + + ULONG i, n = 0; + rStrm >> n; + + 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. + */ +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") +}; + +#define HDR(n) _ImplINetRFC822MessageHeaderData[(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 += nNum; + rDateField += ' '; + + rDateField += months[(USHORT)(rDateTime.GetMonth() - 1)]; + rDateField += ' '; + + rDateField += rDateTime.GetYear(); + rDateField += ' '; + + // Insert Time. + nNum = rDateTime.GetHour(); + if (nNum < 10) rDateField += '0'; + rDateField += nNum; + rDateField += ':'; + + nNum = rDateTime.GetMin(); + if (nNum < 10) rDateField += '0'; + rDateField += nNum; + rDateField += ':'; + + nNum = rDateTime.GetSec(); + if (nNum < 10) rDateField += '0'; + rDateField += 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()) && rtl_char_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()) && rtl_char_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()) && + (rtl_char_isLetter (rDateField.GetChar(nIndex)) || + (rDateField.GetChar(nIndex) == ',') )) + nIndex++; + + while ((nIndex < rDateField.Len()) && + (rDateField.GetChar(nIndex) == ' ')) + nIndex++; + + if (rtl_char_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 (rtl_char_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 (rtl_char_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 (rtl_char_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 (rtl_char_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 (rtl_char_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 (rtl_char_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 && + (rtl_char_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 << m_nIndex[i]; + + return rStrm; +} + +/* + * operator>> + */ +SvStream& INetRFC822Message::operator>> (SvStream& rStrm) +{ + INetMessage::operator>> (rStrm); + + for (USHORT i = 0; i < INETMSG_RFC822_NUMHDR; i++) + rStrm >> m_nIndex[i]; + + return rStrm; +} + +/*======================================================================= + * + * INetMIMEMessage Implementation. + * + *=====================================================================*/ +/* + * _ImplINetMIMEMessageHeaderData. + */ +static const ByteString _ImplINetMIMEMessageHeaderData[] = +{ + ByteString ("MIME-Version"), + ByteString ("Content-Description"), + ByteString ("Content-Disposition"), + ByteString ("Content-ID"), + ByteString ("Content-Type"), + ByteString ("Content-Transfer-Encoding") +}; + +#define MIMEHDR(n) _ImplINetMIMEMessageHeaderData[(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 (), + nNumChildren (0), + pParent (NULL), + 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 (rtl_char_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 (rtl_char_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 (rtl_char_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 (rtl_char_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 && + (rtl_char_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; + sprintf (sTail, "%08X%08X", aCurTime.GetTime(), (ULONG)this); + 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), NULL); + 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 << m_nIndex[i]; + +#ifdef ENABLE_BYTESTRING_STREAM_OPERATORS + rStrm << m_aBoundary; +#else + rStrm.WriteByteString (m_aBoundary); +#endif + rStrm << nNumChildren; + + return rStrm; +} + +/* + * operator>> + */ +SvStream& INetMIMEMessage::operator>> (SvStream& rStrm) +{ + INetRFC822Message::operator>> (rStrm); + + for (USHORT i = 0; i < INETMSG_MIME_NUMHDR; i++) + rStrm >> m_nIndex[i]; + +#ifdef ENABLE_BYTESTRING_STREAM_OPERATORS + rStrm >> m_aBoundary; +#else + rStrm.ReadByteString (m_aBoundary); +#endif + rStrm >> nNumChildren; + + return rStrm; +} + +/*======================================================================= + * + * INetNewsMessage Implementation. + * + *=====================================================================*/ +/* + * _ImplINetNewsMessageHeaderData. + */ +static const ByteString _ImplINetNewsMessageHeaderData[] = +{ + ByteString ("Approved"), + ByteString ("Control"), + ByteString ("Distribution"), + ByteString ("Expires"), + ByteString ("Followup-To"), + ByteString ("Lines"), + ByteString ("Newsgroups"), + ByteString ("Organization"), + ByteString ("Path"), + ByteString ("Summary"), + ByteString ("Xref"), + ByteString ("X-Newsreader") +}; + +#define NEWSHDR(n) _ImplINetNewsMessageHeaderData[(n)] + +/* + * _ImplINetNewsMessageHeaderState. + */ +enum _ImplINetNewsMessageHeaderState +{ + INETMSG_NEWS_BEGIN, + INETMSG_NEWS_CHECK, + INETMSG_NEWS_OK, + INETMSG_NEWS_JUNK, + + INETMSG_NEWS_LETTER_X +}; + +/* + * INetNewsMessage. + */ +INetNewsMessage::INetNewsMessage (void) + : INetMIMEMessage () +{ + for (USHORT i = 0; i < INETMSG_NEWS_NUMHDR; i++) + m_nIndex[i] = LIST_ENTRY_NOTFOUND; +} + +INetNewsMessage::INetNewsMessage (const INetNewsMessage& rMsg) + : INetMIMEMessage (rMsg) +{ + for (USHORT i = 0; i < INETMSG_NEWS_NUMHDR; i++) + m_nIndex[i] = rMsg.m_nIndex[i]; +} + +/* + * operator= + */ +INetNewsMessage& INetNewsMessage::operator= (const INetNewsMessage& rMsg) +{ + if (this != &rMsg) + { + // Assign base. + INetMIMEMessage::operator= (rMsg); + + // Cleanup and copy. + for (USHORT i = 0; i < INETMSG_NEWS_NUMHDR; i++) + m_nIndex[i] = rMsg.m_nIndex[i]; + } + return *this; +} + +/* + * ~INetNewsMessage. + */ +INetNewsMessage::~INetNewsMessage (void) +{ +} + +/* + * CreateMessage. + */ +INetNewsMessage *INetNewsMessage::CreateMessage ( + const INetNewsMessage& rMsg) const +{ + return (new INetNewsMessage (rMsg)); +} + +/* + * SetHeaderField. + * (Header Field Parser). + */ +ULONG INetNewsMessage::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_NEWS_BEGIN; + int eOkState = INETMSG_NEWS_OK; + + while (pData < pStop) + { + switch (eState) + { + case INETMSG_NEWS_BEGIN: + eState = INETMSG_NEWS_CHECK; + eOkState = INETMSG_NEWS_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'a': + check = "pproved"; + nIdx = INETMSG_NEWS_APPROVED; + break; + + case 'c': + check = "ontrol"; + nIdx = INETMSG_NEWS_CONTROL; + break; + + case 'd': + check = "istribution"; + nIdx = INETMSG_NEWS_DISTRIBUTION; + break; + + case 'e': + check = "xpires"; + nIdx = INETMSG_NEWS_EXPIRES; + break; + + case 'f': + check = "ollowup-to"; + nIdx = INETMSG_NEWS_FOLLOWUP_TO; + break; + + case 'l': + check = "ines"; + nIdx = INETMSG_NEWS_LINES; + break; + + case 'n': + check = "ewsgroups"; + nIdx = INETMSG_NEWS_NEWSGROUPS; + break; + + case 'o': + check = "rganization"; + nIdx = INETMSG_NEWS_ORGANIZATION; + break; + + case 'p': + check = "ath"; + nIdx = INETMSG_NEWS_PATH; + break; + + case 's': + check = "ummary"; + nIdx = INETMSG_NEWS_SUMMARY; + break; + + case 'x': + eState = INETMSG_NEWS_LETTER_X; + break; + + default: + eState = INETMSG_NEWS_JUNK; + break; + } + pData++; + break; + + case INETMSG_NEWS_LETTER_X: + eState = INETMSG_NEWS_CHECK; + eOkState = INETMSG_NEWS_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'r': + check = "ef"; + nIdx = INETMSG_NEWS_XREF; + break; + + case '-': + check = "newsreader"; + nIdx = INETMSG_NEWS_X_NEWSREADER; + break; + + default: + eState = INETMSG_NEWS_JUNK; + break; + } + pData++; + break; + + case INETMSG_NEWS_CHECK: + if (*check) + { + while (*pData && *check && + (rtl_char_toLowerCase (*pData) == *check)) + { + pData++; + check++; + } + } + else + { + check = pData; + } + eState = (*check == '\0') ? eOkState : INETMSG_NEWS_JUNK; + break; + + case INETMSG_NEWS_OK: + pData = pStop; + SetHeaderField_Impl ( + HEADERFIELD (NEWSHDR(nIdx), rHeader.GetValue()), + m_nIndex[nIdx]); + nNewIndex = m_nIndex[nIdx]; + break; + + default: // INETMSG_NEWS_JUNK + pData = pStop; + nNewIndex = INetMIMEMessage::SetHeaderField ( + rHeader, nNewIndex); + break; + } + } + return nNewIndex; +} + +/* + * Specific Set-Methods. + */ +void INetNewsMessage::SetApproved (const String& rApproved) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_APPROVED), rApproved, + m_nIndex[INETMSG_NEWS_APPROVED]); +} + +void INetNewsMessage::SetControl (const String& rControl) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_CONTROL), rControl, + m_nIndex[INETMSG_NEWS_CONTROL]); +} + +void INetNewsMessage::SetDistribution (const String& rDistribution) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_DISTRIBUTION), rDistribution, + m_nIndex[INETMSG_NEWS_DISTRIBUTION]); +} + +void INetNewsMessage::SetExpires (const String& rExpires) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_EXPIRES), rExpires, + m_nIndex[INETMSG_NEWS_EXPIRES]); +} + +void INetNewsMessage::SetFollowupTo (const String& rFollowupTo) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_FOLLOWUP_TO), rFollowupTo, + m_nIndex[INETMSG_NEWS_FOLLOWUP_TO]); +} + +void INetNewsMessage::SetLines (const String& rLines) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_LINES), rLines, + m_nIndex[INETMSG_NEWS_LINES]); +} + +void INetNewsMessage::SetNewsgroups (const String& rNewsgroups) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_NEWSGROUPS), rNewsgroups, + m_nIndex[INETMSG_NEWS_NEWSGROUPS]); +} + +void INetNewsMessage::SetOrganization (const String& rOrganization) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_ORGANIZATION), rOrganization, + m_nIndex[INETMSG_NEWS_ORGANIZATION]); +} + +void INetNewsMessage::SetPath (const String& rPath) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_PATH), rPath, + m_nIndex[INETMSG_NEWS_PATH]); +} + +void INetNewsMessage::SetSummary (const String& rSummary) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_SUMMARY), rSummary, + m_nIndex[INETMSG_NEWS_SUMMARY]); +} + +void INetNewsMessage::SetXref (const String& rXref) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_XREF), rXref, + m_nIndex[INETMSG_NEWS_XREF]); +} + +void INetNewsMessage::SetXNewsreader (const String& rXNewsreader) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + NEWSHDR(INETMSG_NEWS_X_NEWSREADER), rXNewsreader, + m_nIndex[INETMSG_NEWS_X_NEWSREADER]); +} + +/* + * operator<< + */ +SvStream& INetNewsMessage::operator<< (SvStream& rStrm) const +{ + INetMIMEMessage::operator<< (rStrm); + + for (USHORT i = 0; i < INETMSG_NEWS_NUMHDR; i++) + rStrm << m_nIndex[i]; + + return rStrm; +} + +/* + * operator>> + */ +SvStream& INetNewsMessage::operator>> (SvStream& rStrm) +{ + INetMIMEMessage::operator>> (rStrm); + + for (USHORT i = 0; i < INETMSG_NEWS_NUMHDR; i++) + rStrm >> m_nIndex[i]; + + return rStrm; +} + +/*======================================================================= + * + * INetHTTPMessage Implementation. + * + *=====================================================================*/ +/* + * _ImplINetHTTPMessageHeaderData. + */ +static const ByteString _ImplINetHTTPMessageHeaderData[] = +{ + ByteString ("Accept"), + ByteString ("Accept-Charset"), + ByteString ("Accept-Encoding"), + ByteString ("Accept-Language"), + ByteString ("Allow"), + ByteString ("Authorization"), + ByteString ("Cache-Control"), + ByteString ("Connection"), + ByteString ("Content-Encoding"), + ByteString ("Content-Language"), + ByteString ("Content-Length"), + ByteString ("Content-MD5"), + ByteString ("Content-Range"), + ByteString ("Content-Version"), + ByteString ("Cookie"), + ByteString ("Derived-From"), + ByteString ("Expires"), + ByteString ("Forwarded"), + ByteString ("Host"), + ByteString ("If-Modified-Since"), + ByteString ("Keep-Alive"), + ByteString ("Last-Modified"), + ByteString ("Link"), + ByteString ("Location"), + ByteString ("Proxy-Authenticate"), + ByteString ("Proxy-Authorization"), + ByteString ("Pragma"), + ByteString ("Public"), + ByteString ("Range"), + ByteString ("Referer"), + ByteString ("Retry-After"), + ByteString ("Server"), + ByteString ("Title"), + ByteString ("Transfer-Encoding"), + ByteString ("Unless"), + ByteString ("Upgrade"), + ByteString ("URI"), + ByteString ("User-Agent"), + ByteString ("WWW-Authenticate") +}; + +#define HTTPHDR(n) _ImplINetHTTPMessageHeaderData[(n)] + +/* + * _ImplINetHTTPMessageHeaderState. + */ +enum _ImplINetHTTPMessageHeaderState +{ + INETMSG_HTTP_BEGIN, + INETMSG_HTTP_CHECK, + INETMSG_HTTP_OK, + INETMSG_HTTP_JUNK, + + INETMSG_HTTP_LETTER_A, + INETMSG_HTTP_LETTER_C, + INETMSG_HTTP_LETTER_L, + INETMSG_HTTP_LETTER_P, + INETMSG_HTTP_LETTER_R, + INETMSG_HTTP_LETTER_T, + INETMSG_HTTP_LETTER_U, + INETMSG_HTTP_TOKEN_CON, + INETMSG_HTTP_CONTENT, + INETMSG_HTTP_PROXY_AUTH +}; + +/* + * INetHTTPMessage. + */ +INetHTTPMessage::INetHTTPMessage (void) + : INetMIMEMessage () +{ + for (USHORT i = 0; i < INETMSG_HTTP_NUMHDR; i++) + m_nIndex[i] = LIST_ENTRY_NOTFOUND; +} + +INetHTTPMessage::INetHTTPMessage (const INetHTTPMessage& rMsg) + : INetMIMEMessage (rMsg) +{ + for (USHORT i = 0; i < INETMSG_HTTP_NUMHDR; i++) + m_nIndex[i] = rMsg.m_nIndex[i]; +} + +/* + * operator= + */ +INetHTTPMessage& INetHTTPMessage::operator= (const INetHTTPMessage& rMsg) +{ + if (this != &rMsg) + { + // Assign base. + INetMIMEMessage::operator= (rMsg); + + // Cleanup and copy. + for (USHORT i = 0; i < INETMSG_HTTP_NUMHDR; i++) + m_nIndex[i] = rMsg.m_nIndex[i]; + } + return *this; +} + +/* + * ~INetHTTPMessage. + */ +INetHTTPMessage::~INetHTTPMessage (void) +{ +} + +/* + * CreateMessage. + */ +INetHTTPMessage *INetHTTPMessage::CreateMessage ( + const INetHTTPMessage& rMsg) const +{ + return (new INetHTTPMessage (rMsg)); +} + +/* + * SetHeaderField. + * (Header Field Parser). + */ +ULONG INetHTTPMessage::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_HTTP_BEGIN; + int eOkState = INETMSG_HTTP_OK; + + while (pData < pStop) + { + switch (eState) + { + case INETMSG_HTTP_BEGIN: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'a': + eState = INETMSG_HTTP_LETTER_A; + break; + + case 'c': + eState = INETMSG_HTTP_LETTER_C; + break; + + case 'd': + check = "erived-from"; + nIdx = INETMSG_HTTP_DERIVED_FROM; + break; + + case 'e': + check = "xpires"; + nIdx = INETMSG_HTTP_EXPIRES; + break; + + case 'f': + check = "orwarded"; + nIdx = INETMSG_HTTP_FORWARDED; + break; + + case 'h': + check = "ost"; + nIdx = INETMSG_HTTP_HOST; + break; + + case 'i': + check = "f-modified-since"; + nIdx = INETMSG_HTTP_IF_MODIFIED_SINCE; + break; + + case 'k': + check = "eep-alive"; + nIdx = INETMSG_HTTP_KEEP_ALIVE; + break; + + case 'l': + eState = INETMSG_HTTP_LETTER_L; + break; + + case 'p': + eState = INETMSG_HTTP_LETTER_P; + break; + + case 'r': + eState = INETMSG_HTTP_LETTER_R; + break; + + case 's': + check = "erver"; + nIdx = INETMSG_HTTP_SERVER; + break; + + case 't': + eState = INETMSG_HTTP_LETTER_T; + break; + + case 'u': + eState = INETMSG_HTTP_LETTER_U; + break; + + case 'w': + check = "ww-authenticate"; + nIdx = INETMSG_HTTP_WWW_AUTHENTICATE; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_LETTER_A: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'c': + if (INetMIME::equalIgnoreCase ( + pData, pData + 14, "ccept-language")) + { + nIdx = INETMSG_HTTP_ACCEPT_LANGUAGE; + pData += 14; + } + else if (INetMIME::equalIgnoreCase ( + pData, pData + 14, "ccept-encoding")) + { + nIdx = INETMSG_HTTP_ACCEPT_ENCODING; + pData += 14; + } + else if (INetMIME::equalIgnoreCase ( + pData, pData + 13, "ccept-charset")) + { + nIdx = INETMSG_HTTP_ACCEPT_CHARSET; + pData += 13; + } + else if (INetMIME::equalIgnoreCase ( + pData, pData + 5, "ccept")) + { + nIdx = INETMSG_HTTP_ACCEPT; + pData += 5; + } + else + { + eState = INETMSG_HTTP_JUNK; + } + break; + + case 'l': + check = "low"; + nIdx = INETMSG_HTTP_ALLOW; + break; + + case 'u': + check = "thorization"; + nIdx = INETMSG_HTTP_AUTHORIZATION; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_LETTER_C: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'a': + check = "che-control"; + nIdx = INETMSG_HTTP_CACHE_CONTROL; + break; + + case 'o': + if (rtl_char_toLowerCase (*(pData + 1)) == 'n') + { + eState = INETMSG_HTTP_TOKEN_CON; + } + else if (rtl_char_toLowerCase (*(pData + 1)) == 'o') + { + check = "kie"; + nIdx = INETMSG_HTTP_COOKIE; + } + else + { + eState = INETMSG_HTTP_JUNK; + } + pData++; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_LETTER_L: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'a': + check = "st-modified"; + nIdx = INETMSG_HTTP_LAST_MODIFIED; + break; + + case 'i': + check = "nk"; + nIdx = INETMSG_HTTP_LINK; + break; + + case 'o': + check = "cation"; + nIdx = INETMSG_HTTP_LOCATION; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_LETTER_P: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'r': + switch (rtl_char_toLowerCase (*(pData + 1))) + { + case 'a': + check = "gma"; + nIdx = INETMSG_HTTP_PRAGMA; + break; + + case 'o': + check = "xy-auth"; + eOkState = INETMSG_HTTP_PROXY_AUTH; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case 'u': + check = "blic"; + nIdx = INETMSG_HTTP_PUBLIC; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_LETTER_R: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'a': + check = "nge"; + nIdx = INETMSG_HTTP_RANGE; + break; + + case 'e': + switch (rtl_char_toLowerCase (*(pData + 1))) + { + case 'f': + check = "erer"; + nIdx = INETMSG_HTTP_REFERER; + break; + + case 't': + check = "ry-after"; + nIdx = INETMSG_HTTP_RETRY_AFTER; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_LETTER_T: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'i': + check = "tle"; + nIdx = INETMSG_HTTP_TITLE; + break; + + case 'r': + check = "ansfer-encoding"; + nIdx = INETMSG_HTTP_TRANSFER_ENCODING; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_LETTER_U: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'n': + check = "less"; + nIdx = INETMSG_HTTP_UNLESS; + break; + + case 'p': + check = "grade"; + nIdx = INETMSG_HTTP_UPGRADE; + break; + + case 'r': + check = "i"; + nIdx = INETMSG_HTTP_URI; + break; + + case 's': + check = "er-agent"; + nIdx = INETMSG_HTTP_USER_AGENT; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_TOKEN_CON: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'n': + check = "ection"; + nIdx = INETMSG_HTTP_CONNECTION; + break; + + case 't': + check = "ent-"; + eOkState = INETMSG_HTTP_CONTENT; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_CONTENT: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'e': + check = "ncoding"; + nIdx = INETMSG_HTTP_CONTENT_ENCODING; + break; + + case 'l': + switch (rtl_char_toLowerCase (*(pData + 1))) + { + case 'a': + check = "nguage"; + nIdx = INETMSG_HTTP_CONTENT_LANGUAGE; + break; + + case 'e': + check = "ngth"; + nIdx = INETMSG_HTTP_CONTENT_LENGTH; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case 'm': + check = "d5"; + nIdx = INETMSG_HTTP_CONTENT_MD5; + break; + + case 'r': + check = "ange"; + nIdx = INETMSG_HTTP_CONTENT_RANGE; + break; + + case 'v': + check = "ersion"; + nIdx = INETMSG_HTTP_CONTENT_VERSION; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_PROXY_AUTH: + eState = INETMSG_HTTP_CHECK; + eOkState = INETMSG_HTTP_OK; + + switch (rtl_char_toLowerCase (*pData)) + { + case 'e': + check = "nticate"; + nIdx = INETMSG_HTTP_PROXY_AUTHENTICATE; + break; + + case 'o': + check = "rization"; + nIdx = INETMSG_HTTP_PROXY_AUTHORIZATION; + break; + + default: + eState = INETMSG_HTTP_JUNK; + break; + } + pData++; + break; + + case INETMSG_HTTP_CHECK: + if (*check) + { + while (*pData && *check && + (rtl_char_toLowerCase (*pData) == *check)) + { + pData++; + check++; + } + } + else + { + check = pData; + } + eState = (*check == '\0') ? eOkState : INETMSG_HTTP_JUNK; + break; + + case INETMSG_HTTP_OK: + pData = pStop; + SetHeaderField_Impl ( + HEADERFIELD (HTTPHDR(nIdx), rHeader.GetValue()), + m_nIndex[nIdx]); + nNewIndex = m_nIndex[nIdx]; + break; + + default: // INETMSG_HTTP_JUNK + pData = pStop; + nNewIndex = INetMIMEMessage::SetHeaderField ( + rHeader, nNewIndex); + break; + } + } + return nNewIndex; +} + +/* + * Specific Set-Methods. + */ +void INetHTTPMessage::SetAccept (const String& rAccept) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_ACCEPT), rAccept, + m_nIndex[INETMSG_HTTP_ACCEPT]); +} + +void INetHTTPMessage::SetAcceptCharset (const String& rAcceptCharset) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_ACCEPT_CHARSET), rAcceptCharset, + m_nIndex[INETMSG_HTTP_ACCEPT_CHARSET]); +} + +void INetHTTPMessage::SetAcceptEncoding (const String& rAcceptEncoding) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_ACCEPT_ENCODING), rAcceptEncoding, + m_nIndex[INETMSG_HTTP_ACCEPT_ENCODING]); +} + +void INetHTTPMessage::SetAcceptLanguage (const String& rAcceptLanguage) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_ACCEPT_LANGUAGE), rAcceptLanguage, + m_nIndex[INETMSG_HTTP_ACCEPT_LANGUAGE]); +} + +void INetHTTPMessage::SetAllow (const String& rAllow) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_ALLOW), rAllow, + m_nIndex[INETMSG_HTTP_ALLOW]); +} + +void INetHTTPMessage::SetAuthorization (const String& rAuthorization) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_AUTHORIZATION), rAuthorization, + m_nIndex[INETMSG_HTTP_AUTHORIZATION]); +} + +void INetHTTPMessage::SetCacheControl (const String& rCacheControl) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_CACHE_CONTROL), rCacheControl, + m_nIndex[INETMSG_HTTP_CACHE_CONTROL]); +} + +void INetHTTPMessage::SetConnection (const String& rConnection) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_CONNECTION), rConnection, + m_nIndex[INETMSG_HTTP_CONNECTION]); +} + +void INetHTTPMessage::SetContentEncoding (const String& rContentEncoding) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_CONTENT_ENCODING), rContentEncoding, + m_nIndex[INETMSG_HTTP_CONTENT_ENCODING]); +} + +void INetHTTPMessage::SetContentLanguage (const String& rContentLanguage) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_CONTENT_LANGUAGE), rContentLanguage, + m_nIndex[INETMSG_HTTP_CONTENT_LANGUAGE]); +} + +void INetHTTPMessage::SetContentLength (const String& rContentLength) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_CONTENT_LENGTH), rContentLength, + m_nIndex[INETMSG_HTTP_CONTENT_LENGTH]); +} + +void INetHTTPMessage::SetContentMD5 (const String& rContentMD5) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_CONTENT_MD5), rContentMD5, + m_nIndex[INETMSG_HTTP_CONTENT_MD5]); +} + +void INetHTTPMessage::SetContentRange (const String& rContentRange) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_CONTENT_RANGE), rContentRange, + m_nIndex[INETMSG_HTTP_CONTENT_RANGE]); +} + +void INetHTTPMessage::SetContentVersion (const String& rContentVersion) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_CONTENT_VERSION), rContentVersion, + m_nIndex[INETMSG_HTTP_CONTENT_VERSION]); +} + +void INetHTTPMessage::SetCookie (const String& rCookie) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_COOKIE), rCookie, + m_nIndex[INETMSG_HTTP_COOKIE]); +} + +void INetHTTPMessage::SetDerivedFrom (const String& rDerivedFrom) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_DERIVED_FROM), rDerivedFrom, + m_nIndex[INETMSG_HTTP_DERIVED_FROM]); +} + +void INetHTTPMessage::SetExpires (const String& rExpires) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_EXPIRES), rExpires, + m_nIndex[INETMSG_HTTP_EXPIRES]); +} + +void INetHTTPMessage::SetForwarded (const String& rForwarded) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_FORWARDED), rForwarded, + m_nIndex[INETMSG_HTTP_FORWARDED]); +} + +void INetHTTPMessage::SetHost (const String& rHost) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_HOST), rHost, + m_nIndex[INETMSG_HTTP_HOST]); +} + +void INetHTTPMessage::SetIfModifiedSince (const String& rIfModifiedSince) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_IF_MODIFIED_SINCE), rIfModifiedSince, + m_nIndex[INETMSG_HTTP_IF_MODIFIED_SINCE]); +} + +void INetHTTPMessage::SetKeepAlive (const String& rKeepAlive) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_KEEP_ALIVE), rKeepAlive, + m_nIndex[INETMSG_HTTP_KEEP_ALIVE]); +} + +void INetHTTPMessage::SetLastModified (const String& rLastModified) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_LAST_MODIFIED), rLastModified, + m_nIndex[INETMSG_HTTP_LAST_MODIFIED]); +} + +void INetHTTPMessage::SetLink (const String& rLink) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_LINK), rLink, + m_nIndex[INETMSG_HTTP_LINK]); +} + +void INetHTTPMessage::SetLocation (const String& rLocation) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_LOCATION), rLocation, + m_nIndex[INETMSG_HTTP_LOCATION]); +} + +void INetHTTPMessage::SetProxyAuthenticate ( + const String& rProxyAuthenticate) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_PROXY_AUTHENTICATE), rProxyAuthenticate, + m_nIndex[INETMSG_HTTP_PROXY_AUTHENTICATE]); +} + +void INetHTTPMessage::SetProxyAuthorization ( + const String& rProxyAuthorization) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_PROXY_AUTHORIZATION), rProxyAuthorization, + m_nIndex[INETMSG_HTTP_PROXY_AUTHORIZATION]); +} + +void INetHTTPMessage::SetPragma (const String& rPragma) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_PRAGMA), rPragma, + m_nIndex[INETMSG_HTTP_PRAGMA]); +} + +void INetHTTPMessage::SetPublic (const String& rPublic) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_PUBLIC), rPublic, + m_nIndex[INETMSG_HTTP_PUBLIC]); +} + +void INetHTTPMessage::SetRange (const String& rRange) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_RANGE), rRange, + m_nIndex[INETMSG_HTTP_RANGE]); +} + +void INetHTTPMessage::SetReferer (const String& rReferer) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_REFERER), rReferer, + m_nIndex[INETMSG_HTTP_REFERER]); +} + +void INetHTTPMessage::SetRetryAfter (const String& rRetryAfter) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_RETRY_AFTER), rRetryAfter, + m_nIndex[INETMSG_HTTP_RETRY_AFTER]); +} + +void INetHTTPMessage::SetServer (const String& rServer) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_SERVER), rServer, + m_nIndex[INETMSG_HTTP_SERVER]); +} + +void INetHTTPMessage::SetTitle (const String& rTitle) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_TITLE), rTitle, + m_nIndex[INETMSG_HTTP_TITLE]); +} + +void INetHTTPMessage::SetTransferEncoding ( + const String& rTransferEncoding) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_TRANSFER_ENCODING), rTransferEncoding, + m_nIndex[INETMSG_HTTP_TRANSFER_ENCODING]); +} + +void INetHTTPMessage::SetUnless (const String& rUnless) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_UNLESS), rUnless, + m_nIndex[INETMSG_HTTP_UNLESS]); +} + +void INetHTTPMessage::SetUpgrade (const String& rUpgrade) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_UPGRADE), rUpgrade, + m_nIndex[INETMSG_HTTP_UPGRADE]); +} + +void INetHTTPMessage::SetURI (const String& rURI) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_URI), rURI, + m_nIndex[INETMSG_HTTP_URI]); +} + +void INetHTTPMessage::SetUserAgent (const String& rUserAgent) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_USER_AGENT), rUserAgent, + m_nIndex[INETMSG_HTTP_USER_AGENT]); +} + +void INetHTTPMessage::SetWWWAuthenticate (const String& rWWWAuthenticate) +{ + SetHeaderField_Impl ( + INetMIME::HEADER_FIELD_TEXT, + HTTPHDR(INETMSG_HTTP_WWW_AUTHENTICATE), rWWWAuthenticate, + m_nIndex[INETMSG_HTTP_WWW_AUTHENTICATE]); +} + +/* + * operator<< + */ +SvStream& INetHTTPMessage::operator<< (SvStream& rStrm) const +{ + INetMIMEMessage::operator<< (rStrm); + + for (USHORT i = 0; i < INETMSG_HTTP_NUMHDR; i++) + rStrm << m_nIndex[i]; + + return rStrm; +} + +/* + * operator>> + */ +SvStream& INetHTTPMessage::operator>> (SvStream& rStrm) +{ + INetMIMEMessage::operator>> (rStrm); + + for (USHORT i = 0; i < INETMSG_HTTP_NUMHDR; i++) + rStrm >> m_nIndex[i]; + + return rStrm; +} + diff --git a/tools/source/inet/inetstrm.cxx b/tools/source/inet/inetstrm.cxx new file mode 100644 index 000000000000..04072d617642 --- /dev/null +++ b/tools/source/inet/inetstrm.cxx @@ -0,0 +1,2059 @@ +/************************************************************************* + * + * $RCSfile: inetstrm.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SAL_TYPES_H_ +#include <sal/types.h> +#endif + +#ifndef _RTL_CHAR_H_ +#include <rtl/char.h> +#endif +#ifndef _RTL_MEMORY_H_ +#include <rtl/memory.h> +#endif + +#ifndef _CACHESTR_HXX +#include <cachestr.hxx> +#endif +#ifndef _TOOLS_DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _TOOLS_INETMSG_HXX +#include <inetmsg.hxx> +#endif +#ifndef _TOOLS_INETSTRM_HXX +#include <inetstrm.hxx> +#endif +#ifndef _ZCODEC_HXX +#include <zcodec.hxx> +#endif + +#include <ctype.h> // toupper + +#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, void *pCtx = NULL); + +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, void *pCtx = NULL); + +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, void *pCtx = NULL); + +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, void *pCtx = NULL); + +public: + INetMessageDecode64Stream_Impl (ULONG nMsgBufferSize = 128); + virtual ~INetMessageDecode64Stream_Impl (void); +}; + +/*========================================================================= + * + * INetIStream Implementation. + * + *=======================================================================*/ +/* + * INetIStream. + */ +INetIStream::INetIStream (ULONG nIBufferSize) +{ +} + +/* + * ~INetIStream. + */ +INetIStream::~INetIStream (void) +{ +} + +/* + * Read. + */ +int INetIStream::Read (sal_Char *pData, ULONG nSize, void *pCtx) +{ + return GetData (pData, nSize, pCtx); +} + +/* + * 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 (ULONG nOBufferSize) +{ +} + +/* + * ~INetOStream. + */ +INetOStream::~INetOStream (void) +{ +} + +/* + * Write. + */ +int INetOStream::Write (const sal_Char *pData, ULONG nSize, void *pCtx) +{ + return PutData (pData, nSize, pCtx); +} + +/*========================================================================= + * + * INetMessageIStream Implementation. + * + *=======================================================================*/ +/* + * INetMessageIStream. + */ +INetMessageIStream::INetMessageIStream (ULONG nBufferSize) + : INetIStream (0), + 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, void *pCtx) +{ + 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, pCtx); + 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, void *pCtx) +{ + 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) + : INetOStream (0), + 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, void *pCtx) +{ + 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(), pCtx); + 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(), pCtx); + 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 (rtl_char_isWhitespace (*pData & 0x7f)) + { + // Any <LWS> is folded into a single <SP> character. + sal_Char c = *((const sal_Char *) pMsgBuffer->GetData() + pMsgBuffer->Tell() - 1); + if (!rtl_char_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), pCtx); + } + + return INETSTREAM_STATUS_OK; +} + +/* + * PutMsgLine. + */ +int INetMessageOStream::PutMsgLine ( + const sal_Char *pData, ULONG nSize, void *pCtx) +{ + // 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; + + ULONG nDocSiz = pTargetMsg->GetDocumentSize(); + ULONG nWrite = 0; + + ErrCode status = 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, void *pCtx) +{ + 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, void *pCtx) +{ + 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++) = 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) + { + ULONG nRead = pMsgBuffer->Tell(); + if (nRead > 0) + { + // Emit buffer. + ULONG nDocSiz = pMsg->GetDocumentSize(); + ULONG 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, void *pCtx) +{ + 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, void *pCtx) +{ + 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. + ULONG nDocSiz = pMsg->GetDocumentSize(); + ULONG nRead = pMsgWrite - pMsgBuffer; + ULONG 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. + ULONG nDocSiz = pMsg->GetDocumentSize(); + ULONG nRead = pMsgWrite - pMsgBuffer; + ULONG 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, void *pCtx) +{ + // 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, pCtx); + 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, pCtx); + 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, pCtx); + } + 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, pCtx); + if (nRead > 0) + { + return nRead; + } + else + { + // Cleanup exhausted encoder stream. + delete pEncodeStrm; + pEncodeStrm = NULL; + + // Mark we're done. + eState = INETMSG_EOL_DONE; + } + } + return 0; + } + } + } + } + return INETSTREAM_STATUS_ERROR; // Never reached. +} + +/* + * PutMsgLine. + * (Message Parser). + */ +int INetMIMEMessageStream::PutMsgLine ( + const sal_Char *pData, ULONG nSize, void *pCtx) +{ + // 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, pCtx); + 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, NULL ); + if (status != INETSTREAM_STATUS_OK) + return status; + } + + return INetMessageIOStream::PutMsgLine ( + pData, nSize, pCtx); + } + 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, pCtx ); + 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, pCtx ); + 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, pCtx); + } + 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, pCtx); + } + } + } +} + +/*========================================================================= + * + * INetMessageDecodeGZStream_Impl Implementation. + * (GZIP Decoding). + * + *=======================================================================*/ +class INetMessageDecodeGZStream_Impl : public INetMessageOStream +{ + SvMemoryStream m_aStrm; + GZCodec m_aCodec; + sal_uInt8 m_pBuffer[1024]; + + virtual int PutMsgLine ( + const sal_Char *pData, ULONG nSize, void *pCtx = NULL); + +public: + INetMessageDecodeGZStream_Impl (void); +}; + +/* + * INetMessageDecodeGZStream_Impl. + */ +INetMessageDecodeGZStream_Impl::INetMessageDecodeGZStream_Impl (void) + : INetMessageOStream() +{ + ParseHeader (FALSE); + m_aCodec.BeginCompression(); +} + +/* + * PutMsgLine. + */ +int INetMessageDecodeGZStream_Impl::PutMsgLine ( + const sal_Char *pData, ULONG nSize, void *pCtx) +{ + INetMessage *pMsg = GetTargetMessage(); + if (pMsg == NULL) + return INETSTREAM_STATUS_ERROR; + + SvOpenLockBytes * pLB = PTR_CAST(SvOpenLockBytes, pMsg->GetDocumentLB()); + if (pLB == NULL) + return INETSTREAM_STATUS_WOULDBLOCK; + + m_aStrm.Seek (STREAM_SEEK_TO_BEGIN); + m_aStrm.Write (pData, nSize); + + m_aStrm.Seek (STREAM_SEEK_TO_BEGIN); + long nRead = 0; + + // Decode into buffer. + m_aCodec.SetBreak (nSize); + while ((nRead = m_aCodec.Read (m_aStrm, m_pBuffer, sizeof(m_pBuffer))) > 0) + { + // Emit Buffer. + ULONG nDocSize = pMsg->GetDocumentSize(); + ULONG nWrite = 0; + + pLB->FillAppend (m_pBuffer, nRead, &nWrite); + pMsg->SetDocumentSize (nDocSize + nWrite); + + if ((long)nWrite < nRead) + return INETSTREAM_STATUS_ERROR; + } + + if (m_aCodec.IsFinished()) + return INETSTREAM_STATUS_LOADED; + else if (nRead < 0) + return INETSTREAM_STATUS_ERROR; + else + return INETSTREAM_STATUS_OK; +} + +/*========================================================================= + * + * INetHTTPMessageStream Implementation. + * + *=======================================================================*/ +/* + * INetHTTPMessageStream. + */ +INetHTTPMessageStream::INetHTTPMessageStream (ULONG nBufferSize) + : INetMIMEMessageStream (nBufferSize), + m_eState (INETMSG_EOL_BEGIN), + m_pDecodeStrm (NULL) +{ +} + +/* + * ~INetHTTPMessageStream. + */ +INetHTTPMessageStream::~INetHTTPMessageStream (void) +{ + delete m_pDecodeStrm; +} + +/* + * GetMsgLine. + * (Message Generator). + */ +int INetHTTPMessageStream::GetMsgLine ( + sal_Char *pData, ULONG nSize, void *pCtx) +{ + // Check for header generation. + if (!IsHeaderGenerated()) + { + if (m_eState == INETMSG_EOL_BEGIN) + { + // Check for message container. + INetHTTPMessage *pMsg = GetSourceMessage(); + if (pMsg == NULL) + return INETSTREAM_STATUS_ERROR; + + // Set Accept-Encoding header. + pMsg->SetAcceptEncoding ( + String ("gzip", RTL_TEXTENCODING_ASCII_US)); + + // Mark done. + m_eState = INETMSG_EOL_DONE; + } + } + + // Initial approximation: Generate as plain message (w/o encoding). + return INetMessageIOStream::GetMsgLine (pData, nSize, pCtx); +} + +/* + * PutMsgLine. + * (Message Parser). + */ +int INetHTTPMessageStream::PutMsgLine ( + const sal_Char *pData, ULONG nSize, void *pCtx) +{ + // Check for header or body. + if (!IsHeaderParsed()) + { + // Parse the message header. + return INetMessageIOStream::PutMsgLine (pData, nSize, pCtx); + } + else + { + // Parse the message body. + if (m_eState == INETMSG_EOL_BEGIN) + { + // Check for message container. + INetHTTPMessage *pMsg = GetTargetMessage(); + if (pMsg == NULL) + return INETSTREAM_STATUS_ERROR; + + // Obtain ContentEncoding. + String aEncoding (pMsg->GetContentEncoding()); + aEncoding.EraseLeadingChars (' '); + + // Check for supported encoding. + if ((aEncoding.CompareIgnoreCaseToAscii ("gzip") == 0) || + (aEncoding.CompareIgnoreCaseToAscii ("x-gzip") == 0) ) + { + // Initialize decode stream. + m_pDecodeStrm = new INetMessageDecodeGZStream_Impl; + m_pDecodeStrm->SetTargetMessage (pMsg); + } + + // Mark done. + m_eState = INETMSG_EOL_DONE; + } + + // Check for Decode stream. + if (m_pDecodeStrm) + { + // Decode. + return m_pDecodeStrm->Write (pData, nSize, pCtx); + } + else + { + // No decoding necessary. + return INetMessageIOStream::PutMsgLine (pData, nSize, pCtx); + } + } +} + diff --git a/tools/source/inet/makefile.mk b/tools/source/inet/makefile.mk new file mode 100644 index 000000000000..74926210cd36 --- /dev/null +++ b/tools/source/inet/makefile.mk @@ -0,0 +1,83 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ = ..$/.. +PRJNAME = tools +TARGET = inet + +.INCLUDE: svpre.mk +.INCLUDE: settings.mk +.INCLUDE: sv.mk + +SLOFILES=\ + $(SLO)$/inetmime.obj \ + $(SLO)$/inetmsg.obj \ + $(SLO)$/inetstrm.obj + +.IF "$(UPDATER)" != "" +OBJFILES=\ + $(OBJ)$/inetmime.obj \ + $(OBJ)$/inetmsg.obj \ + $(OBJ)$/inetstrm.obj +.ENDIF + +.INCLUDE: target.mk diff --git a/tools/source/makefile.mk b/tools/source/makefile.mk new file mode 100644 index 000000000000..d340637a4f27 --- /dev/null +++ b/tools/source/makefile.mk @@ -0,0 +1,96 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:05 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=.. + +TARGET=source + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +.IF "$(GUI)" == "UNX" +SUBDIRS+= solar +.ENDIF + +SUBDIRS+= \ + datetime \ + timestamp \ + debug \ + fsys \ + generic \ + intntl \ + memmgr \ + 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..8228ecb4c880 --- /dev/null +++ b/tools/source/memtools/contnr.cxx @@ -0,0 +1,1754 @@ +/************************************************************************* + * + * $RCSfile: contnr.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define private public +#define protected public + +#ifndef _LIMITS_H +#include <limits.h> +#endif + +#ifndef _STRING_H +#include <string.h> +#endif + +#ifndef _STDIO_H +#include <stdio.h> +#endif + +#ifndef _SOLAR_H +#include <solar.h> +#endif + +#ifndef _IMPCONT_HXX +#include <impcont.hxx> +#endif + +#ifndef _CONTNR_HXX +#include <contnr.hxx> +#endif + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif + +// ----------------------------------------------------------------------- + +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* 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 = (void**)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 = (void**)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 = (void**)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 += nReSize; + void** pNewNodes = (void**)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 += nReSize; + } + } + + // 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 -= nMiddle; + // 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 = (void**)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 -= nMiddle; + + // Die zweite Haelfte in einen neuen Block kopieren + if ( nSize != nNewSize ) + { + void** pNewNodes = (void**)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 -= nReSize; + void** pNewNodes = (void**)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* 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 +|* +*************************************************************************/ + +static void ImpCopyContainer( Container* pCont1, const Container* pCont2 ) +{ + // Werte vom uebergebenen Container uebernehmen + pCont1->nCount = pCont2->nCount; + pCont1->nCurIndex = pCont2->nCurIndex; + pCont1->nInitSize = pCont2->nInitSize; + pCont1->nReSize = pCont2->nReSize; + pCont1->nBlockSize = pCont2->nBlockSize; + + // Alle Bloecke kopieren + if ( pCont2->nCount ) + { + CBlock* pBlock1; + CBlock* pBlock2; + CBlock* pTempBlock; + + // Erstmal ersten Block kopieren + pBlock2 = pCont2->pFirstBlock; + pCont1->pFirstBlock = new CBlock( *pBlock2, NULL ); + // Ist erster Block der Current-Block, dann Current-Block setzen + if ( pBlock2 == pCont2->pCurBlock ) + pCont1->pCurBlock = pCont1->pFirstBlock; + pBlock1 = pCont1->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 ) + pCont1->pCurBlock = pBlock1; + + // Auf naechsten Block weitersetzen + pBlock2 = pBlock2->GetNextBlock(); + } + + // Letzten Block setzen + pCont1->pLastBlock = pBlock1; + } + else + { + pCont1->pFirstBlock = NULL; + pCont1->pLastBlock = NULL; + pCont1->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( this, &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 -= pBlock->nCount; + } + } + } + else + { + // Gegebenenfalls FirstBlock anpassen + if ( pBlock == pFirstBlock ) + pFirstBlock = pNewBlock; + + // Current-Position nachfuehren + if ( pBlock == pCurBlock ) + { + if ( nIndex <= nCurIndex ) + nCurIndex++; + if ( pNewBlock->nCount <= nCurIndex ) + nCurIndex -= pNewBlock->nCount; + 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( this, &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..bc8e84bf15b1 --- /dev/null +++ b/tools/source/memtools/makefile.mk @@ -0,0 +1,92 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=mtools + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/contnr.obj \ + $(SLO)$/table.obj \ + $(SLO)$/unqidx.obj \ + $(SLO)$/mempool.obj \ + $(SLO)$/multisel.obj + +.IF "$(UPDATER)"!="" +OBJFILES= $(OBJ)$/contnr.obj \ + $(OBJ)$/table.obj \ + $(OBJ)$/unqidx.obj \ + $(OBJ)$/mempool.obj \ + $(OBJ)$/multisel.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/tools/source/memtools/mempool.cxx b/tools/source/memtools/mempool.cxx new file mode 100644 index 000000000000..25d4149bcdb4 --- /dev/null +++ b/tools/source/memtools/mempool.cxx @@ -0,0 +1,323 @@ +/************************************************************************* + * + * $RCSfile: mempool.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define private public + +#include <limits.h> + +#include <debug.hxx> +#include <mempool.hxx> + +// ----------------------------------------------------------------------- + +#if ( __ALIGNMENT8 > 4 ) +#define MEMPOOL_ALIGNMENT __ALIGNMENT8 +#else +#define MEMPOOL_ALIGNMENT 4 +#endif + +// ----------------- +// - FixedMemBlock - +// ----------------- + +struct FixedMemBlock +{ + USHORT nSize; + USHORT nFree; + USHORT nFirst; + USHORT nDummyAlign1; + FixedMemBlock* pNext; +#if (__SIZEOFPOINTER == 4) && (__ALIGNMENT8 == 8) + void* pDummyAlign2; +#endif + char aData[1]; +}; + +/************************************************************************* +|* +|* ImpDbgPoolTest() +|* +|* Beschreibung MEMPOOL.SDW +|* Ersterstellung TH 30.11.94 +|* Letzte Aenderung TH 30.11.94 +|* +*************************************************************************/ + +#ifdef DBG_UTIL + +static void ImpDbgPoolTest( FixedMemPool* pMemPool ) +{ + DbgData* pData = DbgGetData(); + + if ( !pData ) + return; + + if ( !(pData->nTestFlags & (DBG_TEST_MEM_OVERWRITE | DBG_TEST_MEM_OVERWRITEFREE)) ) + return; + + FixedMemBlock* pFirst = pMemPool->pFirst; + FixedMemBlock* pBlock = pFirst; + while ( pBlock ) + { + if ( pBlock->nFree ) + { + USHORT i = pBlock->nFree; + USHORT n = pBlock->nFirst; + char* pData = pBlock->aData; + while ( i ) + { + if ( !(n < (pBlock->nSize/pMemPool->nTypeSize)) ) + DbgError( "MemPool: Memory Overwrite" ); + + char* pNext = pData+(n*pMemPool->nTypeSize); + n = *((USHORT*)pNext); + i--; + } + } + + pBlock = pBlock->pNext; + } +} + +#endif + +/************************************************************************* +|* +|* FixedMemPool::FixedMemPool() +|* +|* Beschreibung MEMPOOL.SDW +|* Ersterstellung TH 02.09.94 +|* Letzte Aenderung TH 02.09.94 +|* +*************************************************************************/ + +FixedMemPool::FixedMemPool( USHORT _nTypeSize, + USHORT _nInitSize, USHORT _nGrowSize ) +{ + pFirst = NULL; + nInitSize = _nInitSize; + nGrowSize = _nGrowSize; + + if ( _nTypeSize > 4 ) + nTypeSize = (_nTypeSize + (MEMPOOL_ALIGNMENT-1)) & ~(MEMPOOL_ALIGNMENT-1); + else if ( _nTypeSize <= 2 ) + nTypeSize = 2; + else + nTypeSize = 4; + + DBG_ASSERT( (ULONG)nTypeSize*nInitSize <= USHRT_MAX, + "FixedMemPool: TypeSize*nInitSize > USHRT_MAX" ); + DBG_ASSERT( (ULONG)nTypeSize*nGrowSize <= USHRT_MAX, + "FixedMemPool: TypeSize*GrowSize > USHRT_MAX" ); +} + +/************************************************************************* +|* +|* FixedMemPool::~FixedMemPool() +|* +|* Beschreibung MEMPOOL.SDW +|* Ersterstellung TH 02.09.94 +|* Letzte Aenderung TH 02.09.94 +|* +*************************************************************************/ + +FixedMemPool::~FixedMemPool() +{ + FixedMemBlock* pBlock = pFirst; + while ( pBlock ) + { + FixedMemBlock* pTemp = pBlock; + pBlock = pBlock->pNext; + delete pTemp; + } +} + +/************************************************************************* +|* +|* FixedMemPool::Alloc() +|* +|* Beschreibung MEMPOOL.SDW +|* Ersterstellung TH 02.09.94 +|* Letzte Aenderung TH 02.09.94 +|* +*************************************************************************/ + +void* FixedMemPool::Alloc() +{ +#ifdef DBG_UTIL + ImpDbgPoolTest( this ); +#endif + + USHORT i; + char* pData; + + if ( !pFirst ) + { + pFirst = (FixedMemBlock*)new char[sizeof(FixedMemBlock)-1+(nInitSize*nTypeSize)]; + + if ( !pFirst ) + return NULL; + + pFirst->pNext = NULL; + pFirst->nSize = nInitSize*nTypeSize;; + pFirst->nFree = nInitSize-1; + pFirst->nFirst = 1; + + pData = pFirst->aData; + for ( i = 1; i < nInitSize; i++ ) + { + *((USHORT*)pData) = i; + pData += nTypeSize; + } + + return (void*)(pFirst->aData); + } + + FixedMemBlock* pBlock = pFirst; + while ( pBlock && !pBlock->nFree ) + pBlock = pBlock->pNext; + + if ( pBlock ) + { + pData = pBlock->aData; + char* pFree = pData+(pBlock->nFirst*nTypeSize); + pBlock->nFirst = *((USHORT*)pFree); // UMR, wenn letzter freier Block, ist OK + pBlock->nFree--; + return (void*)pFree; + } + else + { + if ( !nGrowSize ) + return NULL; + + pBlock = (FixedMemBlock*)new char[sizeof(FixedMemBlock)-1+(nGrowSize*nTypeSize)]; + + if ( !pBlock ) + return NULL; + + pData = pBlock->aData; + for ( i = 1; i < nGrowSize; i++ ) + { + *((USHORT*)pData) = i; + pData += nTypeSize; + } + + pBlock->pNext = pFirst->pNext; + pBlock->nSize = nGrowSize*nTypeSize; + pBlock->nFree = nGrowSize-1; + pBlock->nFirst = 1; + pFirst->pNext = pBlock; + + return (void*)(pBlock->aData); + } +} + +/************************************************************************* +|* +|* FixedMemPool::Free() +|* +|* Beschreibung MEMPOOL.SDW +|* Ersterstellung TH 02.09.94 +|* Letzte Aenderung TH 02.09.94 +|* +*************************************************************************/ + +void FixedMemPool::Free( void* pFree ) +{ + if ( !pFree ) + return; + +#ifdef DBG_UTIL + ImpDbgPoolTest( this ); +#endif + + FixedMemBlock* pBlock = pFirst; + FixedMemBlock* pPrev = NULL; + while ( ((ULONG)pBlock->aData > (ULONG)pFree) || + ((ULONG)pFree >= ((ULONG)pBlock->aData+pBlock->nSize)) ) + { + pPrev = pBlock; + pBlock = pBlock->pNext; + +#ifdef DBG_UTIL + DBG_ASSERT( pBlock, "FixedMemPool - Delete: Wrong Pointer" ); +#endif + } + + pBlock->nFree++; + *((USHORT*)pFree) = pBlock->nFirst; + pBlock->nFirst = (USHORT)(((ULONG)pFree-(ULONG)(pBlock->aData)) / nTypeSize); + + if ( pPrev && (pBlock->nFree*nTypeSize == pBlock->nSize) ) + { + pPrev->pNext = pBlock->pNext; + delete pBlock; + } + else + { + if ( pPrev ) + { + pPrev->pNext = pBlock->pNext; + pBlock->pNext = pFirst->pNext; + pFirst->pNext = pBlock; + } + } +} diff --git a/tools/source/memtools/multisel.cxx b/tools/source/memtools/multisel.cxx new file mode 100644 index 000000000000..8bd47a028019 --- /dev/null +++ b/tools/source/memtools/multisel.cxx @@ -0,0 +1,897 @@ +/************************************************************************* + * + * $RCSfile: multisel.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_MULTISEL_CXX + +#ifdef MI_DEBUG +#define private public +#include <stdio.h> +#endif + +#include <debug.hxx> +#include <multisel.hxx> + +#pragma hdrstop + +#ifdef MI_DEBUG +#define DBG(x) x +#else +#define DBG(x) +#endif + +//================================================================== + +#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 ), + nSelCount(0), + nCurSubSel(0), + bCurValid(FALSE), + bSelectNew(FALSE) +{ +} + +// ----------------------------------------------------------------------- + +MultiSelection::MultiSelection( const UniString& rString, sal_Unicode cRange, sal_Unicode cSep ): + aTotRange(0,RANGE_MAX), + nSelCount(0), + nCurSubSel(0), + bCurValid(FALSE), + bSelectNew(FALSE) +{ + // Dies ist nur ein Schnellschuss und sollte bald optimiert, + // an die verschiedenen Systeme (MAC, 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), + bCurValid(rOrig.bCurValid), + nSelCount(rOrig.nSelCount), + 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), + nSelCount(0), + nCurSubSel(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( BOOL bInverse ) +{ + 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; +} diff --git a/tools/source/memtools/table.cxx b/tools/source/memtools/table.cxx new file mode 100644 index 000000000000..d84676f2c052 --- /dev/null +++ b/tools/source/memtools/table.cxx @@ -0,0 +1,442 @@ +/************************************************************************* + * + * $RCSfile: table.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _TOOLS_TABLE_CXX + +// ----------------------------------------------------------------------- + +#define protected public + +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _IMPCONT_HXX +#include <impcont.hxx> +#endif +#ifndef _TOOLS_TABLE_HXX +#include <table.hxx> +#endif + +// ======================================================================= + +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; + 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; + } + } + 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..435e5fc117be --- /dev/null +++ b/tools/source/memtools/unqidx.cxx @@ -0,0 +1,643 @@ +/************************************************************************* + * + * $RCSfile: unqidx.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define protected public + +#ifndef _IMPCONT_HXX +#include <impcont.hxx> +#endif + +#ifndef _UNQIDX_HXX +#include <unqidx.hxx> +#endif + +#ifndef _UNQID_HXX +#include <unqid.hxx> +#endif + +/************************************************************************* +|* +|* 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/rc/makefile.mk b/tools/source/rc/makefile.mk new file mode 100644 index 000000000000..8aadfce6a2b0 --- /dev/null +++ b/tools/source/rc/makefile.mk @@ -0,0 +1,89 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=rc + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +CXXFILES= rc.cxx \ + resmgr.cxx + +SLOFILES= $(SLO)$/rc.obj \ + $(SLO)$/resmgr.obj + +.IF "$(UPDATER)"!="" +OBJFILES= $(OBJ)$/rc.obj \ + $(OBJ)$/resmgr.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/tools/source/rc/rc.cxx b/tools/source/rc/rc.cxx new file mode 100644 index 000000000000..daa5ffdb71d9 --- /dev/null +++ b/tools/source/rc/rc.cxx @@ -0,0 +1,311 @@ +/************************************************************************* + * + * $RCSfile: rc.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _TOOLS_RC_CXX + +#include <string.h> + +#ifndef _DATE_HXX +#include <date.hxx> +#endif +#ifndef _TIME_HXX +#include <time.hxx> +#endif +#ifndef _INTN_HXX +#include <intn.hxx> +#endif + +#ifndef _TOOLS_RC_HXX +#include <rc.hxx> +#endif +#ifndef _TOOLS_RCID_H +#include <rcid.h> +#endif + +#pragma hdrstop + +// ======================================================================= + +ImplSVResourceData aResData; + +inline ImplSVResourceData* GetResData() +{ + //return &ImplGetSVData()->maResourceData; + return &aResData; +} + +// ======================================================================= + +Resource::Resource( const ResId& rResId ) +{ + GetRes( rResId.SetRT( RSC_RESOURCE ) ); +} + +// ----------------------------------------------------------------------- + +void Resource::GetRes( const ResId& rResId ) +{ + if ( rResId.GetResMgr() ) + rResId.GetResMgr()->GetResource( rResId, this ); + else + GetResManager()->GetResource( rResId, this ); + + IncrementRes( sizeof( RSHEADER_TYPE ) ); +} + +// ----------------------------------------------------------------------- + +void Resource::TestRes() +{ + ImplSVResourceData* pSVInData = GetResData(); + if( pSVInData->pAppResMgr ) + GetResManager()->TestStack( this ); +} + +// ----------------------------------------------------------------------- + +void Resource::SetResManager( ResMgr* pNewResMgr ) +{ + ImplSVResourceData * pSVInData = GetResData(); + pSVInData->pAppResMgr = pNewResMgr; +} + +// ----------------------------------------------------------------------- + +ResMgr* Resource::GetResManager() +{ + ImplSVResourceData* pSVInData = GetResData(); + + return pSVInData->pAppResMgr; +} + +// ======================================================================= + +#ifndef ENABLEUNICODE + +String::String( const ResId& rResId ) +{ + rResId.SetRT( RSC_STRING ); + ResMgr* pResMgr = rResId.GetResMgr(); + if ( !pResMgr ) + pResMgr = Resource::GetResManager(); + + if ( pResMgr->GetResource( rResId ) ) + { + // String laden + RSHEADER_TYPE * pResHdr = (RSHEADER_TYPE*)pResMgr->GetClass(); + USHORT nLen = pResHdr->GetLocalOff() - sizeof( RSHEADER_TYPE ); + + USHORT nStringLen = strlen( (char*)(pResHdr+1) ); + UniString aWString( (const char*)(pResHdr+1), RTL_TEXTENCODING_UTF8, + RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE | + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT | + RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT ); + InitStringRes( aWString ); + + USHORT nSize = sizeof( RSHEADER_TYPE ) + nStringLen + 1; + nSize += nSize % 2; + pResMgr->Increment( nSize ); + } +} + +#endif + +// ======================================================================= + +UniString::UniString( const ResId& rResId ) +{ + rResId.SetRT( RSC_STRING ); + ResMgr* pResMgr = rResId.GetResMgr(); + if ( !pResMgr ) + pResMgr = Resource::GetResManager(); + + if ( pResMgr->GetResource( rResId ) ) + { + // String laden + RSHEADER_TYPE * pResHdr = (RSHEADER_TYPE*)pResMgr->GetClass(); + USHORT nLen = pResHdr->GetLocalOff() - sizeof( RSHEADER_TYPE ); + + USHORT nStringLen = strlen( (char*)(pResHdr+1) ); + InitStringRes( (const char*)(pResHdr+1), nStringLen ); + + USHORT nSize = sizeof( RSHEADER_TYPE ) + nStringLen + 1; + nSize += nSize % 2; + pResMgr->Increment( nSize ); + } +} + +// ======================================================================= + +Time::Time( const ResId& rResId ) +{ + nTime = 0; + rResId.SetRT( RSC_TIME ); + ResMgr* pResMgr = NULL; + + ResMgr::GetResourceSkipHeader( rResId, &pResMgr ); + + USHORT nObjMask = (USHORT)pResMgr->ReadShort(); + + 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 ) +{ + rResId.SetRT( RSC_DATE ); + ResMgr* pResMgr = NULL; + + ResMgr::GetResourceSkipHeader( rResId, &pResMgr ); + + USHORT nObjMask = (USHORT)pResMgr->ReadShort(); + + if ( 0x01 & nObjMask ) + SetYear( (USHORT)pResMgr->ReadShort() ); + if ( 0x02 & nObjMask ) + SetMonth( (USHORT)pResMgr->ReadShort() ); + if ( 0x04 & nObjMask ) + SetDay( (USHORT)pResMgr->ReadShort() ); +} + +// ======================================================================= + +International::International( const ResId& rResId ) +{ + rResId.SetRT( RSC_INTERNATIONAL ); + ResMgr* pResMgr = NULL; + + ResMgr::GetResourceSkipHeader( rResId, &pResMgr ); + + USHORT nObjMask = (USHORT)pResMgr->ReadShort(); + + LanguageType eLangType = LANGUAGE_SYSTEM; + LanguageType eFormatType = LANGUAGE_SYSTEM; + + if ( 0x0001 & nObjMask ) + { + eLangType = (LanguageType)(USHORT)pResMgr->ReadShort(); + eFormatType = eLangType; + } + if ( 0x0002 & nObjMask ) + eFormatType = (LanguageType)(USHORT)pResMgr->ReadShort(); + Init( eLangType, eFormatType ); + + if ( 0x0004 & nObjMask ) + SetDateFormat( (DateFormat)(USHORT)pResMgr->ReadShort() ); + if ( 0x0008 & nObjMask ) + SetDateDayLeadingZero( (BOOL)(USHORT)pResMgr->ReadShort() ); + if ( 0x0010 & nObjMask ) + SetDateMonthLeadingZero( (BOOL)(USHORT)pResMgr->ReadShort() ); + if ( 0x0020 & nObjMask ) + SetDateCentury( (BOOL)(USHORT)pResMgr->ReadShort() ); + if ( 0x0040 & nObjMask ) + SetLongDateFormat( (DateFormat)(USHORT)pResMgr->ReadShort() ); + if ( 0x0080 & nObjMask ) + SetLongDateDayOfWeekFormat( (DayOfWeekFormat)(USHORT)pResMgr->ReadShort() ); + if ( 0x0100 & nObjMask ) + SetLongDateDayOfWeekSep( pResMgr->ReadString() ); + if ( 0x0200 & nObjMask ) + SetLongDateDayLeadingZero( (BOOL)(USHORT)pResMgr->ReadShort() ); + if ( 0x0400 & nObjMask ) + SetLongDateDaySep( pResMgr->ReadString() ); + if ( 0x0800 & nObjMask ) + SetLongDateMonthFormat( (MonthFormat)(USHORT)pResMgr->ReadShort() ); + if ( 0x1000 & nObjMask ) + SetLongDateMonthSep( pResMgr->ReadString() ); + if ( 0x2000 & nObjMask ) + SetLongDateCentury( (BOOL)(USHORT)pResMgr->ReadShort() ); + if ( 0x4000 & nObjMask ) + SetLongDateYearSep( pResMgr->ReadString() ); + if ( 0x8000 & nObjMask ) + SetTimeFormat( (TimeFormat)(USHORT)pResMgr->ReadShort() ); + + // Zweite Maske holen + nObjMask = (USHORT)pResMgr->ReadShort(); + if ( 0x0001 & nObjMask ) + SetTimeLeadingZero( (BOOL)(USHORT)pResMgr->ReadShort() ); + if ( 0x0002 & nObjMask ) + SetTimeAM( pResMgr->ReadString() ); + if ( 0x0004 & nObjMask ) + SetTimePM( pResMgr->ReadString() ); + if ( 0x0008 & nObjMask ) + SetNumLeadingZero( (BOOL)(USHORT)pResMgr->ReadShort() ); + if ( 0x0010 & nObjMask ) + SetNumDigits( (USHORT)pResMgr->ReadShort() ); + if ( 0x0020 & nObjMask ) + SetCurrPositiveFormat( (USHORT)pResMgr->ReadShort() ); + if ( 0x0040 & nObjMask ) + SetCurrNegativeFormat( (USHORT)pResMgr->ReadShort() ); + if ( 0x0080 & nObjMask ) + SetCurrDigits( (USHORT)pResMgr->ReadShort() ); + if ( 0x0100 & nObjMask ) + SetNumTrailingZeros( (BOOL)(USHORT)pResMgr->ReadShort() ); + if ( 0x0200 & nObjMask ) + SetMeasurementSystem( (MeasurementSystem)(USHORT)pResMgr->ReadShort() ); +} diff --git a/tools/source/rc/resmgr.cxx b/tools/source/rc/resmgr.cxx new file mode 100644 index 000000000000..610f884b9b2b --- /dev/null +++ b/tools/source/rc/resmgr.cxx @@ -0,0 +1,1364 @@ +/************************************************************************* + * + * $RCSfile: resmgr.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef _VOS_SIGNAL_HXX_ +#include <vos/signal.hxx> +#endif + +#ifndef _NEW_HXX +#include <new.hxx> +#endif +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _TABLE_HXX +#include <table.hxx> +#endif +#ifndef _FSYS_HXX +#include <fsys.hxx> +#endif +#ifndef _STREAM_HXX +#include <stream.hxx> +#endif +#ifndef _INTN_HXX +#include <intn.hxx> +#endif +#ifndef _TOOLS_RESMGR_HXX +#include <resmgr.hxx> +#endif +#ifndef _TOOLS_RC_HXX +#include <rc.hxx> +#endif +#ifndef _TOOLS_RCID_H +#include <rcid.h> +#endif + +#ifndef _TOOLS_SIMPLERESMGR_HXX_ +#include "simplerm.hxx" +#endif + +#pragma hdrstop + +// ======================================================================= + +extern ImplSVResourceData aResData; +inline ImplSVResourceData* GetResData() +{ + return &aResData; +} + +static List & GetResMgrList() +{ + ImplSVResourceData * pRD = GetResData(); + if ( !pRD->pInternalResMgrList ) + pRD->pInternalResMgrList = new List(); + return *pRD->pInternalResMgrList; +} + +struct ImpContent +{ + ULONG nTypeAndId; + ULONG nOffset; +}; + +#if defined( OS2 ) && defined( ICC ) +static int _Optlink Compare( const void * pFirst, const void * pSecond ) +#elif S390 +extern "C" { int Compare( const void * pFirst, const void * pSecond ) +#else +static int __LOADONCALLAPI Compare( const void * pFirst, const void * pSecond ) +#endif +{ + if( ((ImpContent *)pFirst)->nTypeAndId > ((ImpContent *)pSecond)->nTypeAndId ) + return( 1 ); + else if( ((ImpContent *)pFirst)->nTypeAndId < ((ImpContent *)pSecond)->nTypeAndId ) + return( -1 ); + else + return( 0 ); +} + +#ifdef S390 +} +#endif + +#if defined( OS2 ) && defined( ICC ) +static int _Optlink Search( const void * nTypeAndId, const void * pSecond ) +#elif S390 +extern "C" { int Search( const void * nTypeAndId, const void * pSecond ) +#else +static int __LOADONCALLAPI Search( const void * nTypeAndId, const void * pSecond ) +#endif +{ + if( (ULONG)nTypeAndId > (((ImpContent *)pSecond)->nTypeAndId) ) + return( 1 ); + else if( (ULONG)nTypeAndId < (((ImpContent *)pSecond)->nTypeAndId) ) + return( -1 ); + else + return( 0 ); +} + +#ifdef S390 +} +#endif + +// ======================================================================= + +SvStream * InternalResMgr::GetBitmapStream( USHORT nId ) +{ + // Anfang der Strings suchen + ImpContent * pFind = (ImpContent *) + bsearch( (void *)((ULONG(RT_SYS_BITMAP) << 16) | nId), pContent, nEntries, + sizeof( ImpContent ), Search ); + + if ( pFind ) + { + pStm->Seek( pFind->nOffset ); + return pStm; + } + return NULL; +} + +// ----------------------------------------------------------------------- + +void InternalResMgr::GetResMgrPath( InternalResMgr* pThis, + const UniString& rFileName, + const UniString* pAppFileName, + const UniString* pResourcePath ) +{ + UniString aResFile; + if ( rFileName.Len() ) + { + UniString aResPath; + if( pResourcePath ) + aResPath += *pResourcePath; + if ( pAppFileName ) + { + DirEntry aAppDir( *pAppFileName ); + aAppDir.CutName(); + UniString aAppPath = aAppDir.GetFull(); + DirEntry aResSubPath( UniString( RTL_CONSTASCII_USTRINGPARAM( "resource" ) ) ); + aAppDir += aResSubPath; + UniString aAppResPath = aAppDir.GetFull(); + + // Default resource path is bin\resource + if ( aResPath.Len() ) + aResPath += DirEntry::GetSearchDelimiter(); + aResPath += aAppResPath; + + // we a search also in the bin path + aResPath += DirEntry::GetSearchDelimiter(); + aResPath += aAppPath; + } + const sal_Char* pEnv = getenv( "STAR_RESOURCEPATH" ); + if( pEnv ) + { + if ( aResPath.Len() ) + aResPath += DirEntry::GetSearchDelimiter(); + aResPath.AppendAscii( pEnv ); + } + + DirEntry aFullName( rFileName ); + if ( aFullName.Find( aResPath ) ) + aResFile = aFullName.GetFull(); + else + aResFile = rFileName; + } + else if ( pAppFileName ) + { + // Default Resourcefile ist die Anwendung + aResFile = *pAppFileName; +#if defined( OS2 ) || defined( WIN ) || defined( WNT ) + aResFile.Erase( aResFile.Len() - 4 ); +#endif + aResFile.AppendAscii( ".res" ); + } + + if( aResFile.Len() ) + { + DirEntry aEntry = aResFile; + + FileStat aStat( aEntry ); + if( aStat.IsKind( FSYS_KIND_FILE ) ) + { + pThis->aFileName = aEntry.GetFull(); + pThis->aShortFileName = aEntry.GetName(); + } + } +} + +// ----------------------------------------------------------------------- + +InternalResMgr::InternalResMgr() + : pContent( NULL ) + , pStringBlock( NULL ) + , pStm( NULL ) + , bEqual2Content( TRUE ) + , nEntries( 0 ) + , pResUseDump( 0 ) +{ +} + +// ----------------------------------------------------------------------- + +InternalResMgr::~InternalResMgr() +{ + SvMemFree(pContent); + SvMemFree(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( aFileName, RTL_TEXTENCODING_UTF8 ) ); + aStm.WriteLine( aLine ); + + for( ULONG i = 0; i < pResUseDump->Count(); i++ ) + { + ULONG nKeyId = pResUseDump->GetObjectKey( i ); + aLine.Assign( "Type/Id: " ); + aLine.Append( ByteString::CreateFromInt32( (nKeyId >> 16) & 0xFFFF ) ); + aLine.Append( '/' ); + aLine.Append( ByteString::CreateFromInt32( nKeyId & 0xFFFF ) ); + aStm.WriteLine( aLine ); + } + } + } +#endif + + delete pResUseDump; +} + +// ----------------------------------------------------------------------- + +InternalResMgr* InternalResMgr::Create( const UniString& rName, + const UniString* pAppName, + const UniString* pResPath ) +{ + InternalResMgr* pThis = new InternalResMgr(); + + GetResMgrPath( pThis, rName, pAppName, pResPath ); + + if ( pThis->aFileName.Len() && pThis->Create() ) + return pThis; + + delete pThis; + return NULL; +} + +// ----------------------------------------------------------------------- + +BOOL InternalResMgr::Create() +{ + 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 ); + pContent = (ImpContent *)SvMemAlloc( lContLen ); + pStm->Read( pContent, lContLen ); + // Auf die Anzahl der ImpContent krzen + nEntries = (UINT32)lContLen / sizeof( ImpContent ); + 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 Table(); + for( ULONG i = 0; i < nEntries; i++ ) + pResUseDump->Insert( pContent[i].nTypeAndId, NULL ); + } +#endif + // swap the content to the right endian + pContent[0].nTypeAndId = ResMgr::GetLong( &pContent[0].nTypeAndId ); + pContent[0].nOffset = ResMgr::GetLong( &pContent[0].nOffset ); + for( ULONG i = 0; i < nEntries -1; i++ ) + { + // swap the content to the right endian + pContent[i+1].nTypeAndId = ResMgr::GetLong( &pContent[i+1].nTypeAndId ); + pContent[i+1].nOffset = ResMgr::GetLong( &pContent[i+1].nOffset ); + if( pContent[i].nTypeAndId >= pContent[i +1].nTypeAndId ) + bSorted = FALSE; + if( (pContent[i].nTypeAndId & 0xFFFF0000) == (pContent[i +1].nTypeAndId & 0xFFFF0000) + && pContent[i].nOffset >= pContent[i +1].nOffset ) + bEqual2Content = FALSE; + } + } + DBG_ASSERT( bSorted, "content not sorted" ) + DBG_ASSERT( bEqual2Content, "resource structure wrong" ) + if( !bSorted ) + qsort( pContent, nEntries, sizeof( ImpContent ), Compare ); + + bDone = TRUE; + } + + return bDone; +} + +// ----------------------------------------------------------------------- + +InternalResMgr* InternalResMgr::GetInternalResMgr( const UniString& rFileName, + const UniString* pAppName, + const UniString* pResPath ) +{ + ImplSVResourceData* pSVInData = GetResData(); + + // Nur InternalResMgr's mit FileNamen stehen in der Liste + if ( rFileName.Len() ) + { + List& rMgrList = GetResMgrList(); + + InternalResMgr* pEle = (InternalResMgr*)rMgrList.First(); + while( pEle ) + { + if ( rFileName.EqualsIgnoreCaseAscii( pEle->aFileName ) || + rFileName.EqualsIgnoreCaseAscii( pEle->aShortFileName ) ) + { + pEle->AddRef(); + return pEle; + } + pEle = (InternalResMgr*)rMgrList.Next(); + } + +#ifdef DBG_UTIL + ByteString aTraceStr( "Search/Load-RESDLL:" ); + aTraceStr += ByteString( rFileName, RTL_TEXTENCODING_UTF8 ); + DBG_TRACE( aTraceStr.GetBuffer() ); +#endif + + pEle = Create( rFileName, pAppName, pResPath ); + + if ( pEle ) + { + pEle->AddRef(); + rMgrList.Insert( pEle ); + } + + return pEle; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +void InternalResMgr::FreeInternalResMgr( InternalResMgr* pFreeInternalResMgr ) +{ + // Nur InternalResMgr's mit FileNamen stehen in der Liste und werden vor dem + // Programmende freigegeben + if( pFreeInternalResMgr->aFileName.Len() ) + { + if( pFreeInternalResMgr->ReleaseRef() == 0 ) + GetResMgrList().Remove( pFreeInternalResMgr ); + } +} + +// ----------------------------------------------------------------------- + +BOOL InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, USHORT nId ) const +{ + // Anfang der Strings suchen + ImpContent * pFind = (ImpContent *) + bsearch( (void *)((ULONG(nRT) << 16) | nId), pContent, nEntries, + sizeof( ImpContent ), Search ); + return pFind != NULL; +} + +// ----------------------------------------------------------------------- + +void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, USHORT nId, + void **pResHandle ) +{ +#ifdef DBG_UTIL + if( pResUseDump ) + pResUseDump->Remove( (ULONG(nRT) << 16) | nId ); +#endif + // Anfang der Strings suchen + ImpContent * pFind = (ImpContent *) + bsearch( (void *)((ULONG(nRT) << 16) | nId), pContent, nEntries, + sizeof( ImpContent ), Search ); + if( nRT == RSC_STRING && bEqual2Content && pFind ) + { + // String Optimierung + if( !pStringBlock ) + { + // Anfang der Strings suchen + ImpContent * pFirst = pFind; + ImpContent * pLast = pFirst; + while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 16) == RSC_STRING ) + pFirst--; + while( pLast < (pContent + nEntries) && (pLast->nTypeAndId >> 16) == 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*)SvMemAlloc( nSize ); + pStm->Seek( pFirst->nOffset ); + pStm->Read( pStringBlock, nSize ); + } + *pResHandle = pStringBlock; + return (BYTE*)pStringBlock + pFind->nOffset - nOffCorrection; + } + *pResHandle = 0; + if( pFind ) + { + RSHEADER_TYPE aHeader; + pStm->Seek( pFind->nOffset ); + pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) ); + void * pRes = new BYTE[ aHeader.GetGlobOff() ]; + memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) ); + pStm->Read( (BYTE*)pRes + sizeof( RSHEADER_TYPE ), + aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) ); + return pRes; + } + //Resource holen + return NULL; +} + +// ----------------------------------------------------------------------- + +void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource ) +{ + if ( !pResHandle ) + // REsource wurde extra allokiert + delete pResource; +} + +// ======================================================================= + +#ifdef DBG_UTIL + +UniString GetTypeRes_Impl( const ResId& rTypeId ) +{ + // Funktion verlassen, falls Resourcefehler in dieser Funktion + static bInUse = FALSE; + UniString aTypStr( rTypeId.GetId() ); + + if ( !bInUse ) + { + bInUse = TRUE; + + ResId aResId( RSCVERSION_ID ); + 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 + Resource::GetResManager()->Increment( sizeof( RSHEADER_TYPE ) ); + } + } + bInUse = FALSE; + } + + return aTypStr; +} + +// ----------------------------------------------------------------------- + +static void RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr, + RESOURCE_TYPE nRT, USHORT nId, + ImpRCStack* pResStack, short nStackTop ) +{ + // neuen ResourceMgr erzeugen + ResMgr* pNewResMgr = new ResMgr( pResMgr->GetFileName() ); + + ByteString aStr = ByteString( 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( nStackTop > 0 ) + { + aStr.Append( "Class: " ); + aStr.Append( ByteString( GetTypeRes_Impl( ResId( (pResStack + nStackTop)->pResource->GetRT(), pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) ); + aStr.Append( ", Id: " ); + aStr.Append( ByteString::CreateFromInt32( (long)(pResStack + nStackTop)->pResource->GetId() ) ); + nStackTop--; + } + + 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(); + break; + + case NAMESPACE_VOS(OSignalHandler)::TAction_Ignore: + return; + break; + + case NAMESPACE_VOS(OSignalHandler)::TAction_AbortApplication: + abort(); + break; + + case NAMESPACE_VOS(OSignalHandler)::TAction_KillApplication: + exit(-1); + break; + } +} + +// ======================================================================= + +void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, USHORT 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, + USHORT 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::DestroyAllResMgr() +{ + ImplSVResourceData* pSVInData = GetResData(); + + // Da auch von Abort gerufen werden kann, geben wir alle + // ResMgr's und alle InternalResMgr's hier frei + List* pMgrList = pSVInData->pInternalResMgrList; + if ( pMgrList ) + { + InternalResMgr* pEle = (InternalResMgr*)pMgrList->First(); + while ( pEle ) + { + DBG_WARNING1( "ResMgr's not destroyed: %s", + ByteString( pEle->aFileName, RTL_TEXTENCODING_UTF8 ).GetBuffer() ); + pEle->ReleaseReference(); + pEle = (InternalResMgr*)pMgrList->Next(); + } + delete pMgrList; + } +} + +// ----------------------------------------------------------------------- + +void ResMgr::Init( const UniString& rFileName ) +{ + if ( !pImpRes ) + { +#ifdef DBG_UTIL + ByteString aStr( "Resourcefile not found:\n" ); + aStr += ByteString( 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( pImpRes->aFileName, RTL_TEXTENCODING_UTF8 ); + DbgError( aStr.GetBuffer() ); + } + } +#endif + + nTopRes = 0; + aStack[0].Clear(); +} + +// ----------------------------------------------------------------------- + +ResMgr::ResMgr( const UniString& rFileName, + const UniString* pAppName, + const UniString* pResPath ) +{ + pImpRes = InternalResMgr::GetInternalResMgr( rFileName, pAppName, pResPath ); + Init( pImpRes ? (const UniString&)pImpRes->aFileName : rFileName ); +} + +// ----------------------------------------------------------------------- + +ResMgr::ResMgr( InternalResMgr * pImpMgr ) +{ + pImpRes = pImpMgr; + Init( pImpMgr->aFileName ); +} + +// ----------------------------------------------------------------------- + +ResMgr::~ResMgr() +{ + InternalResMgr::FreeInternalResMgr( pImpRes ); +} + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL + +void ResMgr::TestStack( const Resource* pResObj ) +{ + if ( DbgIsResource() ) + { + for( short i = 1; i <= nTopRes; 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 +{ + BOOL bAvailable = FALSE; + RSHEADER_TYPE* pClassRes = rId.GetpResource(); + RESOURCE_TYPE nRT = rId.GetRT2(); + USHORT nId = rId.GetId(); + const ResMgr* pMgr = rId.GetResMgr(); + + if ( !pMgr ) + pMgr = this; + + if ( !pResObj || pResObj == pMgr->aStack[pMgr->nTopRes].pResObj ) + { + if ( !pClassRes ) + pClassRes = LocalResource( &pMgr->aStack[pMgr->nTopRes], nRT, nId ); + if ( pClassRes ) + { + if ( pClassRes->GetRT() == nRT ) + bAvailable = TRUE; + } + } + + // vieleicht globale Resource + if ( !pClassRes ) + bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId ); + + return bAvailable; +} + +// ----------------------------------------------------------------------- + +inline ResMgr* GetActualResMgr() +{ + return GetResData()->pAppResMgr; +} + +// ----------------------------------------------------------------------- + +BOOL ResMgr::GetResource( const ResId& rId, const Resource* pResObj ) +{ + DBG_TESTSOLARMUTEX(); + + ResMgr* pMgr = rId.GetResMgr(); + if ( pMgr && (this != pMgr) ) + return pMgr->GetResource( rId, pResObj ); + + RSHEADER_TYPE* pClassRes = rId.GetpResource(); + RESOURCE_TYPE nRT = rId.GetRT2(); + USHORT nId = rId.GetId(); + + ResMgr* pLastMgr = GetActualResMgr(); + if ( pLastMgr != this ) + Resource::SetResManager( this ); + + nTopRes++; // Stackzeiger erhoehen + ImpRCStack* pTop = &aStack[nTopRes]; + pTop->Init( pLastMgr, 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, nTopRes -1 ); +#endif + RscException_Impl(); + nTopRes--; + return FALSE; + } + } + else + pTop->pClassRes = LocalResource( pTop -1, nRT, nId ); + + if ( pTop->pClassRes ) + // lokale Resource, nicht system Resource + pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes; + else + { + pTop->Flags |= RC_GLOBAL; + pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle ); + if ( pTop->pClassRes ) + pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes; + else + { +#ifdef DBG_UTIL + RscError_Impl( "Cannot load resource! ", + this, nRT, nId, aStack, nTopRes -1 ); +#endif + RscException_Impl(); + ImplSVResourceData * pRD = GetResData(); + nTopRes--; + return FALSE; + } + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr ) +{ + if ( rResId.GetResMgr() ) + *ppResMgr = rResId.GetResMgr(); + else + *ppResMgr = Resource::GetResManager(); + (*ppResMgr)->GetResource( rResId ); + (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) ); + return (*ppResMgr)->GetClass(); +} + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL +void ResMgr::PopContext( const Resource* pResObj ) +#else +void ResMgr::PopContext( const Resource* ) +#endif +{ +#ifdef DBG_UTIL + if ( DbgIsResource() ) + { + if ( (aStack[nTopRes].pResObj != pResObj) || !nTopRes ) + { + RscError_Impl( "Cannot free resource! ", this, + RSC_NOTYPE, 0, aStack, nTopRes ); + } + } +#endif + + if ( nTopRes ) + { + ImpRCStack* pTop = &aStack[nTopRes]; +#ifdef DBG_UTIL + if ( DbgIsResource() ) + { + 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, nTopRes -1 ); + } + } +#endif + + // Resource freigeben + if ( pTop->Flags & RC_GLOBAL ) + // kann auch Fremd-Ressource sein + pImpRes->FreeGlobalRes( pTop->aResHandle, pTop->pResource ); + if ( pTop->pResMgr != this ) + // wurde durch ResId gesetzt, automatisch zuruecksetzen + Resource::SetResManager( pTop->pResMgr ); + nTopRes--; + } +} + +// ----------------------------------------------------------------------- + +RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId ) +{ + 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*)new BYTE[ 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 ) +{ +#ifdef __BIGENDIAN + return *(UINT16*)pShort; +#else + return SWAPSHORT( *(UINT16*)pShort ); +#endif +} + +// ------------------------------------------------------------------ + +INT32 ResMgr::GetLong( void * pLong ) +{ +#ifdef __BIGENDIAN + return (long)(((INT32)(*(UINT16*)pLong) << 16) | *(((UINT16*)pLong) + 1)); +#else + return ((INT32)(*(BYTE*)pLong) << 24) + | ((INT32)(*((BYTE*)pLong +1)) << 16) + | ((INT32)(*((BYTE*)pLong +2)) << 8) + | (INT32)(*((BYTE*)pLong +3)); +#endif +} + +// ----------------------------------------------------------------------- + +USHORT ResMgr::GetString( UniString& rStr, const BYTE* 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 GetStringSize( pStr ); +} + +// ------------------------------------------------------------------ + +USHORT ResMgr::GetStringSize( const BYTE* pStr ) +{ + return GetStringSize( strlen( (const char*)pStr ) ); +} + +// ----------------------------------------------------------------------- + +USHORT ResMgr::GetRemainSize() +{ + return (USHORT)((long)(BYTE *)aStack[nTopRes].pResource + + aStack[nTopRes].pResource->GetLocalOff() - + (long)(BYTE *)aStack[nTopRes].pClassRes); +} + +// ----------------------------------------------------------------------- + +void* ResMgr::Increment( USHORT nSize ) +{ + BYTE* pClassRes = (BYTE*)aStack[nTopRes].pClassRes + nSize; + + aStack[nTopRes].pClassRes = pClassRes; + + RSHEADER_TYPE* pRes = aStack[nTopRes].pResource; + + if ( (pRes->GetGlobOff() == pRes->GetLocalOff()) && + (((char*)pRes + pRes->GetLocalOff()) == aStack[nTopRes].pClassRes) && + (aStack[nTopRes].Flags & RC_AUTORELEASE)) + { + PopContext( aStack[nTopRes].pResObj ); + } + + return pClassRes; +} + +// ----------------------------------------------------------------------- + +const char* ResMgr::GetLang( LanguageType& nType, USHORT nPrio ) +{ + static sal_Char const aDefEng[] = "44"; + static sal_Char const aDefUSEng[] = "01"; + static sal_Char const aDefGerman[] = "49"; + static sal_Char const aDefFrench[] = "33"; + static sal_Char const aDefPortuguese[] = "03"; + + if ( nType == LANGUAGE_SYSTEM || nType == LANGUAGE_DONTKNOW ) + nType = ::GetSystemLanguage(); + + 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 aDefEng; + + case LANGUAGE_ENGLISH_US: + case LANGUAGE_ENGLISH_CAN: + return aDefUSEng; + + case LANGUAGE_ENGLISH_AUS: + case LANGUAGE_ENGLISH_NZ: + return "61"; + + case LANGUAGE_FINNISH: + return "05"; + + 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 aDefFrench; + + case LANGUAGE_GERMAN: + case LANGUAGE_GERMAN_SWISS: + case LANGUAGE_GERMAN_AUSTRIAN: + case LANGUAGE_GERMAN_LUXEMBOURG: + case LANGUAGE_GERMAN_LIECHTENSTEIN: + return aDefGerman; + + case LANGUAGE_ITALIAN: + case LANGUAGE_ITALIAN_SWISS: + return "39"; + + case LANGUAGE_NORWEGIAN: + case LANGUAGE_NORWEGIAN_BOKMAL: + return "47"; + + case LANGUAGE_PORTUGUESE: + return aDefPortuguese; + + case LANGUAGE_PORTUGUESE_BRAZILIAN: + return "55"; + + case LANGUAGE_SPANISH: + 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_HUNGARIAN: + return "36"; + case LANGUAGE_RUSSIAN: + return "07"; + case LANGUAGE_SLOVAK: + return "04"; + 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_ARABIC: + 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"; + + default: + return aDefUSEng; + } + } + else if ( nPrio == 1 ) + { + switch ( nType ) + { + case LANGUAGE_FRENCH_CANADIAN: + return aDefFrench; + + case LANGUAGE_PORTUGUESE_BRAZILIAN: + return aDefPortuguese; + + default: + return NULL; + } + } + else if ( nPrio == 2 ) + return aDefUSEng; + else if ( nPrio == 3 ) + return aDefEng; + else + return aDefGerman; +} + +// ----------------------------------------------------------------------- + +ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName, + LanguageType nType, + const UniString* pAppName, + const UniString* pResPath ) +{ + // Suchreihenfolge festlegen + const sal_Char* pLang[5]; + + // Resourcefile suchen + UniString aName; + InternalResMgr* pInternalResMgr = NULL; + for ( int i = 0; i < 5; i++ ) + { + pLang[i] = GetLang( nType, i ); + + if ( pLang[i] && (i == 0 || pLang[i] != pLang[0]) ) + { + aName.AssignAscii( pPrefixName ); + aName.AppendAscii( pLang[i] ); + aName.AppendAscii( ".res" ); + pInternalResMgr = InternalResMgr::GetInternalResMgr( aName, pAppName, pResPath ); + if ( pInternalResMgr ) + break; + } + } + + if ( pInternalResMgr ) + return new ResMgr( pInternalResMgr ); + + return NULL; +} + +// ----------------------------------------------------------------------- + +INT16 ResMgr::ReadShort() +{ + INT16 n = GetShort( GetClass() ); + Increment( sizeof( INT16 ) ); + return n; +} + +// ----------------------------------------------------------------------- + +INT32 ResMgr::ReadLong() +{ + INT32 n = GetLong( GetClass() ); + Increment( sizeof( INT32 ) ); + return n; +} + +// ----------------------------------------------------------------------- + +UniString ResMgr::ReadString() +{ + UniString aRet; + Increment( GetString( aRet, (const BYTE*)GetClass() ) ); + return aRet; +} + +// ======================================================================= + +SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName, + LanguageType nType, + const UniString* pAppName, + const UniString* pResPath ) +{ + // Suchreihenfolge festlegen + const sal_Char* pLang[5]; + + // Resourcefile suchen + UniString aName; + for ( int i = 0; i < 5; i++ ) + { + pLang[i] = ResMgr::GetLang( nType, i ); + + if ( pLang[i] && (i == 0 || pLang[i] != pLang[0]) ) + { + aName.AssignAscii( pPrefixName ); + aName.AppendAscii( pLang[i] ); + aName.AppendAscii( ".res" ); + m_pResImpl = InternalResMgr::Create( aName, pAppName, pResPath ); + if ( m_pResImpl ) + break; + } + } +} + +// ----------------------------------------------------------------------- + +SimpleResMgr::~SimpleResMgr() +{ + delete m_pResImpl; +} + +// ----------------------------------------------------------------------- + +UniString SimpleResMgr::ReadString( USHORT 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; + RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle ); + if ( !pResHeader ) + // no such resource + return sReturn; + + USHORT 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 .... + m_pResImpl->FreeGlobalRes( pResHeader, pResHandle ); + return sReturn; +} + +// ----------------------------------------------------------------------- + +USHORT SimpleResMgr::ReadBlob( USHORT 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; + 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 !" ); + + // no exception handling, this would require the locking of the solar mutex which isn't allowed within this class + if ( !pResHeader ) + 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 .... + + USHORT nRemaining = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE); + *pBuffer = (void*)(((BYTE*)pResHeader) + sizeof(RSHEADER_TYPE)); + return nRemaining; +} + +// ----------------------------------------------------------------------- + +void SimpleResMgr::FreeBlob( void* pBuffer ) +{ + void* pCompleteBuffer = (void*)(((BYTE*)pBuffer) - sizeof(RSHEADER_TYPE)); + delete pCompleteBuffer; +} diff --git a/tools/source/ref/errinf.cxx b/tools/source/ref/errinf.cxx new file mode 100644 index 000000000000..3db59910725c --- /dev/null +++ b/tools/source/ref/errinf.cxx @@ -0,0 +1,443 @@ +/************************************************************************* + * + * $RCSfile: errinf.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <limits.h> +#include <shl.hxx> +#include <debug.hxx> +#include <errinf.hxx> +#include <string.hxx> + +class ErrorHandler; + +struct EDcrData +{ + public: + + ErrorHandler *pFirstHdl; + ErrorContext *pFirstCtx; + void *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 lUserId, ULONG lArgExtId, USHORT nFlags) +: DynamicErrorInfo(lUserId, nFlags), lExtId(lArgExtId) +{ +} + + +StringErrorInfo::StringErrorInfo( + ULONG lUserId, const String& aStringP, USHORT nFlags) +: DynamicErrorInfo(lUserId, 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=(void*)aDsp; +} + +void ErrorHandler::RegisterDisplay(BasicDisplayErrorFunc *aDsp) +{ + EDcrData *pData=EDcrData::GetData(); + pData->bIsWindowDsp=FALSE; + pData->pDsp=(void*)aDsp; +} + +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 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; + } + + USHORT nErrFlags = ERRCODE_BUTTON_DEF_OK | ERRCODE_BUTTON_OK | + 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)) + { + delete pInfo; + 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 + 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(1, USHRT_MAX); + else + DBG_ERROR("Error 1 nicht gehandeled"); + delete pInfo; + return 0; +} + +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..f19c0e5fa805 --- /dev/null +++ b/tools/source/ref/globname.cxx @@ -0,0 +1,441 @@ +/************************************************************************* + * + * $RCSfile: globname.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:08 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include <stream.hxx> +#include <globname.hxx> + +#pragma hdrstop + +/************** 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 + (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 + (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 + (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; +} diff --git a/tools/source/ref/makefile.mk b/tools/source/ref/makefile.mk new file mode 100644 index 000000000000..ad85f0accd62 --- /dev/null +++ b/tools/source/ref/makefile.mk @@ -0,0 +1,90 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=ref + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/ref.obj \ + $(SLO)$/pstm.obj \ + $(SLO)$/globname.obj \ + $(SLO)$/errinf.obj + +.IF "$(UPDATER)"!="" +OBJFILES= $(OBJ)$/ref.obj \ + $(OBJ)$/pstm.obj \ + $(OBJ)$/globname.obj \ + $(OBJ)$/errinf.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/tools/source/ref/pstm.cxx b/tools/source/ref/pstm.cxx new file mode 100644 index 000000000000..93ba671a2da1 --- /dev/null +++ b/tools/source/ref/pstm.cxx @@ -0,0 +1,945 @@ +/************************************************************************* + * + * $RCSfile: pstm.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <debug.hxx> +#include <pstm.hxx> + +#pragma hdrstop + +#define STOR_NO_OPTIMIZE + +/***********************************************************************/ +/************************************************************************ +|* SvClassManager::Register() +*************************************************************************/ +void SvClassManager::Register( USHORT nClassId, SvCreateInstancePersist pFunc ) +{ +#ifdef DBG_UTIL + SvCreateInstancePersist p; + p = (SvCreateInstancePersist)aAssocTable.Get( nClassId ); + DBG_ASSERT( !p || p == pFunc, "register class with same id" ) +#endif + aAssocTable.Insert( nClassId, (void *)pFunc ); +} + +/************************************************************************ +|* SvClassManager::Get() +*************************************************************************/ +SvCreateInstancePersist SvClassManager::Get( USHORT nClassId ) +{ + return (SvCreateInstancePersist)aAssocTable.Get( nClassId ); +} + +/****************** SvRttiBase *******************************************/ +TYPEINIT0( SvRttiBase ); + +/****************** SvPersistBaseMemberList ******************************/ +#define inline +SV_IMPL_REF_LIST(SuperSvPersistBase,SuperSvPersistBase*) +#undef inline + +#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 nCount = Count(); + ULONG nCountPos = rStm.Tell(); + UINT32 nWriteCount = 0; + rStm << nCount; + //bloss die Liste nicht veraendern, + //wegen Seiteneffekten beim Save + for( ULONG n = 0; n < nCount; n++ ) + { + SvPersistBase * pObj = GetObject( n ); + if( !bOnlyStreamed || rStm.IsStreamed( pObj ) ) + { // Objekt soll geschrieben werden + rStm << GetObject( n ); + nWriteCount++; + } + } + if( nWriteCount != nCount ) + { + // 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, nObjPos; + if( nVer & PERSIST_LIST_DBGUTIL ) + nObjLen = rStm.ReadLen( &nObjPos ); + + ULONG 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 += 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; + 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; + 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, nObjPos; + 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..bfaa76fe9641 --- /dev/null +++ b/tools/source/ref/ref.cxx @@ -0,0 +1,90 @@ +/************************************************************************* + * + * $RCSfile: ref.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <ref.hxx> +#pragma hdrstop + +/****************** SvRefBaseMemberList **********************************/ +#define inline +SV_IMPL_REF_LIST( SvRefBase,SvRefBase* ) +#undef inline + +/************************************************************************** +#* SvRefBase::~SvRefBase() +**************************************************************************/ +SvRefBase::~SvRefBase() +{ +} + +/************************************************************************** +#* SvRefBase::QueryDelete() +**************************************************************************/ +void SvRefBase::QueryDelete() +{ + nRefCount = SV_NO_DELETE_REFCOUNT / 2; + delete this; +} + +SvCompatRefBase::~SvCompatRefBase() +{ + (*pFunc)( pObj ); +} + diff --git a/tools/source/solar/makefile.mk b/tools/source/solar/makefile.mk new file mode 100644 index 000000000000..f38364e9f623 --- /dev/null +++ b/tools/source/solar/makefile.mk @@ -0,0 +1,100 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=mksvconf +TARGETTYPE=CUI + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +CFILES= solar.c + +OBJFILES= $(OBJ)$/solar.obj + +APP1TARGET= $(TARGET) +APP1OBJS= $(OBJFILES) +APP1STDLIBS= +APP1DEPN= +APP1DEF= + +.IF "$(depend)" == "" +ALL: \ + $(INCCOM)$/svconf.h \ + ALLTAR + +$(INCCOM)$/svconf.h : $(BIN)$/$(TARGET) + $(BIN)$/$(TARGET) $@ + +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/tools/source/solar/solar.c b/tools/source/solar/solar.c new file mode 100644 index 000000000000..a119ce84304d --- /dev/null +++ b/tools/source/solar/solar.c @@ -0,0 +1,590 @@ +/************************************************************************* + * + * $RCSfile: solar.c,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#include <stdio.h> + +#ifdef UNX + +#include <unistd.h> +#include <sys/types.h> + +#ifdef HPUX +#include <stdlib.h> +#endif + +#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 + +#else +#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); +} + +/************************************************************************* +|* +|* IsStackGrowingDown() +|* +|* 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* ); + + +#ifdef UNX + +/************************************************************************* +|* +|* 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( sig, SignalHdl ); + /**/ + longjmp( 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 ( !setjmp( check_env ) ) + { + 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 +} + +#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 ); +#ifdef DEBUG + 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 ); +#ifdef DEBUG + 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 +|* +*************************************************************************/ +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 +|* +*************************************************************************/ +Description_Print( struct Description* pThis, char* name ) +{ + int i; + FILE* f = fopen( name, "w" ); + 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, "#define __STACKALIGNMENT wird nicht benutzt\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" ) ); + } +} + +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..f4533f76515b --- /dev/null +++ b/tools/source/stream/cachestr.cxx @@ -0,0 +1,329 @@ +/************************************************************************* + * + * $RCSfile: cachestr.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <debug.hxx> +#include <stream.hxx> +#include <cachestr.hxx> +#include <tempfile.hxx> + +/************************************************************************* +|* +|* SvCacheStream::SvCacheStream() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 27.09.94 +|* Letzte Aenderung OV 27.09.94 +|* +*************************************************************************/ + +SvCacheStream::SvCacheStream( ULONG nMaxMemSize ) +{ + if( !nMaxMemSize ) +#if defined WIN || defined WNT || defined OS2 || defined MAC || defined UNX + nMaxMemSize = 20480; +#else + nMaxMemSize = 20480; +#endif + 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 ) +#if defined WIN || defined WNT || defined OS2 || defined MAC || defined UNX + nMaxMemSize = 20480; +#else + nMaxMemSize = 20480; +#endif + + 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..da71d3c408bc --- /dev/null +++ b/tools/source/stream/makefile.mk @@ -0,0 +1,103 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=stream + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/stream.obj \ + $(SLO)$/strmsys.obj \ + $(SLO)$/cachestr.obj \ + $(SLO)$/vcompat.obj + +.IF "$(UPDATER)" != "" +.IF "$(GUI)" != "MAC" +OBJFILES= $(OBJ)$/stdstrm.obj +.ENDIF + +OBJFILES+= $(OBJ)$/stream.obj \ + $(OBJ)$/strmsys.obj \ + $(OBJ)$/cachestr.obj \ + $(OBJ)$/vcompat.obj +.ENDIF + +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk + +$(SLO)$/strmsys.obj : \ + strmos2.cxx \ + strmwnt.cxx \ + strmwin.cxx \ + strmmac.cxx \ + strmunx.cxx \ + strmstd.cxx + diff --git a/tools/source/stream/stream.cxx b/tools/source/stream/stream.cxx new file mode 100644 index 000000000000..adca76dfd39e --- /dev/null +++ b/tools/source/stream/stream.cxx @@ -0,0 +1,2905 @@ +/************************************************************************* + * + * $RCSfile: stream.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +// ToDo: +// - Read->RefreshBuffer->Auf Aenderungen von nBufActualLen reagieren + +#include <string.h> +#include <stdio.h> +#include <ctype.h> // isspace +#include <stdlib.h> // strtol, _crotl + +/* +#if defined( DBG_UTIL ) && defined( DEBUG ) +// prueft Synchronisation des Buffers nach allen Read, Write, Seek +#define OV_DEBUG +#endif +*/ + +#ifdef WIN +#include <dll.hxx> +#include <svwin.h> +#ifndef SEG +#define SEG(fp) (*((size_t*)&(fp) + 1)) +#endif +#include <solar.h> +#endif + +#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 <new.hxx> +#include <debug.hxx> +#define ENABLE_BYTESTRING_STREAM_OPERATORS +#include <stream.hxx> +#include <osl/thread.h> + +// ----------------------------------------------------------------------- + +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 + +#if SUPD <= 344 +#define _CR '\n' +#define _LF '\r' +#endif + +// ----------------------------------------------------------------------- + +// !!! Nicht inline, wenn Operatoren <<,>> inline sind +inline static void SwapUShort( USHORT& r ) + { r = SWAPSHORT(r); } +inline static void SwapShort( short& r ) + { r = SWAPSHORT(r); } +inline static void SwapInt( int& r ) + { r = SWAPSHORT(r); } +inline static void SwapUInt( unsigned int& r ) + { r = SWAPSHORT(r); } +inline static void SwapLong( long& r ) + { r = SWAPLONG(r); } +inline static void SwapULong( ULONG& 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 ) + { + DBG_ASSERT( FALSE, "SwapFloat noch nicht implementiert!\n" ); + } +inline static void SwapDouble( double& r ) + { + if( sizeof(double) != 8 ) + { + DBG_ASSERT( FALSE, "Can only swap 8-Byte-doubles\n" ); + } + else + { + UINT32* c = (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]); + } + } + +#elif MAC + +inline static void SwapFloat( float& r ) + { + DBG_ASSERT( FALSE, "SwapFloat noch nicht implementiert!\n" ); + } + +inline static void SwapDouble( double& r ) + { +#ifdef DBG_UTIL + if( sizeof(double) != 8 ) + DBG_ASSERT( FALSE, "Can only swap 8-Byte-doubles\n" ); +#endif + + UINT32* c = (UINT32*)(void*)&r; + UINT32 nHelp; + // zwei 32-Bit-Werte in situ vertauschen + // und die beiden 32-Bit-Werte selbst in situ drehen + nHelp = SWAPLONG(c[0]); + c[0] = SWAPLONG(c[1]); + c[1] = nHelp; + } +#endif // #ifdef UNX / elif MAC + +//SDO + +#define READNUMBER_WITHOUT_SWAP(datatype,value) \ +{\ +int tmp = eIOMode; \ +if( (tmp == STREAM_IO_READ) && sizeof(datatype)<=nBufFree) \ +{\ + for (int i = 0; i < sizeof(datatype); i++)\ + ((char *)&r)[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 (int 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(ULONG nPos, void * pBuffer, ULONG nCount, + ULONG * pRead) const +{ + if (!m_pStream) + { + DBG_ERROR("SvLockBytes::ReadAt(): Bad stream"); + return ERRCODE_NONE; + } + + m_pStream->Seek(nPos); + ULONG nTheRead = m_pStream->Read(pBuffer, nCount); + if (pRead) + *pRead = nTheRead; + return m_pStream->GetErrorCode(); +} + +//============================================================================ +// virtual +ErrCode SvLockBytes::WriteAt(ULONG nPos, const void * pBuffer, ULONG nCount, + ULONG * pWritten) +{ + if (!m_pStream) + { + DBG_ERROR("SvLockBytes::WriteAt(): Bad stream"); + return ERRCODE_NONE; + } + + m_pStream->Seek(nPos); + ULONG 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(ULONG nSize) +{ + if (!m_pStream) + { + DBG_ERROR("SvLockBytes::SetSize(): Bad stream"); + return ERRCODE_NONE; + } + + m_pStream->SetStreamSize(nSize); + return m_pStream->GetErrorCode(); +} + +//============================================================================ +ErrCode SvLockBytes::LockRegion(ULONG, ULONG, LockType) +{ + DBG_ERROR("SvLockBytes::LockRegion(): Not implemented"); + return ERRCODE_NONE; +} + +//============================================================================ + +ErrCode SvLockBytes::UnlockRegion(ULONG, ULONG, 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) + { + ULONG 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(ULONG nPos, void * pBuffer, ULONG nCount, + ULONG * pRead) const +{ + if (m_bTerminated) + return SvOpenLockBytes::ReadAt(nPos, pBuffer, nCount, pRead); + else + { + ULONG nTheCount = 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(ULONG nPos, const void * pBuffer, + ULONG nCount, ULONG * pWritten) +{ + if (m_bTerminated) + return SvOpenLockBytes::WriteAt(nPos, pBuffer, nCount, pWritten); + else + { + ULONG nTheCount = 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, ULONG nCount, + ULONG * pWritten) +{ + ULONG nTheWritten; + ErrCode nError = SvOpenLockBytes::WriteAt(m_nSize, pBuffer, nCount, + &nTheWritten); + if (!nError) + m_nSize += nTheWritten; + if (pWritten) + *pWritten = nTheWritten; + return nError; +} + +//============================================================================ +// virtual +ULONG SvAsyncLockBytes::Seek(ULONG nPos) +{ + if (nPos != STREAM_SEEK_TO_END) + m_nSize = nPos; + return m_nSize; +} + +//============================================================================ +// +// class SvStream +// +//============================================================================ + +ULONG SvStream::GetData( void* pData, ULONG nSize ) +{ + if( !GetError() ) + { + DBG_ASSERT( xLockBytes.Is(), "pure virtual function" ); + ULONG 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; +} + +//======================================================================== + +ULONG SvStream::PutData( const void* pData, ULONG nSize ) +{ + if( !GetError() ) + { + DBG_ASSERT( xLockBytes.Is(), "pure virtual function" ); + ULONG nRet; + nError = xLockBytes->WriteAt( nActPos, pData, nSize, &nRet ); + nActPos += nRet; + return nRet; + } + else return 0; +} + +//======================================================================== + +ULONG SvStream::SeekPos( ULONG 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( ULONG 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( MAC ) + eLineDelimiter = LINEEND_CR; // MAC-Format +#elif 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() ) ) + 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 +|* +*************************************************************************/ + +USHORT SvStream::IsA() const +{ + return (USHORT)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( ULONG 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( USHORT nNewFormat ) +{ + nNumberFormatInt = nNewFormat; + bSwap = FALSE; +#ifdef __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( USHORT nBufferSize ) +{ + ULONG nActualFilePos = Tell(); + BOOL bDontSeek = (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 +|* +*************************************************************************/ + +BOOL SvStream::ReadByteStringLine( String& rStr, rtl_TextEncoding eSrcCharSet ) +{ + BOOL bRet; + ByteString aStr; + + bRet = ReadLine(aStr); + rStr = UniString( aStr, eSrcCharSet ); + return bRet; +} + +BOOL SvStream::ReadLine( ByteString& rStr ) +{ + sal_Char buf[256+1]; + BOOL bEnd = FALSE; + ULONG nOldFilePos = Tell(); + sal_Char c = 0; + + rStr.Erase(); + while( !bEnd && !GetError() ) // !!! nicht auf EOF testen, + // !!! weil wir blockweise + // !!! lesen + { + USHORT nLen = (USHORT)Read( buf, sizeof(buf)-1 ); + if ( !nLen ) + { + if ( rStr.Len() == 0 ) + { + // der allererste Blockread hat fehlgeschlagen -> Abflug + bIsEof = TRUE; + return FALSE; + } + else + break; + } + + for( USHORT n = 0; n < nLen ; n++ ) + { + c = buf[n]; + if ( c != '\n' && c != '\r' ) + rStr += c; + else + { + bEnd = TRUE; + break; + } + } + } + + if ( !bEnd && !GetError() && rStr.Len() ) + bEnd = TRUE; + + nOldFilePos += rStr.Len(); + if( Tell() > nOldFilePos ) + nOldFilePos++; + Seek( nOldFilePos ); // seeken wg. obigem BlockRead! + + if ( bEnd && (c=='\r' || c=='\n') ) // Sonderbehandlung DOS-Dateien + { + char cTemp; + Read((char*)&cTemp , sizeof(cTemp) ); + if( cTemp == c || (cTemp != '\n' && cTemp != '\r') ) + Seek( nOldFilePos ); + } + + if ( bEnd ) + bIsEof = FALSE; + return bEnd; +} + +/************************************************************************* +|* +|* Stream::WriteLine() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 08.06.94 +|* Letzte Aenderung OV 08.06.94 +|* +*************************************************************************/ + +BOOL SvStream::WriteByteStringLine( const String& rStr, rtl_TextEncoding eDestCharSet ) +{ + return WriteLine( ByteString( rStr, eDestCharSet ) ); +} + +BOOL SvStream::WriteLine( const ByteString& rStr ) +{ + Write( rStr.GetBuffer(), rStr.Len() ); + endl(*this); + return nError == SVSTREAM_OK; +} + +/************************************************************************* +|* +|* Stream::WriteLines() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 17.07.95 +|* Letzte Aenderung OV 17.07.95 +|* +*************************************************************************/ + +BOOL SvStream::WriteByteStringLines( const String& rStr, rtl_TextEncoding eDestCharSet ) +{ + return WriteLines( ByteString( rStr, eDestCharSet ) ); +} + +BOOL SvStream::WriteLines( const ByteString& rStr ) +{ + ByteString aStr( rStr ); + aStr.ConvertLineEnd( eLineDelimiter ); + Write( aStr.GetBuffer(), aStr.Len() ); + endl( *this ); + return (BOOL)(nError == SVSTREAM_OK); +} + +/************************************************************************* +|* +|* Stream::SeekRel() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 08.06.94 +|* Letzte Aenderung OV 08.06.94 +|* +*************************************************************************/ + +ULONG SvStream::SeekRel( long nPos ) +{ + ULONG nActualPos = Tell(); + nActualPos += nPos; + 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 >> ( USHORT& r ) +{ + READNUMBER_WITHOUT_SWAP(USHORT,r) + if( bSwap ) + SwapUShort(r); + return *this; +} + +SvStream& SvStream::operator>> ( ULONG& r) +{ +#if(__SIZEOFLONG != 4) + unsigned int tmp = r; + READNUMBER_WITHOUT_SWAP(ULONG,tmp) + r = tmp; + if( bSwap ) + SwapULong(r); +#else + READNUMBER_WITHOUT_SWAP(ULONG,r) + if( bSwap ) + SwapULong(r); +#endif + return *this; +} + +SvStream& SvStream::operator >> ( long& r ) +{ +#if(__SIZEOFLONG != 4) + unsigned int tmp = r; + READNUMBER_WITHOUT_SWAP(long,tmp) + r = tmp; + if( bSwap ) + SwapLong(r); +#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 ) + { +#if(__SIZEOFINT == 2) + SwapInt(r); +#else + SwapLongInt(r); +#endif + } + return *this; +} + +SvStream& SvStream::operator>>( unsigned int& r) +{ + READNUMBER_WITHOUT_SWAP(unsigned int,r) + if( bSwap ) + { +#if(__SIZEOFINT == 2) + SwapUInt(r); +#else + SwapLongUInt(r); +#endif + } + 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) +#ifdef 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 ) || defined ( MAC ) + if( bSwap ) + SwapDouble(r); +#endif + return *this; +} + +SvStream& SvStream::operator>> ( SvStream& rStream ) +{ + const ULONG cBufLen = 0x8000; + char* pBuf = new char[ cBufLen ]; + + ULONG 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<< ( USHORT v ) +{ + if( bSwap ) + SwapUShort(v); + WRITENUMBER_WITHOUT_SWAP(USHORT,v) + return *this; +} + +SvStream& SvStream::operator<< ( ULONG v) +{ +#if(__SIZEOFLONG != 4) + unsigned int tmp = v; + if( bSwap ) + SwapUInt(tmp); + WRITENUMBER_WITHOUT_SWAP(unsigned int,tmp) +#else + if( bSwap ) + SwapULong(v); + WRITENUMBER_WITHOUT_SWAP(ULONG,v) +#endif + return *this; +} + +SvStream& SvStream::operator<< ( long v ) +{ +#if(__SIZEOFLONG != 4) + int tmp = v; + if( bSwap ) + SwapInt(tmp); + WRITENUMBER_WITHOUT_SWAP(int,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 ) + { +#if( __SIZEOFINT == 2 ) + SwapInt( v ); +#else + SwapLongInt( v ); +#endif + } + 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; +} + + +SvStream& SvStream::operator<< ( unsigned int v) +{ + if( bSwap ) + { +#if( __SIZEOFINT == 2 ) + SwapUInt( v ); +#else + SwapLongUInt( v ); +#endif + } + WRITENUMBER_WITHOUT_SWAP(int,v) + 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 ) || defined ( MAC ) + 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 ULONG cBufLen = 0x8000; + char* pBuf = new char[ cBufLen ]; + ULONG 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) + { + sal_Unicode *pStr = rStr.AllocBuffer(nLen); + 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 ) +{ + USHORT nLen = 0; + operator>>( nLen ); + if( nLen ) + { + char* pTmp = rStr.AllocBuffer( nLen ); + nLen = (USHORT)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(USHORT,c) + } + } + else + Write( rStr.GetBuffer(), nLen << 1 ); + } + + return *this; + } + + return WriteByteString(ByteString( rStr, eDestCharSet )); +} + +// ----------------------------------------------------------------------- + +SvStream& SvStream::WriteByteString( const ByteString& rStr) +{ + USHORT 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 +|* +*************************************************************************/ + +ULONG SvStream::Read( void* pData, ULONG nCount ) +{ + ULONG 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 <= (ULONG)(nBufActualLen - nBufActualPos ) ) + { + // Ja! +#ifdef WIN + hmemcpy( pData, pBufPos, nCount ); +#else + memcpy(pData, pBufPos, (size_t) nCount); +#endif + nBufActualPos += (USHORT)nCount; + pBufPos += nCount; + nBufFree -= (USHORT)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, USHORT nCountTmp + ULONG nCountTmp = GetData( pRWBuf, nBufSize ); + if( nCryptMask ) + EncryptBuffer(pRWBuf, nCountTmp); + nBufActualLen = (USHORT)nCountTmp; + if( nCount > nCountTmp ) + { + nCount = nCountTmp; // zurueckstutzen, Eof siehe unten + } +#ifdef WIN + hmemcpy( pData, pRWBuf, nCount ); +#else + memcpy( pData, pRWBuf, (size_t)nCount ); +#endif + nBufActualPos = (USHORT)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 +|* +*************************************************************************/ + +ULONG SvStream::Write( const void* pData, ULONG 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 <= (ULONG)(nBufSize - nBufActualPos) ) + { +#ifdef WIN + hmemcpy( pBufPos, pData, nCount ); +#else + memcpy( pBufPos, pData, (size_t)nCount ); +#endif + nBufActualPos += (USHORT)nCount; + // wurde der Puffer erweitert ? + if( nBufActualPos > nBufActualLen ) + nBufActualLen = nBufActualPos; + + pBufPos += nCount; + bIsDirty = TRUE; + } + else + { + // Flushen ? + if( bIsDirty ) + { + SeekPos( nBufFilePos ); + if( nCryptMask ) + CryptAndWriteBuffer( pRWBuf, (ULONG)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 +#ifdef WIN + hmemcpy( pRWBuf, pData, nCount ); +#else + memcpy( pRWBuf, pData, (size_t)nCount ); +#endif + // Reihenfolge! + nBufFilePos += nBufActualPos; + nBufActualPos = (USHORT)nCount; + pBufPos = pRWBuf + nCount; + nBufActualLen = (USHORT)nCount; + bIsDirty = TRUE; + } + } + nBufFree = nBufSize - nBufActualPos; + return nCount; +} + + +/************************************************************************* +|* +|* Stream::Seek() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 08.06.94 +|* Letzte Aenderung OV 08.06.94 +|* +*************************************************************************/ + +ULONG SvStream::Seek( ULONG 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 = (USHORT)(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 + { + ULONG 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, (ULONG)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, (USHORT)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, (ULONG)nBufActualLen ); + else + PutData( pRWBuf, nBufActualLen ); + bIsDirty = FALSE; + } + SeekPos( nBufFilePos ); + nBufActualLen = (USHORT)GetData( pRWBuf, nBufSize ); + if( nBufActualLen && nError == ERRCODE_IO_PENDING ) + nError = ERRCODE_NONE; + if( nCryptMask ) + EncryptBuffer(pRWBuf, (ULONG)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; + } + ULONG nFPtr = Tell(); + char buf[ BUFSIZE_LONG ]; + memset( buf, 0, BUFSIZE_LONG ); + ULONG nTemp = Read( buf, BUFSIZE_LONG-1 ); + if( !nTemp || nError ) + { + SetError( SVSTREAM_GENERALERROR ); + return *this; + } + char *pEndPtr; + rLong = strtol( buf, &pEndPtr, (int)nRadix ); + nFPtr += ( (ULONG)pEndPtr - (ULONG)(&(buf[0])) ); + Seek( nFPtr ); + bIsEof = FALSE; + return *this; +} + +SvStream& SvStream::ReadNumber( ULONG& rULong ) +{ + EatWhite(); + if( bIsEof || nError ) + { + SetError( SVSTREAM_GENERALERROR ); + return *this; + } + ULONG nFPtr = Tell(); + char buf[ BUFSIZE_LONG ]; + memset( buf, 0, BUFSIZE_LONG ); + ULONG nTemp = Read( buf, BUFSIZE_LONG-1 ); + if( !nTemp || nError ) + { + SetError( SVSTREAM_GENERALERROR ); + return *this; + } + char *pEndPtr; + rULong = strtoul( buf, &pEndPtr, (int)nRadix ); + nFPtr += ( (ULONG)pEndPtr - (ULONG)buf ); + Seek( nFPtr ); + bIsEof = FALSE; + return *this; +} + +SvStream& SvStream::ReadNumber( double& rDouble ) +{ + EatWhite(); + if( bIsEof || nError ) + { + SetError( SVSTREAM_GENERALERROR ); + return *this; + } + ULONG nFPtr = Tell(); + char buf[ BUFSIZE_LONG ]; + memset( buf, 0, BUFSIZE_LONG ); + ULONG nTemp = Read( buf, BUFSIZE_LONG-1 ); + if( !nTemp || nError ) + { + SetError( SVSTREAM_GENERALERROR ); + return *this; + } + char *pEndPtr; + rDouble = strtod( buf, &pEndPtr ); + nFPtr += ( (ULONG)pEndPtr - (ULONG)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( ULONG nULong ) +{ + 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(), nULong ); + break; + case SPECIAL_PARAM_WIDTH : + nLen = sprintf( buffer, aFStr.GetBuffer(), nWidth, nULong ); + break; + case SPECIAL_PARAM_PRECISION : + nLen = sprintf( buffer, aFStr.GetBuffer(), nPrecision,nULong); + break; + default: + nLen=sprintf(buffer,aFStr.GetBuffer(),nWidth,nPrecision,nULong); + } + 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 + +ULONG SvStream::CryptAndWriteBuffer( const void* pStart, ULONG nLen) +{ + unsigned char* pTemp = new unsigned char[CRYPT_BUFSIZE]; + unsigned char* pDataPtr = (unsigned char*)pStart; + ULONG nCount = 0; + ULONG nBufCount; + unsigned char nMask = nCryptMask; + do + { + if( nLen >= CRYPT_BUFSIZE ) + nBufCount = CRYPT_BUFSIZE; + else + nBufCount = nLen; + nLen -= nBufCount; + memcpy( pTemp, pDataPtr, (USHORT)nBufCount ); + // **** Verschluesseln ***** + for ( USHORT 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 ); + delete pTemp; + return nCount; +} + +/************************************************************************* +|* +|* Stream::EncryptBuffer() +|* +|* Beschreibung Buffer entschluesseln +|* Ersterstellung OV 08.06.94 +|* Letzte Aenderung OV 08.06.94 +|* +*************************************************************************/ + +BOOL SvStream::EncryptBuffer(void* pStart, ULONG nLen) +{ + unsigned char* pTemp = (unsigned char*)pStart; + unsigned char nMask = nCryptMask; + + for ( ULONG 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( USHORT 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( ULONG 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 +|* +*************************************************************************/ + +BOOL SvStream::SetStreamSize( ULONG nSize ) +{ +#ifdef DBG_UTIL + ULONG nFPos = Tell(); +#endif + USHORT nBuf = nBufSize; + SetBufferSize( 0 ); + SetSize( nSize ); + SetBufferSize( nBuf ); + DBG_ASSERT(Tell()==nFPos,"SetStreamSize failed") + return (BOOL)(nError == 0); +} + +//============================================================================ + +void SvStream::AddMark( ULONG nPos ) +{ +} + +//============================================================================ + +void SvStream::RemoveMark( ULONG nPos ) +{ +} + +/************************************************************************* +|* +|* 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; +} + +/************************************************************************* +|* +|* SvMemoryStream::SvMemoryStream() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 20.06.94 +|* Letzte Aenderung OV 20.06.94 +|* +*************************************************************************/ + +SvMemoryStream::SvMemoryStream( void* pBuffer, ULONG nBufSize, + StreamMode eMode ) +{ + if( eMode & STREAM_WRITE ) + bIsWritable = TRUE; + else + bIsWritable = FALSE; + nEndOfData = nBufSize; + bOwnsData = FALSE; + pBuf = (BYTE *) pBuffer; + nResize = 0L; + nSize = nBufSize; + nPos = 0L; + SetBufferSize( 0 ); +} + +/************************************************************************* +|* +|* SvMemoryStream::SvMemoryStream() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 20.06.94 +|* Letzte Aenderung OV 20.06.94 +|* +*************************************************************************/ + +SvMemoryStream::SvMemoryStream( ULONG nInitSize, ULONG 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 +|* +*************************************************************************/ + +USHORT SvMemoryStream::IsA() const +{ + return (USHORT)ID_MEMORYSTREAM; +} + +/************************************************************************* +|* +|* SvMemoryStream::SetBuffer() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 20.06.94 +|* Letzte Aenderung OV 20.06.94 +|* +*************************************************************************/ + +void* SvMemoryStream::SetBuffer( void* pNewBuf, ULONG nCount, + BOOL bOwnsDat, ULONG 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 +|* +*************************************************************************/ + +ULONG SvMemoryStream::GetData( void* pData, ULONG nCount ) +{ + ULONG nMaxCount = nEndOfData-nPos; + if( nCount > nMaxCount ) + nCount = nMaxCount; +#ifdef WIN + void _huge* pTmp = (void _huge*)((char _huge*)pBuf + nPos); + hmemcpy( (void _huge*)pData, pTmp, (long)nCount); +#else + memcpy( pData, pBuf+nPos, (size_t)nCount ); +#endif + nPos += nCount; + return nCount; +} + +/************************************************************************* +|* +|* SvMemoryStream::PutData() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 20.06.94 +|* Letzte Aenderung OV 20.06.94 +|* +*************************************************************************/ + +ULONG SvMemoryStream::PutData( const void* pData, ULONG nCount ) +{ + if( GetError() ) + return 0L; + + ULONG 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"); +#ifdef WIN + void _huge* pTmp = (void _huge*)((char _huge*)pBuf + nPos); + hmemcpy( pTmp, (void _huge*)pData,(long)nCount); +#else + memcpy( pBuf+nPos, pData, (size_t)nCount); +#endif + + 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 + +ULONG SvMemoryStream::SeekPos( ULONG 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 +|* +*************************************************************************/ + +BOOL SvMemoryStream::AllocateMemory( ULONG nNewSize ) +{ + pBuf = (BYTE*)SvMemAlloc( nNewSize, MEM_NOCALLNEWHDL ); + return( pBuf != 0 ); +} + +/************************************************************************* +|* +|* SvMemoryStream::ReAllocateMemory() (Bozo-Algorithmus) +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 20.06.94 +|* Letzte Aenderung OV 20.06.94 +|* +*************************************************************************/ + +BOOL SvMemoryStream::ReAllocateMemory( long nDiff ) +{ + BOOL bRetVal = FALSE; + long nTemp = (long)nSize; + nTemp += nDiff; + ULONG nNewSize = (ULONG)nTemp; + + if( nNewSize ) + { + BYTE* pNewBuf = (BYTE *) SvMemAlloc( nNewSize,MEM_NOCALLNEWHDL ); + + if( pNewBuf ) + { + bRetVal = TRUE; // Success! + if( nNewSize < nSize ) // Verkleinern ? + { +#ifdef WIN + hmemcpy((void _huge*)pNewBuf,(void _huge*)pBuf,(long)nNewSize ); +#else + memcpy( pNewBuf, pBuf, (size_t)nNewSize ); +#endif + if( nPos > nNewSize ) + nPos = 0L; + if( nEndOfData >= nNewSize ) + nEndOfData = nNewSize-1L; + } + else + { +#ifdef WIN + hmemcpy( (void _huge*)pNewBuf, (void _huge*)pBuf, (long)nSize ); +#else + memcpy( pNewBuf, pBuf, (size_t)nSize ); +#endif + } + + FreeMemory(); + + pBuf = pNewBuf; + nSize = nNewSize; + } + } + else + { + bRetVal = TRUE; + pBuf = 0; + nSize = 0; + nEndOfData = 0; + nPos = 0; + } + + return bRetVal; +} + +void SvMemoryStream::FreeMemory() +{ + SvMemFree( pBuf ); +} + +/************************************************************************* +|* +|* SvMemoryStream::SwitchBuffer() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 26.07.94 +|* Letzte Aenderung OV 26.07.94 +|* +*************************************************************************/ + +void* SvMemoryStream::SwitchBuffer( ULONG nInitSize, ULONG 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( ULONG nNewSize ) +{ + long nDiff = (long)nNewSize - (long)nSize; + ReAllocateMemory( nDiff ); +} + +// ********************************************************************* +// Mac implementierung (mit Handles) in StrmMac.cxx +// ********************************************************************* + +#ifndef MAC + +/************************************************************************* +|* +|* SvSharedMemoryStream::SvSharedMemoryStream() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +SvSharedMemoryStream::SvSharedMemoryStream( void* pBuffer,ULONG nBufSize, + StreamMode eMode ) : + SvMemoryStream( (char*)pBuffer, nBufSize, eMode ) +{ + aHandle = 0; +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::SvSharedMemoryStream() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +SvSharedMemoryStream::SvSharedMemoryStream( ULONG nInitSize, + ULONG nResizeOffset) : + SvMemoryStream( (void*)NULL ) +{ + if( !nInitSize ) + nInitSize = 1024; + + aHandle = 0; + 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 ); +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::~SvSharedMemoryStream() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +SvSharedMemoryStream::~SvSharedMemoryStream() +{ + if( bOwnsData ) + { + FreeMemory(); + pBuf = 0; // damit der Dtor von SvMemoryStream nicht mehr zuschlaegt + } + else + Flush(); +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::GetData() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 08.06.94 +|* Letzte Aenderung OV 08.06.94 +|* +*************************************************************************/ + +const void* SvSharedMemoryStream::GetData() +{ + Flush(); + return pBuf; +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::operator const char*() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 08.06.94 +|* Letzte Aenderung OV 08.06.94 +|* +*************************************************************************/ + +SvSharedMemoryStream::operator const void*() +{ + Flush(); + return pBuf; +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::IsA() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +USHORT SvSharedMemoryStream::IsA() const +{ + return (USHORT)ID_SHAREDMEMORYSTREAM; +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::SwitchBuffer() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung KH 16.06.95 +|* Letzte Aenderung KH 16.06.95 +|* +*************************************************************************/ + +void* SvSharedMemoryStream::SwitchBuffer( ULONG nInitSize, ULONG nResize ) +{ + return (void*)SvMemoryStream::SwitchBuffer(nInitSize, nResize); +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::SetBuffer() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung KH 16.06.95 +|* Letzte Aenderung KH 16.06.95 +|* +*************************************************************************/ + +void* SvSharedMemoryStream::SetBuffer( void* pBuf, ULONG nSize, BOOL bOwnsData, + ULONG nEof) +{ + return (void*)SvMemoryStream::SetBuffer((char*)pBuf,nSize,bOwnsData,nEof); +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::GetData() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung KH 19.06.95 +|* Letzte Aenderung KH 19.06.95 +|* +*************************************************************************/ + +ULONG SvSharedMemoryStream::GetData( void* pData, ULONG nCount ) +{ + return SvMemoryStream::GetData(pData, nCount); +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::PutData() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung KH 19.06.95 +|* Letzte Aenderung KH 19.06.95 +|* +*************************************************************************/ + +ULONG SvSharedMemoryStream::PutData( const void* pData, ULONG nCount ) +{ + return SvMemoryStream::PutData(pData, nCount); +} + + +// +// Speicherverwaltung (Alloc, Free, Realloc, SetHandle) +// Standardimplementation DOS & UNIX +// + +#if defined(DOS) || defined(UNX) + +/************************************************************************* +|* +|* SvSharedMemoryStream::SetHandle() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 05.10.95 +|* Letzte Aenderung OV 05.10.95 +|* +*************************************************************************/ + +void* SvSharedMemoryStream::SetHandle( void* aHandle, ULONG nSize, + BOOL bOwnsData, ULONG nEOF) +{ + DBG_ERROR("SvSharedMemoryStream::SetHandle not implemented"); + return 0; +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::AllocateMemory() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +BOOL SvSharedMemoryStream::AllocateMemory( ULONG nNewSize ) +{ + pBuf = new BYTE[ nNewSize ]; + return( pBuf != 0 ); +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::ReAllocateMemory() (Bozo-Algorithmus) +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +BOOL SvSharedMemoryStream::ReAllocateMemory( long nDiff ) +{ + BOOL bRetVal = FALSE; + ULONG nNewSize = nSize + nDiff; + 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 + { + FreeMemory(); + bRetVal = TRUE; + pBuf = 0; + nSize = 0; + nPos = 0; + nEndOfData = 0; + } + return bRetVal; +} + +void SvSharedMemoryStream::FreeMemory() +{ + delete pBuf; +} + + +#endif + +#endif + +TYPEINIT0 ( SvDataCopyStream ) + +// -------------------- + +// Diese Methoden muessen fuer die Win16-Version implementiert werden, +// da sonst der Compiler Aerger macht. (?) +/* +TypeId SvDataCopyStream::Type() const +{ + return 0; +} + +BOOL SvDataCopyStream::IsA(TypeId aId) const +{ + return FALSE; +} +*/ + +void SvDataCopyStream::Assign( const SvDataCopyStream& rHack) +{ +} diff --git a/tools/source/stream/strmos2.cxx b/tools/source/stream/strmos2.cxx new file mode 100644 index 000000000000..7f96a70ba194 --- /dev/null +++ b/tools/source/stream/strmos2.cxx @@ -0,0 +1,870 @@ +/************************************************************************* + * + * $RCSfile: strmos2.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string.h> +#include <limits.h> + +#define INCL_PM +#define INCL_DOS +#include <svpm.h> +#include <bseerr.h> + +#include <debug.hxx> +#include <fsys.hxx> +#include <stream.hxx> +#include <fastfsys.hxx> + +// ----------------------------------------------------------------------- + +// -------------- +// - 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 ); + Open( rFileName, 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( char* pData, ULONG nSize ) +{ +#ifdef DBG_UTIL + String aTraceStr( "SvFileStream::GetData(): " ); + aTraceStr += nSize; + aTraceStr += " Bytes from "; + aTraceStr += aFilename; + DBG_TRACE( aTraceStr ); +#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 char* pData, ULONG nSize ) +{ +#ifdef DBG_UTIL + String aTraceStr( "SvFileStrean::PutData: " ); + aTraceStr += nSize; + aTraceStr += " Bytes to "; + aTraceStr += aFilename; + DBG_TRACE( aTraceStr ); +#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 +|* +*************************************************************************/ + +BOOL SvFileStream::LockRange( ULONG nByteOffset, ULONG nBytes ) +{ + 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 +|* +*************************************************************************/ + +BOOL SvFileStream::UnlockRange( ULONG nByteOffset, ULONG nBytes ) +{ + 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 +|* +*************************************************************************/ + +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 OV 15.06.94 +|* +*************************************************************************/ + +BOOL createLongNameEA ( const PCSZ pszPath, ULONG ulAttributes, const String& aLongName ); + +void SvFileStream::Open( const String& rFilename, StreamMode nOpenMode ) +{ + String aParsedFilename; + + 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 + { + 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; + } + + // + // 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; + } + } + + aFilename = aParsedFilename; + FSysRedirector::DoRedirect( aFilename ); + +#ifdef DBG_UTIL + String aTraceStr( "SvFileStream::Open(): " ); + aTraceStr += aFilename; + DBG_TRACE( aTraceStr ); +#endif + + APIRET nRet = DosOpen( (const char*)aFilename, &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( (const char*)aFilename, &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( (const char*)aFilename, &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 (bIsOpen && bIsLongOS2) + { + //file schlieen, da sonst createLongName u.U. nicht mglich + Close(); + + // erzeugtem File langen Namen geben + DirEntry aDirEntry(rFilename); + createLongNameEA((const char*)aFilename, FILE_NORMAL, aDirEntry.GetName()); + + // und wieder oeffnen + ReOpen(); + } + +} + +/************************************************************************* +|* +|* 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 + String aTraceStr( "SvFileStream::Close(): " ); + aTraceStr += aFilename; + DBG_TRACE( aTraceStr ); +#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 ) ); + } +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::AllocateMemory() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +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 ); + return( nRet == 0 ); +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::ReAllocateMemory() (Bozo-Algorithmus) +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +BOOL SvSharedMemoryStream::ReAllocateMemory( long nDiff ) +{ + DBG_ASSERT(aHandle==0,"Keine Handles unter OS/2"); + 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 ); + 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 = 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*, ULONG,BOOL, ULONG ) +{ + DBG_ERROR("OS/2 does not support memory handles"); + // return SetBuffer(aNewHandle, nSize, bOwnsData, nEOF ); + return 0; +} + + diff --git a/tools/source/stream/strmsys.cxx b/tools/source/stream/strmsys.cxx new file mode 100644 index 000000000000..5639174d3fec --- /dev/null +++ b/tools/source/stream/strmsys.cxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * $RCSfile: strmsys.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#if defined( OS2 ) +#include "strmos2.cxx" +#elif defined( WNT ) +#include "strmwnt.cxx" +#elif defined( WIN ) +#include "strmwin.cxx" +#elif defined( MAC ) +#include "strmmac.cxx" +#elif defined( UNX ) +#include "strmunx.cxx" +#else +#include "strmstd.cxx" +#endif diff --git a/tools/source/stream/strmunx.cxx b/tools/source/stream/strmunx.cxx new file mode 100644 index 000000000000..cab977989456 --- /dev/null +++ b/tools/source/stream/strmunx.cxx @@ -0,0 +1,897 @@ +/************************************************************************* + * + * $RCSfile: strmunx.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#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 <debug.hxx> +#include <fsys.hxx> +#include <stream.hxx> + +#include <vos/mutex.hxx> +#include <osl/thread.h> // osl_getThreadTextEncoding + +// class FileBase +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif +using namespace osl; + +// ----------------------------------------------------------------------- + +// ---------------- +// - InternalLock - +// ---------------- + +class InternalStreamLock; +DECLARE_LIST( InternalStreamLockList, InternalStreamLock* ); + +class InternalStreamLock +{ + ULONG m_nStartPos; + ULONG m_nEndPos; + SvFileStream* m_pStream; + struct stat m_aStat; + + static InternalStreamLockList LockList; +#ifndef BOOTSTRAP + static NAMESPACE_VOS(OMutex) LockMutex; +#endif + + InternalStreamLock( ULONG, ULONG, SvFileStream* ); + ~InternalStreamLock(); +public: + static BOOL LockFile( ULONG nStart, ULONG nEnd, SvFileStream* ); + static void UnlockFile( ULONG nStart, ULONG nEnd, SvFileStream* ); +}; + +InternalStreamLockList InternalStreamLock::LockList; +#ifndef BOOTSTRAP +NAMESPACE_VOS(OMutex) InternalStreamLock::LockMutex; +#endif + +InternalStreamLock::InternalStreamLock( + ULONG nStart, + ULONG 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.Insert( this, LIST_APPEND ); +#ifdef DEBUG + fprintf( stderr, "locked %s", aFileName.GetBuffer() ); + if( m_nStartPos || m_nEndPos ) + fprintf(stderr, " [ %d ... %d ]", m_nStartPos, m_nEndPos ); + fprintf( stderr, "\n" ); +#endif +} + +InternalStreamLock::~InternalStreamLock() +{ + LockList.Remove( this ); +#ifdef DEBUG + ByteString aFileName(m_pStream->GetFileName(), osl_getThreadTextEncoding()); + fprintf( stderr, "unlocked %s", aFileName.GetBuffer() ); + if( m_nStartPos || m_nEndPos ) + fprintf(stderr, " [ %d ... %d ]", m_nStartPos, m_nEndPos ); + fprintf( stderr, "\n" ); +#endif +} + +BOOL InternalStreamLock::LockFile( ULONG nStart, ULONG nEnd, SvFileStream* pStream ) +{ +#ifndef BOOTSTRAP + NAMESPACE_VOS( OGuard ) aGuard( LockMutex ); +#endif + ByteString aFileName(pStream->GetFileName(), osl_getThreadTextEncoding()); + struct stat aStat; + if( stat( aFileName.GetBuffer(), &aStat ) ) + return FALSE; + + if( S_ISDIR( aStat.st_mode ) ) + return TRUE; + + InternalStreamLock* pLock = NULL; + for( int i = 0; i < LockList.Count(); i++ ) + { + pLock = LockList.GetObject( i ); + if( aStat.st_ino == pLock->m_aStat.st_ino ) + { + BOOL bDenyByOptions = FALSE; + StreamMode nLockMode = pLock->m_pStream->GetStreamMode(); + StreamMode nNewMode = pStream->GetStreamMode(); + + if( nLockMode & STREAM_SHARE_DENYALL ) + bDenyByOptions = TRUE; + else if( ( nLockMode & STREAM_SHARE_DENYWRITE ) && + ( nNewMode & STREAM_WRITE ) ) + bDenyByOptions = TRUE; + else if( ( nLockMode & STREAM_SHARE_DENYREAD ) && + ( nNewMode & STREAM_READ ) ) + bDenyByOptions = TRUE; + + if( bDenyByOptions ) + { + if( pLock->m_nStartPos == 0 && pLock->m_nEndPos == 0 ) // whole file is already locked + return FALSE; + if( nStart == 0 && nEnd == 0) // cannot lock whole file + return FALSE; + + if( ( nStart < pLock->m_nStartPos && nEnd > pLock->m_nStartPos ) || + ( nStart < pLock->m_nEndPos && nEnd > pLock->m_nEndPos ) ) + return FALSE; + } + } + } + pLock = new InternalStreamLock( nStart, nEnd, pStream ); + return TRUE; +} + +void InternalStreamLock::UnlockFile( ULONG nStart, ULONG nEnd, SvFileStream* pStream ) +{ +#ifndef BOOTSTRAP + NAMESPACE_VOS( OGuard ) aGuard( LockMutex ); +#endif + InternalStreamLock* pLock = NULL; + if( nStart == 0 && nEnd == 0 ) + { + for( int i = 0; i < LockList.Count(); i++ ) + { + if( ( pLock = LockList.GetObject( i ) )->m_pStream == pStream ) + { + delete pLock; + i--; + } + } + return; + } + for( int i = 0; i < LockList.Count(); i++ ) + { + if( ( pLock = LockList.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 ULONG GetSvError( int nErrno ) +{ + static struct { int nErr; ULONG sv; } errArr[] = + { + { 0, SVSTREAM_OK }, + { EACCES, SVSTREAM_ACCESS_DENIED }, + { EBADF, SVSTREAM_INVALID_HANDLE }, +#if defined( RS6000 ) || defined( ALPHA ) || defined( HP9000 ) || defined( NETBSD ) || defined( S390 ) || defined(FREEBSD) || defined(MACOSX) + { 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) + { 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 } + }; + + ULONG 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 = FALSE; + nLockCounter = 0; + bIsWritable = FALSE; + pInstanceData = new StreamData; + + SetBufferSize( 1024 ); + // convert URL to SystemPath, if necessary + ::rtl::OUString aFileName, aNormPath; + if ( FileBase::getNormalizedPathFromFileURL( rFileName, aNormPath ) == FileBase::E_None ) + FileBase::getSystemPathFromNormalizedPath( aNormPath, aFileName ); + else + 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( 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 +|* +*************************************************************************/ + +ULONG SvFileStream::GetFileHandle() const +{ + return (ULONG)pInstanceData->nHandle; +} + +/************************************************************************* +|* +|* 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 +|* 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 += 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 (ULONG)nRead; +} + +/************************************************************************* +|* +|* 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 += 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 (ULONG)nWrite; +} + +/************************************************************************* +|* +|* SvFileStream::SeekPos() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 15.06.94 +|* Letzte Aenderung OV 15.06.94 +|* +*************************************************************************/ + +ULONG SvFileStream::SeekPos( ULONG 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 +|* +*************************************************************************/ + +BOOL SvFileStream::LockRange( ULONG nByteOffset, ULONG nBytes ) +{ + struct flock aflock; + aflock.l_start = nByteOffset; + aflock.l_whence = SEEK_SET; + aflock.l_len = nBytes; + + int nLockMode = 0; + + if ( ! IsOpen() ) + return 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 FALSE; + } + + if ( eStreamMode & STREAM_SHARE_DENYWRITE ) + if (bIsWritable) + nLockMode = F_WRLCK; + else + nLockMode = F_RDLCK; + + if (!nLockMode) + return TRUE; + + if( ! InternalStreamLock::LockFile( nByteOffset, nByteOffset+nBytes, this ) ) + { +#ifdef DEBUG + fprintf( stderr, "InternalLock on %s [ %d ... %d ] failed\n", + ByteString(aFilename, osl_getThreadTextEncoding()).GetBuffer(), nByteOffset, nByteOffset+nBytes ); +#endif + return 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 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 TRUE; + #endif + #if defined SINIX + if (errno == EINVAL) + return TRUE; + #endif + #if defined SOLARIS + if (errno == ENOSYS) + return TRUE; + #endif + SetError( ::GetSvError( errno )); + return FALSE; + } + if (aflock.l_type != F_UNLCK) + { + SetError(SVSTREAM_LOCKING_VIOLATION); + return FALSE; + } + + aflock.l_type = nLockMode; + if (fcntl(pInstanceData->nHandle, F_SETLK, &aflock) == -1) + { + SetError( ::GetSvError( errno )); + return FALSE; + } + return TRUE; +} + +/************************************************************************* +|* +|* SvFileStream::UnlockRange() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 15.06.94 +|* Letzte Aenderung OV 15.06.94 +|* +*************************************************************************/ + +BOOL SvFileStream::UnlockRange( ULONG nByteOffset, ULONG 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 FALSE; + + InternalStreamLock::UnlockFile( nByteOffset, nByteOffset+nBytes, this ); + + if ( ! (eStreamMode & + (STREAM_SHARE_DENYALL | STREAM_SHARE_DENYREAD | STREAM_SHARE_DENYWRITE))) + return TRUE; + + // wenn File Locking ausgeschaltet, siehe SvFileStream::LockRange + if ( ! pFileLockEnvVar ) + return TRUE; + + if (fcntl(pInstanceData->nHandle, F_SETLK, &aflock) != -1) + return 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 TRUE; +#endif +#if ( defined SINIX ) + if (errno == EINVAL) + return TRUE; +#endif + + SetError( ::GetSvError( errno )); + return FALSE; +} + +/************************************************************************* +|* +|* SvFileStream::LockFile() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 15.06.94 +|* Letzte Aenderung OV 15.06.94 +|* +*************************************************************************/ + +BOOL SvFileStream::LockFile() +{ + return LockRange( 0UL, 0UL ); +} + +/************************************************************************* +|* +|* SvFileStream::UnlockFile() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 15.06.94 +|* Letzte Aenderung OV 15.06.94 +|* +*************************************************************************/ + +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; + BOOL bStatValid = 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 = 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 = TRUE; + if ( nAccessRW != O_RDONLY ) + bIsWritable = TRUE; + + if ( !LockFile() ) // ganze Datei + { + close( nHandleTmp ); + bIsOpen = FALSE; + bIsWritable = 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 = FALSE; + 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 15.06.94 +|* Letzte Aenderung OV 15.06.94 +|* +*************************************************************************/ + +void SvFileStream::SetSize (ULONG nSize) +{ + if ( IsOpen() ) + { + if ( ftruncate ( pInstanceData->nHandle, (off_t) nSize ) == -1 ) + SetError ( ::GetSvError( errno )); + } +} + + diff --git a/tools/source/stream/strmwnt.cxx b/tools/source/stream/strmwnt.cxx new file mode 100644 index 000000000000..3d219a84bfd4 --- /dev/null +++ b/tools/source/stream/strmwnt.cxx @@ -0,0 +1,892 @@ +/************************************************************************* + * + * $RCSfile: strmwnt.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +/* + Todo: StreamMode <-> AllocateMemory +*/ + +#include <string.h> +#include <limits.h> + +#include <svwin.h> + +#include <debug.hxx> +#include <fsys.hxx> +#include <stream.hxx> + +// class FileBase +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif +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::getNormalizedPathFromFileURL( rFileName, aNormPath ) == FileBase::E_None ) + FileBase::getSystemPathFromNormalizedPath( aNormPath, aFileName ); + else + 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() ) ); + } +} + +/************************************************************************* +|* +|* ImpAlloc() +|* +|* Beschreibung Legt SharedMemory an +|* Ersterstellung OV 28.09.95 +|* Letzte Aenderung OV 28.09.95 +|* +*************************************************************************/ + +static BYTE* ImpAlloc( ULONG nSize, HANDLE& rHandle ) +{ + rHandle = 0; + HANDLE aHandle = CreateFileMapping((HANDLE)0xffffffff, + (LPSECURITY_ATTRIBUTES)0,PAGE_READWRITE,0,nSize,0); + if( !aHandle ) + return 0; + BYTE* pBuf = (BYTE*)MapViewOfFile(aHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if( !pBuf ) + { + CloseHandle( aHandle ); + return 0; + } + rHandle = aHandle; + return pBuf; +} + +/************************************************************************* +|* +|* ImpFree() +|* +|* Beschreibung Gibt SharedMemory frei +|* Ersterstellung OV 28.09.95 +|* Letzte Aenderung OV 28.09.95 +|* +*************************************************************************/ + +static void ImpFree( BYTE* pBuf, HANDLE aHandle ) +{ + if( pBuf ) + { + UnmapViewOfFile( pBuf ); + pBuf = 0; + } + CloseHandle( aHandle ); +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::AllocateMemory() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 28.09.95 +|* Letzte Aenderung OV 28.09.95 +|* +*************************************************************************/ + +BOOL SvSharedMemoryStream::AllocateMemory( ULONG nNewSize ) +{ + HANDLE aWNTHandle; + pBuf = ImpAlloc( nNewSize, aWNTHandle ); + if( !pBuf ) + return FALSE; + aHandle = (void*)aWNTHandle; + return TRUE; +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::ReAllocateMemory() +|* +|* Beschreibung STREAM.SDW (Bozo-Algorithmus) +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +BOOL SvSharedMemoryStream::ReAllocateMemory( long nDiff ) +{ + BOOL bRetVal = FALSE; + ULONG nNewSize = nSize + nDiff; + if( nNewSize ) + { + HANDLE aNewHandle; + BYTE* pNewBuf = ImpAlloc( nNewSize, aNewHandle ); + 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 ); + + ImpFree( pBuf, (HANDLE)aHandle ); + pBuf = pNewBuf; + nSize = nNewSize; + aHandle = (void*)aNewHandle; + } + } + else + { + FreeMemory(); + bRetVal = TRUE; + pBuf = 0; + nSize = 0; + nEndOfData = 0; + nPos = 0; + aHandle = 0; + } + return bRetVal; +} + +/************************************************************************* +|* +|* SvSharedMemoryStream::FreeMemory() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung CL 05.05.95 +|* Letzte Aenderung CL 05.05.95 +|* +*************************************************************************/ + +void SvSharedMemoryStream::FreeMemory() +{ + ImpFree( pBuf, (HANDLE)aHandle ); + aHandle = 0; +} + + +/************************************************************************* +|* +|* SvSharedMemoryStream::SetHandle() +|* +|* Beschreibung STREAM.SDW +|* Ersterstellung OV 05.10.95 +|* Letzte Aenderung OV 05.10.95 +|* +*************************************************************************/ + + +void* SvSharedMemoryStream::SetHandle( void* aNewHandle, ULONG nSize, + BOOL bOwnsData, ULONG nEOF ) +{ + void* pLocalBuf = MapViewOfFile(aNewHandle,FILE_MAP_ALL_ACCESS,0,0,0); + if( !pLocalBuf ) + { + SetError( SVSTREAM_OUTOFMEMORY ); + return 0; + } + if( aNewHandle == aHandle ) + { + // den aktuellen Handle temporaer auf Null setzen, damit FreeMemory + // (wird u.U. von SetBuffer aufgerufen) nicht den Handle schliesst, + // sondern nur die View loescht + aHandle = 0; + } + pLocalBuf = SetBuffer( pLocalBuf, nSize, bOwnsData, nEOF ); + aHandle = aNewHandle; + return pLocalBuf; +} + + diff --git a/tools/source/stream/vcompat.cxx b/tools/source/stream/vcompat.cxx new file mode 100644 index 000000000000..2e80897db707 --- /dev/null +++ b/tools/source/stream/vcompat.cxx @@ -0,0 +1,116 @@ +/************************************************************************* + * + * $RCSfile: vcompat.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _VCOMPAT_CXX + +#ifndef _STREAM_HXX +#include "stream.hxx" +#endif +#ifndef _VCOMPAT_HXX +#include "vcompat.hxx" +#endif + +// ----------------- +// - 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/makefile.mk b/tools/source/string/makefile.mk new file mode 100644 index 000000000000..a0005f53cec4 --- /dev/null +++ b/tools/source/string/makefile.mk @@ -0,0 +1,88 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=str + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/tstring.obj \ + $(SLO)$/tustring.obj \ + $(SLO)$/charset.obj + +.IF "$(UPDATER)"!="" +OBJFILES= $(OBJ)$/tstring.obj \ + $(OBJ)$/tustring.obj \ + $(OBJ)$/charset.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/tools/source/string/strascii.cxx b/tools/source/string/strascii.cxx new file mode 100644 index 000000000000..9b54b920a2c2 --- /dev/null +++ b/tools/source/string/strascii.cxx @@ -0,0 +1,773 @@ +/************************************************************************* + * + * $RCSfile: strascii.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +// ======================================================================= + +#ifdef DBG_UTIL + +static BOOL ImplDbgCheckAsciiStr( const sal_Char* pAsciiStr, xub_StrLen 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, + xub_StrLen 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 ) + { + if ( nLen > STRING_MAXLEN ) + nLen = STRING_MAXLEN; + 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 ) + { + if ( nLen > STRING_MAXLEN ) + nLen = STRING_MAXLEN; + 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 ) + { + ImplDeleteData( mpData ); + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } + 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 + ImplDeleteData( 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 ) + { + ImplDeleteData( mpData ); + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } + 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 + ImplDeleteData( 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 + xub_StrLen 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 + ImplDeleteData( 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 + xub_StrLen 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 + ImplDeleteData( 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 + xub_StrLen 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 = 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 + ImplDeleteData( 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 ( (ULONG)nIndex+nCount > mpData->mnLen ) + nCount = mpData->mnLen-nIndex; + + // Reicht eine zeichenweise Zuweisung + if ( nCount == nStrLen ) + { + ImplCopyData( this ); + ImplCopyAsciiStr( mpData->maStr+nIndex, pAsciiStr, nStrLen ); + 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 ) ); + ImplCopyAsciiStr( pNewData->maStr+nIndex, pAsciiStr, nStrLen ); + memcpy( pNewData->maStr+nIndex+nStrLen, mpData->maStr+nIndex+nCount, + (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) ); + + // Alte Daten loeschen und Neue zuweisen + ImplDeleteData( 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" ); + + xub_StrLen 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 ( (ULONG)nIndex+nStrLen <= nLen ) + { + // 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 += rRepStr.Len(); + nSPos = SearchAscii( pAsciiStr, nSPos ); + } +} + +// ======================================================================= + +#ifndef ENABLEUNICODE + +ByteString ByteString::CreateFromAscii( const sal_Char* pAsciiStr ) +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ), + "ByteString::CreateFromAscii() - pAsciiStr include characters > 127" ); + + return ByteString( pAsciiStr ); +} + +// ----------------------------------------------------------------------- + +ByteString ByteString::CreateFromAscii( const sal_Char* pAsciiStr, xub_StrLen nLen ) +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, nLen ), + "ByteString::CreateFromAscii() - pAsciiStr include characters > 127" ); + + return ByteString( pAsciiStr, nLen ); +} + +// ----------------------------------------------------------------------- + +ByteString& ByteString::AssignAscii( const sal_Char* pAsciiStr ) +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ), + "ByteString::AssignAscii() - pAsciiStr include characters > 127" ); + + return Assign( pAsciiStr ); +} + +// ----------------------------------------------------------------------- + +ByteString& ByteString::AssignAscii( const sal_Char* pAsciiStr, xub_StrLen nLen ) +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, nLen ), + "ByteString::AssignAscii() - pAsciiStr include characters > 127" ); + + return Assign( pAsciiStr, nLen ); +} + +// ----------------------------------------------------------------------- + +ByteString& ByteString::AppendAscii( const sal_Char* pAsciiStr, xub_StrLen nLen ) +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, nLen ), + "ByteString::AppendAscii() - pAsciiStr include characters > 127" ); + + return Append( pAsciiStr, nLen ); +} + +// ----------------------------------------------------------------------- + +StringCompare ByteString::CompareToAscii( const sal_Char* pAsciiStr, + xub_StrLen nLen ) const +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, nLen ), + "ByteString::CompareToAscii() - pAsciiStr include characters > 127" ); + + return CompareTo( pAsciiStr, nLen ); +} + +// ----------------------------------------------------------------------- + +BOOL ByteString::EqualsAscii( const sal_Char* pAsciiStr ) const +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ), + "ByteString::EqualsAscii() - pAsciiStr include characters > 127" ); + + return Equals( pAsciiStr ); +} + +// ----------------------------------------------------------------------- + +xub_StrLen ByteString::SearchAscii( const sal_Char* pAsciiStr, xub_StrLen nIndex ) const +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ), + "ByteString::SearchAscii() - pAsciiStr include characters > 127" ); + + return Search( pAsciiStr, nIndex ); +} + +// ----------------------------------------------------------------------- + +xub_StrLen ByteString::SearchAndReplaceAscii( const sal_Char* pAsciiStr, const ByteString& rRepStr, + xub_StrLen nIndex ) +{ + DBG_ASSERT( ImplDbgCheckAsciiStr( pAsciiStr, STRING_LEN ), + "ByteString::SearchAscii() - pAsciiStr include characters > 127" ); + + return SearchAndReplace( pAsciiStr, rRepStr, nIndex ); +} + +#endif diff --git a/tools/source/string/strcvt.cxx b/tools/source/string/strcvt.cxx new file mode 100644 index 000000000000..cd6e84a918c8 --- /dev/null +++ b/tools/source/string/strcvt.cxx @@ -0,0 +1,757 @@ +/************************************************************************* + * + * $RCSfile: strcvt.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +// ======================================================================= + +static ByteStringData* ImplGetStringDataFromUniString( const sal_Unicode* pUniStr, sal_Size nUniLen, + rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags ) +{ + DBG_ASSERT( (eTextEncoding != 9) && + (eTextEncoding != RTL_TEXTENCODING_DONTKNOW) && + (eTextEncoding != RTL_TEXTENCODING_UCS2) && + (eTextEncoding != RTL_TEXTENCODING_UCS4), + "UniString-->ByteString: Wrong TextEncoding" ); + + if ( !nUniLen ) + { + ImplIncRefCount( &aImplEmptyStrData ); + return &aImplEmptyStrData; + } + +#ifndef NOOLDSTRING + if ( eTextEncoding == CHARSET_SYSTEM ) + eTextEncoding = GetSystemCharSet(); +#endif + nCvtFlags |= RTL_UNICODETOTEXT_FLAGS_FLUSH; + + ByteStringData* pData; + rtl_TextEncodingInfo aTextEncInfo; + rtl_UnicodeToTextConverter hConverter = rtl_createUnicodeToTextConverter( eTextEncoding ); + sal_uInt32 nInfo; + sal_Size nSrcChars; + sal_Size nDestBytes; + sal_Size nNewLen; + + // get TextEncodingInfo + aTextEncInfo.StructSize = sizeof( aTextEncInfo ); + rtl_getTextEncodingInfo( eTextEncoding, &aTextEncInfo ); + + // Zuerst konvertieren wir mit der wahrscheinlichen Anzahl + // der zu konvertierenden Zeichen + nNewLen = nUniLen*aTextEncInfo.AverageCharSize; + if ( nNewLen > STRING_MAXLEN ) + nNewLen = STRING_MAXLEN; + pData = ImplAllocData( (xub_StrLen)nNewLen ); + nDestBytes = rtl_convertUnicodeToText( hConverter, 0, + pUniStr, nUniLen, + (sal_Char*)pData->maStr, nNewLen, + nCvtFlags, + &nInfo, &nSrcChars ); + // Solange versuchen zu konvertieren, bis der Buffer ausreicht, oder + // die maximale Stringlaenge erreicht ist + while ( (nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) && + (nNewLen != STRING_MAXLEN) ) + { + rtl_freeMemory( pData ); + + // Dann mit der maximalen Anzahl der Zeichen versuchen + // und etwas mehr Overhead geben, falls nicht zu konvertierende + // Zeichen durch mehrere Ersatzzeichen ersetzt werden + sal_Size nNotConvertedChars = nUniLen-nSrcChars; + nNewLen = nDestBytes+(nNotConvertedChars*aTextEncInfo.MaximumCharSize)+ + nNotConvertedChars+4; + if ( nNewLen > STRING_MAXLEN ) + nNewLen = STRING_MAXLEN; + pData = ImplAllocData( (xub_StrLen)nNewLen ); + nDestBytes = rtl_convertUnicodeToText( hConverter, 0, + pUniStr, nUniLen, + (sal_Char*)pData->maStr, nNewLen, + nCvtFlags, + &nInfo, &nSrcChars ); + } + + // String entsprechend der durch das Konvertieren tatsaechlich + // entstehenden Bytes anpassen + if ( !nDestBytes ) + { + rtl_freeMemory( pData ); + ImplIncRefCount( &aImplEmptyStrData ); + pData = &aImplEmptyStrData; + } + else if ( nNewLen > nDestBytes+8 ) + { + ByteStringData* pTempData = ImplAllocData( (xub_StrLen)nDestBytes ); + memcpy( pTempData->maStr, pData->maStr, nDestBytes ); + rtl_freeMemory( pData ); + pData = pTempData; + } + else + { + pData->mnLen = (xub_StrLen)nDestBytes; + pData->maStr[nDestBytes] = '\0'; + } + rtl_destroyUnicodeToTextConverter( hConverter ); + return pData; +} + +// ----------------------------------------------------------------------- + +static void ImplUpdateStringFromUniString( ByteString* pString, + const sal_Unicode* pUniStr, sal_Size nUniLen, + rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags ) +{ + ByteStringData* pNewStringData; + pNewStringData = ImplGetStringDataFromUniString( pUniStr, nUniLen, eTextEncoding, nCvtFlags ); + ImplDeleteData( pString->mpData ); + pString->mpData = pNewStringData; +} + +// ======================================================================= + +#ifndef ENABLEUNICODE +void ByteString::InitStringRes( const UniString& rUniStr ) +{ + DBG_CTOR( ByteString, DbgCheckByteString ); + DBG_CHKOBJ( &rUniStr, UniString, DbgCheckUniString ); + + mpData = ImplGetStringDataFromUniString( rUniStr.mpData->maStr, rUniStr.mpData->mnLen, + gsl_getSystemTextEncoding(), + 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 ); +} +#endif + +// ======================================================================= + +ByteString::ByteString( const UniString& rUniStr, rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags ) +{ + DBG_CTOR( ByteString, DbgCheckByteString ); + DBG_CHKOBJ( &rUniStr, UniString, DbgCheckUniString ); + + mpData = ImplGetStringDataFromUniString( 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 + xub_StrLen nMaxLen = rUniStr.mpData->mnLen-nPos; + if ( nLen > nMaxLen ) + nLen = nMaxLen; + } + + mpData = ImplGetStringDataFromUniString( 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 = ImplGetStringDataFromUniString( 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 = ImplGetStringDataFromUniString( 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; +} + +// ======================================================================= + +static void ImplStringConvert( ByteString* pString, + rtl_TextEncoding eSource, rtl_TextEncoding eTarget, + BOOL bReplace ) +{ + sal_uChar* pConvertTab = ImplGet1ByteConvertTab( eSource, eTarget, bReplace ); + if ( pConvertTab ) + { + char* pStr = pString->mpData->maStr; + while ( *pStr ) + { + sal_uChar c = (sal_uChar)*pStr; + sal_uChar cConv = pConvertTab[c]; + if ( c != cConv ) + { + pStr = ImplCopyStringData( pString, 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 = pString->mpData->mnLen; + pTempBuf = new sal_Unicode[nTempLen]; + nDestChars = rtl_convertTextToUnicode( hSrcConverter, 0, + pString->mpData->maStr, pString->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( pString, 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; + +#ifndef NOOLDSTRING + if ( eSource == CHARSET_SYSTEM ) + eSource = GetSystemCharSet(); + if ( eTarget == CHARSET_SYSTEM ) + eTarget = GetSystemCharSet(); +#endif + + // 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( this, 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'; + +#ifndef NOOLDSTRING + if ( eSource == CHARSET_SYSTEM ) + eSource = GetSystemCharSet(); + if ( eTarget == CHARSET_SYSTEM ) + eTarget = GetSystemCharSet(); +#endif + + // 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; +#ifndef NOOLDSTRING + else if ( eTextEncoding == CHARSET_SYSTEM ) + eTextEncoding = GetSystemCharSet(); +#endif + + 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'; +#ifndef NOOLDSTRING + else if ( eTextEncoding == CHARSET_SYSTEM ) + eTextEncoding = GetSystemCharSet(); +#endif + + 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 NAMESPACE_RTL(OString)& rStr ) +{ + DBG_CTOR( ByteString, DbgCheckByteString ); + + mpData = (ByteStringData*)rStr.pData; + ImplIncRefCount( mpData ); +} + +// ----------------------------------------------------------------------- + +NAMESPACE_RTL(OString)::OString( const ByteString& rStr ) +{ + pData = (rtl_String*)rStr.mpData; + rtl_string_acquire( pData ); +} + +// ----------------------------------------------------------------------- + +ByteString& ByteString::Assign( const NAMESPACE_RTL(OString)& rStr ) +{ + DBG_CHKTHIS( ByteString, DbgCheckByteString ); + + rtl_string_acquire( rStr.pData ); + ImplDeleteData( mpData ); + mpData = (ByteStringData*)rStr.pData; + return *this; +} diff --git a/tools/source/string/strimp.cxx b/tools/source/string/strimp.cxx new file mode 100644 index 000000000000..0b667f14e6c4 --- /dev/null +++ b/tools/source/string/strimp.cxx @@ -0,0 +1,2306 @@ +/************************************************************************* + * + * $RCSfile: strimp.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +// ======================================================================= + +// Daten des Strings fuer einen NULL-String +static STRINGDATA aImplEmptyStrData = { 1, 0, 0 }; + +// ======================================================================= + +static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2 ) +{ + sal_Int32 nRet; +#if STRCODE == sal_Unicode + while ( ((nRet = ((sal_Int32)*pStr1)-((sal_Int32)*pStr2)) == 0) && + *pStr2 ) +#else + while ( ((nRet = ((sal_Int32)((unsigned STRCODE)*pStr1))-((sal_Int32)((unsigned STRCODE)*pStr2))) == 0) && + *pStr2 ) +#endif + { + pStr1++; + pStr2++; + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2, + xub_StrLen nCount ) +{ + sal_Int32 nRet = 0; +#if STRCODE == sal_Unicode + while ( nCount && + ((nRet = ((sal_Int32)*pStr1)-((sal_Int32)*pStr2)) == 0) && + *pStr2 ) +#else + while ( nCount && + ((nRet = ((sal_Int32)((unsigned STRCODE)*pStr1))-((sal_Int32)((unsigned STRCODE)*pStr2))) == 0) && + *pStr2 ) +#endif + { + pStr1++; + pStr2++; + nCount--; + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +static sal_Int32 ImplStringCompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2, + xub_StrLen nCount ) +{ + sal_Int32 nRet = 0; +#if STRCODE == sal_Unicode + while ( nCount && + ((nRet = ((sal_Int32)*pStr1)-((sal_Int32)*pStr2)) == 0) ) +#else + while ( nCount && + ((nRet = ((sal_Int32)((unsigned STRCODE)*pStr1))-((sal_Int32)((unsigned STRCODE)*pStr2))) == 0) ) +#endif + { + 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; +#if STRCODE == sal_Unicode + nRet = ((sal_Int32)c1)-((sal_Int32)c2); +#else + nRet = ((sal_Int32)((unsigned STRCODE)c1))-((sal_Int32)((unsigned STRCODE)c2)); +#endif + 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; +#if STRCODE == sal_Unicode + nRet = ((sal_Int32)c1)-((sal_Int32)c2); +#else + nRet = ((sal_Int32)((unsigned STRCODE)c1))-((sal_Int32)((unsigned STRCODE)c2)); +#endif + if ( nRet != 0 ) + break; + + pStr1++; + pStr2++; + nCount--; + } + while ( c2 ); + + return nRet; +} + +// ----------------------------------------------------------------------- + +static sal_Int32 ImplStringICompareWithoutZero( 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; +#if STRCODE == sal_Unicode + nRet = ((sal_Int32)c1)-((sal_Int32)c2); +#else + nRet = ((sal_Int32)((unsigned STRCODE)c1))-((sal_Int32)((unsigned STRCODE)c2)); +#endif + + pStr1++; + pStr2++; + nCount--; + } + while ( nRet == 0 ); + + return nRet; +} + +// ======================================================================= + +#ifdef DBG_UTIL +const char* DBGCHECKSTRING( const void* pString ) +{ + STRING* p = (STRING*)pString; + + if ( p->mpData->maStr[p->mpData->mnLen] != 0 ) + return "String damaged: aStr[nLen] != 0"; + + return NULL; +} +#endif + +// ======================================================================= + +static STRINGDATA* ImplAllocData( xub_StrLen 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 void _ImplDeleteData( STRINGDATA* pStrData ) +{ + // alle referenzierten Strings koennen zur gleichen Zeit geloescht + // wurden sein, somit muss hier noch geprueft werden, ob ich + // der letzte gleichzeitig zerstoerte String bin + if ( !osl_decrementInterlockedCount(&pStrData->mnRefCount) ) + { + DBG_ASSERT( aImplEmptyStrData.mnRefCount != 0, "String::ImplIncRefCount() - EmptyStr RefCount == 0" ); + rtl_freeMemory( pStrData ); + } +} + +// ----------------------------------------------------------------------- + +inline void ImplDeleteData( STRINGDATA* pStrData ) +{ + DBG_ASSERT( aImplEmptyStrData.mnRefCount != 0, "String::ImplIncRefCount() - EmptyStr RefCount == 0" ); + + // Ist der ReferenzCounter groesser 0 + if ( pStrData->mnRefCount == 1 ) + rtl_freeMemory( pStrData ); + else + _ImplDeleteData( pStrData ); +} + +// ----------------------------------------------------------------------- + +static STRINGDATA* _ImplCopyData( STRINGDATA* pData ) +{ + xub_StrLen nSize = sizeof(STRINGDATA)+(pData->mnLen*sizeof( STRCODE )); + STRINGDATA* pNewData = (STRINGDATA*)rtl_allocateMemory( nSize ); + memcpy( pNewData, pData, nSize ); + pNewData->mnRefCount = 1; + _ImplDeleteData( pData ); + return pNewData; +} + +// ----------------------------------------------------------------------- + +inline void ImplCopyData( STRING* pString ) +{ + DBG_ASSERT( (pString->mpData->mnRefCount > 0), "String::ImplCopyData() - RefCount == 0" ); + DBG_ASSERT( aImplEmptyStrData.mnRefCount != 0, "String::ImplIncRefCount() - EmptyStr RefCount == 0" ); + + // ist es ein referenzierter String, dann die Daten abkoppeln + if ( pString->mpData->mnRefCount != 1 ) + pString->mpData = _ImplCopyData( pString->mpData ); +} + +// ----------------------------------------------------------------------- + +static STRCODE* _ImplCopyStringData( STRING* pString, STRCODE* pStr ) +{ + DBG_ASSERT( (pStr >= pString->mpData->maStr) && + ((pStr-pString->mpData->maStr) < pString->mpData->mnLen), + "ImplCopyStringData - pStr from other String-Instanz" ); + + unsigned int nIndex = (unsigned int)(pStr-pString->mpData->maStr); + pString->mpData = _ImplCopyData( pString->mpData ); + pStr = pString->mpData->maStr + nIndex; + return pStr; +} + +// ----------------------------------------------------------------------- + +inline STRCODE* ImplCopyStringData( STRING* pString, STRCODE* pStr ) +{ + // Ist der Referenzzaehler groesser 0 + if ( pString->mpData->mnRefCount != 1 ) + pStr = _ImplCopyStringData( pString, pStr ); + return pStr; +} + +// ----------------------------------------------------------------------- + +inline void ImplIncRefCount( STRINGDATA* pData ) +{ + osl_incrementInterlockedCount( &pData->mnRefCount ); +} + +// ----------------------------------------------------------------------- + +inline xub_StrLen ImplGetCopyLen( xub_StrLen nStrLen, xub_StrLen nCopyLen ) +{ + if ( (ULONG)nStrLen+nCopyLen > STRING_MAXLEN ) + nCopyLen = STRING_MAXLEN-nStrLen; + return nCopyLen; +} + +// ======================================================================= + +STRING::STRING() +{ + DBG_CTOR( STRING, DBGCHECKSTRING ); + + // Leerer String + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; +} + +// ----------------------------------------------------------------------- + +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 + ImplIncRefCount( rStr.mpData ); + mpData = rStr.mpData; +} + +// ----------------------------------------------------------------------- + +STRING::STRING( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen ) +{ + DBG_CTOR( STRING, DBGCHECKSTRING ); + DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING ); + + // Stringlaenge ermitteln + if ( nPos > rStr.mpData->mnLen ) + nLen = 0; + else + { + // Laenge korrigieren, wenn noetig + xub_StrLen nMaxLen = rStr.mpData->mnLen-nPos; + if ( nLen > nMaxLen ) + nLen = nMaxLen; + } + + // Ist es kein leerer String + if ( nLen ) + { + // Reicht ein einfaches erhoehen des Referenzcounters + if ( (nPos == 0) && (nLen == rStr.mpData->mnLen) ) + { + ImplIncRefCount( 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 + { + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } +} + +// ----------------------------------------------------------------------- + +STRING::STRING( const STRCODE* pCharStr ) +{ + 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 ) + { + if ( nLen > STRING_MAXLEN ) + nLen = STRING_MAXLEN; + + // Verwaltungsdaten anlegen und String kopieren + mpData = ImplAllocData( nLen ); + memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) ); + } + else + { + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } +} + +// ----------------------------------------------------------------------- + +STRING::STRING( const STRCODE* pCharStr, xub_StrLen nLen ) +{ + 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 ) + { + if ( nLen > STRING_MAXLEN ) + nLen = STRING_MAXLEN; + + // Verwaltungsdaten anlegen und String kopieren + mpData = ImplAllocData( nLen ); + memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) ); + } + else + { + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } +} + +// ----------------------------------------------------------------------- + +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 + ImplDeleteData( mpData ); +} + +// ----------------------------------------------------------------------- + +STRING& STRING::Assign( const STRING& rStr ) +{ + DBG_CHKTHIS( STRING, DBGCHECKSTRING ); + DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING ); + + ImplIncRefCount( rStr.mpData ); + ImplDeleteData( 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 +#ifdef NOOLDSTRING + xub_StrLen nLen = ImplStringLen( pCharStr ); +#else + xub_StrLen nLen; + if ( pCharStr ) + nLen = ImplStringLen( pCharStr ); + else + nLen = 0; +#endif + + if ( !nLen ) + { + ImplDeleteData( mpData ); + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } + 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 + ImplDeleteData( 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 ) + { + ImplDeleteData( mpData ); + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } + 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 + ImplDeleteData( 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 + ImplDeleteData( 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 + xub_StrLen nLen = mpData->mnLen; + if ( !nLen ) + { + ImplIncRefCount( rStr.mpData ); + ImplDeleteData( mpData ); + mpData = rStr.mpData; + } + else + { + // Ueberlauf abfangen + xub_StrLen 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 + ImplDeleteData( 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 + xub_StrLen nLen = mpData->mnLen; +#ifdef NOOLDSTRING + xub_StrLen nCopyLen = ImplStringLen( pCharStr ); +#else + xub_StrLen nCopyLen; + if ( pCharStr ) + nCopyLen = ImplStringLen( pCharStr ); + else + nCopyLen = 0; +#endif + + // 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 + ImplDeleteData( 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 + xub_StrLen nLen = mpData->mnLen; + xub_StrLen 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 + ImplDeleteData( mpData ); + mpData = pNewData; + } + + return *this; +} + +// ----------------------------------------------------------------------- + +STRING& STRING::Append( STRCODE c ) +{ + DBG_CHKTHIS( STRING, DBGCHECKSTRING ); + + // kein 0-Character und maximale Stringlaenge nicht ueberschreiten + xub_StrLen 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 + ImplDeleteData( 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( this ); + mpData->maStr[nIndex] = c; +} + +// ----------------------------------------------------------------------- + +STRING& STRING::Insert( const STRING& rStr, xub_StrLen nIndex ) +{ + DBG_CHKTHIS( STRING, DBGCHECKSTRING ); + DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING ); + + // Ueberlauf abfangen + xub_StrLen 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 = 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 + ImplDeleteData( 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 + xub_StrLen nMaxLen = rStr.mpData->mnLen-nPos; + if ( nLen > nMaxLen ) + nLen = nMaxLen; + } + + // Ueberlauf abfangen + xub_StrLen nCopyLen = ImplGetCopyLen( mpData->mnLen, nLen ); + + // Ist der einzufuegende String ein Leerstring + if ( !nCopyLen ) + return *this; + + // Index groesser als Laenge + if ( nIndex > mpData->mnLen ) + nIndex = 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 + ImplDeleteData( 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 + xub_StrLen 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 = 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 + ImplDeleteData( 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 = 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 + ImplDeleteData( 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 + xub_StrLen nStrLen = rStr.mpData->mnLen; + if ( !nStrLen ) + return Erase( nIndex, nCount ); + + // nCount darf nicht ueber das Stringende hinnausgehen + if ( (ULONG)nIndex+nCount > mpData->mnLen ) + nCount = mpData->mnLen-nIndex; + + // Reicht ein Insert + if ( !nCount ) + return Insert( rStr, nIndex ); + + // Reicht eine zeichenweise Zuweisung + if ( nCount == nStrLen ) + { + ImplCopyData( this ); + 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 + ImplDeleteData( 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 ( (ULONG)nIndex+nCount > mpData->mnLen ) + nCount = 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 + ImplDeleteData( mpData ); + mpData = pNewData; + } + else + { + // Leerer String + ImplDeleteData( mpData ); + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } + + 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 ) + { + // Auf max. Laenge beschraenken + if ( nCount > STRING_MAXLEN ) + nCount = STRING_MAXLEN; + + // dann neuen String mit der neuen Laenge anlegen + STRINGDATA* pNewData = ImplAllocData( nCount ); + ImplDeleteData( mpData ); + mpData = pNewData; + } + else + ImplCopyData( this ); + + 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 + xub_StrLen 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; + nCount -= nLen; + do + { + *pStr = cExpandChar; + pStr++; + nCount--; + } + while ( nCount ); + + // Alte Daten loeschen und Neue zuweisen + ImplDeleteData( 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 ); + + xub_StrLen nEnd = mpData->mnLen; + while ( nEnd && (mpData->maStr[nEnd-1] == c) ) + nEnd--; + + if ( nEnd != mpData->mnLen ) + Erase( 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 ); + + xub_StrLen nEnd = mpData->mnLen; + while ( nEnd && (mpData->maStr[nEnd-1] == c) ) + nEnd--; + if ( nEnd != mpData->mnLen ) + Erase( nEnd ); + + return *this; +} + +// ----------------------------------------------------------------------- + +STRING& STRING::EraseAllChars( STRCODE c ) +{ + DBG_CHKTHIS( STRING, DBGCHECKSTRING ); + + xub_StrLen nCount = 0; + xub_StrLen i = 0; + while ( i < mpData->mnLen ) + { + if ( mpData->maStr[i] == c ) + nCount++; + i++; + } + + if ( nCount ) + { + if ( nCount == mpData->mnLen ) + { + ImplDeleteData( mpData ); + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } + else + { + // Neuen String anlegen + STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount ); + + // Alten String kopieren und initialisieren + nCount = 0; + for( xub_StrLen i = 0; i < mpData->mnLen; i++ ) + { + if ( mpData->maStr[i] != c ) + { + pNewData->maStr[nCount] = mpData->maStr[i]; + nCount++; + } + } + + // Alte Daten loeschen und Neue zuweisen + ImplDeleteData( mpData ); + mpData = pNewData; + } + } + + return *this; +} + +// ----------------------------------------------------------------------- + +STRING& STRING::Reverse() +{ + DBG_CHKTHIS( STRING, DBGCHECKSTRING ); + + if ( !mpData->mnLen ) + return *this; + + // Daten kopieren, wenn noetig + ImplCopyData( this ); + + // Reverse + STRCODE cTemp; + xub_StrLen nCount = mpData->mnLen / 2; + for ( xub_StrLen i = 0; i < nCount; i++ ) + { + 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 ); + + xub_StrLen nIndex = 0; + xub_StrLen 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( this, pStr ); + *pStr += 32; + } + + pStr++; + nIndex++; + } + + return *this; +} + +// ----------------------------------------------------------------------- + +STRING& STRING::ToUpperAscii() +{ + DBG_CHKTHIS( STRING, DBGCHECKSTRING ); + + xub_StrLen nIndex = 0; + xub_StrLen 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( this, 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 += 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 + ImplDeleteData( 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 = mpData->mnLen+1; + if ( rStr.mpData->mnLen < nLen ) + nLen = 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 = mpData->mnLen+1; + if ( rStr.mpData->mnLen < nLen ) + nLen = 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); + xub_StrLen nMaxLen = mpData->mnLen-nIndex; + if ( nMaxLen < nLen ) + { + if ( rStr.mpData->mnLen != nMaxLen ) + return FALSE; + nLen = 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); + xub_StrLen nMaxLen = mpData->mnLen-nIndex; + if ( nMaxLen < nLen ) + { + if ( rStr.mpData->mnLen != nMaxLen ) + return FALSE; + nLen = 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 ); + + xub_StrLen 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 ); + + xub_StrLen nLen = mpData->mnLen; + xub_StrLen 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 ( (ULONG)nIndex+nStrLen <= nLen ) + { + // 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 ); + + xub_StrLen 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 ( (ULONG)nIndex+nStrLen <= nLen ) + { + // 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 ); + + xub_StrLen 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 ); + + xub_StrLen nLen = mpData->mnLen; + const STRCODE* pStr = mpData->maStr; + pStr += nIndex; + while ( nIndex < nLen ) + { + if ( *pStr == c ) + { + ImplCopyData( this ); + 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 ); + + xub_StrLen nLen = mpData->mnLen; + const STRCODE* pStr = mpData->maStr; + xub_StrLen nIndex = 0; + while ( nIndex < nLen ) + { + if ( *pStr == c ) + { + ImplCopyData( this ); + 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 += 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 += 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; + xub_StrLen nLen = mpData->mnLen; + const STRCODE* pStr = mpData->maStr; + xub_StrLen 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; + xub_StrLen nLen = mpData->mnLen; + xub_StrLen nQuotedLen = rQuotedPairs.Len(); + STRCODE cQuotedEndChar = 0; + const STRCODE* pQuotedStr = rQuotedPairs.mpData->maStr; + const STRCODE* pStr = mpData->maStr; + xub_StrLen 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( this ); + + // 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 ); + + if ( !nLen ) + { + ImplDeleteData( mpData ); + ImplIncRefCount( &aImplEmptyStrData ); + mpData = &aImplEmptyStrData; + } + // Bei mehr als 8 Zeichen unterschied, kuerzen wir den Buffer + else if ( ((ULONG)nLen)+8 < mpData->mnLen ) + { + STRINGDATA* pNewData = ImplAllocData( nLen ); + memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) ); + ImplDeleteData( mpData ); + mpData = pNewData; + } + else + mpData->mnLen = nLen; +} + +// ----------------------------------------------------------------------- + +STRCODE* STRING::AllocBuffer( xub_StrLen nLen ) +{ + DBG_CHKTHIS( STRING, DBGCHECKSTRING ); + + // Vorhandene Daten loeschen und neue anlegen + ImplDeleteData( mpData ); + if ( nLen ) + mpData = ImplAllocData( nLen ); + else + mpData = &aImplEmptyStrData; + + // Pointer auf den angelegten Buffer zurueckgeben + return mpData->maStr; +} + +// ----------------------------------------------------------------------- +#ifndef NOOLDSTRING +STRING operator + ( const STRING& rStr1, const STRING& rStr2 ) +{ + DBG_CHKOBJ( &rStr1, STRING, DBGCHECKSTRING ); + DBG_CHKOBJ( &rStr2, STRING, DBGCHECKSTRING ); + DBG_WARNING( "String::operator+(): Use String::operator+=() for better performence and smaller code" ); + + STRING aTmpStr( rStr1 ); + aTmpStr += rStr2; + return aTmpStr; +} + +// ----------------------------------------------------------------------- + +STRING operator + ( const STRING& rStr, const STRCODE* pCharStr ) +{ + DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING ); + DBG_WARNING( "String::operator+(): Use String::operator+=() for better performence and smaller code" ); + + STRING aTmpStr( rStr ); + aTmpStr += pCharStr; + return aTmpStr; +} + +// ----------------------------------------------------------------------- + +STRING operator + ( const STRCODE* pCharStr, const STRING& rStr ) +{ + DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING ); + DBG_WARNING( "String::operator+(): - Use String::operator+=() for better performence and smaller code" ); + + STRING aTmpStr( pCharStr ); + aTmpStr += rStr; + return aTmpStr; +} +#endif diff --git a/tools/source/string/strucvt.cxx b/tools/source/string/strucvt.cxx new file mode 100644 index 000000000000..ab7190c662ff --- /dev/null +++ b/tools/source/string/strucvt.cxx @@ -0,0 +1,251 @@ +/************************************************************************* + * + * $RCSfile: strucvt.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +// ======================================================================= + +static UniStringData* ImplGetUniStringDataFromString( const char* pStr, sal_Size nLen, + rtl_TextEncoding eTextEncoding, sal_uInt32 nCvtFlags ) +{ + DBG_ASSERT( (eTextEncoding != 9) && + (eTextEncoding != RTL_TEXTENCODING_DONTKNOW) && + (eTextEncoding != RTL_TEXTENCODING_UCS2) && + (eTextEncoding != RTL_TEXTENCODING_UCS4), + "ByteString-->UniString: Wrong TextEncoding" ); + + if ( !nLen ) + { + ImplIncRefCount( &aImplEmptyStrData ); + return &aImplEmptyStrData; + } + +#ifndef NOOLDSTRING + if ( eTextEncoding == CHARSET_SYSTEM ) + eTextEncoding = GetSystemCharSet(); +#endif + nCvtFlags |= RTL_TEXTTOUNICODE_FLAGS_FLUSH; + + UniStringData* pData; + rtl_TextEncodingInfo aTextEncInfo; + rtl_TextToUnicodeConverter hConverter = rtl_createTextToUnicodeConverter( eTextEncoding ); + sal_uInt32 nInfo; + sal_Size nSrcBytes; + sal_Size nDestChars; + sal_Size nNewLen; + + // get TextEncodingInfo + aTextEncInfo.StructSize = sizeof( aTextEncInfo ); + rtl_getTextEncodingInfo( eTextEncoding, &aTextEncInfo ); + + // Zuerst konvertieren wir mit der wahrscheinlichen Anzahl + // der zu konvertierenden Zeichen + nNewLen = nLen/aTextEncInfo.AverageCharSize; + if ( nNewLen > STRING_MAXLEN ) + nNewLen = STRING_MAXLEN; + pData = ImplAllocData( (xub_StrLen)nNewLen ); + nDestChars = rtl_convertTextToUnicode( hConverter, 0, + pStr, nLen, + pData->maStr, nNewLen, + nCvtFlags, + &nInfo, &nSrcBytes ); + + // Buffer hat nicht gereicht, dann mit maximaler Buffergroesse + if ( (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL) && + (nNewLen != STRING_MAXLEN) ) + { + rtl_freeMemory( pData ); + nNewLen = nLen; + if ( nNewLen > STRING_MAXLEN ) + nNewLen = STRING_MAXLEN; + pData = ImplAllocData( (xub_StrLen)nNewLen ); + nDestChars = rtl_convertTextToUnicode( hConverter, 0, + pStr, nLen, + pData->maStr, nNewLen, + nCvtFlags, + &nInfo, &nSrcBytes ); + } + + // String entsprechend der durch das Konvertieren tatsaechlich + // entstehenden Bytes anpassen + if ( !nDestChars ) + { + rtl_freeMemory( pData ); + ImplIncRefCount( &aImplEmptyStrData ); + pData = &aImplEmptyStrData; + } + else if ( nNewLen > nDestChars+8 ) + { + UniStringData* pTempData = ImplAllocData( (xub_StrLen)nDestChars ); + memcpy( pTempData->maStr, pData->maStr, nDestChars*sizeof( sal_Unicode ) ); + rtl_freeMemory( pData ); + pData = pTempData; + } + else + { + pData->mnLen = (xub_StrLen)nDestChars; + pData->maStr[nDestChars] = '\0'; + } + rtl_destroyTextToUnicodeConverter( hConverter ); + return pData; +} + +// ======================================================================= + +void UniString::InitStringRes( const char* pUTF8Str, xub_StrLen nLen ) +{ + DBG_CTOR( UniString, DbgCheckUniString ); + + mpData = ImplGetUniStringDataFromString( 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 = ImplGetUniStringDataFromString( 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 + xub_StrLen nMaxLen = rByteStr.mpData->mnLen-nPos; + if ( nLen > nMaxLen ) + nLen = nMaxLen; + } + + mpData = ImplGetUniStringDataFromString( 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 = ImplGetUniStringDataFromString( 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 = ImplGetUniStringDataFromString( pByteStr, nLen, + eTextEncoding, nCvtFlags ); +} + +// ======================================================================= + +UniString::UniString( const NAMESPACE_RTL(OUString)& rStr ) +{ + DBG_CTOR( UniString, DbgCheckUniString ); + + mpData = (UniStringData*)rStr.pData; + ImplIncRefCount( mpData ); +} + +// ----------------------------------------------------------------------- + +NAMESPACE_RTL(OUString)::OUString( const UniString& rStr ) +{ + pData = (rtl_uString*)rStr.mpData; + rtl_uString_acquire( pData ); +} + +// ----------------------------------------------------------------------- + +UniString& UniString::Assign( const NAMESPACE_RTL(OUString)& rStr ) +{ + DBG_CHKTHIS( UniString, DbgCheckUniString ); + + rtl_uString_acquire( rStr.pData ); + ImplDeleteData( mpData ); + mpData = (UniStringData*)rStr.pData; + return *this; +} diff --git a/tools/source/string/tstring.cxx b/tools/source/string/tstring.cxx new file mode 100644 index 000000000000..9e8cda42b736 --- /dev/null +++ b/tools/source/string/tstring.cxx @@ -0,0 +1,304 @@ +/************************************************************************* + * + * $RCSfile: tstring.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string.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 +#ifndef _RTL_TENCINFO_H +#include <rtl/tencinfo.h> +#endif + +#define private public +#include <string.hxx> +#undef private +#include <impstrg.hxx> + +// For shared byte convert tables +#ifndef _TOOLS_TOOLSIN_HXX +#include <toolsin.hxx> +#endif + +#include <debug.hxx> + +// ======================================================================= + +DBG_NAME( ByteString ); +DBG_NAMEEX( UniString ); + +// ----------------------------------------------------------------------- + +#define STRCODE sal_Char +#define STRING ByteString +#define STRINGDATA ByteStringData +#define DBGCHECKSTRING DbgCheckByteString + +// ----------------------------------------------------------------------- + +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> + +#ifndef NOOLDSTRING +#include <strold.cxx> +#endif + +// ----------------------------------------------------------------------- + +ByteString ByteString::CreateFromInt32( sal_Int32 n, sal_Int16 nRadix ) +{ + sal_Char aBuf[RTL_STR_MAX_VALUEOFINT32]; + return ByteString( aBuf, rtl_str_valueOfInt32( aBuf, n, nRadix ) ); +} + +// ----------------------------------------------------------------------- + +ByteString ByteString::CreateFromInt64( sal_Int64 n, sal_Int16 nRadix ) +{ + sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64]; + return ByteString( aBuf, rtl_str_valueOfInt64( aBuf, n, nRadix ) ); +} + +// ----------------------------------------------------------------------- + +ByteString ByteString::CreateFromFloat( float f ) +{ + sal_Char aBuf[RTL_STR_MAX_VALUEOFFLOAT]; + return ByteString( aBuf, rtl_str_valueOfFloat( aBuf, f ) ); +} + +// ----------------------------------------------------------------------- + +ByteString ByteString::CreateFromDouble( double d ) +{ + sal_Char aBuf[RTL_STR_MAX_VALUEOFDOUBLE]; + return ByteString( aBuf, rtl_str_valueOfDouble( aBuf, d ) ); +} + +// ----------------------------------------------------------------------- + +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 ); + + return 0; +} + +// ----------------------------------------------------------------------- + +double ByteString::ToDouble() const +{ + DBG_CHKTHIS( ByteString, DbgCheckByteString ); + + return 0; +} + +// ----------------------------------------------------------------------- + +BOOL ByteString::IsLowerAscii() const +{ + DBG_CHKTHIS( ByteString, DbgCheckByteString ); + + xub_StrLen nIndex = 0; + xub_StrLen 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 ); + + xub_StrLen nIndex = 0; + xub_StrLen 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 ); + + xub_StrLen nIndex = 0; + xub_StrLen 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 ); + + xub_StrLen nIndex = 0; + xub_StrLen 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 ); + + xub_StrLen nIndex = 0; + xub_StrLen 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..22c894063441 --- /dev/null +++ b/tools/source/string/tustring.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * $RCSfile: tustring.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:09 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string.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 +#ifndef _RTL_TENCINFO_H +#include <rtl/tencinfo.h> +#endif + +#define private public +#include <string.hxx> +#undef private +#include <impstrg.hxx> + +#include <debug.hxx> + +// ======================================================================= + +DBG_NAME( UniString ); +DBG_NAMEEX( ByteString ); + +// ----------------------------------------------------------------------- + +#define STRCODE sal_Unicode +#define STRING UniString +#define STRINGDATA UniStringData +#define DBGCHECKSTRING DbgCheckUniString + +// ----------------------------------------------------------------------- + +#include <strimp.cxx> +#include <strucvt.cxx> +#include <strascii.cxx> + +#ifndef NOOLDSTRING +#include <struold.cxx> +#endif + +// ----------------------------------------------------------------------- + +UniString UniString::CreateFromInt32( sal_Int32 n, sal_Int16 nRadix ) +{ + sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT32]; + return UniString( aBuf, rtl_ustr_valueOfInt32( aBuf, n, nRadix ) ); +} + +// ----------------------------------------------------------------------- + +UniString UniString::CreateFromInt64( sal_Int64 n, sal_Int16 nRadix ) +{ + sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT64]; + return UniString( aBuf, rtl_ustr_valueOfInt64( aBuf, n, nRadix ) ); +} + +// ----------------------------------------------------------------------- + +UniString UniString::CreateFromFloat( float f ) +{ + sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFFLOAT]; + return UniString( aBuf, rtl_ustr_valueOfFloat( aBuf, f ) ); +} + +// ----------------------------------------------------------------------- + +UniString UniString::CreateFromDouble( double d ) +{ + sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFDOUBLE]; + return UniString( aBuf, rtl_ustr_valueOfDouble( aBuf, d ) ); +} + +// ----------------------------------------------------------------------- + +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/zcodec/makefile.mk b/tools/source/zcodec/makefile.mk new file mode 100644 index 000000000000..f7f3fcdf21e3 --- /dev/null +++ b/tools/source/zcodec/makefile.mk @@ -0,0 +1,80 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:03:10 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=zcodec + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +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..86230b275004 --- /dev/null +++ b/tools/source/zcodec/zcodec.cxx @@ -0,0 +1,524 @@ +/************************************************************************* + * + * $RCSfile: zcodec.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:10 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _STREAM_HXX +#include "stream.hxx" +#endif +#ifndef _ZLIB_H +#include "zlib/zlib.h" +#endif +#ifndef _ZCODEC_HXX +#include "zcodec.hxx" +#endif +#ifndef _RTL_CRC_H_ +#include <rtl/crc.h> +#endif + +// ----------- +// - 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 ) +{ + mnMemUsage = nMemUsage; + mnInBufSize = nInBufSize; + mnOutBufSize = nOutBufSize; + mpsC_Stream = new z_stream; +} + +ZCodec::ZCodec( void ) +{ + 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; + + 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 ) +{ + char err; + 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(); + err = deflate( PZSTREAM, Z_NO_FLUSH ); + if ( err < 0 ) + { + mbStatus = FALSE; + break; + } + }; + return ( mbStatus ) ? PZSTREAM->total_in - nOldTotal_In : -1; +} + +// ------------------------------------------------------------------------ + +long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm ) +{ + char 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 ) ? 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 ) ? nSize : -1; +} + +// ------------------------------------------------------------------------ + +long ZCodec::Read( SvStream& rIStm, BYTE* pData, ULONG nSize ) +{ + char 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 ? nSize - PZSTREAM->avail_out : -1); +} + +// ------------------------------------------------------------------------ + +#pragma optimize ("",off) + +long ZCodec::ReadAsynchron( SvStream& rIStm, BYTE* pData, ULONG nSize ) +{ + char err; + 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 ); + 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 ? nSize - PZSTREAM->avail_out : -1); +} + +#pragma optimize ("",on) + +// ------------------------------------------------------------------------ + +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 __LITTLEENDIAN + 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 ); +}; + + |