diff options
Diffstat (limited to 'tools/source/fsys')
-rw-r--r-- | tools/source/fsys/comdep.cxx | 47 | ||||
-rw-r--r-- | tools/source/fsys/comdep.hxx | 159 | ||||
-rw-r--r-- | tools/source/fsys/dirent.cxx | 3197 | ||||
-rw-r--r-- | tools/source/fsys/filecopy.cxx | 489 | ||||
-rw-r--r-- | tools/source/fsys/fstat.cxx | 422 | ||||
-rw-r--r-- | tools/source/fsys/makefile.mk | 67 | ||||
-rw-r--r-- | tools/source/fsys/os2.cxx | 885 | ||||
-rw-r--r-- | tools/source/fsys/os2.hxx | 94 | ||||
-rw-r--r-- | tools/source/fsys/tdir.cxx | 769 | ||||
-rw-r--r-- | tools/source/fsys/tempfile.cxx | 303 | ||||
-rw-r--r-- | tools/source/fsys/unx.cxx | 663 | ||||
-rw-r--r-- | tools/source/fsys/unx.hxx | 98 | ||||
-rw-r--r-- | tools/source/fsys/urlobj.cxx | 5575 | ||||
-rw-r--r-- | tools/source/fsys/wldcrd.cxx | 146 | ||||
-rw-r--r-- | tools/source/fsys/wntmsc.cxx | 1083 | ||||
-rw-r--r-- | tools/source/fsys/wntmsc.hxx | 105 |
16 files changed, 14102 insertions, 0 deletions
diff --git a/tools/source/fsys/comdep.cxx b/tools/source/fsys/comdep.cxx new file mode 100644 index 000000000000..2278e8dd1357 --- /dev/null +++ b/tools/source/fsys/comdep.cxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" + +#include "comdep.hxx" +#include <tools/debug.hxx> +#include <tools/list.hxx> +#include <tools/fsys.hxx> + +DBG_NAMEEX( DirEntry ) + +#if defined UNX +#include "unx.cxx" +#elif defined WNT +#include "wntmsc.cxx" +#elif defined OS2 +#include "os2.cxx" +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/comdep.hxx b/tools/source/fsys/comdep.hxx new file mode 100644 index 000000000000..286557167ae7 --- /dev/null +++ b/tools/source/fsys/comdep.hxx @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _COMDEP_HXX +#define _COMDEP_HXX + +#include <tools/fsys.hxx> + +#define ACCESSDELIM(e) ( (e == FSYS_STYLE_MAC) ? ":" : \ + ( ( e == FSYS_STYLE_VFAT || e == FSYS_STYLE_HPFS || \ + e == FSYS_STYLE_FAT ) || e == FSYS_STYLE_NTFS ) \ + ? "\\" : "/" ) +#define ACCESSDELIM_C(e)(char)\ + ( (e == FSYS_STYLE_MAC) ? ':' : \ + ( ( e == FSYS_STYLE_VFAT || e == FSYS_STYLE_HPFS || \ + e == FSYS_STYLE_FAT ) || e == FSYS_STYLE_NTFS ) \ + ? '\\' : '/' ) +#define SEARCHDELIM(e) ( (e == FSYS_STYLE_SYSV || e == FSYS_STYLE_BSD) ? ":" \ + : ";" ) +#define SEARCHDELIM_C(e)(char)\ + ( (e == FSYS_STYLE_SYSV || e == FSYS_STYLE_BSD) ? ':' \ + : ';' ) +#define ACTPARENT(e) ( (e == FSYS_STYLE_MAC) ? ":" : ".." ) +#define ACTCURRENT(e) ( (e == FSYS_STYLE_MAC) ? "" : "." ) + +#if defined UNX +#include "unx.hxx" +#elif defined WNT +#include "wntmsc.hxx" +#elif defined OS2 +#include "os2.hxx" +#endif + +//-------------------------------------------------------------------- + +#ifndef LINUX +DIR *opendir( const char* pPfad ); +dirent *readdir( DIR *pDir ); +int closedir( DIR *pDir ); +char *volumeid( const char* pPfad ); +#endif + +//-------------------------------------------------------------------- + +struct DirReader_Impl +{ + Dir* pDir; + DIR* pDosDir; + dirent* pDosEntry; + DirEntry* pParent; + String aPath; + ByteString aBypass; + BOOL bReady; + BOOL bInUse; + + DirReader_Impl( Dir &rDir ) + : pDir( &rDir ), + pDosEntry( 0 ), + pParent( 0 ), + aPath( GUI2FSYS(rDir.GetFull()) ), + bReady ( FALSE ), + bInUse( FALSE ) + { +#ifndef BOOTSTRAP + // Redirection + FSysRedirector::DoRedirect( aPath ); +#endif + + // nur den String der Memer-Var nehmen! + +#if defined(UNX) || defined(OS2) //for further exlpanation see DirReader_Impl::Read() in unx.cxx + pDosDir = NULL; +#else + aBypass = ByteString(aPath, osl_getThreadTextEncoding()); + pDosDir = opendir( (char*) aBypass.GetBuffer() ); +#endif + + // Parent f"ur die neuen DirEntries ermitteln + pParent = pDir->GetFlag() == FSYS_FLAG_NORMAL || + pDir->GetFlag() == FSYS_FLAG_ABSROOT + ? pDir + : pDir->GetParent(); + + } + + ~DirReader_Impl() + { if( pDosDir ) closedir( pDosDir ); } + + // die folgenden sind systemabh"angig implementiert + USHORT Init(); // initialisiert, liest ggf. devices + USHORT Read(); // liest 1 Eintrag, F2ugt ein falls ok +}; + +//-------------------------------------------------------------------- + +struct FileCopier_Impl +{ + FSysAction nActions; // was zu tun ist (Copy/Move/recur) + Link aErrorLink; // bei Fehlern zu rufen + ErrCode eErr; // aktueller Fehlercode im Error-Handler + const DirEntry* pErrSource; // fuer Error-Handler falls Source-Fehler + const DirEntry* pErrTarget; // fuer Error-Handler falls Target-Fehler + + FileCopier_Impl() + : nActions( 0 ), eErr( 0 ), + pErrSource( 0 ), pErrTarget( 0 ) + {} + FileCopier_Impl( const FileCopier_Impl &rOrig ) + : nActions( rOrig.nActions ), eErr( 0 ), + pErrSource( 0 ), pErrTarget( 0 ) + {} + + FileCopier_Impl& operator=( const FileCopier_Impl &rOrig ) + { + nActions = rOrig.nActions; + eErr = 0; pErrSource = 0; pErrTarget = 0; + return *this; + } +}; + +//-------------------------------------------------------------------- + +#if defined WNT || defined OS2 +BOOL IsRedirectable_Impl( const ByteString &rPath ); +#else +#define IsRedirectable_Impl( rPath ) TRUE +#endif + +//-------------------------------------------------------------------- + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/dirent.cxx b/tools/source/fsys/dirent.cxx new file mode 100644 index 000000000000..debb0fa44ad5 --- /dev/null +++ b/tools/source/fsys/dirent.cxx @@ -0,0 +1,3197 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" + + +#if !defined UNX +#include <io.h> +#include <process.h> +#endif + +#if defined(UNX) || defined(OS2) +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#endif + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <tools/debug.hxx> +#include <tools/list.hxx> +#include "comdep.hxx" +#include <tools/fsys.hxx> +#define _TOOLS_HXX +#include <tools/urlobj.hxx> + +#ifdef UNX +#define _MAX_PATH 260 +#endif +#include <tools/stream.hxx> + +#include <osl/mutex.hxx> + +#include <osl/file.hxx> +#include <rtl/instance.hxx> + + +using namespace osl; +using namespace rtl; + +int ApiRet2ToSolarError_Impl( int nApiRet ); + +//-------------------------------------------------------------------- +int Sys2SolarError_Impl( int nSysErr ) +{ + switch ( nSysErr ) + { +#ifdef WNT + case NO_ERROR: return ERRCODE_NONE; + case ERROR_INVALID_FUNCTION: return ERRCODE_IO_GENERAL; + case ERROR_FILE_NOT_FOUND: return ERRCODE_IO_NOTEXISTS; + case ERROR_PATH_NOT_FOUND: return ERRCODE_IO_NOTEXISTSPATH; + case ERROR_TOO_MANY_OPEN_FILES: return ERRCODE_IO_TOOMANYOPENFILES; + case ERROR_ACCESS_DENIED: return ERRCODE_IO_ACCESSDENIED; + case ERROR_INVALID_HANDLE: return ERRCODE_IO_GENERAL; + case ERROR_NOT_ENOUGH_MEMORY: return ERRCODE_IO_OUTOFMEMORY; + case ERROR_INVALID_BLOCK: return ERRCODE_IO_GENERAL; +// case ERROR_BAD_ENVIRONMENT: return ERRCODE_IO_; + case ERROR_BAD_FORMAT: return ERRCODE_IO_WRONGFORMAT; + case ERROR_INVALID_ACCESS: return ERRCODE_IO_ACCESSDENIED; +// case ERROR_INVALID_DATA: return ERRCODE_IO_; + case ERROR_INVALID_DRIVE: return ERRCODE_IO_INVALIDDEVICE; + case ERROR_CURRENT_DIRECTORY: return ERRCODE_IO_CURRENTDIR; + case ERROR_NOT_SAME_DEVICE: return ERRCODE_IO_NOTSAMEDEVICE; +// case ERROR_NO_MORE_FILES: return ERRCODE_IO_; + case ERROR_WRITE_PROTECT: return ERRCODE_IO_CANTWRITE; + case ERROR_BAD_UNIT: return ERRCODE_IO_INVALIDDEVICE; + case ERROR_NOT_READY: return ERRCODE_IO_DEVICENOTREADY; + case ERROR_BAD_COMMAND: return ERRCODE_IO_GENERAL; + case ERROR_CRC: return ERRCODE_IO_BADCRC; + case ERROR_BAD_LENGTH: return ERRCODE_IO_INVALIDLENGTH; + case ERROR_SEEK: return ERRCODE_IO_CANTSEEK; + case ERROR_NOT_DOS_DISK: return ERRCODE_IO_WRONGFORMAT; + case ERROR_SECTOR_NOT_FOUND: return ERRCODE_IO_GENERAL; + case ERROR_WRITE_FAULT: return ERRCODE_IO_CANTWRITE; + case ERROR_READ_FAULT: return ERRCODE_IO_CANTREAD; + case ERROR_GEN_FAILURE: return ERRCODE_IO_GENERAL; + case ERROR_SHARING_VIOLATION: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_LOCK_VIOLATION: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_WRONG_DISK: return ERRCODE_IO_INVALIDDEVICE; + case ERROR_NOT_SUPPORTED: return ERRCODE_IO_NOTSUPPORTED; +#else + case 0: return ERRCODE_NONE; + case ENOENT: return ERRCODE_IO_NOTEXISTS; + case EACCES: return ERRCODE_IO_ACCESSDENIED; + case EEXIST: return ERRCODE_IO_ALREADYEXISTS; + case EINVAL: return ERRCODE_IO_INVALIDPARAMETER; + case EMFILE: return ERRCODE_IO_TOOMANYOPENFILES; + case ENOMEM: return ERRCODE_IO_OUTOFMEMORY; + case ENOSPC: return ERRCODE_IO_OUTOFSPACE; +#endif + } + + DBG_TRACE1( "FSys: unknown system error %d occured", nSysErr ); + return FSYS_ERR_UNKNOWN; +} + +//-------------------------------------------------------------------- + +#ifndef BOOTSTRAP + +FSysRedirector* FSysRedirector::_pRedirector = 0; +BOOL FSysRedirector::_bEnabled = TRUE; +#ifdef UNX +BOOL bInRedirection = TRUE; +#else +BOOL bInRedirection = FALSE; +#endif +static osl::Mutex* pRedirectMutex = 0; + +//------------------------------------------------------------------------ +void FSysRedirector::Register( FSysRedirector *pRedirector ) +{ + if ( pRedirector ) + pRedirectMutex = new osl::Mutex; + else + DELETEZ( pRedirectMutex ); + _pRedirector = pRedirector; +} + +//------------------------------------------------------------------------ + +void FSysRedirector::DoRedirect( String &rPath ) +{ + String aURL(rPath); + + // if redirection is disabled or not even registered do nothing + if ( !_bEnabled || !pRedirectMutex ) + return; + + // redirect only removable or remote volumes + if ( !IsRedirectable_Impl( ByteString( aURL, osl_getThreadTextEncoding() ) ) ) + return; + + // Redirection is acessible only by one thread per time + // dont move the guard behind the bInRedirection check!!! + // think of nested calls (when called from callback) + osl::MutexGuard aGuard( pRedirectMutex ); + + // if already in redirection, dont redirect + if ( bInRedirection ) + return; + + // dont redirect on nested calls + bInRedirection = TRUE; + + // convert to URL +#ifndef UNX + for ( sal_Unicode *p = (sal_Unicode*)aURL.GetBuffer(); *p; ++p ) + if ( '\\' == *p ) *p = '/'; + else if ( ':' == *p ) *p = '|'; +#endif + + aURL.Insert( String("file:///", osl_getThreadTextEncoding()), 0 ); + + // do redirection + Redirector(); + + bInRedirection = FALSE; + return; +} + +//------------------------------------------------------------------------ + +FSysRedirector* FSysRedirector::Redirector() +{ + if ( !_pRedirector ) + Register( new FSysRedirector ); + return _pRedirector; +} + +#endif // BOOTSTRAP + +//-------------------------------------------------------------------- + +class DirEntryStack: public List +{ +public: + DirEntryStack() {}; + ~DirEntryStack(); + + inline void Push( DirEntry *pEntry ); + inline DirEntry* Pop(); + inline DirEntry* Top(); + inline DirEntry* Bottom(); +}; + +inline void DirEntryStack::Push( DirEntry *pEntry ) +{ + List::Insert( pEntry, LIST_APPEND ); +} + +inline DirEntry* DirEntryStack::Pop() +{ + return (DirEntry*) List::Remove( Count() - 1 ); +} + +inline DirEntry* DirEntryStack::Top() +{ + return (DirEntry*) List::GetObject( Count() - 1 ); +} + +inline DirEntry* DirEntryStack::Bottom() +{ + return (DirEntry*) List::GetObject( 0 ); +} + +//-------------------------------------------------------------------- + +DBG_NAME( DirEntry ); + +/************************************************************************* +|* +|* DirEntry::~DirEntryStack() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 04.07.91 +|* +*************************************************************************/ + +DirEntryStack::~DirEntryStack() +{ + while ( Count() ) + delete Pop(); +} + +/************************************************************************* +|* +|* ImpCheckDirEntry() +|* +|* Beschreibung Pruefung eines DirEntry fuer DBG_UTIL +|* Parameter void* p Zeiger auf den DirEntry +|* Return-Wert char* Fehlermeldungs-TExtension oder NULL +|* Ersterstellung MI 16.07.91 +|* Letzte Aenderung MI 26.05.93 +|* +*************************************************************************/ + +#ifdef DBG_UTIL +const char* ImpCheckDirEntry( const void* p ) +{ + DirEntry* p0 = (DirEntry*)p; + + if ( p0->pParent ) + DBG_CHKOBJ( p0->pParent, DirEntry, ImpCheckDirEntry ); + + return NULL; +} +#endif + +/************************************************************************* +|* +|* ImplCutPath() +|* +|* Beschreibung Fuegt ... ein, damit maximal nMaxChars lang +|* Ersterstellung MI 06.04.94 +|* Letzte Aenderung DV 24.06.96 +|* +*************************************************************************/ + +ByteString ImplCutPath( const ByteString& rStr, USHORT nMax, char cAccDel ) +{ + USHORT nMaxPathLen = nMax; + ByteString aCutPath( rStr ); + BOOL bInsertPrefix = FALSE; + USHORT nBegin = aCutPath.Search( cAccDel ); + + if( nBegin == STRING_NOTFOUND ) + nBegin = 0; + else + nMaxPathLen += 2; // fuer Prefix <Laufwerk>: + + while( aCutPath.Len() > nMaxPathLen ) + { + USHORT nEnd = aCutPath.Search( cAccDel, nBegin + 1 ); + USHORT nCount; + + if ( nEnd != STRING_NOTFOUND ) + { + nCount = nEnd - nBegin; + aCutPath.Erase( nBegin, nCount ); + bInsertPrefix = TRUE; + } + else + break; + } + + if ( aCutPath.Len() > nMaxPathLen ) + { + for ( USHORT n = nMaxPathLen; n > nMaxPathLen/2; --n ) + if ( !ByteString(aCutPath.GetChar(n)).IsAlphaNumericAscii() ) + { + aCutPath.Erase( n ); + aCutPath += "..."; + break; + } + } + + if ( bInsertPrefix ) + { + ByteString aIns( cAccDel ); + aIns += "..."; + aCutPath.Insert( aIns, nBegin ); + } + + return aCutPath; +} + +/************************************************************************* +|* +|* DirEntry::ImpParseOs2Name() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 23.06.95 +|* +*************************************************************************/ + +FSysError DirEntry::ImpParseOs2Name( const ByteString& rPfad, FSysPathStyle eStyle ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + // die einzelnen Namen auf einen Stack packen + String aPfad( rPfad, osl_getThreadTextEncoding() ); + DirEntryStack aStack; + + do + { + // den Namen vor dem ersten "\\" abspalten, + // falls '\\' am Anfang, ist der Name '\\', + // der Rest immer ohne die fuehrenden '\\'. + // ein ":" trennt ebenfalls, gehoert aber zum Namen + // den ersten '\\', '/' oder ':' suchen + USHORT nPos; + for ( nPos = 0; + nPos < aPfad.Len() && //?O + aPfad.GetChar(nPos) != '\\' && aPfad.GetChar(nPos) != '/' && //?O + aPfad.GetChar(nPos) != ':'; //?O + nPos++ ) + /* do nothing */; + + // ist der Name ein UNC Pathname? + if ( nPos == 0 && aPfad.Len() > 1 && + ( ( aPfad.GetChar(0) == '\\' && aPfad.GetChar(1) == '\\' ) || + ( aPfad.GetChar(0) == '/' && aPfad.GetChar(1) == '/' ) ) ) + { + for ( nPos = 2; aPfad.Len() > nPos; ++nPos ) + if ( aPfad.GetChar(nPos) == '\\' || aPfad.GetChar(nPos) == '/' ) + break; + aName = ByteString( aPfad.Copy( 2, nPos-2 ), osl_getThreadTextEncoding() ); + aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT, eStyle ) ); + } + // ist der Name die Root des aktuellen Drives? + else if ( nPos == 0 && aPfad.Len() > 0 && + ( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) ) + { + // Root-Directory des aktuellen Drives + aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) ); + } + else + { + // ist der Name ein Drive? + if ( nPos < aPfad.Len() && aPfad.GetChar(nPos) == ':' ) + { + aName = ByteString( aPfad.Copy( 0, nPos + 1 ), osl_getThreadTextEncoding() ); + + // ist der Name die Root des Drives + if ( (nPos + 1) < aPfad.Len() && + ( aPfad.GetChar(nPos+1) == '\\' || aPfad.GetChar(nPos+1) == '/' ) ) + { + // schon was auf dem Stack? + // oder Novell-Format? (not supported wegen URLs) + if ( aStack.Count() || aName.Len() > 2 ) + { + aName = rPfad; + return FSYS_ERR_MISPLACEDCHAR; + } + // Root-Directory des Drive + aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT, eStyle ) ); + } + else + { + // liegt ein anderes Drive auf dem Stack? + if ( aStack.Count() && + COMPARE_EQUAL != aStack.Bottom()->aName.CompareIgnoreCaseToAscii(aName) ) + aStack.Clear(); + + // liegt jetzt nichts mehr auf dem Stack? + if ( !aStack.Count() ) + aStack.Push( new DirEntry( aName, FSYS_FLAG_RELROOT, eStyle ) ); + } + } + + // es ist kein Drive + else + { + // den Namen ohne Trenner abspalten + aName = ByteString( aPfad.Copy( 0, nPos ), osl_getThreadTextEncoding() ); + + // stellt der Name die aktuelle Directory dar? + if ( aName == "." ) + /* do nothing */; + + // stellt der Name die Parent-Directory dar? + else if ( aName == ".." ) + { + // ist nichts, ein Parent oder eine relative Root + // auf dem Stack? + if ( ( aStack.Count() == 0 ) || + ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) || + ( aStack.Top()->eFlag == FSYS_FLAG_RELROOT ) ) + // fuehrende Parents kommen auf den Stack + aStack.Push( new DirEntry( FSYS_FLAG_PARENT ) ); + + // ist es eine absolute Root + else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT ) + { + // die hat keine Parent-Directory + aName = rPfad; + return FSYS_ERR_NOTEXISTS; + } + else + // sonst hebt der Parent den TOS auf + delete aStack.Pop(); + } + + else + { + if ( eStyle == FSYS_STYLE_FAT ) + { + // ist der Name grundsaetzlich ungueltig? + int nPunkte = 0; + const char *pChar; + for ( pChar = aName.GetBuffer(); + nPunkte < 2 && *pChar != 0; + pChar++ ) + { + if ( *pChar == ';' ) + nPunkte = 0; + else + nPunkte += ( *pChar == '.' ) ? 1 : 0; + } + if ( nPunkte > 1 ) + { + aName = rPfad; + return FSYS_ERR_MISPLACEDCHAR; + } + } + + // normalen Entries kommen auf den Stack + DirEntry *pNew = new DirEntry( aName, FSYS_FLAG_NORMAL, eStyle ); + if ( !pNew->IsValid() ) + { + aName = rPfad; + ErrCode eErr = pNew->GetError(); + delete pNew; + return eErr; + } + aStack.Push( pNew ); + } + } + } + + // den Restpfad bestimmen + aPfad.Erase( 0, nPos + 1 ); + while ( aPfad.Len() && ( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) ) + aPfad.Erase( 0, 1 ); + } + while ( aPfad.Len() ); + + ULONG nErr = ERRCODE_NONE; + // Haupt-Entry (selbst) zuweisen + if ( aStack.Count() == 0 ) + { + eFlag = FSYS_FLAG_CURRENT; + aName.Erase(); + } + else + { + eFlag = aStack.Top()->eFlag; + aName = aStack.Top()->aName; + nErr = aStack.Top()->nError; + delete aStack.Pop(); + } + + // die Parent-Entries vom Stack holen + DirEntry** pTemp = &pParent; // Zeiger auf den Member pParent setzen + while ( aStack.Count() ) + { + *pTemp = aStack.Pop(); + + // Zeiger auf den Member pParent des eigenen Parent setzen + pTemp = &( (*pTemp)->pParent ); + } + + // wird damit ein Volume beschrieben? + if ( !pParent && eFlag == FSYS_FLAG_RELROOT && aName.Len() ) + eFlag = FSYS_FLAG_VOLUME; + + // bei gesetztem ErrorCode den Namen komplett "ubernehmen + if ( nErr ) + aName = rPfad; + return nErr; +} + +/************************************************************************* +|* +|* DirEntry::ImpParseName() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.08.91 +|* Letzte Aenderung MI 26.05.93 +|* +*************************************************************************/ + +FSysError DirEntry::ImpParseName( const ByteString& rbInitName, + FSysPathStyle eStyle ) +{ + String rInitName( rbInitName, osl_getThreadTextEncoding() ); + if ( eStyle == FSYS_STYLE_HOST ) + eStyle = DEFSTYLE; + + // KI-Division of FSys + if ( eStyle == FSYS_STYLE_DETECT ) + { + sal_Unicode cFirst = rInitName.GetChar(0); + if ( rInitName.Len() == 2 && rInitName.GetChar(1) == ':' && + ((cFirst >= 'A' && cFirst <= 'Z') || + (cFirst >= 'a' && cFirst <= 'z'))) + eStyle = FSYS_STYLE_HPFS; + else if ( rInitName.Len() > 2 && rInitName.GetChar(1) == ':' ) + { + if ( rInitName.Search( ':', 2 ) == STRING_NOTFOUND ) + eStyle = FSYS_STYLE_HPFS; + else + eStyle = FSYS_STYLE_MAC; + } + else if ( rInitName.Search( '/' ) != STRING_NOTFOUND ) + eStyle = FSYS_STYLE_BSD; + else if ( rInitName.Search( '\\' ) != STRING_NOTFOUND ) + eStyle = FSYS_STYLE_HPFS; + else if ( rInitName.Search( ':' ) != STRING_NOTFOUND ) + eStyle = FSYS_STYLE_MAC; + else + eStyle = FSYS_STYLE_HPFS; + } + + switch ( eStyle ) + { + case FSYS_STYLE_FAT: + case FSYS_STYLE_VFAT: + case FSYS_STYLE_HPFS: + case FSYS_STYLE_NTFS: + case FSYS_STYLE_NWFS: + return ImpParseOs2Name( rbInitName, eStyle ); + + case FSYS_STYLE_BSD: + case FSYS_STYLE_SYSV: + return ImpParseUnixName( rbInitName, eStyle ); + + case FSYS_STYLE_MAC: + return FSYS_ERR_OK; + + default: + return FSYS_ERR_UNKNOWN; + } +} + +/************************************************************************* +|* +|* GetStyle() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 15.11.91 +|* Letzte Aenderung MI 15.11.91 +|* +*************************************************************************/ + +static FSysPathStyle GetStyle( FSysPathStyle eStyle ) +{ + if ( eStyle == FSYS_STYLE_HOST || eStyle == FSYS_STYLE_DETECT ) + return DEFSTYLE; + else + return eStyle; +} + +/************************************************************************* +|* +|* DirEntry::ImpTrim() +|* +|* Beschreibung bringt den Namen auf Betriebssystem-Norm +|* z.B. 8.3 lower beim MS-DOS Formatter +|* wirkt nicht rekursiv +|* Ersterstellung MI 12.08.91 +|* Letzte Aenderung MI 21.05.92 +|* +*************************************************************************/ + +void DirEntry::ImpTrim( FSysPathStyle eStyle ) +{ + // Wildcards werden nicht geclipt + if ( ( aName.Search( '*' ) != STRING_NOTFOUND ) || + ( aName.Search( '?' ) != STRING_NOTFOUND ) || + ( aName.Search( ';' ) != STRING_NOTFOUND ) ) + return; + + switch ( eStyle ) + { + case FSYS_STYLE_FAT: + { + USHORT nPunktPos = aName.Search( '.' ); + if ( nPunktPos == STRING_NOTFOUND ) + { + if ( aName.Len() > 8 ) + { + nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; + aName.Erase( 8 ); + } + } + else + { + if ( nPunktPos > 8 ) + { + nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; + aName.Erase( 8, nPunktPos - 8 ); + nPunktPos = 8; + } + if ( aName.Len() > nPunktPos + 3 ) + { + if ( aName.Len() - nPunktPos > 4 ) + { + nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; + aName.Erase( nPunktPos + 4 ); + } + } + } + aName.ToLowerAscii(); + break; + } + + case FSYS_STYLE_VFAT: + case FSYS_STYLE_HPFS: + case FSYS_STYLE_NTFS: + case FSYS_STYLE_NWFS: + if ( aName.Len() > 254 ) + { + nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; + aName.Erase( 254 ); + } + + if ( eStyle == FSYS_STYLE_HPFS && + ( eFlag == FSYS_FLAG_ABSROOT || eFlag == FSYS_FLAG_RELROOT ) ) + aName.ToUpperAscii(); + break; + + case FSYS_STYLE_SYSV: + if ( aName.Len() > 14 ) + { + nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; + aName.Erase( 14 ); + } + break; + + case FSYS_STYLE_BSD: + if ( aName.Len() > 250 ) + { + nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; + aName.Erase( 250 ); + } + break; + + case FSYS_STYLE_MAC: + if ( eFlag & ( FSYS_FLAG_ABSROOT | FSYS_FLAG_VOLUME ) ) + { + if ( aName.Len() > 27 ) + { + nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; + aName.Erase( 27 ); + } + } + else + { + if ( aName.Len() > 31 ) + { + nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; + aName.Erase( 31 ); + } + } + break; + + default: + /* kann nicht sein */; + } +} + +/************************************************************************* +|* +|* DirEntry::DirEntry() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry::DirEntry( const ByteString& rName, DirEntryFlag eDirFlag, + FSysPathStyle eStyle ) : +#ifdef FEAT_FSYS_DOUBLESPEED + pStat( 0 ), +#endif + aName( rName ) +{ + DBG_CTOR( DirEntry, ImpCheckDirEntry ); + + pParent = NULL; + eFlag = eDirFlag; + nError = FSYS_ERR_OK; + + ImpTrim( eStyle ); +} + +/************************************************************************* +|* +|* DirEntry::DirEntry() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry::DirEntry( const DirEntry& rOrig ) : +#ifdef FEAT_FSYS_DOUBLESPEED + pStat( rOrig.pStat ? new FileStat(*rOrig.pStat) : 0 ), +#endif + aName( rOrig.aName ) +{ + DBG_CTOR( DirEntry, ImpCheckDirEntry ); + + eFlag = rOrig.eFlag; + nError = rOrig.nError; + + if ( rOrig.pParent ) + { + pParent = new DirEntry( *rOrig.pParent ); + } + else + { + pParent = NULL; + } +} + +/************************************************************************* +|* +|* DirEntry::DirEntry() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry::DirEntry( const String& rInitName, FSysPathStyle eStyle ) +#ifdef FEAT_FSYS_DOUBLESPEED + : pStat( 0 ) +#endif +{ + DBG_CTOR( DirEntry, ImpCheckDirEntry ); + + pParent = NULL; + + // schnelle Loesung fuer Leerstring + if ( !rInitName.Len()) + { + eFlag = FSYS_FLAG_CURRENT; + nError = FSYS_ERR_OK; + return; + } + + ByteString aTmpName(rInitName, osl_getThreadTextEncoding()); + if( eStyle == FSYS_STYLE_URL || aTmpName.CompareIgnoreCaseToAscii("file:",5 ) == COMPARE_EQUAL ) + { +#ifndef BOOTSTRAP + DBG_WARNING( "File URLs are not permitted but accepted" ); + aTmpName = ByteString(String(INetURLObject( rInitName ).PathToFileName()), osl_getThreadTextEncoding()); + eStyle = FSYS_STYLE_HOST; +#endif // BOOTSTRAP + } + else + { + ::rtl::OUString aTmp; + ::rtl::OUString aOInitName; + if ( FileBase::getFileURLFromSystemPath( OUString( rInitName ), aTmp ) == FileBase::E_None ) + { + aOInitName = OUString( rInitName ); + aTmpName = ByteString( String(aOInitName), osl_getThreadTextEncoding() ); + } + +#ifdef DBG_UTIL + // ASF nur bei Default eStyle, nicht z.B. aus MakeShortName() + if( eStyle == FSYS_STYLE_HOST && + aTmpName.Search( "://" ) != STRING_NOTFOUND ) + { + ByteString aErr = "DirEntries akzeptieren nur File URLS: "; + aErr += aTmpName; + DBG_WARNING( aErr.GetBuffer() ); + } +#endif + } + + nError = ImpParseName( aTmpName, eStyle ); + + if ( nError != FSYS_ERR_OK ) + eFlag = FSYS_FLAG_INVALID; +} + +/*************************************************************************/ + +DirEntry::DirEntry( const ByteString& rInitName, FSysPathStyle eStyle ) +#ifdef FEAT_FSYS_DOUBLESPEED + : pStat( 0 ) +#endif +{ + DBG_CTOR( DirEntry, ImpCheckDirEntry ); + + pParent = NULL; + + // schnelle Loesung fuer Leerstring + if ( !rInitName.Len() ) + { + eFlag = FSYS_FLAG_CURRENT; + nError = FSYS_ERR_OK; + return; + } + + ByteString aTmpName( rInitName ); + if( eStyle == FSYS_STYLE_URL || rInitName.CompareIgnoreCaseToAscii("file:",5 ) == COMPARE_EQUAL ) + { +#ifndef BOOTSTRAP + DBG_WARNING( "File URLs are not permitted but accepted" ); + aTmpName = ByteString(String(INetURLObject( rInitName ).PathToFileName()), osl_getThreadTextEncoding()); + eStyle = FSYS_STYLE_HOST; +#endif + } +#ifdef DBG_UTIL + else + // ASF nur bei Default eStyle, nicht z.B. aus MakeShortName() + if( eStyle == FSYS_STYLE_HOST && + rInitName.Search( "://" ) != STRING_NOTFOUND ) + { + ByteString aErr = "DirEntries akzeptieren nur File URLS: "; + aErr += rInitName; + DBG_WARNING( aErr.GetBuffer() ); + } +#endif + + nError = ImpParseName( aTmpName, eStyle ); + + if ( nError != FSYS_ERR_OK ) + eFlag = FSYS_FLAG_INVALID; +} + +/************************************************************************* +|* +|* DirEntry::DirEntry() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry::DirEntry( DirEntryFlag eDirFlag ) +#ifdef FEAT_FSYS_DOUBLESPEED + : pStat( 0 ) +#endif +{ + DBG_CTOR( DirEntry, ImpCheckDirEntry ); + + eFlag = eDirFlag; + nError = ( eFlag == FSYS_FLAG_INVALID ) ? FSYS_ERR_UNKNOWN : FSYS_ERR_OK; + pParent = NULL; +} + +/************************************************************************* +|* +|* DirEntry::~DirEntry() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry::~DirEntry() +{ + DBG_DTOR( DirEntry, ImpCheckDirEntry ); + + delete pParent; +#ifdef FEAT_FSYS_DOUBLESPEED + delete pStat; +#endif + +} + +/************************************************************************* +|* +|* DirEntry::ImpGetTopPtr() const +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +const DirEntry* DirEntry::ImpGetTopPtr() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + const DirEntry *pTemp = this; + while ( pTemp->pParent ) + pTemp = pTemp->pParent; + + return pTemp; +} + +/************************************************************************* +|* +|* DirEntry::ImpGetTopPtr() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 13.11.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry* DirEntry::ImpGetTopPtr() +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntry *pTemp = this; + while ( pTemp->pParent ) + pTemp = pTemp->pParent; + + return pTemp; +} + +/************************************************************************* +|* +|* DirEntry::ImpGetPreTopPtr() +|* +|* Beschreibung liefert einen Pointer auf den vorletzten Entry +|* Ersterstellung MI 01.11.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry* DirEntry::ImpGetPreTopPtr() +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntry *pTemp = this; + if ( pTemp->pParent ) + { + while ( pTemp->pParent->pParent ) + pTemp = pTemp->pParent; + } + + return pTemp; +} + +/************************************************************************* +|* +|* DirEntry::ImpChangeParent() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 21.05.92 +|* +*************************************************************************/ + +DirEntry* DirEntry::ImpChangeParent( DirEntry* pNewParent, BOOL bNormalize ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntry *pTemp = pParent; + if ( bNormalize && pNewParent && + pNewParent->eFlag == FSYS_FLAG_RELROOT && !pNewParent->aName.Len() ) + { + pParent = 0; + delete pNewParent; + } + else + pParent = pNewParent; + + return pTemp; +} + +/************************************************************************* +|* +|* DirEntry::Exists() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 24.09.91 +|* +*************************************************************************/ + +BOOL DirEntry::Exists( FSysAccess nAccess ) const +{ +#ifndef BOOTSTRAP + static osl::Mutex aLocalMutex; + osl::MutexGuard aGuard( aLocalMutex ); +#endif + if ( !IsValid() ) + return FALSE; + +#if defined WNT || defined OS2 + // spezielle Filenamen sind vom System da + if ( ( aName.CompareIgnoreCaseToAscii("CLOCK$") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("CON") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("AUX") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("COM1") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("COM2") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("COM3") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("COM4") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("LPT1") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("LPT2") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("LPT3") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("NUL") == COMPARE_EQUAL || + aName.CompareIgnoreCaseToAscii("PRN") == COMPARE_EQUAL ) ) + return TRUE; +#endif + + FSysFailOnErrorImpl(); + DirEntryKind eKind = FileStat( *this, nAccess ).GetKind(); + if ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) ) + { + return TRUE; + } + +#if defined WNT || defined OS2 + if ( 0 != ( eKind & FSYS_KIND_DEV ) ) + { + return DRIVE_EXISTS( ImpGetTopPtr()->aName.GetChar(0) ); + } +#endif + + return 0 != ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) ); +} + +/************************************************************************* +|* +|* DirEntry::First() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 15.01.92 +|* +*************************************************************************/ + +BOOL DirEntry::First() +{ + FSysFailOnErrorImpl(); + + String aUniPathName( GetPath().GetFull() ); +#ifndef BOOTSTRAP + FSysRedirector::DoRedirect( aUniPathName ); + ByteString aPathName(aUniPathName, osl_getThreadTextEncoding()); +#else + ByteString aPathName(aUniPathName, gsl_getSystemTextEncoding()); +#endif + aPathName = GUI2FSYS( aPathName ); + + DIR *pDir = opendir( (char*) aPathName.GetBuffer() ); + if ( pDir ) + { +#ifndef BOOTSTRAP + WildCard aWildeKarte( String(CMP_LOWER( aName ), osl_getThreadTextEncoding()) ); +#else + WildCard aWildeKarte( String(CMP_LOWER( aName ), gsl_getSystemTextEncoding()) ); +#endif + for ( dirent* pEntry = readdir( pDir ); + pEntry; + pEntry = readdir( pDir ) ) + { + ByteString aFound( FSYS2GUI( ByteString( pEntry->d_name ) ) ); + if ( aWildeKarte.Matches( String(CMP_LOWER( aFound ), osl_getThreadTextEncoding()))) + { + aName = aFound; + closedir( pDir ); + return TRUE; + } + } + closedir( pDir ); + } + return FALSE; +} + +/************************************************************************* +|* +|* DirEntry::GetFull() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +String DirEntry::GetFull( FSysPathStyle eStyle, BOOL bWithDelimiter, + USHORT nMaxChars ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + ByteString aRet; + eStyle = GetStyle( eStyle ); + if ( pParent ) + { + if ( ( pParent->eFlag == FSYS_FLAG_ABSROOT || + pParent->eFlag == FSYS_FLAG_RELROOT || + pParent->eFlag == FSYS_FLAG_VOLUME ) ) + { + aRet = ByteString(pParent->GetName( eStyle ), osl_getThreadTextEncoding()); + aRet += ByteString(GetName( eStyle ), osl_getThreadTextEncoding()); + } + else + { + aRet = ByteString(pParent->GetFull( eStyle ), osl_getThreadTextEncoding()); + aRet += ACCESSDELIM_C(eStyle); + aRet += ByteString(GetName( eStyle ), osl_getThreadTextEncoding()); + } + } + else + { + aRet = ByteString(GetName( eStyle ), osl_getThreadTextEncoding()); + } + + if ( ( eStyle == FSYS_STYLE_MAC ) && + ( ImpGetTopPtr()->eFlag != FSYS_FLAG_VOLUME ) && + ( ImpGetTopPtr()->eFlag != FSYS_FLAG_ABSROOT ) && + ( aRet.GetChar(0) != ':' ) ) + aRet.Insert( ACCESSDELIM_C(eStyle), 0 ); + + //! Hack + if ( bWithDelimiter ) + if ( aRet.GetChar( aRet.Len()-1 ) != ACCESSDELIM_C(eStyle) ) + aRet += ACCESSDELIM_C(eStyle); + + //! noch ein Hack + if ( nMaxChars < STRING_MAXLEN ) + aRet = ImplCutPath( aRet, nMaxChars, ACCESSDELIM_C(eStyle) ); + + return String(aRet, osl_getThreadTextEncoding()); +} + +/************************************************************************* +|* +|* DirEntry::GetPath() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry DirEntry::GetPath() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + if ( pParent ) + return DirEntry( *pParent ); + + return DirEntry(); +} + +/************************************************************************* +|* +|* DirEntry::GetExtension() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +String DirEntry::GetExtension( char cSep ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + const char *p0 = ( aName.GetBuffer() ); + const char *p1 = p0 + aName.Len() - 1; + while ( p1 >= p0 && *p1 != cSep ) + p1--; + + if ( p1 >= p0 ) + // es wurde ein cSep an der Position p1 gefunden + return String( + aName.Copy( static_cast< xub_StrLen >(p1 - p0 + 1) ), + osl_getThreadTextEncoding()); + return String(); +} + +/************************************************************************* +|* +|* DirEntry::GetBase() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +String DirEntry::GetBase( char cSep ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + const char *p0 = ( aName.GetBuffer() ); + const char *p1 = p0 + aName.Len() - 1; + while ( p1 >= p0 && *p1 != cSep ) + p1--; + + if ( p1 >= p0 ) + // es wurde ein cSep an der Position p1 gefunden + return String( + aName.Copy( 0, static_cast< xub_StrLen >(p1 - p0) ), + osl_getThreadTextEncoding()); + + else + // es wurde kein cSep gefunden + return String(aName, osl_getThreadTextEncoding()); +} + +/************************************************************************* +|* +|* DirEntry::GetName() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 13:47 +|* +*************************************************************************/ + +String DirEntry::GetName( FSysPathStyle eStyle ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + ByteString aRet; + eStyle = GetStyle( eStyle ); + + switch( eFlag ) + { + case FSYS_FLAG_PARENT: + aRet = ACTPARENT(eStyle); + break; + + case FSYS_FLAG_ABSROOT: + { + if ( eStyle == FSYS_STYLE_URL ) + { + aRet = "file:///"; + aRet += aName; + +#ifndef UNX + if ( aName.Len()) + { + if ( aName.GetChar(aName.Len()-1) == ':' ) + { + aRet.SetChar(aRet.Len()-1, '|'); + } + else + { + aRet.Insert( '/', 5 ); + } + aRet += "/"; + } +#endif + } + else if ( eStyle != FSYS_STYLE_MAC && + aName.Len() > 1 && aName.GetChar( 1 ) != ':' ) + { + // UNC-Pathname + aRet = ACCESSDELIM_C(eStyle); + aRet += ACCESSDELIM_C(eStyle); + aRet += aName ; + aRet += ACCESSDELIM_C(eStyle); + } + else + { + aRet = aName; + aRet += ACCESSDELIM_C(eStyle); + } + break; + } + + case FSYS_FLAG_INVALID: + case FSYS_FLAG_VOLUME: + { + if ( eStyle == FSYS_STYLE_URL ) + { + aRet = "file:///"; + aRet += aName; +#ifndef UNX + if ( aName.Len() && aName.GetChar(aName.Len()-1) == ':' ) + { + aRet.SetChar(aRet.Len()-1, '|'); + } +#endif + } + else + { + aRet = aName; + } + + break; + } + + case FSYS_FLAG_RELROOT: + if ( !aName.Len() ) + { + aRet = ACTCURRENT(eStyle); + break; + } + + default: + aRet = aName; + } + + return String(aRet, osl_getThreadTextEncoding()); +} + +/************************************************************************* +|* +|* DirEntry::IsAbs() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +bool DirEntry::IsAbs() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + +#ifdef UNX + return ( pParent ? pParent->IsAbs() : eFlag == FSYS_FLAG_ABSROOT ); +#else + return ( pParent ? pParent->IsAbs() : eFlag == FSYS_FLAG_ABSROOT && aName.Len() > 0 ); +#endif +} + +/************************************************************************* +|* +|* DirEntry::CutName() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +String DirEntry::CutName( FSysPathStyle eStyle ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + eStyle = GetStyle( eStyle ); + + String aOldName( GetName( eStyle ) ); + + if ( pParent ) + { + DirEntry *pOldParent = pParent; + if ( pOldParent ) + { + pParent = pOldParent->pParent; + eFlag = pOldParent->eFlag; + aName = pOldParent->aName; + pOldParent->pParent = NULL; + delete pOldParent; + } + else + { + eFlag = FSYS_FLAG_CURRENT; + aName.Erase(); + } + } + else + { + eFlag = FSYS_FLAG_CURRENT; + aName.Erase(); + delete pParent; + pParent = NULL; + } + + return aOldName; +} + +/************************************************************************* +|* +|* DirEntry::NameCompare +|* +|* Beschreibung Vergleich nur die Namen (ohne Pfad, aber mit Gross/Klein) +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +StringCompare DirEntry::NameCompare( const DirEntry &rWith ) const +{ + ByteString aThisName; + ByteString aParameterName; + +#ifdef UNX + aThisName = aName; + aParameterName = rWith.aName; +#else + aThisName = ByteString(aName).ToLowerAscii(); + aParameterName = ByteString(rWith.aName).ToLowerAscii(); +#endif + + return aThisName.CompareTo( aParameterName ); +} + + +/************************************************************************* +|* +|* DirEntry::operator==() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +BOOL DirEntry::operator==( const DirEntry& rEntry ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + // test wheather the contents are textual the same + + if ( nError && ( nError == rEntry.nError ) ) + return TRUE; + if ( nError || rEntry.nError || + ( eFlag == FSYS_FLAG_INVALID ) || + ( rEntry.eFlag == FSYS_FLAG_INVALID ) ) + return FALSE; + +#ifndef OS2 + const +#endif + DirEntry *pThis = (DirEntry *)this; +#ifndef OS2 + const +#endif + DirEntry *pWith = (DirEntry *)&rEntry; + while( pThis && pWith && (pThis->eFlag == pWith->eFlag) ) + { + if ( CMP_LOWER(pThis->aName) != CMP_LOWER(pWith->aName) ) + break; + pThis = pThis->pParent; + pWith = pWith->pParent; + } + + return ( !pThis && !pWith ); +} + +/************************************************************************* +|* +|* DirEntry::operator=() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry& DirEntry::operator=( const DirEntry& rEntry ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + if ( this == &rEntry ) + return *this; + if ( rEntry.nError != FSYS_ERR_OK ) { + DBG_ERROR("Zuweisung mit invalidem DirEntry"); + nError = rEntry.nError; + return *this; + } + + // Name und Typ uebernehmen, Refs beibehalten + aName = rEntry.aName; + eFlag = rEntry.eFlag; + nError = FSYS_ERR_OK; + + DirEntry *pOldParent = pParent; + if ( rEntry.pParent ) + pParent = new DirEntry( *rEntry.pParent ); + else + pParent = NULL; + + if ( pOldParent ) + delete pOldParent; + return *this; +} + +/************************************************************************* +|* +|* DirEntry::operator+() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry DirEntry::operator+( const DirEntry& rEntry ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); +#ifdef DBG_UTIL + static BOOL bTested = FALSE; + if ( !bTested ) + { + bTested = TRUE; + FSysTest(); + } +#endif + + const DirEntry *pEntryTop = rEntry.ImpGetTopPtr(); + const DirEntry *pThisTop = ImpGetTopPtr(); + + // "." + irgendwas oder irgendwas + "d:irgendwas" +/* TPF:org + if ( ( eFlag == FSYS_FLAG_RELROOT && !aName ) || + ( pEntryTop->aName.Len() && + ( pEntryTop->eFlag == FSYS_FLAG_ABSROOT || + pEntryTop->eFlag == FSYS_FLAG_RELROOT || + pEntryTop->eFlag == FSYS_FLAG_VOLUME ) ) ) + return rEntry; +*/ + + if ( + (eFlag == FSYS_FLAG_RELROOT && !aName.Len()) || + ( + (pEntryTop->aName.Len() || + ((rEntry.Level()>1)?(rEntry[rEntry.Level()-2].aName.CompareIgnoreCaseToAscii(RFS_IDENTIFIER)==COMPARE_EQUAL):FALSE)) + && + (pEntryTop->eFlag == FSYS_FLAG_ABSROOT || + pEntryTop->eFlag == FSYS_FLAG_RELROOT || + pEntryTop->eFlag == FSYS_FLAG_VOLUME) + ) + ) + { + return rEntry; + } + + // irgendwas + "." (=> pEntryTop == &rEntry) + if ( pEntryTop->eFlag == FSYS_FLAG_RELROOT && !pEntryTop->aName.Len() ) + { + DBG_ASSERT( pEntryTop == &rEntry, "DirEntry::op+ buggy" ); + return *this; + } + + // root += ".." (=> unmoeglich) + if ( pEntryTop->eFlag == FSYS_FLAG_PARENT && pThisTop == this && + ( eFlag == FSYS_FLAG_ABSROOT ) ) + return DirEntry( FSYS_FLAG_INVALID ); + + // irgendwas += abs (=> nur Device uebernehmen falls vorhanden) + if ( pEntryTop->eFlag == FSYS_FLAG_ABSROOT ) + { + ByteString aDevice; + if ( pThisTop->eFlag == FSYS_FLAG_ABSROOT ) + aDevice = pThisTop->aName; + DirEntry aRet = rEntry; + if ( aDevice.Len() ) + aRet.ImpGetTopPtr()->aName = aDevice; + return aRet; + } + + // irgendwas += ".." (=> aufloesen) + if ( eFlag == FSYS_FLAG_NORMAL && pEntryTop->eFlag == FSYS_FLAG_PARENT ) + { + String aConcated( GetFull() ); + aConcated += ACCESSDELIM_C(FSYS_STYLE_HOST); + aConcated += rEntry.GetFull(); + return DirEntry( aConcated ); + } + + // sonst einfach hintereinander haengen + DirEntry aRet( rEntry ); + DirEntry *pTop = aRet.ImpGetTopPtr(); + pTop->pParent = new DirEntry( *this ); + + return aRet; +} + +/************************************************************************* +|* +|* DirEntry::operator+=() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +DirEntry &DirEntry::operator+=( const DirEntry& rEntry ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + return *this = *this + rEntry; +} + +/************************************************************************* +|* +|* DirEntry::GetAccessDelimiter() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 27.05.93 +|* Letzte Aenderung MI 10.06.93 +|* +*************************************************************************/ + +String DirEntry::GetAccessDelimiter( FSysPathStyle eFormatter ) +{ + return String( ACCESSDELIM_C( GetStyle( eFormatter ) ) ); +} + +/************************************************************************* +|* +|* DirEntry::SetExtension() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 02.08.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +void DirEntry::SetExtension( const String& rExtension, char cSep ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + // do not set extensions for drives + if(eFlag == FSYS_FLAG_ABSROOT) + { + nError = FSYS_ERR_NOTSUPPORTED; + return; + } + + // cSep im Namen suchen + const char *p0 = ( aName.GetBuffer() ); + const char *p1 = p0 + aName.Len() - 1; + while ( p1 >= p0 && *p1 != cSep ) + p1--; + if ( p1 >= p0 ) + { + // es wurde ein cSep an der Position p1 gefunden + aName.Erase( + static_cast< xub_StrLen >( + p1 - p0 + 1 - ( rExtension.Len() ? 0 : 1 )) ); + aName += ByteString(rExtension, osl_getThreadTextEncoding()); + } + else if ( rExtension.Len() ) + { + // es wurde kein cSep gefunden + aName += cSep; + aName += ByteString(rExtension, osl_getThreadTextEncoding()); + } +} + +/************************************************************************* +|* +|* DirEntry::CutExtension() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 23.07.93 +|* Letzte Aenderung MI 23.07.93 +|* +*************************************************************************/ + +String DirEntry::CutExtension( char cSep ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + const char *p0 = ( aName.GetBuffer() ); + const char *p1 = p0 + aName.Len() - 1; + while ( p1 >= p0 && *p1 != cSep ) + p1--; + + if ( p1 >= p0 ) + { + // es wurde ein cSep an der Position p1 gefunden + aName.Erase( static_cast< xub_StrLen >(p1-p0) ); + return String(p1 + 1, osl_getThreadTextEncoding()); + } + + return String(); +} + +/************************************************************************* +|* +|* DirEntry::SetName() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 04.09.93 +|* Letzte Aenderung MI 04.09.93 +|* +*************************************************************************/ + +void DirEntry::SetName( const String& rName, FSysPathStyle eFormatter ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + if ( eFormatter == FSYS_STYLE_HOST || eFormatter == FSYS_STYLE_DETECT ) + eFormatter = DEFSTYLE; + ByteString aAccDelim( ACCESSDELIM_C( eFormatter ) ); + + if ( (eFlag != FSYS_FLAG_NORMAL) || + (aName.Search( ':' ) != STRING_NOTFOUND) || + (aName.Search( aAccDelim ) != STRING_NOTFOUND) || + (eFormatter == FSYS_STYLE_FAT && (aName.GetTokenCount( '.' ) > 2) ) ) + { + eFlag = FSYS_FLAG_INVALID; + } + else + { + aName = ByteString(rName, osl_getThreadTextEncoding()); + } +} + +/************************************************************************* +|* +|* DirEntry::Find() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ +BOOL DirEntry::Find( const String& rPfad, char cDelim ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + if ( ImpGetTopPtr()->eFlag == FSYS_FLAG_ABSROOT ) + return TRUE; + + BOOL bWild = aName.Search( '*' ) != STRING_NOTFOUND || + aName.Search( '?' ) != STRING_NOTFOUND; + if ( !cDelim ) + cDelim = SEARCHDELIM(DEFSTYLE)[0]; + + USHORT nTokenCount = rPfad.GetTokenCount( cDelim ); + USHORT nIndex = 0; + ByteString aThis = ACCESSDELIM(DEFSTYLE); + aThis += ByteString(GetFull(), osl_getThreadTextEncoding()); + for ( USHORT nToken = 0; nToken < nTokenCount; ++nToken ) + { + ByteString aPath = ByteString(rPfad, osl_getThreadTextEncoding()).GetToken( 0, cDelim, nIndex ); + + if ( aPath.Len() ) + { + if (aPath.GetChar(aPath.Len()-1)== ACCESSDELIM(DEFSTYLE)[0]) + aPath.Erase(aPath.Len()-1); + aPath += aThis; + DirEntry aEntry( String(aPath, osl_getThreadTextEncoding())); + if ( aEntry.ToAbs() && + ( ( !bWild && aEntry.Exists() ) || ( bWild && aEntry.First() ) ) ) + { + (*this) = aEntry; + return TRUE; + } + } + } + return FALSE; +} + +/************************************************************************* +|* +|* DirEntry::ImpToRel() +|* +|* Beschreibung +|* Ersterstellung MI 17.06.93 +|* Letzte Aenderung MI 17.06.93 +|* +*************************************************************************/ + +BOOL DirEntry::ImpToRel( String aCurStr ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntry aThis(*this); + aThis.ToAbs(); + String aThisStr( aThis.GetFull( FSYS_STYLE_HPFS ) ); + + // #109512 preserve case of path even if caseinsensitive + String aThisCompareStr( aThisStr ), aCurCompareStr( aCurStr ); + if ( ! IsCaseSensitive() ) + { + aThisCompareStr.ToLowerAscii(); + aCurCompareStr.ToLowerAscii(); + } + + // "Ubereinstimmung pr"ufen + USHORT nPos = aThisCompareStr.Match( aCurCompareStr ); + if ( nPos == STRING_MATCH && aThisStr.Len() != aCurStr.Len() ) + nPos = Min( aThisStr.Len(), aCurStr.Len() ); + + // Sonderfall, die DirEntries sind identisch + if ( nPos == STRING_MATCH ) + { + // dann ist der relative Pfad das aktuelle Verzeichnis + *this = DirEntry(); + return TRUE; + } + + // Sonderfall, die DirEntries sind total verschieden + if ( nPos == 0 ) + { + // dann ist der relativste Pfad absolut + *this = aThis; + return FALSE; + } + + // sonst nehmen wir die identischen Einzelteile vorne weg + while ( nPos > 0 && aThisStr.GetChar(nPos) != '\\' ) + --nPos; + aThisStr.Erase( 0, nPos + ( ( aThisStr.GetChar(nPos) == '\\' ) ? 1 : 0 ) ); + aCurStr.Erase( 0, nPos + ( ( aCurStr.GetChar(nPos) == '\\' ) ? 1 : 0 ) ); + + // und fuellen mit dem Level der Directories auf + for ( nPos = 0; nPos < aCurStr.Len(); ++nPos ) + if ( aCurStr.GetChar(nPos) == '\\' ) + aThisStr.Insert( String( "..\\", osl_getThreadTextEncoding() ), 0 ); + + // das ist dann unser relativer Pfad + *this = DirEntry( aThisStr, FSYS_STYLE_HPFS ); + return TRUE; +} + +/************************************************************************* +|* +|* DirEntry::CutRelParents() +|* +|* Beschreibung +|* Ersterstellung MI 01.08.95 +|* Letzte Aenderung MI 01.08.95 +|* +*************************************************************************/ + +USHORT DirEntry::CutRelParents() +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + // erstes '..' finden + DirEntry *pDir = 0; + DirEntry *pPar; + + for ( pPar = this; + pPar && pPar->eFlag != FSYS_FLAG_PARENT; + pPar = pPar->pParent ) + pDir = pPar; + + // '..' zaehlen + USHORT nParCount = 0; + while ( pPar && pPar->eFlag == FSYS_FLAG_PARENT ) + { + ++nParCount; + pPar = pPar->pParent; + } + + // cutten + if ( pDir ) + DELETEZ(pDir->pParent); + else + eFlag = FSYS_FLAG_CURRENT; + + return nParCount; +} + +/************************************************************************* +|* +|* DirEntry::ToRel() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.06.93 +|* Letzte Aenderung MI 17.06.93 +|* +*************************************************************************/ + +BOOL DirEntry::ToRel() +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntry aCur; + aCur.ToAbs(); + return ImpToRel( aCur.GetFull( FSYS_STYLE_HPFS ) ); +} + +/************************************************************************* +|* +|* DirEntry::ToRel() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +BOOL DirEntry::ToRel( const DirEntry& rStart ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntry aStart( rStart ); + aStart.ToAbs(); + return ImpToRel( aStart.GetFull( FSYS_STYLE_HPFS ) ); +} + +/************************************************************************* +|* +|* DirEntry::GetDevice() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +#ifndef UNX + +DirEntry DirEntry::GetDevice() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + const DirEntry *pTop = ImpGetTopPtr(); + + if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT || pTop->eFlag == FSYS_FLAG_RELROOT ) && + pTop->aName.Len() ) + return DirEntry( pTop->aName, FSYS_FLAG_VOLUME, FSYS_STYLE_HOST ); + else + return DirEntry( ByteString(), FSYS_FLAG_INVALID, FSYS_STYLE_HOST ); +} + +#endif + +/************************************************************************* +|* +|* DirEntry::SetBase() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 23.10.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +void DirEntry::SetBase( const String& rBase, char cSep ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + const char *p0 = ( aName.GetBuffer() ); + const char *p1 = p0 + aName.Len() - 1; + while ( p1 >= p0 && *p1 != cSep ) + p1--; + + if ( p1 >= p0 ) + { + // es wurde ein cSep an der Position p1 gefunden + aName.Erase( 0, static_cast< xub_StrLen >(p1 - p0) ); + aName.Insert( ByteString(rBase, osl_getThreadTextEncoding()), 0 ); + } + else + aName = ByteString(rBase, osl_getThreadTextEncoding()); +} + +/************************************************************************* +|* +|* DirEntry::GetSearchDelimiter() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 10.06.93 +|* Letzte Aenderung MI 10.06.93 +|* +*************************************************************************/ + +String DirEntry::GetSearchDelimiter( FSysPathStyle eFormatter ) +{ + return String( ByteString(SEARCHDELIM( GetStyle( eFormatter ) ) ), osl_getThreadTextEncoding()); +} + +/************************************************************************* +|* +|* DirEntry::GetMaxNameLen() +|* +|* Beschreibung Liefert die maximale Anzahl von Zeichen in +|* einzelnen Namensteile. Bei FileSystmen mit +|* fester Extension (FAT) zaehlt diese nicht mit. +|* Bei unbekannten FileSytemen und FSYS_STYLE_URL +|* wird USHRT_MAX zurueckgegeben. +|* Ersterstellung MI 17.06.97 +|* Letzte Aenderung MI 17.06.97 +|* +*************************************************************************/ + +USHORT DirEntry::GetMaxNameLen( FSysPathStyle eFormatter ) +{ + eFormatter = GetStyle( eFormatter ); + switch ( eFormatter ) + { + case FSYS_STYLE_MAC: return 31; + + case FSYS_STYLE_FAT: return 8; + + case FSYS_STYLE_VFAT: + case FSYS_STYLE_NTFS: + case FSYS_STYLE_NWFS: + case FSYS_STYLE_HPFS: return 255; + + + case FSYS_STYLE_SYSV: return 14; + + case FSYS_STYLE_BSD: return 250; + + default: + return USHRT_MAX; + } +} + +/************************************************************************* +|* +|* DirEntry::TempName() +|* +|* Beschreibung FSYS.SDW - Aha, wo? +|* Ersterstellung VB 06.09.93 (im SWG) +|* Letzte Aenderung MI 06.02.98 +|* +*************************************************************************/ +namespace { struct TempNameBase_Impl : public rtl::Static< DirEntry, TempNameBase_Impl > {}; } + +const DirEntry& DirEntry::SetTempNameBase( const String &rBase ) +{ + DirEntry aTempDir = DirEntry().TempName().GetPath(); + aTempDir += DirEntry( rBase ); +#ifdef UNX + ByteString aName( aTempDir.GetFull(), osl_getThreadTextEncoding()); + if ( access( aName.GetBuffer(), W_OK | X_OK | R_OK ) ) + { + // Create the directory and only on success give all rights to + // everyone. Use mkdir instead of DirEntry::MakeDir because + // this returns TRUE even if directory already exists. + + if ( !mkdir( aName.GetBuffer(), S_IRWXU | S_IRWXG | S_IRWXO ) ) + chmod( aName.GetBuffer(), S_IRWXU | S_IRWXG | S_IRWXO ); + + // This will not create a directory but perhaps FileStat called + // there modifies the DirEntry + + aTempDir.MakeDir(); + } +#else + aTempDir.MakeDir(); +#endif + DirEntry &rEntry = TempNameBase_Impl::get(); + rEntry = aTempDir.TempName( FSYS_KIND_DIR ); + return rEntry; +} + +DirEntry DirEntry::TempName( DirEntryKind eKind ) const +{ + // ggf. Base-Temp-Dir verwenden (macht Remote keinen Sinn => vorher) + const DirEntry &rEntry = TempNameBase_Impl::get(); + if ( !pParent && FSYS_FLAG_CURRENT != rEntry.eFlag && FSYS_FLAG_ABSROOT != eFlag ) + + { + DirEntry aFactory( rEntry ); + aFactory += GetName(); + return aFactory.TempName(); + } + + ByteString aDirName; // hiermit hatte MPW C++ Probleme - immmer noch?? + char *ret_val; + size_t i; + + // dertermine Directory, Prefix and Extension + char pfx[6]; + char ext[5]; + const char *dir; + const char *pWild = strchr( aName.GetBuffer(), '*' ); + if ( !pWild ) + pWild = strchr( aName.GetBuffer(), '?' ); + + if ( pWild ) + { + if ( pParent ) + aDirName = ByteString(pParent->GetFull(), osl_getThreadTextEncoding()); + strncpy( pfx, aName.GetBuffer(), Min( (int)5, (int)(pWild-aName.GetBuffer()) ) ); + pfx[ pWild-aName.GetBuffer() ] = 0; + const char *pExt = strchr( pWild, '.' ); + if ( pExt ) + { + strncpy( ext, pExt, 4 ); + ext[4] = 0; + } + else + strcpy( ext, ".tmp" ); + } + else + { + aDirName = ByteString(GetFull(), osl_getThreadTextEncoding()); + strcpy( pfx, "sv" ); + strcpy( ext, ".tmp" ); + } + dir = aDirName.GetBuffer(); + + // wurde kein Dir angegeben, dann nehmen wir ein passendes TEMP-Verz. + char sBuf[_MAX_PATH]; + if ( eFlag == FSYS_FLAG_CURRENT || ( !pParent && pWild ) ) + dir = TempDirImpl(sBuf); + + // ab hier leicht modifizierter Code von VB + DirEntry aRet(FSYS_FLAG_INVALID); + i = strlen(dir); + // need to add ?\\? + prefix + number + pid + .ext + '\0' +# define TMPNAME_SIZE ( 1 + 5 + 5 + 10 + 4 + 1 ) + ret_val = new char[i + TMPNAME_SIZE ]; + if (ret_val) + { + strcpy(ret_val,dir); + + /* Make sure directory ends with a separator */ +#if defined(WNT) || defined(OS2) + if ( i>0 && ret_val[i-1] != '\\' && ret_val[i-1] != '/' && + ret_val[i-1] != ':') + ret_val[i++] = '\\'; +#elif defined UNX + if (i>0 && ret_val[i-1] != '/') + ret_val[i++] = '/'; +#else +#error unknown operating system +#endif + + strncpy(ret_val + i, pfx, 5); + ret_val[i + 5] = '\0'; /* strncpy doesn't put a 0 if more */ + i = strlen(ret_val); /* than 'n' chars. */ + + /* Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576 + * Welcome to the 21st century, we can have longer filenames now ;) + * New format: pfx + "5 char milli/micro second res" + "current pid" + ".tmp" + */ +#if (defined MSC || defined __MINGW32__) && defined WNT + /* Milliseconds !! */ + static unsigned long u = GetTickCount(); + unsigned long mypid = static_cast<unsigned long>(_getpid()); +#else + /* Microseconds !! */ + static unsigned long u = clock(); + unsigned long mypid = static_cast<unsigned long>(getpid()); +#endif + for ( unsigned long nOld = u; ++u != nOld; ) /* Hae??? */ + { + u %= 100000; /* on *NIX repeats every 100ms, maybe less if CLOCKS_PER_SEC > 10^6 */ + snprintf(ret_val+i, TMPNAME_SIZE, "%05lu%lu", u, mypid); + + strcat(ret_val,ext); + + if ( FSYS_KIND_FILE == eKind ) + { + SvFileStream aStream( String( ret_val, osl_getThreadTextEncoding()), + STREAM_WRITE|STREAM_SHARE_DENYALL ); + if ( aStream.IsOpen() ) + { + aStream.Seek( STREAM_SEEK_TO_END ); + if ( 0 == aStream.Tell() ) + { + aRet = DirEntry( String( ret_val, osl_getThreadTextEncoding())); + break; + } + aStream.Close(); + } + } + else + { + // Redirect + String aRetVal(ret_val, osl_getThreadTextEncoding()); + String aRedirected (aRetVal); +#ifndef BOOTSTRAP + FSysRedirector::DoRedirect( aRedirected ); +#endif + if ( FSYS_KIND_DIR == eKind ) + { + if ( 0 == _mkdir( ByteString(aRedirected.GetBuffer(), osl_getThreadTextEncoding()).GetBuffer() ) ) + { + aRet = DirEntry( aRetVal ); + break; + } + } + else + { +#if defined(UNX) || defined(OS2) + if( access( ByteString(aRedirected, osl_getThreadTextEncoding()).GetBuffer(), F_OK ) ) + { + aRet = DirEntry( aRetVal ); + break; + } +#else + struct stat aStat; + if ( stat( ByteString(aRedirected, osl_getThreadTextEncoding()).GetBuffer(), &aStat ) ) + { + aRet = DirEntry( aRetVal ); + break; + } +#endif + } + } + } + + delete[] ret_val; + ret_val = 0; + } + + return aRet; +} + +/************************************************************************* +|* +|* DirEntry::operator[]() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 03.03.92 +|* Letzte Aenderung MI 03.03.92 +|* +*************************************************************************/ + +const DirEntry &DirEntry::operator[]( USHORT nParentLevel ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + //TPF: maybe to be implemented (FastFSys) + + const DirEntry *pRes = this; + while ( pRes && nParentLevel-- ) + pRes = pRes->pParent; + + return *pRes; +} + +/************************************************************************* +|* +|* DirEntry::ImpParseUnixName() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 26.05.93 +|* +*************************************************************************/ + +FSysError DirEntry::ImpParseUnixName( const ByteString& rPfad, FSysPathStyle eStyle ) +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + // die einzelnen Namen auf einen Stack packen + DirEntryStack aStack; + ByteString aPfad( rPfad ); + do + { + // den Namen vor dem ersten "/" abspalten, + // falls '/' am Anfang, ist der Name '/', + // der Rest immer ohne die fuehrenden '/'. + // den ersten '/' suchen + USHORT nPos; + for ( nPos = 0; + nPos < aPfad.Len() && aPfad.GetChar(nPos) != '/'; + nPos++ ) + /* do nothing */; + + // ist der Name die Root des aktuellen Drives? + if ( nPos == 0 && aPfad.Len() > 0 && ( aPfad.GetChar(0) == '/' ) ) + { + // Root-Directory des aktuellen Drives + aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) ); + } + else + { + // den Namen ohne Trenner abspalten + aName = aPfad.Copy( 0, nPos ); + + // stellt der Name die aktuelle Directory dar? + if ( aName == "." ) + /* do nothing */; + +#ifdef UNX + // stellt der Name das User-Dir dar? + else if ( aName == "~" ) + { + DirEntry aHome( String( (const char *) getenv( "HOME" ), osl_getThreadTextEncoding()) ); + for ( USHORT n = aHome.Level(); n; --n ) + aStack.Push( new DirEntry( aHome[ (USHORT) n-1 ] ) ); + } +#endif + + // stellt der Name die Parent-Directory dar? + else if ( aName == ".." ) + { + // ist nichts, ein Parent oder eine relative Root + // auf dem Stack? + if ( ( aStack.Count() == 0 ) || + ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) ) + // fuehrende Parents kommen auf den Stack + aStack.Push( new DirEntry( ByteString(), FSYS_FLAG_PARENT, eStyle ) ); + + // ist es eine absolute Root + else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT ) { + // die hat keine Parent-Directory + return FSYS_ERR_NOTEXISTS; + } + else + // sonst hebt der Parent den TOS auf + delete aStack.Pop(); + } + else + { + DirEntry *pNew = NULL; + // normalen Entries kommen auf den Stack + pNew = new DirEntry( aName, FSYS_FLAG_NORMAL, eStyle ); + if ( !pNew->IsValid() ) + { + aName = rPfad; + ErrCode eErr = pNew->GetError(); + delete pNew; + return eErr; + } + aStack.Push( pNew ); + } + } + + // den Restpfad bestimmen + aPfad.Erase( 0, nPos + 1 ); + while ( aPfad.Len() && ( aPfad.GetChar(0) == '/' ) ) + aPfad.Erase( 0, 1 ); + } + while ( aPfad.Len() ); + + // Haupt-Entry (selbst) zuweisen + if ( aStack.Count() == 0 ) + { + eFlag = FSYS_FLAG_CURRENT; + aName.Erase(); + } + else + { + eFlag = aStack.Top()->eFlag; + aName = aStack.Top()->aName; + delete aStack.Pop(); + } + + // die Parent-Entries vom Stack holen + DirEntry** pTemp = &pParent; + while ( aStack.Count() ) + { + *pTemp = aStack.Pop(); + pTemp = &( (*pTemp)->pParent ); + } + + return FSYS_ERR_OK; +} + +/************************************************************************* +|* +|* DirEntry::MakeShortName() +|* +|* Beschreibung +|* Ersterstellung TLX +|* Letzte Aenderung PB 21.08.97 (in CreateEntry_Impl()) +|* +*************************************************************************/ + +ErrCode CreateEntry_Impl( const DirEntry &rPath, DirEntryKind eKind ) +{ + // versuchen, anzulegen (ausser bei FSYS_KIND_ALL) + ErrCode eErr = ERRCODE_NONE; + if ( FSYS_KIND_FILE == eKind ) + { + SvFileStream aStream( rPath.GetFull(), STREAM_STD_WRITE ); + aStream.WriteLine( "" ); + eErr = aStream.GetError(); + } + else if ( FSYS_KIND_ALL != eKind ) + eErr = rPath.MakeDir() ? ERRCODE_NONE : ERRCODE_IO_UNKNOWN; + + // erfolgreich? + if ( !rPath.Exists() ) + eErr = ERRCODE_IO_UNKNOWN; // Doch was schiefgegangen ? + + // ggf. wieder l"oschen + if ( FSYS_KIND_NONE == eKind ) + rPath.Kill(); + + // Fehlercode zur?ckliefern + return eErr; +} + +BOOL IsValidEntry_Impl( const DirEntry &rPath, + const String &rLongName, + DirEntryKind eKind, + BOOL bIsShortened, + BOOL bUseDelim ) +{ + // Parameter-Pr"uefung + DBG_ASSERT( eKind == FSYS_KIND_NONE || eKind == FSYS_KIND_ALL || + eKind == FSYS_KIND_FILE || eKind == FSYS_KIND_DIR, + "invalid entry-kind" ); + + // Alle von MSDOS erreichbaren FSYS_STYLES muessen den + // MSDOS Filenamenanforderungen genuegen. Sonst wird probiert, + // ob sich eine Datei des gewuenschten Names anlegen laesst. + FSysPathStyle eStyle = DirEntry::GetPathStyle( rPath.GetDevice().GetName() ); + DirEntry aPath(rPath); + DirEntry aName(rLongName, eStyle); + if ( !aName.IsValid() || aName.Level() != 1 ) + return FALSE; + aPath += aName; + if ( 1 == aPath.Level() ) + return FALSE; + if ( eStyle == FSYS_STYLE_FAT || eStyle == FSYS_STYLE_NWFS || + eStyle == FSYS_STYLE_UNKNOWN ) + { + DirEntry aDosEntry( rLongName, FSYS_STYLE_FAT ); + if ( !aDosEntry.IsValid() ) + return FALSE; + } + + // Pfad-Trenner sind nicht erlaubt (bei ungek"urzten auch nicht FSYS_SHORTNAME_DELIMITER) + char cDelim = bUseDelim == 2 ? FSYS_SHORTNAME_DELIMITER : char(0); + if ( + rLongName.Search(DirEntry::GetAccessDelimiter()) != STRING_NOTFOUND || + (!bIsShortened && rLongName.Search(cDelim) != STRING_NOTFOUND) + ) + { + return FALSE; + } + + // MI: Abfrage nach 'CON:' etc. wird jetzt in Exists() mitgemacht + if ( aPath.Exists() ) + return FALSE; + + return (ERRCODE_NONE == CreateEntry_Impl( aPath, eKind )); +} + +//------------------------------------------------------------------------- + +#define MAX_EXT_FAT 3 +#define MAX_LEN_FAT 8 +#define INVALID_CHARS_FAT "\\/\"':|^<>[]?* " + +#define MAX_EXT_MAC 16 // nur wegen sinnvoller Namensk"rzung +#define MAX_LEN_MAC 31 +#define INVALID_CHARS_MAC "\":" + +#define MAX_EXT_MAX 250 +#define MAX_LEN_MAX 255 +#define INVALID_CHARS_DEF "\\/\"':|^<>?*" + +BOOL DirEntry::MakeShortName( const String& rLongName, DirEntryKind eKind, + BOOL bUseDelim, FSysPathStyle eStyle ) +{ + String aLongName(rLongName); + + // Alle '#' aus den Dateinamen entfernen, weil das INetURLObject + // damit Probleme hat. Siehe auch #51246# + aLongName.EraseAllChars( '#' ); + ByteString bLongName(aLongName, osl_getThreadTextEncoding()); + + // Auf Novell-Servern (wegen der rottigen Clients) nur 7bit ASCII + + // bei FSYS_KIND_ALL den alten Namen merken und abh"angen (rename) + ByteString aOldName; + if ( FSYS_KIND_ALL == eKind ) + { + aOldName = ByteString(CutName(), osl_getThreadTextEncoding()); + aOldName = CMP_LOWER(aOldName); + } + + // ist der Langname direkt verwendbar? + if ( IsValidEntry_Impl( *this, aLongName, eKind, FALSE, bUseDelim ) ) + { + operator+=( DirEntry(aLongName) ); + return TRUE; + } + + // max L"angen feststellen + USHORT nMaxExt, nMaxLen; + if ( FSYS_STYLE_DETECT == eStyle ) + eStyle = DirEntry::GetPathStyle( GetDevice().GetName() ); + ByteString aInvalidChars; + switch ( eStyle ) + { + case FSYS_STYLE_FAT: + nMaxExt = MAX_EXT_FAT; + nMaxLen = MAX_LEN_FAT; + aInvalidChars = INVALID_CHARS_FAT; + break; + + case FSYS_STYLE_MAC: + nMaxExt = MAX_EXT_MAC; + nMaxLen = MAX_LEN_MAC; + aInvalidChars = INVALID_CHARS_MAC; + break; + + default: + nMaxExt = MAX_EXT_MAX; + nMaxLen = MAX_LEN_MAX; + aInvalidChars = INVALID_CHARS_DEF; + } + + // Extension abschneiden und kuerzen + ByteString aExt; + ByteString aFName = bLongName; + if ( FSYS_STYLE_MAC != eStyle ) + { + DirEntry aUnparsed; + aUnparsed.aName = bLongName; + aExt = ByteString(aUnparsed.CutExtension(), osl_getThreadTextEncoding()); + aFName = aUnparsed.aName; + if ( aExt.Len() > nMaxExt ) + { + char c = aExt.GetChar( aExt.Len() - 1 ); + aExt.Erase(nMaxExt-1); + aExt += c; + } + } + + if ( FSYS_STYLE_FAT != eStyle ) + { + // ausser auf einem FAT-System geh"ort die Extension zur + // Maxl"ange. Muss also vorher mit dem Punkt abgezogen werden. + nMaxLen -= ( aExt.Len() + 1 ); + } + + // Name k"urzen + ByteString aSName; + for ( const char *pc = aFName.GetBuffer(); aSName.Len() < nMaxLen && *pc; ++pc ) + { + if ( STRING_NOTFOUND == aInvalidChars.Search( *pc ) && + (unsigned char) *pc >= (unsigned char) 32 && + ( !aSName.Len() || *pc != ' ' || aSName.GetChar(aSName.Len()-1) != ' ' ) ) + aSName += *pc; + } + aSName.EraseTrailingChars(); + + // HRO: #74246# Also cut leading spaces + aSName.EraseLeadingChars(); + + if ( !aSName.Len() ) + aSName = "noname"; + + // kommt dabei der alte Name raus? + ByteString aNewName = aSName; + if ( aExt.Len() ) + ( aNewName += '.' ) += aExt; + operator+=( DirEntry(String(aNewName, osl_getThreadTextEncoding())) ); + if ( FSYS_KIND_ALL == eKind && CMP_LOWER(aName) == aOldName ) + if ( FSYS_KIND_ALL == eKind && CMP_LOWER(ByteString(GetName(), osl_getThreadTextEncoding())) == aOldName ) + return TRUE; + + // kann der gek"urzte Name direkt verwendet werden? + if ( !Exists() && (ERRCODE_NONE == CreateEntry_Impl( *this, eKind )) ) + return TRUE; + + // darf '?##' verwendet werden, um eindeutigen Name zu erzeugen? + if ( bUseDelim ) + { + // eindeutigen Namen per '?##' erzeugen + aSName.Erase( nMaxLen-3 ); + if ( bUseDelim != 2 ) + aSName += FSYS_SHORTNAME_DELIMITER; + for ( int n = 1; n < 99; ++n ) + { + // Name zusammensetzen + ByteString aTmpStr( aSName ); + aTmpStr += ByteString::CreateFromInt32(n); + if ( aExt.Len() ) + ( aTmpStr += '.' ) += aExt; + + // noch nicht vorhanden? + SetName( String(aTmpStr, osl_getThreadTextEncoding()) ); + + if ( !Exists() ) + { + // Fehler setzen !!! + nError = CreateEntry_Impl( *this, eKind ); + return (ERRCODE_NONE == nError); + } + } + } + + // keine ## mehr frei / ?## soll nicht verwendet werden + nError = ERRCODE_IO_ALREADYEXISTS; + return FALSE; +} + +/************************************************************************* +|* +|* DirEntry::CreatePath() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +BOOL DirEntry::MakeDir( BOOL bSloppy ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + // Schnellpruefung, ob vorhanden + if ( FileStat( *this ).IsKind( FSYS_KIND_DIR ) ) + return TRUE; + if ( bSloppy && pParent ) + if ( FileStat( *pParent ).IsKind( FSYS_KIND_DIR ) ) + return TRUE; + + const DirEntry *pNewDir = bSloppy ? pParent : this; + if ( pNewDir ) + { + // den Path zum Dir erzeugen + if ( pNewDir->pParent && !pNewDir->pParent->MakeDir(FALSE) ) + return FALSE; + + // das Dir selbst erzeugen + if ( pNewDir->eFlag == FSYS_FLAG_ABSROOT || + pNewDir->eFlag == FSYS_FLAG_ABSROOT || + pNewDir->eFlag == FSYS_FLAG_VOLUME ) + return TRUE; + else + { + //? nError = ??? + if ( FileStat( *pNewDir ).IsKind( FSYS_KIND_DIR ) ) + return TRUE; + else + { + FSysFailOnErrorImpl(); + String aDirName(pNewDir->GetFull()); +#ifndef BOOTSTRAP + FSysRedirector::DoRedirect( aDirName ); +#endif + ByteString bDirName( aDirName, osl_getThreadTextEncoding() ); + bDirName = GUI2FSYS( bDirName ); + +#ifdef WIN32 + SetLastError(0); +#endif + BOOL bResult = (0 == _mkdir( (char*) bDirName.GetBuffer() )); + if ( !bResult ) + { + // Wer hat diese Methode const gemacht ? +#ifdef WIN32 + ((DirEntry *)this)->SetError( Sys2SolarError_Impl( GetLastError() ) ); +#else + ((DirEntry *)this)->SetError( Sys2SolarError_Impl( errno ) ); +#endif + } + + return bResult; + } + } + } + return TRUE; +} + +/************************************************************************* +|* +|* DirEntry::CopyTo() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 07.08.96 +|* +*************************************************************************/ + +FSysError DirEntry::CopyTo( const DirEntry& rDest, FSysAction nActions ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + if ( FSYS_ACTION_COPYFILE != (nActions & FSYS_ACTION_COPYFILE) ) +#ifdef UNX + { + // Hardlink anlegen + HACK(redirection missing) + ByteString aThis(GUI2FSYS(GetFull()), osl_getThreadTextEncoding()); + ByteString aDest(GUI2FSYS(rDest.GetFull()), osl_getThreadTextEncoding()); + if (link( aThis.GetBuffer(), aDest.GetBuffer() ) == -1) + return Sys2SolarError_Impl( errno ); + else + return FSYS_ERR_OK; + } +#else + return FSYS_ERR_NOTSUPPORTED; +#endif + + FileCopier fc(*this, rDest); + return fc.Execute(nActions); +} + +/************************************************************************* +|* +|* DirEntry::MoveTo() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung HRO 24.03.99 +|* +*************************************************************************/ + +#if defined WNT || defined UNX || defined OS2 + +FSysError DirEntry::MoveTo( const DirEntry& rNewName ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + +/* + FileStat aSourceStat(*this); + if ( !aSourceStat.IsKind(FSYS_KIND_FILE) ) + return FSYS_ERR_NOTAFILE; +*/ + + DirEntry aDest(rNewName); + FileStat aDestStat(rNewName); + if ( aDestStat.IsKind(FSYS_KIND_DIR ) ) + { + aDest += String(aName, osl_getThreadTextEncoding()); + } + if ( aDest.Exists() ) + { + return FSYS_ERR_ALREADYEXISTS; + } + +#if defined(OS2) + if ( FileStat(*this).IsKind(FSYS_KIND_DIR) && aDest.GetPath() != GetPath() ) + { + return FSYS_ERR_NOTSUPPORTED; + } +#endif + + FSysFailOnErrorImpl(); + String aFrom( GetFull() ); + +#ifndef BOOTSTRAP + FSysRedirector::DoRedirect(aFrom); +#endif + + String aTo( aDest.GetFull() ); + +#ifndef BOOTSTRAP + FSysRedirector::DoRedirect(aTo); +#endif + + ByteString bFrom(aFrom, osl_getThreadTextEncoding()); + ByteString bTo(aTo, osl_getThreadTextEncoding()); + bFrom = GUI2FSYS(bFrom); + bTo = GUI2FSYS(bTo); + +#ifdef WNT + // MoveTo nun atomar + SetLastError(0); + + DirEntry aFromDevice(String(bFrom, osl_getThreadTextEncoding())); + DirEntry aToDevice(String(bTo,osl_getThreadTextEncoding())); + aFromDevice.ToAbs(); + aToDevice.ToAbs(); + aFromDevice=aFromDevice.GetDevice(); + aToDevice=aToDevice.GetDevice(); + + //Quelle und Ziel auf gleichem device? + if (aFromDevice==aToDevice) + { + // ja, also intra-device-move mit MoveFile + MoveFile( bFrom.GetBuffer(), bTo.GetBuffer() ); + // MoveFile ist buggy bei cross-device operationen. + // Der R?ckgabewert ist auch dann TRUE, wenn nur ein Teil der Operation geklappt hat. + // Zudem zeigt MoveFile unterschiedliches Verhalten bei unterschiedlichen NT-Versionen. + return Sys2SolarError_Impl( GetLastError() ); + } + else + { + //nein, also inter-device-move mit copy/delete + FSysError nCopyError = CopyTo(rNewName, FSYS_ACTION_COPYFILE); + + DirEntry aKill(String(bTo, osl_getThreadTextEncoding())); + FileStat aKillStat(String(bTo, osl_getThreadTextEncoding())); + if ( aKillStat.IsKind(FSYS_KIND_DIR ) ) + { + aKill += String(aName, osl_getThreadTextEncoding()); + } + + if (nCopyError==FSYS_ERR_OK) + { + if (Kill()==FSYS_ERR_OK) + { + return FSYS_ERR_OK; + } + else + { + aKill.Kill(); + return FSYS_ERR_ACCESSDENIED; + } + } + else + { + aKill.Kill(); + return nCopyError; + } + } +#else + // #68639# + // on some nfs connections rename with from == to + // leads to destruction of file + if ( ( aFrom != aTo ) && ( 0 != rename( bFrom.GetBuffer(), bTo.GetBuffer() ) ) ) +#if !defined(UNX) && !defined(OS2) + return Sys2SolarError_Impl( GetLastError() ); +#else + { + if( errno == EXDEV ) +// cross device geht latuernich nicht mit rename + { + FILE *fpIN = fopen( bFrom.GetBuffer(), "r" ); + FILE *fpOUT = fopen( bTo.GetBuffer(), "w" ); + if( fpIN && fpOUT ) + { + char pBuf[ 16384 ]; + int nBytes, nWritten, nErr = 0; + errno = 0; + while( ( nBytes = fread( pBuf, 1, sizeof(pBuf), fpIN ) ) && ! nErr ) + { + nWritten = fwrite( pBuf, 1, nBytes, fpOUT ); + // Fehler im fwrite ? + if( nWritten < nBytes ) + { + nErr = errno; + break; + } + } + fclose( fpIN ); + fclose( fpOUT ); + if ( nErr ) + { + unlink( bTo.GetBuffer() ); + return Sys2SolarError_Impl( nErr ); + } + else + { + unlink( bFrom.GetBuffer() ); + } + } + else + { + return Sys2SolarError_Impl( EXDEV ); + } + } + else + { + return Sys2SolarError_Impl( errno ); + } + } +#endif +#endif + return ERRCODE_NONE; +} + +#endif + +/************************************************************************* +|* +|* DirEntry::Kill() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 07.08.96 +|* +*************************************************************************/ + +FSysError DirEntry::Kill( FSysAction nActions ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + FSysError eError = FSYS_ERR_OK; + FSysFailOnErrorImpl(); + + // Name als doppelt 0-terminierter String + String aTmpName( GetFull() ); +#ifndef BOOTSTRAP + FSysRedirector::DoRedirect( aTmpName ); +#endif + ByteString bTmpName( aTmpName, osl_getThreadTextEncoding()); + bTmpName = GUI2FSYS(bTmpName); + + char *pName = new char[bTmpName.Len()+2]; + strcpy( pName, bTmpName.GetBuffer() ); + pName[bTmpName.Len()+1] = (char) 0; + + //read-only files sollen auch geloescht werden koennen + BOOL isReadOnly = FileStat::GetReadOnlyFlag(*this); + if (isReadOnly) + { + FileStat::SetReadOnlyFlag(*this, FALSE); + } + + // directory? + if ( FileStat( *this ).IsKind(FSYS_KIND_DIR) ) + { + // Inhalte recursiv loeschen? + if ( FSYS_ACTION_RECURSIVE == (nActions & FSYS_ACTION_RECURSIVE) ) + { + Dir aDir( *this, FSYS_KIND_DIR|FSYS_KIND_FILE ); + for ( USHORT n = 0; eError == FSYS_ERR_OK && n < aDir.Count(); ++n ) + { + const DirEntry &rSubDir = aDir[n]; + DirEntryFlag flag = rSubDir.GetFlag(); + if ( flag != FSYS_FLAG_CURRENT && flag != FSYS_FLAG_PARENT ) + eError = rSubDir.Kill(nActions); + } + } + + // das Dir selbst loeschen +#ifdef WIN32 + SetLastError(0); +#endif + if ( eError == FSYS_ERR_OK && 0 != _rmdir( (char*) pName ) ) + // + { + // falls L"oschen nicht ging, CWD umsetzen +#ifdef WIN32 + eError = Sys2SolarError_Impl( GetLastError() ); +#else + eError = Sys2SolarError_Impl( errno ); +#endif + if ( eError ) + { + GetPath().SetCWD(); +#ifdef WIN32 + SetLastError(0); +#endif + if (_rmdir( (char*) pName) != 0) + { +#ifdef WIN32 + eError = Sys2SolarError_Impl( GetLastError() ); +#else + eError = Sys2SolarError_Impl( errno ); +#endif + } + else + { + eError = FSYS_ERR_OK; + } + } + } + } + else + { + if ( FSYS_ACTION_USERECYCLEBIN == (nActions & FSYS_ACTION_USERECYCLEBIN) ) + { +#ifdef OS2 + eError = ApiRet2ToSolarError_Impl( DosDelete( (PSZ) pName ) ); +#elif defined(WNT) + SHFILEOPSTRUCT aOp; + aOp.hwnd = 0; + aOp.wFunc = FO_DELETE; + aOp.pFrom = pName; + aOp.pTo = 0; + aOp.fFlags = FOF_ALLOWUNDO|FOF_SILENT|FOF_NOCONFIRMATION; + aOp.hNameMappings = 0; + aOp.lpszProgressTitle = 0; + eError = Sys2SolarError_Impl( SHFileOperation( &aOp ) ); +#else + eError = ERRCODE_IO_NOTSUPPORTED; +#endif + } + else + { +#ifdef WIN32 + SetLastError(0); +#endif + if ( 0 != _unlink( (char*) pName ) ) + { +#ifdef WIN32 + eError = Sys2SolarError_Impl( GetLastError() ); +#else + eError = Sys2SolarError_Impl( errno ); +#endif + } + else + { + eError = ERRCODE_NONE; + } + } + } + + //falls Fehler, originales read-only flag wieder herstellen + if ( isReadOnly && (eError!=ERRCODE_NONE) ) + { + FileStat::SetReadOnlyFlag(*this, isReadOnly); + } + + delete[] pName; + return eError; +} + +/************************************************************************* +|* +|* DirEntry::Contains() +|* +|* Beschreibung ob rSubEntry direkt oder indirect in *this liegt +|* Ersterstellung MI 20.03.97 +|* Letzte Aenderung MI 20.03.97 +|* +*************************************************************************/ + +BOOL DirEntry::Contains( const DirEntry &rSubEntry ) const +{ + DBG_ASSERT( IsAbs() && rSubEntry.IsAbs(), "must be absolute entries" ); + + USHORT nThisLevel = Level(); + USHORT nSubLevel = rSubEntry.Level(); + if ( nThisLevel < nSubLevel ) + { + for ( ; nThisLevel; --nThisLevel, --nSubLevel ) + if ( (*this)[nThisLevel-1] != rSubEntry[nSubLevel-1] ) + return FALSE; + return TRUE; + } + return FALSE; +} + +/************************************************************************* +|* +|* DirEntry::Level() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 03.03.92 +|* Letzte Aenderung MI 03.03.92 +|* +*************************************************************************/ + +USHORT DirEntry::Level() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + USHORT nLevel = 0; + const DirEntry *pRes = this; + while ( pRes ) + { + pRes = pRes->pParent; + nLevel++; + } + + return nLevel; +} + +/************************************************************************* +|* +|* DirEntry::ConvertNameToSystem() +|* +|* Beschreibung +|* Ersterstellung DV 29.03.96 +|* Letzte Aenderung DV 29.03.96 +|* +*************************************************************************/ + +String DirEntry::ConvertNameToSystem( const String &rName ) +{ + return rName; +} + +/************************************************************************* +|* +|* DirEntry::ConvertSystemToName() +|* +|* Beschreibung +|* Ersterstellung DV 29.03.96 +|* Letzte Aenderung DV 29.03.96 +|* +*************************************************************************/ + +String DirEntry::ConvertSystemToName( const String &rName ) +{ + return rName; +} + +/************************************************************************* +|* +|* DirEntry::IsValid() +|* +|* Beschreibung +|* Ersterstellung MI 18.09.93 +|* Letzte Aenderung TPF 18.09.98 +|* +*************************************************************************/ + +BOOL DirEntry::IsValid() const +{ + return (nError == FSYS_ERR_OK); +} + +/************************************************************************* +|* +|* DirEntry::IsRFSAvailable() +|* +|* Beschreibung +|* Ersterstellung TPF 21.10.98 +|* Letzte Aenderung TPF 21.10.98 +|* +*************************************************************************/ + +BOOL DirEntry::IsRFSAvailable() +{ + return FALSE; +} + +/************************************************************************* +|* +|* IsLongNameOnFAT() +|* +|* Beschreibung ?berpr?ft , ob das DirEntry einen langen +|* Filenamen auf einer FAT-Partition enth?lt (EAs). +|* (eigentlich nur f?r OS2 interessant) +|* Ersterstellung TPF 02.10.98 +|* Letzte Aenderung TPF 01.03.1999 +|* +*************************************************************************/ + +BOOL DirEntry::IsLongNameOnFAT() const +{ + // FAT-System? + DirEntry aTempDirEntry(*this); + aTempDirEntry.ToAbs(); + if (DirEntry::GetPathStyle(aTempDirEntry.GetDevice().GetName().GetChar(0)) != FSYS_STYLE_FAT) + { + return FALSE; // nein, also false + } + + // DirEntry-Kette auf lange Dateinamen pr?fen + for( USHORT iLevel = this->Level(); iLevel > 0; iLevel-- ) + { + const DirEntry& rEntry = (const DirEntry&) (*this)[iLevel-1]; + String aBase( rEntry.GetBase() ); + String aExtension( rEntry.GetExtension() ); + + if (aBase.Len()>8) // Name > 8? + { + return TRUE; + } + + if (aExtension.Len()>3) // Extension > 3? + { + return TRUE; + } + } + return FALSE; +} + +//======================================================================== + +#if defined(DBG_UTIL) + +void FSysTest() +{ +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/filecopy.cxx b/tools/source/fsys/filecopy.cxx new file mode 100644 index 000000000000..826ffeab31f5 --- /dev/null +++ b/tools/source/fsys/filecopy.cxx @@ -0,0 +1,489 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" + +#if defined WNT +#ifndef _SVWIN_H +#include <io.h> +#include <tools/svwin.h> +#endif + +#elif defined(OS2) +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <share.h> +#include <io.h> + +#elif defined UNX +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> + +#endif + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <stdio.h> +#include "comdep.hxx" +#include <tools/fsys.hxx> +#include <tools/stream.hxx> +#include <osl/file.hxx> + +using namespace ::osl; + +/************************************************************************* +|* +|* FileCopier::FileCopier() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 13.04.94 +|* Letzte Aenderung MI 13.04.94 +|* +*************************************************************************/ + +FileCopier::FileCopier() : + + nBytesTotal ( 0 ), + nBytesCopied( 0 ), + nBlockSize ( 4096 ), + pImp ( new FileCopier_Impl ) + +{ +} + +// ----------------------------------------------------------------------- + +FileCopier::FileCopier( const DirEntry& rSource, const DirEntry& rTarget ) : + + aSource ( rSource ), + aTarget ( rTarget ), + nBytesTotal ( 0 ), + nBytesCopied( 0 ), + nBlockSize ( 4096 ), + pImp ( new FileCopier_Impl ) + +{ +} + +// ----------------------------------------------------------------------- + +FileCopier::FileCopier( const FileCopier& rCopier ) : + + aSource ( rCopier.aSource ), + aTarget ( rCopier.aTarget ), + nBytesTotal ( 0 ), + nBytesCopied ( 0 ), + aProgressLink ( rCopier.aProgressLink ), + nBlockSize ( 4096 ), + pImp ( new FileCopier_Impl ) + +{ +} + +/************************************************************************* +|* +|* FileCopier::~FileCopier() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 13.04.94 +|* Letzte Aenderung MI 13.04.94 +|* +*************************************************************************/ + +FileCopier::~FileCopier() +{ + delete pImp; +} + +/************************************************************************* +|* +|* FileCopier::operator =() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 13.04.94 +|* Letzte Aenderung MI 13.04.94 +|* +*************************************************************************/ + +FileCopier& FileCopier::operator = ( const FileCopier &rCopier ) +{ + aSource = rCopier.aSource; + aTarget = rCopier.aTarget; + nBytesTotal = rCopier.nBytesTotal; + nBytesCopied = rCopier.nBytesCopied; + nBytesCopied = rCopier.nBytesCopied; + nBlockSize = rCopier.nBlockSize; + aProgressLink = rCopier.aProgressLink; + *pImp = *(rCopier.pImp); + return *this; +} + +/************************************************************************* +|* +|* FileCopier::Progress() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 13.04.94 +|* Letzte Aenderung MI 13.04.94 +|* +*************************************************************************/ + +BOOL FileCopier::Progress() +{ + if ( !aProgressLink ) + return TRUE; + else + { + if ( aProgressLink.Call( this ) ) + return TRUE; + return ( 0 == Error( ERRCODE_ABORT, 0, 0 ) ); + } +} + +//--------------------------------------------------------------------------- + +ErrCode FileCopier::Error( ErrCode eErr, const DirEntry* pSource, const DirEntry* pTarget ) +{ + // kein Fehler oder kein ErrorHandler? + if ( !eErr || !pImp->aErrorLink ) + // => Error beibehalten + return eErr; + + // sonst gesetzten ErrorHandler fragen + pImp->pErrSource = pSource; + pImp->pErrTarget = pTarget; + pImp->eErr = eErr; + ErrCode eRet = (ErrCode) pImp->aErrorLink.Call( this ); + pImp->pErrSource = 0; + pImp->pErrTarget = 0; + return eRet; +} + +//--------------------------------------------------------------------------- + +const DirEntry* FileCopier::GetErrorSource() const +{ + return pImp->pErrSource; +} + +//--------------------------------------------------------------------------- + +const DirEntry* FileCopier::GetErrorTarget() const +{ + return pImp->pErrTarget; +} + +//--------------------------------------------------------------------------- + +ErrCode FileCopier::GetError() const +{ + return pImp->eErr; +} + +//--------------------------------------------------------------------------- + +void FileCopier::SetErrorHdl( const Link &rLink ) +{ + pImp->aErrorLink = rLink; +} + +//--------------------------------------------------------------------------- + +const Link& FileCopier::GetErrorHdl() const +{ + return pImp->aErrorLink ; +} + +/************************************************************************* +|* +|* FileCopier::Execute() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 13.04.94 +|* Letzte Aenderung PB 16.06.00 +|* +*************************************************************************/ + +FSysError FileCopier::DoCopy_Impl( + const DirEntry &rSource, const DirEntry &rTarget ) +{ + FSysError eRet = FSYS_ERR_OK; + ErrCode eWarn = FSYS_ERR_OK; + + // HPFS->FAT? + FSysPathStyle eSourceStyle = DirEntry::GetPathStyle( rSource.ImpGetTopPtr()->GetName() ); + FSysPathStyle eTargetStyle = DirEntry::GetPathStyle( rTarget.ImpGetTopPtr()->GetName() ); + BOOL bMakeShortNames = ( eSourceStyle == FSYS_STYLE_HPFS && eTargetStyle == FSYS_STYLE_FAT ); + + // Zieldateiname ggf. kuerzen + DirEntry aTgt; + if ( bMakeShortNames ) + { + aTgt = rTarget.GetPath(); + aTgt.MakeShortName( rTarget.GetName() ); + } + else + aTgt = rTarget; + + // kein Move wenn Namen gekuerzt werden muessten + if ( bMakeShortNames && FSYS_ACTION_MOVE == ( pImp->nActions & FSYS_ACTION_MOVE ) && aTgt != rTarget ) + return ERRCODE_IO_NAMETOOLONG; + + // source is directory? + FileStat aSourceFileStat( rSource ); + if ( aSourceFileStat.IsKind( FSYS_KIND_DIR ) ) + { +#ifdef OS2 + CHAR szSource[CCHMAXPATHCOMP]; + HOBJECT hSourceObject; + + strcpy(szSource, ByteString(rSource.GetFull(), osl_getThreadTextEncoding()).GetBuffer()); + hSourceObject = WinQueryObject(szSource); + + if ( hSourceObject ) + { + PSZ pszSourceName; + PSZ pszTargetName; + CHAR szTarget[CCHMAXPATHCOMP]; + HOBJECT hTargetObject; + HOBJECT hReturn = NULLHANDLE; + + strcpy(szTarget, ByteString(rTarget.GetFull(), osl_getThreadTextEncoding()).GetBuffer()); + pszTargetName = strrchr(szTarget, '\\'); + pszSourceName = strrchr(szSource, '\\'); + + hTargetObject = WinQueryObject(szTarget); + + if ( hTargetObject ) + WinDestroyObject(hTargetObject); + + if ( pszTargetName && pszSourceName ) + { + *pszTargetName = '\0'; + pszSourceName++; + pszTargetName++; + + if(strcmp(pszSourceName, pszTargetName) == 0) + { + hTargetObject = WinQueryObject(szTarget); + + if(pImp->nActions & FSYS_ACTION_MOVE) + { + hReturn = WinMoveObject(hSourceObject, hTargetObject, 0); + } + else + { + hReturn = WinCopyObject(hSourceObject, hTargetObject, 0); + } + if ( bMakeShortNames && aTarget.Exists() ) + aTarget.Kill(); + return hReturn ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN; + } + } + } +#endif + // recursive copy + eRet = Error( aTgt.MakeDir() ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN, 0, &aTgt ); + Dir aSourceDir( rSource, FSYS_KIND_DIR|FSYS_KIND_FILE ); + for ( USHORT n = 0; ERRCODE_TOERROR(eRet) == FSYS_ERR_OK && n < aSourceDir.Count(); ++n ) + { + const DirEntry &rSubSource = aSourceDir[n]; + DirEntryFlag eFlag = rSubSource.GetFlag(); + if ( eFlag != FSYS_FLAG_CURRENT && eFlag != FSYS_FLAG_PARENT ) + { + DirEntry aSubTarget( aTgt ); + aSubTarget += rSubSource.GetName(); + eRet = DoCopy_Impl( rSubSource, aSubTarget ); + if ( eRet && !eWarn ) + eWarn = eRet; + } + } + } + else if ( aSourceFileStat.IsKind(FSYS_KIND_FILE) ) + { + if ( ( FSYS_ACTION_KEEP_EXISTING == ( pImp->nActions & FSYS_ACTION_KEEP_EXISTING ) ) && + aTgt.Exists() ) + { + // Do not overwrite existing file in target folder. + return ERRCODE_NONE; + } + + // copy file + nBytesCopied = 0; + nBytesTotal = FileStat( rSource ).GetSize(); + + ::rtl::OUString aFileName; + FileBase::getFileURLFromSystemPath( ::rtl::OUString(rSource.GetFull()), aFileName ); + SvFileStream aSrc( aFileName, STREAM_READ|STREAM_NOCREATE|STREAM_SHARE_DENYNONE ); + + if ( !aSrc.GetError() ) + { +#ifdef UNX + struct stat buf; + if ( fstat( aSrc.GetFileHandle(), &buf ) == -1 ) + eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt ); +#endif + ::rtl::OUString aTargetFileName; + FileBase::getFileURLFromSystemPath( ::rtl::OUString(aTgt.GetFull()), aTargetFileName ); + + SvFileStream aTargetStream( aTargetFileName, STREAM_WRITE | STREAM_TRUNC | STREAM_SHARE_DENYWRITE ); + if ( !aTargetStream.GetError() ) + { +#ifdef UNX + if ( fchmod( aTargetStream.GetFileHandle(), buf.st_mode ) == -1 ) + eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt ); +#endif + size_t nAllocSize = 0, nSize = 0; + char *pBuf = 0; + while ( Progress() && nSize == nAllocSize && eRet == FSYS_ERR_OK ) + { + // adjust the block-size + if ( nBlockSize > nAllocSize ) + { + delete[] pBuf; + nAllocSize = nBlockSize; + pBuf = new char[nAllocSize]; + } + + // copy one block + nSize = aSrc.Read( pBuf, nBlockSize ); + aTargetStream.Write( pBuf, nSize ); + if ( aTargetStream.GetError() ) + eRet = Error( aTargetStream.GetError(), 0, &aTgt ); + + // adjust counters + nBytesCopied += nSize; + if ( nBytesCopied > nBytesTotal ) + nBytesTotal = nBytesCopied; + } + delete[] pBuf; + } + else + eRet = Error( aTargetStream.GetError(), 0, &aTgt ); + + // unvollstaendiges File wieder loeschen + aTargetStream.Close(); + + if ( nBytesCopied != nBytesTotal ) + { + aTgt.Kill(); + } + } + else + eRet = Error( aSrc.GetError(), &rSource, 0 ); + } + else if ( aSourceFileStat.IsKind(FSYS_KIND_NONE) ) + eRet = Error( ERRCODE_IO_NOTEXISTS, &rSource, 0 ); + else + eRet = Error( ERRCODE_IO_NOTSUPPORTED, &rSource, 0 ); + +#ifdef WNT + // Set LastWriteTime and Attributes of the target identical with the source + + if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) ) + { + WIN32_FIND_DATA fdSource; + ByteString aFullSource(aSource.GetFull(), osl_getThreadTextEncoding()); + ByteString aFullTarget(aTgt.GetFull(), osl_getThreadTextEncoding()); + HANDLE hFind = FindFirstFile( aFullSource.GetBuffer() , &fdSource ); + if ( hFind != INVALID_HANDLE_VALUE ) + { + FindClose( hFind ); + + HANDLE hFile = CreateFile( aFullTarget.GetBuffer(), GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + + if ( hFile != INVALID_HANDLE_VALUE ) + { + SetFileTime( hFile, NULL, NULL, &fdSource.ftLastWriteTime ); + CloseHandle( hFile ); + } + + SetFileAttributes( aFullTarget.GetBuffer(), fdSource.dwFileAttributes ); + } + } +#endif + // bei Move ggf. das File/Dir loeschen + if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) && ( pImp->nActions & FSYS_ACTION_MOVE ) ) + { + ErrCode eKillErr = Error( rSource.Kill() | ERRCODE_WARNING_MASK, &rSource, 0 ); + if ( eKillErr != ERRCODE_WARNING_MASK ) + { + if ( rSource.Exists() ) + // loeschen ging nicht => dann die Kopie wieder loeschen + aTgt.Kill( pImp->nActions ); + if ( !eWarn ) + eWarn = eKillErr; + } + } + + return !eRet ? eWarn : eRet; +} + +// ----------------------------------------------------------------------- + +FSysError FileCopier::Execute( FSysAction nActions ) +{ + return ExecuteExact( nActions ); +} + +// ----------------------------------------------------------------------- + +FSysError FileCopier::ExecuteExact( FSysAction nActions, FSysExact eExact ) +{ + DirEntry aAbsSource = DirEntry( aSource); + DirEntry aAbsTarget = DirEntry( aTarget ); + pImp->nActions = nActions; + + // check if both pathes are accessible and source and target are different + if ( !aAbsTarget.ToAbs() || !aAbsSource.ToAbs() || aAbsTarget == aAbsSource ) + return FSYS_ERR_ACCESSDENIED; + + // check if copy would be endless recursive into itself + if ( FSYS_ACTION_RECURSIVE == ( nActions & FSYS_ACTION_RECURSIVE ) && + aAbsSource.Contains( aAbsTarget ) ) + return ERRCODE_IO_RECURSIVE; + + // target is directory? + if ( eExact == FSYS_NOTEXACT && + FileStat( aAbsTarget ).IsKind(FSYS_KIND_DIR) && FileStat( aAbsSource ).IsKind(FSYS_KIND_FILE) ) + // append name of source + aAbsTarget += aSource.GetName(); + + // recursive copy + return DoCopy_Impl( aAbsSource, aAbsTarget ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/fstat.cxx b/tools/source/fsys/fstat.cxx new file mode 100644 index 000000000000..468fdb6082ea --- /dev/null +++ b/tools/source/fsys/fstat.cxx @@ -0,0 +1,422 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" + +#if defined( WIN) +#include <stdio.h> +#include <dos.h> +#endif + +#ifdef UNX +#include <errno.h> +#endif + +#include <limits.h> +#include <string.h> + +#include "comdep.hxx" +#include <tools/fsys.hxx> + +/************************************************************************* +|* +|* FileStat::FileStat() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 11.06.91 +|* Letzte Aenderung MI 11.06.91 +|* +*************************************************************************/ + +FileStat::FileStat() +: // don't use Default-Ctors! + aDateCreated( ULONG(0) ), + aTimeCreated( ULONG(0) ), + aDateModified( ULONG(0) ), + aTimeModified( ULONG(0) ), + aDateAccessed( ULONG(0) ), + aTimeAccessed( ULONG(0) ) +{ + nSize = 0; + nKindFlags = FSYS_KIND_UNKNOWN; + nError = FSYS_ERR_OK; +} + +/************************************************************************* +|* +|* FileStat::FileStat() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 11.06.91 +|* Letzte Aenderung MI 11.06.91 +|* +*************************************************************************/ + +FileStat::FileStat( const DirEntry& rDirEntry, FSysAccess nAccess ) +: // don't use Default-Ctors! + aDateCreated( ULONG(0) ), + aTimeCreated( ULONG(0) ), + aDateModified( ULONG(0) ), + aTimeModified( ULONG(0) ), + aDateAccessed( ULONG(0) ), + aTimeAccessed( ULONG(0) ) +{ + BOOL bCached = FSYS_ACCESS_CACHED == (nAccess & FSYS_ACCESS_CACHED); + BOOL bFloppy = FSYS_ACCESS_FLOPPY == (nAccess & FSYS_ACCESS_FLOPPY); + +#ifdef FEAT_FSYS_DOUBLESPEED + const FileStat *pStatFromDir = bCached ? rDirEntry.ImpGetStat() : 0; + if ( pStatFromDir ) + { + nError = pStatFromDir->nError; + nKindFlags = pStatFromDir->nKindFlags; + nSize = pStatFromDir->nSize; + aCreator = pStatFromDir->aCreator; + aType = pStatFromDir->aType; + aDateCreated = pStatFromDir->aDateCreated; + aTimeCreated = pStatFromDir->aTimeCreated; + aDateModified = pStatFromDir->aDateModified; + aTimeModified = pStatFromDir->aTimeModified; + aDateAccessed = pStatFromDir->aDateAccessed; + aTimeAccessed = pStatFromDir->aTimeAccessed; + } + else +#endif + Update( rDirEntry, bFloppy ); +} + +/************************************************************************* +|* +|* FileStat::IsYounger() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MA 11.11.91 +|* Letzte Aenderung MA 11.11.91 +|* +*************************************************************************/ + +// TRUE wenn die Instanz j"unger als rIsOlder ist. +// FALSE wenn die Instanz "alter oder gleich alt wie rIsOlder ist. + +BOOL FileStat::IsYounger( const FileStat& rIsOlder ) const +{ + if ( aDateModified > rIsOlder.aDateModified ) + return TRUE; + if ( ( aDateModified == rIsOlder.aDateModified ) && + ( aTimeModified > rIsOlder.aTimeModified ) ) + return TRUE; + + return FALSE; +} + +/************************************************************************* +|* +|* FileStat::IsKind() +|* +|* Ersterstellung MA 11.11.91 (?) +|* Letzte Aenderung KH 16.01.95 +|* +*************************************************************************/ + +BOOL FileStat::IsKind( DirEntryKind nKind ) const +{ + BOOL bRet = ( ( nKind == FSYS_KIND_UNKNOWN ) && + ( nKindFlags == FSYS_KIND_UNKNOWN ) ) || + ( ( nKindFlags & nKind ) == nKind ); + return bRet; +} + +/************************************************************************* +|* +|* FileStat::HasReadOnlyFlag() +|* +|* Ersterstellung MI 06.03.97 +|* Letzte Aenderung UT 01.07.98 +|* +*************************************************************************/ + +BOOL FileStat::HasReadOnlyFlag() +{ +#if defined WNT || defined UNX || defined OS2 + return TRUE; +#else + return FALSE; +#endif +} + +/************************************************************************* +|* +|* FileStat::GetReadOnlyFlag() +|* +|* Ersterstellung MI 06.03.97 +|* Letzte Aenderung UT 02.07.98 +|* +*************************************************************************/ + +BOOL FileStat::GetReadOnlyFlag( const DirEntry &rEntry ) +{ + + ByteString aFPath(rEntry.GetFull(), osl_getThreadTextEncoding()); +#if defined WNT + DWORD nRes = GetFileAttributes( (LPCTSTR) aFPath.GetBuffer() ); + return ULONG_MAX != nRes && + ( FILE_ATTRIBUTE_READONLY & nRes ) == FILE_ATTRIBUTE_READONLY; +#elif defined OS2 + FILESTATUS3 aFileStat; + APIRET nRet = DosQueryPathInfo( (PSZ)aFPath.GetBuffer(), 1, &aFileStat, sizeof(aFileStat) ); + switch ( nRet ) + { + case NO_ERROR: + return FILE_READONLY == ( aFileStat.attrFile & FILE_READONLY ); + default: + return FALSE; + } +#elif defined UNX + /* could we stat the object? */ + struct stat aBuf; + if (stat(aFPath.GetBuffer(), &aBuf)) + return FALSE; + /* jupp, is writable for user? */ + return((aBuf.st_mode & S_IWUSR) != S_IWUSR); +#else + return FALSE; +#endif +} + +/************************************************************************* +|* +|* FileStat::SetReadOnlyFlag() +|* +|* Ersterstellung MI 06.03.97 +|* Letzte Aenderung UT 01.07.98 +|* +*************************************************************************/ + +ULONG FileStat::SetReadOnlyFlag( const DirEntry &rEntry, BOOL bRO ) +{ + + ByteString aFPath(rEntry.GetFull(), osl_getThreadTextEncoding()); + +#if defined WNT + DWORD nRes = GetFileAttributes( (LPCTSTR) aFPath.GetBuffer() ); + if ( ULONG_MAX != nRes ) + nRes = SetFileAttributes( (LPCTSTR) aFPath.GetBuffer(), + ( nRes & ~FILE_ATTRIBUTE_READONLY ) | + ( bRO ? FILE_ATTRIBUTE_READONLY : 0 ) ); + return ( ULONG_MAX == nRes ) ? ERRCODE_IO_UNKNOWN : 0; +#elif defined OS2 + FILESTATUS3 aFileStat; + APIRET nRet = DosQueryPathInfo( (PSZ)aFPath.GetBuffer(), 1, &aFileStat, sizeof(aFileStat) ); + if ( !nRet ) + { + aFileStat.attrFile = ( aFileStat.attrFile & ~FILE_READONLY ) | + ( bRO ? FILE_READONLY : 0 ); + nRet = DosSetPathInfo( (PSZ)aFPath.GetBuffer(), 1, &aFileStat, sizeof(aFileStat), 0 ); + } + switch ( nRet ) + { + case NO_ERROR: + return ERRCODE_NONE; + + case ERROR_SHARING_VIOLATION: + return ERRCODE_IO_LOCKVIOLATION; + + default: + return ERRCODE_IO_NOTEXISTS; + } +#elif defined UNX + /* first, stat the object to get permissions */ + struct stat aBuf; + if (stat(aFPath.GetBuffer(), &aBuf)) + return ERRCODE_IO_NOTEXISTS; + /* set or clear write bit for user */ + mode_t nMode; + if (bRO) + { + nMode = aBuf.st_mode & ~S_IWUSR; + nMode = aBuf.st_mode & ~S_IWGRP; + nMode = aBuf.st_mode & ~S_IWOTH; + } + else + nMode = aBuf.st_mode | S_IWUSR; + /* change it on fs */ + if (chmod(aFPath.GetBuffer(), nMode)) + { + switch (errno) + { + case EPERM : + case EROFS : + return ERRCODE_IO_ACCESSDENIED; + default : + return ERRCODE_IO_NOTEXISTS; + } + } + else + return ERRCODE_NONE; +#else + return ERRCODE_IO_NOTSUPPORTED; +#endif +} + +/************************************************************************* +|* +|* FileStat::SetDateTime +|* +|* Ersterstellung PB 27.06.97 +|* Letzte Aenderung +|* +*************************************************************************/ +#if defined WNT || defined OS2 + +void FileStat::SetDateTime( const String& rFileName, + const DateTime& rNewDateTime ) +{ + ByteString aFileName(rFileName, osl_getThreadTextEncoding()); + + Date aNewDate = rNewDateTime; + Time aNewTime = rNewDateTime; + +#if defined WNT + TIME_ZONE_INFORMATION aTZI; + DWORD dwTZI = GetTimeZoneInformation( &aTZI ); + + if ( dwTZI != (DWORD)-1 && dwTZI != TIME_ZONE_ID_UNKNOWN ) + { + // 1. Korrektur der Zeitzone + LONG nDiff = aTZI.Bias; + Time aOldTime = aNewTime; // alte Zeit merken + + // 2. evt. Korrektur Sommer-/Winterzeit + if ( dwTZI == TIME_ZONE_ID_DAYLIGHT ) + nDiff += aTZI.DaylightBias; + + Time aDiff( abs( nDiff / 60 /*Min -> Std*/ ), 0 ); + + if ( nDiff > 0 ) + { + aNewTime += aDiff; // Stundenkorrektur + + // bei "Uberlauf korrigieren + if ( aNewTime >= Time( 24, 0 ) ) + aNewTime -= Time( 24, 0 ); + + // Tages"uberlauf? + if ( aOldTime == Time( 0, 0 ) || // 00:00 -> 01:00 + aNewTime < aOldTime ) // 23:00 -> 00:00 | 01:00 ... + aNewDate++; + } + else if ( nDiff < 0 ) + { + aNewTime -= aDiff; // Stundenkorrektur + + // negative Zeit (-1:00) korrigieren: 23:00 + if (aNewTime < Time( 0, 0 ) ) + aNewTime += Time( 24, 0 ); + + // Tagesunterlauf ? + if ( aOldTime == Time( 0, 0 ) || // 00:00 -> 23:00 + aNewTime > aOldTime ) // 01:00 -> 23:00 | 22:00 ... + aNewDate--; + } + } + + + SYSTEMTIME aTime; + aTime.wYear = aNewDate.GetYear(); + aTime.wMonth = aNewDate.GetMonth(); + aTime.wDayOfWeek = 0; + aTime.wDay = aNewDate.GetDay(); + aTime.wHour = aNewTime.GetHour(); + aTime.wMinute = aNewTime.GetMin(); + aTime.wSecond = aNewTime.GetSec(); + aTime.wMilliseconds = 0; + FILETIME aFileTime; + SystemTimeToFileTime( &aTime, &aFileTime ); + + HANDLE hFile = CreateFile( aFileName.GetBuffer(), GENERIC_WRITE, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); + + if ( hFile != INVALID_HANDLE_VALUE ) + { + SetFileTime( hFile, &aFileTime, &aFileTime, &aFileTime ); + CloseHandle( hFile ); + } +#elif defined OS2 + + // open file + ULONG nAction = FILE_EXISTED; + HFILE hFile = 0; + ULONG nFlags = OPEN_FLAGS_WRITE_THROUGH | + OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | + OPEN_FLAGS_RANDOM | OPEN_FLAGS_NOINHERIT | + OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE; + + APIRET nRet = DosOpen((PSZ)aFileName.GetBuffer(), &hFile, (PULONG)&nAction, + 0/*size*/, FILE_NORMAL, + OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + nFlags, 0/*ea*/); + + if ( nRet == 0 ) + { + FILESTATUS3 FileInfoBuffer; + + nRet = DosQueryFileInfo( + hFile, 1, &FileInfoBuffer, sizeof(FileInfoBuffer)); + + if ( nRet == 0 ) + { + FDATE aNewDate; + FTIME aNewTime; + + // create date and time words + aNewDate.day = rNewDateTime.GetDay(); + aNewDate.month = rNewDateTime.GetMonth(); + aNewDate.year = rNewDateTime.GetYear() - 1980; + aNewTime.twosecs = rNewDateTime.GetSec() / 2; + aNewTime.minutes = rNewDateTime.GetMin(); + aNewTime.hours = rNewDateTime.GetHour(); + + // set file date and time + FileInfoBuffer.fdateCreation = aNewDate; + FileInfoBuffer.ftimeCreation = aNewTime; + FileInfoBuffer.fdateLastAccess = aNewDate; + FileInfoBuffer.ftimeLastAccess = aNewTime; + FileInfoBuffer.fdateLastWrite = aNewDate; + FileInfoBuffer.ftimeLastWrite = aNewTime; + + DosSetFileInfo(hFile, 1, &FileInfoBuffer, sizeof(FileInfoBuffer)); + } + DosClose(hFile); + } +#endif + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/makefile.mk b/tools/source/fsys/makefile.mk new file mode 100644 index 000000000000..b1d34d6347f3 --- /dev/null +++ b/tools/source/fsys/makefile.mk @@ -0,0 +1,67 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=tools +TARGET=fsys +ENABLE_EXCEPTIONS=true + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +.IF "$(COM)"=="GCC" +CFLAGSCXX+=-fexceptions +.ENDIF + + +# --- Files -------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/tempfile.obj \ + $(SLO)$/wldcrd.obj \ + $(SLO)$/fstat.obj \ + $(SLO)$/comdep.obj \ + $(SLO)$/filecopy.obj \ + $(SLO)$/dirent.obj \ + $(SLO)$/tdir.obj \ + $(SLO)$/urlobj.obj + +OBJFILES= $(OBJ)$/wldcrd.obj \ + $(OBJ)$/fstat.obj \ + $(OBJ)$/comdep.obj \ + $(OBJ)$/filecopy.obj \ + $(OBJ)$/dirent.obj \ + $(OBJ)$/tdir.obj \ + $(OBJ)$/urlobj.obj + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/tools/source/fsys/os2.cxx b/tools/source/fsys/os2.cxx new file mode 100644 index 000000000000..ca57f7dd9ca9 --- /dev/null +++ b/tools/source/fsys/os2.cxx @@ -0,0 +1,885 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define INCL_DOSEXCEPTIONS + +#include <stdlib.h> + +#ifdef __BORLANDC__ +#include <alloc.h> +#else +#include <malloc.h> +#endif +#include <tools/debug.hxx> +#include <tools/list.hxx> +#include <tools/bigint.hxx> +#include <tools/fsys.hxx> +#include "comdep.hxx" + +#ifdef OS2 +#include <osl/mutex.hxx> +#endif + +int Sys2SolarError_Impl( int nSysErr ); + +DECLARE_LIST( DirEntryList, DirEntry* ); +DECLARE_LIST( FSysSortList, FSysSort* ); +DECLARE_LIST( FileStatList, FileStat* ); + +static char sCaseMap[256]; +static BOOL bCaseMap = FALSE; +static BOOL bDriveMap = FALSE; + +struct DriveMapItem +{ + DirEntryKind nKind; + char cName; + FSysPathStyle nStyle; +}; + +void CreateCaseMapImpl(); +void CreateDriveMapImpl(); + +static DriveMapItem aDriveMap[26]; + +static BOOL bLastCaseSensitive = FALSE; + +//==================================================================== + +int ApiRet2ToSolarError_Impl( int nApiRet ) +{ + switch ( nApiRet ) + { + case NO_ERROR: return ERRCODE_NONE; + case ERROR_FILE_NOT_FOUND: return ERRCODE_IO_NOTEXISTS; + case ERROR_PATH_NOT_FOUND: return ERRCODE_IO_NOTEXISTSPATH; + case ERROR_TOO_MANY_OPEN_FILES: return ERRCODE_IO_TOOMANYOPENFILES; + case ERROR_ACCESS_DENIED: return ERRCODE_IO_ACCESSDENIED; + case ERROR_NOT_ENOUGH_MEMORY: return ERRCODE_IO_OUTOFMEMORY; + case ERROR_BAD_FORMAT: return ERRCODE_IO_WRONGFORMAT; + case ERROR_NOT_SAME_DEVICE: return ERRCODE_IO_INVALIDDEVICE; + case ERROR_WRITE_PROTECT: return ERRCODE_IO_INVALIDDEVICE; + case ERROR_BAD_UNIT: return ERRCODE_IO_INVALIDDEVICE; + case ERROR_CRC: return ERRCODE_IO_INVALIDDEVICE; + case ERROR_NOT_DOS_DISK: return ERRCODE_IO_INVALIDDEVICE; + case ERROR_WRITE_FAULT: return ERRCODE_IO_CANTWRITE; + case ERROR_READ_FAULT: return ERRCODE_IO_CANTREAD; + case ERROR_SHARING_VIOLATION: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_LOCK_VIOLATION: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_WRONG_DISK: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_HANDLE_DISK_FULL: return ERRCODE_IO_OUTOFSPACE; + case ERROR_NOT_SUPPORTED: return ERRCODE_IO_NOTSUPPORTED; + case ERROR_DUP_NAME: return ERRCODE_IO_ALREADYEXISTS; + case ERROR_BAD_NETPATH: return ERRCODE_IO_NOTEXISTSPATH; + case ERROR_DEV_NOT_EXIST: return ERRCODE_IO_NOTEXISTS; + case ERROR_NETWORK_ACCESS_DENIED: return ERRCODE_IO_ACCESSDENIED; + case ERROR_INVALID_PARAMETER: return ERRCODE_IO_INVALIDPARAMETER; + case ERROR_NET_WRITE_FAULT: return ERRCODE_IO_CANTWRITE; + case ERROR_DEVICE_IN_USE: return ERRCODE_IO_INVALIDPARAMETER; + case ERROR_DISK_FULL: return ERRCODE_IO_OUTOFSPACE; + case ERROR_BAD_ARGUMENTS: return ERRCODE_IO_INVALIDPARAMETER; + case ERROR_BAD_PATHNAME: return ERRCODE_IO_NOTEXISTSPATH; + case ERROR_LOCK_FAILED: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_LOCKED: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_DUPLICATE_NAME: return ERRCODE_IO_ALREADYEXISTS; + case ERROR_DIRECTORY_IN_CDS: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_CURRENT_DIRECTORY: return ERRCODE_IO_LOCKVIOLATION; + case ERROR_FILENAME_EXCED_RANGE: return ERRCODE_IO_NAMETOOLONG; + } + + DBG_TRACE1( "FSys: unknown apiret error %d occured", nApiRet ); + return FSYS_ERR_UNKNOWN; +} + +//-------------------------------------------------------------------- + +char* volumeid( const char* pPfad ) +{ + static FSINFO aFSInfoBuf; + ULONG ulFSInfoLevel = FSIL_VOLSER; + ULONG nDriveNumber; + + nDriveNumber = toupper(*pPfad) - 'A' + 1; + + if ( nDriveNumber >= 3 ) + { + APIRET rc = DosQueryFSInfo( + nDriveNumber, ulFSInfoLevel, &aFSInfoBuf, sizeof(FSINFO) ); + if ( rc ) + return 0; + return (char*) aFSInfoBuf.vol.szVolLabel; + } + return 0; +} + +//-------------------------------------------------------------------- + +/************************************************************************* +|* +|* DirEntry::ToAbs() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 13:30 +|* +*************************************************************************/ + +BOOL DirEntry::ToAbs() +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + if ( FSYS_FLAG_VOLUME == eFlag ) + { + eFlag = FSYS_FLAG_ABSROOT; + return TRUE; + } + + if ( IsAbs() ) + return TRUE; + + char sBuf[_MAX_PATH + 1]; + *this = DirEntry( String( getcwd( sBuf, _MAX_PATH ), osl_getThreadTextEncoding() ) ) + *this; + + return IsAbs(); +} + +/************************************************************************* +|* +|* DirEntry::GetVolume() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 04.03.92 +|* Letzte Aenderung MI 04.03.92 +|* +*************************************************************************/ + +String DirEntry::GetVolume() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + String aRet; + const DirEntry *pTop = ImpGetTopPtr(); + ByteString aName = ByteString( pTop->aName ).ToLowerAscii(); + + if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT || + pTop->eFlag == FSYS_FLAG_RELROOT || + pTop->eFlag == FSYS_FLAG_VOLUME ) + && aName != "a:" && aName != "b:" && Exists() ) + { + const char *pVol; + pVol = volumeid( (char*) pTop->aName.GetBuffer() ); + if (pVol) + aRet = String( pVol, osl_getThreadTextEncoding()); + } + + return aRet; +} + +/************************************************************************* +|* +|* DirEntry::SetCWD() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 21.05.92 +|* +*************************************************************************/ + +BOOL DirEntry::SetCWD( BOOL bSloppy ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + if ( eFlag == FSYS_FLAG_CURRENT && !aName.Len() ) + return TRUE; + + if ( !chdir(ByteString(GetFull(), osl_getThreadTextEncoding()).GetBuffer()) ) + { + //nError = FSYS_ERR_OK; + return TRUE; + } + + if ( bSloppy && pParent && + !chdir(ByteString(pParent->GetFull(), osl_getThreadTextEncoding()).GetBuffer()) ) + { + //nError = FSYS_ERR_OK; + return TRUE; + } + + //nError = FSYS_ERR_NOTADIRECTORY; + return FALSE; +} + +/************************************************************************* +|* +|* DirEntry::MoveTo() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 14:07 +|* +*************************************************************************/ + + +//------------------------------------------------------------------------- + +USHORT DirReader_Impl::Init() +{ + // Block-Devices auflisten? + if ( pDir->eAttrMask & FSYS_KIND_BLOCK ) + { + CreateDriveMapImpl(); + // CWD merken + DirEntry aCurrentDir; + aCurrentDir.ToAbs(); + + // einzeln auf Existenz und Masken-konformit"at pr"ufen + USHORT nRead = 0; + char sDrive[3] = { '?', ':', 0 }; + char sRoot[4] = { '?', ':', '\\', 0 }; + for ( char c = 'a'; c <= 'z'; c++ ) + { + sDrive[0] = c; + sRoot[0] = c; + DirEntry* pDrive = new DirEntry( sDrive, FSYS_FLAG_VOLUME, FSYS_STYLE_HOST ); + if ( pDir->aNameMask.Matches( String( ByteString(sDrive), osl_getThreadTextEncoding())) + && aDriveMap[c-'a'].nKind != FSYS_KIND_UNKNOWN ) + { + if ( pDir->pStatLst ) //Status fuer Sort gewuenscht? + { + FileStat *pNewStat = new FileStat( *pDrive ); + pDir->ImpSortedInsert( pDrive, pNewStat ); + } + else + pDir->ImpSortedInsert( pDrive, NULL ); + ++nRead; + } + else + delete pDrive; + } + + // CWD restaurieren + aCurrentDir.SetCWD(); + return nRead; + } + + return 0; +} + +//------------------------------------------------------------------------- + +USHORT DirReader_Impl::Read() +{ + if (!pDosDir) + { + pDosDir = opendir( (char*) ByteString(aPath, osl_getThreadTextEncoding()).GetBuffer() ); + } + + if (!pDosDir) + { + bReady = TRUE; + return 0; + } + + // Directories und Files auflisten? + if ( ( pDir->eAttrMask & FSYS_KIND_DIR || pDir->eAttrMask & FSYS_KIND_FILE ) && + ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) ) + { + String aD_Name(pDosEntry->d_name, osl_getThreadTextEncoding()); + if ( pDir->aNameMask.Matches( aD_Name ) ) + { + DirEntryFlag eFlag = + 0 == strcmp( pDosEntry->d_name, "." ) ? FSYS_FLAG_CURRENT + : 0 == strcmp( pDosEntry->d_name, ".." ) ? FSYS_FLAG_PARENT + : FSYS_FLAG_NORMAL; + DirEntry *pTemp = new DirEntry( ByteString(pDosEntry->d_name), eFlag, FSYS_STYLE_UNX ); + if ( pParent ) + pTemp->ImpChangeParent( new DirEntry( *pParent ), FALSE); + FileStat aStat( *pTemp ); + if ( ( ( ( pDir->eAttrMask & FSYS_KIND_DIR ) && + ( aStat.IsKind( FSYS_KIND_DIR ) ) ) || + ( ( pDir->eAttrMask & FSYS_KIND_FILE ) && + !( aStat.IsKind( FSYS_KIND_DIR ) ) ) ) && + !( pDir->eAttrMask & FSYS_KIND_VISIBLE && + pDosEntry->d_name[0] == '.' ) ) + { + if ( pDir->pStatLst ) //Status fuer Sort gewuenscht? + pDir->ImpSortedInsert( pTemp, new FileStat( aStat ) ); + else + pDir->ImpSortedInsert( pTemp, NULL );; + return 1; + } + else + delete pTemp; + } + } + else + bReady = TRUE; + return 0; +} + +/************************************************************************* +|* +|* FileStat::FileStat() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MA 05.11.91 +|* Letzte Aenderung MA 07.11.91 +|* +*************************************************************************/ + +FileStat::FileStat( const void *pInfo, // struct dirent + const void * ): // dummy + aDateCreated(0), + aTimeCreated(0), + aDateModified(0), + aTimeModified(0), + aDateAccessed(0), + aTimeAccessed(0) +{ + struct dirent *pDirent = (struct dirent*) pInfo; + + nSize = pDirent->d_size; + + aDateCreated = MsDos2Date( (FDATE*) &pDirent->d_date ); + aTimeCreated = MsDos2Time( (FTIME*) &pDirent->d_time ); + aDateModified = aDateModified; + aTimeModified = aTimeModified; + aDateAccessed = aDateModified; + aTimeAccessed = aTimeModified; + + nKindFlags = FSYS_KIND_FILE; + if ( pDirent->d_type & DOS_DIRECT ) + nKindFlags = FSYS_KIND_DIR; +} + +/************************************************************************* +|* +|* FileStat::Update() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 11.06.91 +|* Letzte Aenderung MA 07.11.91 +|* +*************************************************************************/ + +struct _FSYS_FSQBUFFER +{ + FSQBUFFER2 aBuf; + UCHAR sBuf[256]; +}; + +BOOL FileStat::Update( const DirEntry& rDirEntry, BOOL bAccessRemovableDevice ) +{ + nSize = 0; + FSysPathStyle eStyle = FSYS_STYLE_UNKNOWN; + aCreator.Erase(); + aType.Erase(); + aDateCreated = Date(0); + aTimeCreated = Time(0); + aDateModified = Date(0); + aTimeModified = Time(0); + aDateAccessed = Date(0); + aTimeAccessed = Time(0); + + if ( !rDirEntry.IsValid() ) + { + nError = FSYS_ERR_NOTEXISTS; + return FALSE; + } + + // Sonderbehandlung falls es sich um eine Root ohne Laufwerk handelt + if ( !rDirEntry.aName.Len() && rDirEntry.eFlag == FSYS_FLAG_ABSROOT ) + { + nKindFlags = FSYS_KIND_DIR; + nError = FSYS_ERR_OK; + return TRUE; + } + + // Sonderbehandlung falls es sich um eine Wildcard handelt + ByteString aTempName( rDirEntry.GetName(), osl_getThreadTextEncoding() ); + if ( strchr( aTempName.GetBuffer(), '?' ) || + strchr( aTempName.GetBuffer(), '*' ) || + strchr( aTempName.GetBuffer(), ';' ) ) + { + nKindFlags = FSYS_KIND_WILD; + nError = FSYS_ERR_OK; + return TRUE; + } + + // Sonderbehandlung falls es sich um eine Root handelt + if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME || + rDirEntry.eFlag == FSYS_FLAG_ABSROOT ) + { + if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME ) + nKindFlags = FSYS_KIND_DEV; + else + nKindFlags = FSYS_KIND_DIR; + + if ( rDirEntry.aName.Len() == 2 ) + { + if ( !bDriveMap ) + CreateDriveMapImpl(); + + ByteString rDirEntryUpperCase = ByteString( rDirEntry.aName ).ToUpperAscii(); + DriveMapItem &rItem = aDriveMap[rDirEntryUpperCase.GetChar(0) - 'A']; + if ( !rItem.nKind ) + { + nError = ERRCODE_IO_INVALIDDEVICE; + nKindFlags = FSYS_KIND_UNKNOWN; + return FALSE; + } + else + { + if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME ) + nKindFlags |= FSYS_KIND_BLOCK | rItem.nKind; + eStyle = rItem.nStyle; + } + } + + nError = FSYS_ERR_OK; + return TRUE; + } + + // disable error-boxes for hard-errors + DosError(FERR_DISABLEHARDERR); + + // Statusinformation vom Betriebssystem holen + DirEntry aTempDirEntry( rDirEntry ); + char* p; + + aTempDirEntry.ToAbs(); + ByteString aFullName( aTempDirEntry.GetFull(), osl_getThreadTextEncoding() ); + + p = (char *) aFullName.GetBuffer(); + + FILESTATUS3 filestat; + memset( &filestat, 0, sizeof( filestat ) ); + if( DosQueryPathInfo( (PSZ)p, 1, &filestat, sizeof( filestat ) ) ) + { + nError = FSYS_ERR_NOTEXISTS; + nKindFlags = FSYS_KIND_UNKNOWN; + return FALSE; + } + + nError = FSYS_ERR_OK; + nSize = filestat.cbFile; + + nKindFlags = FSYS_KIND_UNKNOWN; + if( filestat.attrFile & FILE_DIRECTORY ) + nKindFlags |= FSYS_KIND_DIR; + if ( nKindFlags == FSYS_KIND_UNKNOWN ) + nKindFlags = nKindFlags | FSYS_KIND_FILE; + + aDateModified = Date( filestat.fdateLastWrite.day, + filestat.fdateLastWrite.month, + filestat.fdateLastWrite.year + 1980 ); + + aTimeModified = Time( filestat.ftimeLastWrite.hours, + filestat.ftimeLastWrite.minutes, + filestat.ftimeLastWrite.twosecs*2 ); + + if ( filestat.fdateCreation.day ) + { + aDateCreated = Date( filestat.fdateCreation.day, + filestat.fdateCreation.month, + filestat.fdateCreation.year + 1980 ); + + aTimeCreated = Time( filestat.ftimeCreation.hours, + filestat.ftimeCreation.minutes, + filestat.ftimeCreation.twosecs*2 ); + } + else + { + aDateCreated = aDateModified; + aTimeCreated = aTimeModified; + } + + if ( filestat.fdateLastAccess.day > 0 ) + { + aDateAccessed = Date( filestat.fdateLastAccess.day, + filestat.fdateLastAccess.month, + filestat.fdateLastAccess.year + 1980 ); + + aTimeAccessed = Time( filestat.ftimeLastAccess.hours, + filestat.ftimeLastAccess.minutes, + filestat.ftimeLastAccess.twosecs*2 ); + } + else + { + aDateAccessed = aDateModified; + aTimeAccessed = aTimeModified; + } + + return TRUE; +} + +BOOL IsRedirectable_Impl( const ByteString &rPath ) +{ + if ( rPath.Len() >= 3 && ':' == rPath.GetBuffer()[1] ) + { + ByteString aVolume = rPath.Copy( 0, 3 ); + DriveMapItem &rItem = aDriveMap[toupper(aVolume.GetChar(0)) - 'A']; + return FSYS_KIND_FIXED != rItem.nKind; + } + return FALSE; +} + + +/************************************************************************* +|* +|* TempDirImpl() +|* +|* Beschreibung liefert den Namens des Directories fuer temporaere +|* Dateien +|* Ersterstellung MI 16.03.94 +|* Letzte Aenderung MI 16.03.94 +|* +*************************************************************************/ + +const char* TempDirImpl( char *pBuf ) +{ + PSZ pVar; + USHORT nRet; + BOOL bAppendTemp = FALSE; // mu\s noch \\temp angeh"angt werden + + // Erstmal sehen, ob TEMP oder TMP gesetzt sind + nRet = DosScanEnv( (PSZ)"TEMP", &pVar ); + if( nRet ) + nRet = DosScanEnv( (PSZ)"temp", &pVar ); + if( nRet ) + nRet = DosScanEnv( (PSZ)"TMP", &pVar ); + if( nRet ) + nRet = DosScanEnv( (PSZ)"tmp", &pVar ); + if( nRet ) + nRet = DosScanEnv( (PSZ)"TMPDIR", &pVar ); + + // falls das geklappt hat, und ein Backslash dranhaengt, + // oder falls es bisher nicht geklappt hat, + // muessen wir nachher einen Backslash entfernen + BOOL bRemoveBS = nRet || *(pVar+strlen(pVar)-1) == '\\'; + + // Keine temp-Variable gefunden, dann gehen wir mal auf die Suche + // nach dem System-Laufwerk + if( nRet ) + { + nRet = DosScanEnv( (PSZ)"USER_INI",&pVar ); + bAppendTemp = (0 == nRet); + } + if( nRet ) + { + nRet = DosScanEnv( (PSZ)"SYSTEM_INI", &pVar ); + bAppendTemp = (0 == nRet); + } + if( nRet ) + // Wenn das immer noch nicht reicht nehmen wir eben die Root von C: +#ifdef __BORLANDC__ + pVar = (PSZ)"c:\\temp\\"; +#else + pVar = (PCSZ)"c:\\temp\\"; +#endif + strcpy( pBuf, (const char*)pVar ); + + // jetzt haengt ggf. ein Backlash dran, den wir abschneiden, + // ggf. inklusive dahinter haengendem Dateinamen + if ( bRemoveBS ) + { + char *pTail = pBuf + strlen(pBuf) - 1; + for ( char cLast = *pTail; cLast != '\\'; cLast = *(--pTail) ) + *pTail = 0; + } + + if ( bAppendTemp ) + strcat( pBuf, "\\temp" ); + DirEntry( pBuf ).MakeDir(); + + return pBuf; +} + +#define CURRENT_COUNTRY 0 +#define NLS_CODEPAGE 850 + +/*==================================================================== + * CreateDriveMapImpl() + * creates a map of drive-infos like FileSystem (style) and Kind (remote) + *--------------------------------------------------------------------*/ +typedef struct _FSQBUFFER_ +{ + FSQBUFFER2 aBuf; + UCHAR sBuf[64]; +} FSQBUFFER_; + +void CreateDriveMapImpl() +{ +#ifdef POWERPC + // !!!!! Hack, da der untere Teil mit Beta 2 noch abstuertzt !!!!! + BYTE nFloppies = 1; + for ( USHORT nDrive = 0; nDrive < 26; ++nDrive ) + { + if ( nDrive < nFloppies ) + { + aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE; + aDriveMap[nDrive].nStyle = FSYS_STYLE_FAT; + } + else + { + aDriveMap[nDrive].nKind = FSYS_KIND_UNKNOWN; + aDriveMap[nDrive].nStyle = FSYS_STYLE_UNKNOWN; + } + } + + aDriveMap[2].nKind = FSYS_KIND_FIXED; + aDriveMap[2].nStyle = FSYS_STYLE_FAT; +#else + FSQBUFFER_ aBuf; + ULONG nBufLen; + APIRET nRet; + USHORT nDrive; + + // disable error-boxes for hard-errors + DosError(FERR_DISABLEHARDERR); + + // determine number of floppy-drives + BYTE nFloppies; + nRet = DosDevConfig( (void*) &nFloppies, DEVINFO_FLOPPY ); + + // reset the map + for ( nDrive = 0; nDrive < 26; ++nDrive ) + { + if ( nDrive < nFloppies ) + { + aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE; + aDriveMap[nDrive].nStyle = FSYS_STYLE_FAT; + } + else + { + aDriveMap[nDrive].nKind = FSYS_KIND_UNKNOWN; + aDriveMap[nDrive].nStyle = FSYS_STYLE_UNKNOWN; + } + } + + // determine file-system via DosOpen/DocDevIOCtrl + for ( nDrive = 2; nDrive < 26; ++nDrive ) + { + // open drive + BOOL bFixed; + HFILE nDevHandle; + char pDriveName[3] = "#:"; + pDriveName[0] = nDrive+'a'; + ULONG nAction; + nRet = DosOpen( (PSZ) pDriveName, &nDevHandle, + &nAction, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_FLAGS_DASD|OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, + 0 ); + + // exists? + if ( !nRet ) + { + // removeable? + BYTE nDriveId = nDrive; + ULONG nParaOutLen, nDataOutLen; + nRet = DosDevIOCtl(nDevHandle, 8, 0x20, + &nDriveId, sizeof(nDriveId), &nParaOutLen, + &bFixed, sizeof(bFixed), &nDataOutLen ); + + // prepare the drive-map + if ( !nRet && !bFixed ) + aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE; + + // close drive + DosClose(nDevHandle); + } + else if ( nRet == ERROR_NOT_READY ) + aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE | FSYS_KIND_CDROM; + } + + // determine file-system via FSAttach + nRet = 0; + for ( USHORT n = 3; nRet != ERROR_NO_MORE_ITEMS; ++n ) + { + nBufLen = sizeof( aBuf ); + nRet = DosQueryFSAttach( 0, n, FSAIL_DRVNUMBER, + (_FSQBUFFER2*) &aBuf, &nBufLen ); + if ( !nRet ) + { + nDrive = toupper(aBuf.aBuf.szName[0]) - 'A'; + + if ( aDriveMap[nDrive].nKind == FSYS_KIND_UNKNOWN ) + aDriveMap[nDrive].nKind = + aBuf.aBuf.iType == 3 ? FSYS_KIND_FIXED : + aBuf.aBuf.iType == 4 ? FSYS_KIND_REMOTE : + FSYS_KIND_UNKNOWN; + + char *pType = (char*)(aBuf.aBuf.szName + aBuf.aBuf.cbName + 1); + aDriveMap[nDrive].nStyle = + strcmp( pType, "FAT" ) == 0 ? FSYS_STYLE_FAT : + strcmp( pType, "FAT32" ) == 0 ? FSYS_STYLE_VFAT : + strcmp( pType, "NTFS" ) == 0 ? FSYS_STYLE_NTFS : + strcmp( pType, "HPFS" ) == 0 ? FSYS_STYLE_HPFS : + strcmp( pType, "JFS" ) == 0 ? FSYS_STYLE_HPFS : + strcmp( pType, "RAMFS" ) == 0 ? FSYS_STYLE_HPFS : + strcmp( pType, "NDFS32" ) == 0 ? FSYS_STYLE_HPFS : + strcmp( pType, "NWFS" ) == 0 ? FSYS_STYLE_NWFS : + strcmp( pType, "EXT2" ) == 0 ? FSYS_STYLE_UNX : + strcmp( pType, "NFS" ) == 0 ? FSYS_STYLE_UNX : + FSYS_STYLE_UNKNOWN; + if ( strcmp( pType, "CDFS" ) == 0 ) + aDriveMap[nDrive].nKind = FSYS_KIND_CDROM|FSYS_KIND_REMOVEABLE; + } + } +#endif + + bDriveMap = TRUE; +} + +Time MsDos2Time( const time_t *pTimeT ) +{ + tm *pTm = localtime( pTimeT ); + if ( pTm ) + return Time( pTm->tm_hour, pTm->tm_min, pTm->tm_sec ); + else + return Time(0); +} + +Date MsDos2Date( const time_t *pTimeT ) +{ + tm *pTm = localtime( pTimeT ); + if ( pTm ) + return Date( pTm->tm_mday, pTm->tm_mon + 1, pTm->tm_year ); + else + return Date(0); +} + +/************************************************************************* +|* +|* DirEntry::GetPathStyle() const +|* +|* Beschreibung +|* Ersterstellung MI 11.05.95 +|* Letzte Aenderung MI 11.05.95 +|* +*************************************************************************/ + +FSysPathStyle DirEntry::GetPathStyle( const String &rDevice ) +{ + ByteString aRootDir(rDevice, osl_getThreadTextEncoding()); + // UNC-Pathname? + if ( aRootDir.Len()==0 || ( aRootDir.Len() > 1 && aRootDir.GetChar(1) != ':' ) ) + return FSYS_STYLE_UNKNOWN; + + if ( !bDriveMap ) + CreateDriveMapImpl(); + return aDriveMap[toupper(aRootDir.GetChar(0)) - 'A'].nStyle; +} + +/************************************************************************* +|* +|* DirEntry::IsCaseSensitive() const +|* +|* Beschreibung +|* Ersterstellung TPF 26.02.1999 +|* Letzte Aenderung +|* +*************************************************************************/ + +BOOL DirEntry::IsCaseSensitive( FSysPathStyle eFormatter ) const +{ + if (eFormatter==FSYS_STYLE_HOST) + { + if (GetPathStyle(GetDevice().GetName()) == FSYS_STYLE_UNX) + { + return TRUE; + } + else + { + return FALSE; + } + } + else + { + BOOL isCaseSensitive = FALSE; // ich bin unter OS2, also ist der default im Zweifelsfall case insensitiv + switch ( eFormatter ) + { + case FSYS_STYLE_MAC: + case FSYS_STYLE_FAT: + case FSYS_STYLE_VFAT: + case FSYS_STYLE_NTFS: + case FSYS_STYLE_NWFS: + case FSYS_STYLE_HPFS: + case FSYS_STYLE_DETECT: + { + isCaseSensitive = FALSE; + break; + } + case FSYS_STYLE_SYSV: + case FSYS_STYLE_BSD: + { + isCaseSensitive = TRUE; + break; + } + default: + { + isCaseSensitive = FALSE; // ich bin unter OS2, also ist der default im Zweifelsfall case insensitiv + break; + } + } + return isCaseSensitive; + } +} + + + + +//========================================================================= + +ErrCode FileStat::QueryDiskSpace( const String &rPath, + BigInt &rFreeBytes, BigInt &rTotalBytes ) +{ + FSALLOCATE aFSInfoBuf; + ByteString aVol( DirEntry(rPath).ImpGetTopPtr()->GetName(), osl_getThreadTextEncoding()); + ULONG nDriveNumber = toupper( aVol.GetChar(0) ) - 'A' + 1; + + APIRET rc = DosQueryFSInfo( nDriveNumber, FSIL_ALLOC, + &aFSInfoBuf, sizeof(aFSInfoBuf) ); + if ( rc ) + return Sys2SolarError_Impl( rc ); + + BigInt aBytesPerCluster( BigInt(aFSInfoBuf.cbSector) * + BigInt(aFSInfoBuf.cSectorUnit) ); + rFreeBytes = aBytesPerCluster * BigInt(aFSInfoBuf.cUnitAvail); + rTotalBytes = aBytesPerCluster * BigInt(aFSInfoBuf.cUnit); + return 0; +} + +//========================================================================= + +void FSysEnableSysErrorBox( BOOL bEnable ) +{ + DosError( bEnable ? 0 : FERR_DISABLEHARDERR ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/os2.hxx b/tools/source/fsys/os2.hxx new file mode 100644 index 000000000000..be74befe36b5 --- /dev/null +++ b/tools/source/fsys/os2.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _os2_hxx +#define _os2_hxx + + +#define INCL_DOSEXCEPTIONS +#define INCL_DOSFILEMGR +#define INCL_DOSPROCESS +#define INCL_DOSDEVICES +#define INCL_DOSERRORS +#define INCL_DOSMISC +#define INCL_DOSNLS /* National Language Support values */ +#include <svpm.h> + +#include <dirent.h> +#include <string.h> + +#include <sys\types.h> +#include <sys\stat.h> +#include <stdio.h> +#include <ctype.h> +#include <emx/syscalls.h> + +#define FSYS_UNIX FALSE + +#define DOS_DIRECT _A_SUBDIR +#define DOS_VOLUMEID _A_VOLID + +#define _mkdir(p) mkdir(p, 0777) + +const char* TempDirImpl( char *pBuf ); +String ToLowerImpl( const String& ); + +#define DEFSTYLE FSYS_STYLE_OS2 +#define MKDIR( p ) mkdir( (unsigned char*) p ) +#define CMP_LOWER(s) ( s.ToLowerAscii() ) + +#define START_DRV 'a' + +inline BOOL DRIVE_EXISTS( char c ) +{ + ULONG nCur, nMap; + APIRET nRet = DosQueryCurrentDisk( &nCur, &nMap ); + return ( nMap & 1 << (c - 'a') ) != 0; +} + +#include <time.h> + +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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/tdir.cxx b/tools/source/fsys/tdir.cxx new file mode 100644 index 000000000000..93b67d9c7b2d --- /dev/null +++ b/tools/source/fsys/tdir.cxx @@ -0,0 +1,769 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" + +#define _DIR_CXX + +#include <stdlib.h> +#include <cstdarg> +#include <limits.h> +#include <tools/debug.hxx> +#include <tools/list.hxx> + +#include "comdep.hxx" +#include <tools/fsys.hxx> + + +DBG_NAME( Dir ) + +DECLARE_LIST( DirEntryList, DirEntry* ) +DECLARE_LIST( FSysSortList, FSysSort* ) +DECLARE_LIST( FileStatList, FileStat* ) + +#define APPEND (USHORT) 65535 + +/************************************************************************* +|* +|* Dir::InsertPointReached() +|* +|* Beschreibung stellt fest, ob eingefuegt werden musz +|* Ersterstellung MA 05.11.91 +|* Letzte Aenderung MI 05.02.92 +|* +*************************************************************************/ + +BOOL Dir::ImpInsertPointReached( const DirEntry& rNewEntry, + const FileStat& rNewStat, + ULONG nCurPos, ULONG nSortIndex ) const +{ +#define VALUE( nKindFlags ) \ + ( ( FSYS_KIND_FILE | FSYS_KIND_DIR | FSYS_KIND_DEV | \ + FSYS_KIND_CHAR | FSYS_KIND_BLOCK ) & nKindFlags ) + + // einfache Dinge erfordern einfache Loesungen + if ( !pLst->Count() ) + return TRUE; + + FSysSort nSort = *( pSortLst->GetObject( nSortIndex ) ); + FileStat *pOldStat = NULL; + DirEntry *pCurLstObj = pLst->GetObject( nCurPos ); + if ( pStatLst ) + pOldStat = pStatLst->GetObject( nCurPos ); + + switch( nSort ) + { + case FSYS_SORT_NAME: + case (FSYS_SORT_NAME | FSYS_SORT_ASCENDING): + if ( pCurLstObj->aName > rNewEntry.aName ) + return TRUE; + if ( !(pCurLstObj->aName == rNewEntry.aName) ) + return FALSE; + break; + case (FSYS_SORT_NAME | FSYS_SORT_DESCENDING): + if ( pCurLstObj->aName < rNewEntry.aName ) + return TRUE; + if ( !(pCurLstObj->aName == rNewEntry.aName) ) + return FALSE; + break; + + case FSYS_SORT_EXT: + case (FSYS_SORT_EXT | FSYS_SORT_ASCENDING): + { + if ( pCurLstObj->GetExtension() > rNewEntry.GetExtension() ) + return TRUE; + if ( !(pCurLstObj->GetExtension() == rNewEntry.GetExtension()) ) + return FALSE; + break; + } + case (FSYS_SORT_EXT | FSYS_SORT_DESCENDING): + { + if ( pCurLstObj->GetExtension() < rNewEntry.GetExtension() ) + return TRUE; + if ( !(pCurLstObj->GetExtension() == rNewEntry.GetExtension()) ) + return FALSE; + break; + } + + case FSYS_SORT_KIND: + case (FSYS_SORT_KIND | FSYS_SORT_ASCENDING ): + if ( VALUE(pOldStat->nKindFlags) > VALUE(rNewStat.nKindFlags) ) + return TRUE; + if ( !(VALUE(pOldStat->nKindFlags) == VALUE(rNewStat.nKindFlags)) ) + return FALSE; + break; + case (FSYS_SORT_KIND | FSYS_SORT_DESCENDING): + if ( VALUE(pOldStat->nKindFlags) < VALUE(rNewStat.nKindFlags) ) + return TRUE; + if ( !(VALUE(pOldStat->nKindFlags) == VALUE(rNewStat.nKindFlags)) ) + return FALSE; + break; + + case FSYS_SORT_SIZE: + case (FSYS_SORT_SIZE | FSYS_SORT_ASCENDING): + if ( pOldStat->nSize > rNewStat.nSize ) + return TRUE; + if ( !(pOldStat->nSize == rNewStat.nSize) ) + return FALSE; + break; + case (FSYS_SORT_SIZE | FSYS_SORT_DESCENDING): + if ( pOldStat->nSize < rNewStat.nSize ) + return TRUE; + if ( !(pOldStat->nSize == rNewStat.nSize) ) + return FALSE; + break; + + case FSYS_SORT_MODIFYED: + case (FSYS_SORT_MODIFYED | FSYS_SORT_ASCENDING): + if ( (pOldStat->aDateModified >= rNewStat.aDateModified) && + (pOldStat->aTimeModified > rNewStat.aTimeModified) ) + return TRUE; + if ( !((pOldStat->aDateModified == rNewStat.aDateModified) && + (pOldStat->aTimeModified == rNewStat.aTimeModified)) ) + return FALSE; + break; + case (FSYS_SORT_MODIFYED | FSYS_SORT_DESCENDING): + if ( (pOldStat->aDateModified <= rNewStat.aDateModified) && + (pOldStat->aTimeModified < rNewStat.aTimeModified) ) + return TRUE; + if ( !((pOldStat->aDateModified == rNewStat.aDateModified) && + (pOldStat->aTimeModified == rNewStat.aTimeModified)) ) + return FALSE; + break; + + case FSYS_SORT_CREATED: + case (FSYS_SORT_CREATED | FSYS_SORT_ASCENDING): + if ( (pOldStat->aDateCreated >= rNewStat.aDateCreated) && + (pOldStat->aTimeCreated > rNewStat.aTimeCreated) ) + return TRUE; + if ( !((pOldStat->aDateCreated == rNewStat.aDateCreated) && + (pOldStat->aTimeCreated == rNewStat.aTimeCreated)) ) + return FALSE; + break; + case (FSYS_SORT_CREATED | FSYS_SORT_DESCENDING): + if ( (pOldStat->aDateCreated <= rNewStat.aDateCreated) && + (pOldStat->aTimeCreated < rNewStat.aTimeCreated) ) + return TRUE; + if ( !((pOldStat->aDateCreated == rNewStat.aDateCreated) && + (pOldStat->aTimeCreated == rNewStat.aTimeCreated)) ) + return FALSE; + break; + + case FSYS_SORT_ACCESSED: + case (FSYS_SORT_ACCESSED | FSYS_SORT_ASCENDING): + if ( (pOldStat->aDateAccessed >= rNewStat.aDateAccessed) && + (pOldStat->aTimeAccessed > rNewStat.aTimeAccessed) ) + return TRUE; + if ( !((pOldStat->aDateAccessed == rNewStat.aDateAccessed) && + (pOldStat->aTimeAccessed == rNewStat.aTimeAccessed)) ) + return FALSE; + break; + case (FSYS_SORT_ACCESSED | FSYS_SORT_DESCENDING): + if ( (pOldStat->aDateAccessed <= rNewStat.aDateAccessed) && + (pOldStat->aTimeAccessed < rNewStat.aTimeAccessed) ) + return TRUE; + if ( !((pOldStat->aDateAccessed == rNewStat.aDateAccessed) && + (pOldStat->aTimeAccessed == rNewStat.aTimeAccessed)) ) + return FALSE; + break; + default: /* Kann nicht sein */; + } + + if ( nSortIndex == ( pSortLst->Count() - 1 ) ) + return TRUE; + else + //Rekursion + return ImpInsertPointReached( rNewEntry, rNewStat, + nCurPos, nSortIndex + 1 ); +#undef VALUE +} + +/************************************************************************* +|* +|* Dir::ImpSortedInsert() +|* +|* Beschreibung fuegt sortiert ein +|* Ersterstellung MA 05.11.91 +|* Letzte Aenderung MA 03.12.91 +|* +*************************************************************************/ + +void Dir::ImpSortedInsert( const DirEntry *pNewEntry, const FileStat *pNewStat ) +{ + //Sonderfall, keine Sortierung gewuenscht. + if ( !pSortLst ) { + pLst->Insert( (DirEntry*)pNewEntry, APPEND ); + return; + } + + pLst->First(); + do { + if ( ImpInsertPointReached( *pNewEntry, *pNewStat, pLst->GetCurPos(), + (ULONG)0 ) ) + { + if ( pStatLst ) + pStatLst->Insert( (FileStat*)pNewStat, pLst->GetCurPos() ); + pLst->Insert( (DirEntry*)pNewEntry ); + return; + } + } while( pLst->Next() ); + + if ( pStatLst ) + pStatLst->Insert( (FileStat*)pNewStat, APPEND ); + pLst->Insert( (DirEntry*)pNewEntry, APPEND ); +} + +/************************************************************************* +|* +|* Dir::Construct() +|* +|* Beschreibung gemeinsame Implementation der Ctoren +|* Ersterstellung MI 02.06.93 +|* Letzte Aenderung MI 02.06.93 +|* +*************************************************************************/ + +void Dir::Construct( DirEntryKind nKindFlags ) +{ + pLst = NULL; + pSortLst = NULL; + pStatLst = NULL; + eAttrMask = nKindFlags; + ByteString aTempName( GetName(), osl_getThreadTextEncoding() ); + if ( aTempName.Search( "*" ) != STRING_NOTFOUND || + aTempName.Search( "?" ) != STRING_NOTFOUND ) +#if defined( WNT ) && !defined( WTC ) + { + ByteString aTStr(CutName(), osl_getThreadTextEncoding()); + char* pBuffer = new char[aTStr.Len()+1]; + strcpy( pBuffer, aTStr.GetBuffer() ); + CharLowerBuff( pBuffer, aTStr.Len() ); + aNameMask = WildCard( String(pBuffer, osl_getThreadTextEncoding()), ';' ); + delete [] pBuffer; + } +#else + aNameMask = WildCard( CutName(), ';' ); +#endif + else + aNameMask = String("*", osl_getThreadTextEncoding()); +} + +/************************************************************************* +|* +|* Dir::Update() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 16.05.91 +|* Letzte Aenderung MI 19.09.96 +|* +*************************************************************************/ + +BOOL Dir::Update() +{ + Reset(); + return Scan( USHRT_MAX ) > 0; +} + +/************************************************************************* +|* +|* Dir::Reset() +|* +|* Beschreibung +|* Ersterstellung MI 22.10.96 +|* Letzte Aenderung MI 22.10.96 +|* +*************************************************************************/ + +void Dir::Reset() +{ + // ggf. alten Reader l"oschen + if ( pReader && pReader->bInUse ) + DELETEZ(pReader); + + // alle DirEntries aus der Liste entfernen und deren Speicher freigeben + if ( pLst ) + { + DirEntry* pEntry = pLst->First(); + while (pEntry) + { + DirEntry* pNext = pLst->Next(); + delete pEntry; + pEntry = pNext; + } + pLst->Clear(); + } + else + pLst = new DirEntryList(); + + // Alte File-Stat's Loeschen + if ( pStatLst ) + { + //Erstmal die alten Loeschen + FileStat* pEntry = pStatLst->First(); + while (pEntry) + { + FileStat* pNext = pStatLst->Next(); + delete pEntry; + pEntry = pNext; + } + pStatLst->Clear(); + delete pStatLst; + } + + // Verlangen die Sortierkriterien FileStat's? + if ( pSortLst ) + { + pSortLst->First(); + do + { + if ( *( pSortLst->GetCurObject() ) & + ( FSYS_SORT_KIND | FSYS_SORT_SIZE | + FSYS_SORT_CREATED | FSYS_SORT_MODIFYED | FSYS_SORT_ACCESSED ) ) + pStatLst = new FileStatList(); + } while ( !pStatLst && pSortLst->Next() ); + } + +#ifndef BOOTSTRAP + // ggf. einen neuen Reader aufsetzen + if ( !pReader ) + pReader = new DirReader_Impl( *this ); +#endif + + // gibt es das zu oeffnende Verzeichnis ueberhaupt? +#if !defined(UNX) && !defined(OS2) //explanation: see DirReader_Impl::Read() in unx.cxx + if( !pReader->pDosDir ) + { + nError = FSYS_ERR_NOTADIRECTORY; + DELETEZ( pReader ); + return; + } +#endif +} + +/************************************************************************* +|* +|* Dir::Scan() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 18.09.96 +|* Letzte Aenderung MI 19.09.96 +|* +*************************************************************************/ + +USHORT Dir::Scan( USHORT nCount ) +{ + + USHORT nRead = 0; // Anzahl in dieser Runde gelesener Eintr"age + FSysFailOnErrorImpl(); + + // noch nicht fertig gewesen + if ( pReader ) + { + // frischer Reader? + if ( !pLst->Count() ) + { + // dann ggf. Laufwerke scannen + pReader->bInUse = TRUE; + nRead = pReader->Init(); + } + + // weiterlesen... + while ( nRead <= nCount && !pReader->bReady ) + nRead = nRead + pReader->Read(); + + // fertig? + if ( pReader && pReader->bReady ) + DELETEZ( pReader ); + } + + // Anzahl der gelesenen zur"uckgeben + return nRead; +} + +/************************************************************************* +|* +|* Dir::Dir() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 16.05.91 +|* Letzte Aenderung MI 04.03.92 +|* +*************************************************************************/ + +Dir::Dir( const DirEntry& rDirEntry, DirEntryKind nKindFlags, FSysSort nSort, ... ): + DirEntry( rDirEntry ), + pReader( 0 ) +{ + DBG_CTOR( Dir, NULL ); + + Construct( nKindFlags ); + + std::va_list pArgs; + va_start( pArgs, nSort ); + ImpSetSort( pArgs, nSort ); + + Reset(); +} + +/************************************************************************* +|* +|* Dir::Dir() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 02.06.93 +|* Letzte Aenderung MI 02.06.93 +|* +*************************************************************************/ + +Dir::Dir( const DirEntry& rDirEntry, DirEntryKind nKindFlags ): + DirEntry( rDirEntry ), + pReader( 0 ) +{ + DBG_CTOR( Dir, NULL ); + + Construct( nKindFlags ); + Reset(); +} + +/************************************************************************* +|* +|* Dir::Dir() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 16.05.91 +|* Letzte Aenderung MA 04.11.91 +|* +*************************************************************************/ + +Dir::Dir(): + pReader( 0 ) +{ + DBG_CTOR( Dir, NULL ); + + pLst = NULL; + pSortLst = NULL; + pStatLst = NULL; + eAttrMask = FSYS_KIND_ALL; + aNameMask = String("*", osl_getThreadTextEncoding()); +} + +/************************************************************************* +|* +|* Dir::~Dir() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 16.05.91 +|* Letzte Aenderung MA 04.11.91 +|* +*************************************************************************/ + +Dir::~Dir() +{ + DBG_DTOR( Dir, NULL ); + + // alle DirEntries aus der Liste entfernen und deren Speicher freigeben + if ( pLst ) + { + DirEntry* pEntry = pLst->First(); + while (pEntry) + { + DirEntry* pNext = pLst->Next(); + delete pEntry; + pEntry = pNext; + } + pLst->Clear(); + + delete pLst; + } + + // alle Sorts aus der Liste entfernen und deren Speicher freigeben + if ( pSortLst ) + { + FSysSort* pEntry = pSortLst->First(); + while (pEntry) + { + FSysSort* pNext = pSortLst->Next(); + delete pEntry; + pEntry = pNext; + } + pSortLst->Clear(); + + delete pSortLst; + } + + // alle FileStat's aus der Liste entfernen und deren Speicher freigeben + if ( pStatLst ) + { + FileStat* pEntry = pStatLst->First(); + while (pEntry) + { + FileStat* pNext = pStatLst->Next(); + delete pEntry; + pEntry = pNext; + } + pStatLst->Clear(); + delete pStatLst; + } + + // ggf. laufenden Reader freigeben + delete pReader; +} + +/************************************************************************* +|* +|* Dir::ImpSetSort() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MA 04.11.91 +|* Letzte Aenderung MI 05.02.92 +|* +*************************************************************************/ + +FSysError Dir::ImpSetSort( std::va_list pArgs, int nFirstSort ) +{ + BOOL bLast; + FSysSort *pSort; + FSysSortList *pNewSortLst = new FSysSortList; + + *( pSort = new FSysSort ) = nFirstSort; + do + { + // letztes Kriterium? + bLast = FSYS_SORT_END == (*pSort & FSYS_SORT_END); + *pSort &= ~FSYS_SORT_END; + + FSysSort nSort = *pSort & ~(USHORT)FSYS_SORT_ASCENDING + & ~(USHORT)FSYS_SORT_DESCENDING; + + // g"utliges Sortierkriterium? + if ( ( nSort == FSYS_SORT_NAME ) || + ( nSort == FSYS_SORT_SIZE ) || + ( nSort == FSYS_SORT_EXT ) || + ( nSort == FSYS_SORT_CREATED ) || + ( nSort == FSYS_SORT_MODIFYED ) || + ( nSort == FSYS_SORT_ACCESSED ) || + ( nSort == FSYS_SORT_KIND ) ) + { + pNewSortLst->Insert( pSort, APPEND ); + *(pSort = new FSysSort) = va_arg( pArgs, FSysSort ); + } + else + { // ungueltiger Sort oder FSYS_SORT_NONE + FSysSort* pEntry = pNewSortLst->First(); + while (pEntry) + { + FSysSort* pNext = pNewSortLst->Next(); + delete pEntry; + pEntry = pNext; + } + pNewSortLst->Clear(); + delete pNewSortLst; + if ( *pSort == FSYS_SORT_NONE ) + { + delete pSort; + if ( pSortLst ) + delete pSortLst; + return FSYS_ERR_OK; + } + else + { + delete pSort; + return FSYS_ERR_NOTSUPPORTED; + } + } + } while ( !bLast ); + + va_end( pArgs ); + delete pSort; // JP:6.3.00 - delete the initial pointer + + //Enfernen der alten Sort-Elemente + if ( pSortLst ) + { + FSysSort* pEntry = pSortLst->First(); + while (pEntry) + { + FSysSort* pNext = pSortLst->Next(); + delete pEntry; + pEntry = pNext; + } + pSortLst->Clear(); + delete pSortLst; + } + pSortLst = pNewSortLst; + + //Jetzt noch neu Sortieren... + + //Wenn keine FileStats da sind, aber nun welche gebraucht werden, + //ist der Aufruf von Update() die einfachste Moeglichkeit + if ( !pStatLst && pSortLst ) + { + pSortLst->First(); + do + { + if ( *(pSortLst->GetCurObject()) & + ( FSYS_SORT_CREATED | FSYS_SORT_MODIFYED | FSYS_SORT_SIZE | + FSYS_SORT_ACCESSED | FSYS_SORT_KIND ) ) + { + Update(); + return FSYS_ERR_OK; + } + } while ( !pStatLst && pSortLst->Next() ); + } + + if ( pLst ) { //Keine DirEntry's, kein Sort. + DirEntryList *pOldLst = pLst; //alte Liste merken + pLst = new DirEntryList(); //neue Liste (zu Sortieren) + + FileStatList *pOldStatLst = NULL; //alte StatListe merken + if ( pStatLst ) { + pOldStatLst = pStatLst; + pStatLst = new FileStatList(); //neue StatListe (zu Sortieren) + } + pOldLst->First(); + do + { + //Sortiertes Einfuegen der Elemente aus den gemerkten Listen + //in die 'richtigen' Listen + if ( pOldStatLst ) + ImpSortedInsert( pOldLst->GetCurObject(), + pOldStatLst->GetObject( pOldLst->GetCurPos() ) ); + else + ImpSortedInsert( pOldLst->GetCurObject(), NULL ); + } while( pOldLst->Next() ); + + delete pOldLst; + if ( pOldStatLst ) + delete pOldStatLst; + } + return FSYS_ERR_OK; +} + +/************************************************************************* +|* +|* Dir::SetSort() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MA 04.11.91 +|* Letzte Aenderung MI 05.02.92 +|* +*************************************************************************/ + +FSysError Dir::SetSort( FSysSort nSort, ... ) +{ + std::va_list pArgs; + va_start( pArgs, nSort ); + return ImpSetSort( pArgs, nSort ); +} + +/************************************************************************* +|* +|* Dir::operator[]() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 16.05.91 +|* Letzte Aenderung MI 16.05.91 +|* +*************************************************************************/ + +DirEntry& Dir::operator[] ( USHORT nIndex ) const +{ + DBG_ASSERT( nIndex < Count(), "Dir::operator[] : nIndex > Count()" ); + + DirEntry *pEntry = pLst->GetObject( nIndex ); + return *pEntry; +} + +/************************************************************************* +|* +|* Dir::operator+= () +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 16.05.91 +|* Letzte Aenderung MI 16.05.91 +|* +*************************************************************************/ + +Dir& Dir::operator+=( const Dir& rDir ) +{ + // ggf. erst den Rest lesen + if ( pReader ) + Scan( USHRT_MAX ); + DBG_ASSERT( !rDir.pReader, "Dir::+= with incomplete Dir" ); + + // ggf. initiale Liste erzeugen + if ( !pLst ) + pLst = new DirEntryList(); + + //Verlangen die Sortierkriterien FileStat's? + BOOL bStat = FALSE; + if ( pSortLst ) { + pSortLst->First(); + do { + if ( *(pSortLst->GetCurObject()) & + ( FSYS_SORT_CREATED | FSYS_SORT_MODIFYED | FSYS_SORT_SIZE | + FSYS_SORT_ACCESSED | FSYS_SORT_KIND ) ) + bStat = TRUE; + } while ( !bStat && pSortLst->Next() ); + } + FileStat * stat = NULL; + for ( USHORT nNr = 0; nNr < rDir.Count(); nNr++ ) + { + if ( bStat ) + { + if ( rDir.pStatLst ) + stat = new FileStat( *rDir.pStatLst->GetObject(nNr) ); + else + stat = new FileStat( rDir[nNr] ); + } + ImpSortedInsert( new DirEntry( rDir[nNr] ), stat ); + } + return *this; +} + +/************************************************************************* +|* +|* Dir::Count() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 16.05.91 +|* Letzte Aenderung MI 18.09.96 +|* +*************************************************************************/ + + +USHORT Dir::Count( BOOL bUpdated ) const +{ + // ggf. erst den Rest lesen + if ( bUpdated && pReader ) + ((Dir*)this)->Scan( USHRT_MAX ); + + return pLst == NULL ? 0 : (USHORT) pLst->Count(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/tempfile.cxx b/tools/source/fsys/tempfile.cxx new file mode 100644 index 000000000000..36e06b05bf17 --- /dev/null +++ b/tools/source/fsys/tempfile.cxx @@ -0,0 +1,303 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" + +#include <tools/tempfile.hxx> +#include "comdep.hxx" + +#include <rtl/ustring.hxx> +#include <osl/file.hxx> +#include <rtl/instance.hxx> +#include <tools/time.hxx> +#include <tools/debug.hxx> +#include <stdio.h> + +#ifdef UNX +#define _MAX_PATH 260 +#endif + +using namespace osl; + +namespace { struct TempNameBase_Impl : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {}; } + +struct TempFile_Impl +{ + String aName; + sal_Bool bIsDirectory; +}; + +String GetSystemTempDir_Impl() +{ + char sBuf[_MAX_PATH]; + const char *pDir = TempDirImpl(sBuf); + + ::rtl::OString aTmpA( pDir ); + ::rtl::OUString aTmp = ::rtl::OStringToOUString( aTmpA, osl_getThreadTextEncoding() ); + rtl::OUString aRet; + FileBase::getFileURLFromSystemPath( aTmp, aRet ); + String aName = aRet; + if( aName.GetChar(aName.Len()-1) != '/' ) + aName += '/'; + return aName; +} + +#define TMPNAME_SIZE ( 1 + 5 + 5 + 4 + 1 ) +String ConstructTempDir_Impl( const String* pParent ) +{ + String aName; + if ( pParent && pParent->Len() ) + { + // if parent given try to use it + rtl::OUString aTmp( *pParent ); + rtl::OUString aRet; + + // test for valid filename + { + ::osl::DirectoryItem aItem; + sal_Int32 i = aRet.getLength(); + if ( aRet[i-1] == '/' ) + i--; + + if ( DirectoryItem::get( ::rtl::OUString( aRet, i ), aItem ) == FileBase::E_None ) + aName = aRet; + } + } + + if ( !aName.Len() ) + { + // if no parent or invalid parent : use system directory + ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get(); + if ( !rTempNameBase_Impl.getLength() ) + rTempNameBase_Impl = GetSystemTempDir_Impl(); + aName = rTempNameBase_Impl; + } + + // Make sure that directory ends with a separator + xub_StrLen i = aName.Len(); + if( i>0 && aName.GetChar(i-1) != '/' ) + aName += '/'; + + return aName; +} + +void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True ) +{ + // add a suitable tempname + // Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576 + // ER 13.07.00 why not radix 36 [0-9A-Z] ?!? + const unsigned nRadix = 26; + String aName( rName ); + aName += String::CreateFromAscii( "sv" ); + + rName.Erase(); + static unsigned long u = Time::GetSystemTicks(); + for ( unsigned long nOld = u; ++u != nOld; ) + { + u %= (nRadix*nRadix*nRadix); + String aTmp( aName ); + aTmp += String::CreateFromInt32( (sal_Int32) (unsigned) u, nRadix ); + aTmp += String::CreateFromAscii( ".tmp" ); + + if ( bDir ) + { + FileBase::RC err = Directory::create( aTmp ); + if ( err == FileBase::E_None ) + { + // !bKeep: only for creating a name, not a file or directory + if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None ) + rName = aTmp; + break; + } + else if ( err != FileBase::E_EXIST ) + { + // if f.e. name contains invalid chars stop trying to create dirs + break; + } + } + else + { + DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" ); + File aFile( aTmp ); + FileBase::RC err = aFile.open(osl_File_OpenFlag_Create); + if ( err == FileBase::E_None ) + { + rName = aTmp; + aFile.close(); + break; + } + else if ( err != FileBase::E_EXIST ) + { + // if f.e. name contains invalid chars stop trying to create files + break; + } + } + } +} + +String TempFile::CreateTempName( const String* pParent ) +{ + // get correct directory + String aName = ConstructTempDir_Impl( pParent ); + + // get TempFile name with default naming scheme + CreateTempName_Impl( aName, sal_False ); + + // convert to file URL + rtl::OUString aTmp; + if ( aName.Len() ) + aTmp = aName; + return aTmp; +} + +TempFile::TempFile( const String* pParent, sal_Bool bDirectory ) + : pImp( new TempFile_Impl ) + , bKillingFileEnabled( sal_False ) +{ + pImp->bIsDirectory = bDirectory; + + // get correct directory + pImp->aName = ConstructTempDir_Impl( pParent ); + + // get TempFile with default naming scheme + CreateTempName_Impl( pImp->aName, sal_True, bDirectory ); +} + +TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory ) + : pImp( new TempFile_Impl ) + , bKillingFileEnabled( sal_False ) +{ + pImp->bIsDirectory = bDirectory; + + // get correct directory + String aName = ConstructTempDir_Impl( pParent ); + + // now use special naming scheme ( name takes leading chars and an index counting up from zero + aName += rLeadingChars; + for ( sal_Int32 i=0;; i++ ) + { + String aTmp( aName ); + aTmp += String::CreateFromInt32( i ); + if ( pExtension ) + aTmp += *pExtension; + else + aTmp += String::CreateFromAscii( ".tmp" ); + if ( bDirectory ) + { + FileBase::RC err = Directory::create( aTmp ); + if ( err == FileBase::E_None ) + { + pImp->aName = aTmp; + break; + } + else if ( err != FileBase::E_EXIST ) + // if f.e. name contains invalid chars stop trying to create dirs + break; + } + else + { + File aFile( aTmp ); + FileBase::RC err = aFile.open(osl_File_OpenFlag_Create); + if ( err == FileBase::E_None ) + { + pImp->aName = aTmp; + aFile.close(); + break; + } + else if ( err != FileBase::E_EXIST ) + // if f.e. name contains invalid chars stop trying to create dirs + break; + } + } +} + +TempFile::~TempFile() +{ + if ( bKillingFileEnabled ) + { + if ( pImp->bIsDirectory ) + { + // at the moment no recursiv algorithm present + Directory::remove( pImp->aName ); + } + else + { + File::remove( pImp->aName ); + } + } + + delete pImp; +} + +sal_Bool TempFile::IsValid() const +{ + return pImp->aName.Len() != 0; +} + +String TempFile::GetName() const +{ + rtl::OUString aTmp; + aTmp = pImp->aName; + return aTmp; +} + +String TempFile::SetTempNameBaseDirectory( const String &rBaseName ) +{ + String aName( rBaseName ); + + ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get(); + + FileBase::RC err= Directory::create( aName ); + if ( err == FileBase::E_None || err == FileBase::E_EXIST ) + { + rTempNameBase_Impl = aName; + rTempNameBase_Impl += String( '/' ); + + TempFile aBase( NULL, sal_True ); + if ( aBase.IsValid() ) + rTempNameBase_Impl = aBase.pImp->aName; + } + + rtl::OUString aTmp; + aTmp = rTempNameBase_Impl; + return aTmp; +} + +String TempFile::GetTempNameBaseDirectory() +{ + ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get(); + if ( !rTempNameBase_Impl.getLength() ) + rTempNameBase_Impl = GetSystemTempDir_Impl(); + + rtl::OUString aTmp; + aTmp = rTempNameBase_Impl; + return aTmp; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/unx.cxx b/tools/source/fsys/unx.cxx new file mode 100644 index 000000000000..b1abae49d8b0 --- /dev/null +++ b/tools/source/fsys/unx.cxx @@ -0,0 +1,663 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <utime.h> +#if defined HPUX || defined LINUX +#include <mntent.h> +#define mnttab mntent +#elif defined SCO +#include <mnttab.h> +#elif defined AIX +#include <sys/mntctl.h> +#include <sys/vmount.h> +extern "C" int mntctl( int cmd, size_t size, char* buf ); +#elif defined(NETBSD) +#include <sys/mount.h> +#elif defined(FREEBSD) || defined(MACOSX) || defined(OPENBSD) +#elif defined DECUNIX +struct mnttab +{ + char *mnt_dir; + char *mnt_fsname; +}; +#else +#include <sys/mnttab.h> +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +#include <tools/debug.hxx> +#include <tools/list.hxx> +#include <tools/fsys.hxx> +#include "comdep.hxx" +#include <rtl/instance.hxx> + +DECLARE_LIST( DirEntryList, DirEntry* ) +DECLARE_LIST( FSysSortList, FSysSort* ) +DECLARE_LIST( FileStatList, FileStat* ) + +#if defined SOLARIS || defined SINIX +#define MOUNTSPECIAL mnt_special +#define MOUNTPOINT mnt_mountp +#define MOUNTOPTS mnt_mntopts +#define MOUNTFS mnt_fstype +#elif defined SCO +#define MNTTAB "/etc/mnttab" +#define MOUNTSPECIAL mt_dev +#define MOUNTPOINT mt_filsys +#else +#define MOUNTSPECIAL mnt_fsname +#define MOUNTPOINT mnt_dir +#define MOUNTFS mnt_type +#endif + +struct mymnttab +{ + dev_t mountdevice; + ByteString mountspecial; + ByteString mountpoint; + ByteString mymnttab_filesystem; + mymnttab() { mountdevice = (dev_t) -1; } +}; + + +#if defined(NETBSD) || defined(FREEBSD) || defined(MACOSX) || \ + defined(OPENBSD) +BOOL GetMountEntry(dev_t /* dev */, struct mymnttab * /* mytab */ ) +{ + DBG_WARNING( "Sorry, not implemented: GetMountEntry" ); + return FALSE; +} + +#elif defined AIX +BOOL GetMountEntry(dev_t dev, struct mymnttab *mytab) +{ + int bufsize; + if (mntctl (MCTL_QUERY, sizeof bufsize, (char*) &bufsize)) + return FALSE; + + char* buffer = (char *)malloc( bufsize * sizeof(char) ); + if (mntctl (MCTL_QUERY, bufsize, buffer) != -1) + for ( char* vmt = buffer; + vmt < buffer + bufsize; + vmt += ((struct vmount*)vmt)->vmt_length) + { + struct stat buf; + char *mountp = vmt2dataptr((struct vmount*)vmt, VMT_STUB); + if ((stat (mountp, &buf) != -1) && (buf.st_dev == dev)) + { + mytab->mountpoint = mountp; + mytab->mountspecial + = vmt2dataptr((struct vmount*)vmt, VMT_HOSTNAME); + if (mytab->mountspecial.Len()) + mytab->mountspecial += ':'; + mytab->mountspecial + += vmt2dataptr((struct vmount*)vmt, VMT_OBJECT); + mytab->mountdevice = dev; + free( buffer ); + return TRUE; + } + } + free( buffer ); + return FALSE; +} + +#else + + +static BOOL GetMountEntry(dev_t dev, struct mymnttab *mytab) +{ +#if defined SOLARIS || defined SINIX + FILE *fp = fopen (MNTTAB, "r"); + if (! fp) + return FALSE; + struct mnttab mnt[1]; + while (getmntent (fp, mnt) != -1) +#elif defined SCO + FILE *fp = fopen (MNTTAB, "r"); + if (! fp) + return FALSE; + struct mnttab mnt[1]; + while (fread (&mnt, sizeof mnt, 1, fp) > 0) +#elif defined DECUNIX || defined AIX + FILE *fp = NULL; + if (! fp) + return FALSE; + struct mnttab mnt[1]; + while ( 0 ) +#else + FILE *fp = setmntent (MOUNTED, "r"); + if (! fp) + return FALSE; + struct mnttab *mnt; + while ((mnt = getmntent (fp)) != NULL) +#endif + { +#ifdef SOLARIS + char *devopt = NULL; + if ( mnt->MOUNTOPTS != NULL ) + devopt = strstr (mnt->MOUNTOPTS, "dev="); + if (devopt) + { + if (dev != (dev_t) strtoul (devopt+4, NULL, 16)) + continue; + } + else +#endif + { + struct stat buf; + if ((stat (mnt->MOUNTPOINT, &buf) == -1) || (buf.st_dev != dev)) + continue; + } +# ifdef LINUX + /* #61624# File mit setmntent oeffnen und mit fclose schliessen stoesst + bei der glibc-2.1 auf wenig Gegenliebe */ + endmntent( fp ); +# else + fclose (fp); +# endif + mytab->mountspecial = mnt->MOUNTSPECIAL; + mytab->mountpoint = mnt->MOUNTPOINT; + mytab->mountdevice = dev; +#ifndef SCO + mytab->mymnttab_filesystem = mnt->MOUNTFS; +#else + mytab->mymnttab_filesystem = "ext2"; //default ist case sensitiv unter unix +#endif + return TRUE; + } +# ifdef LINUX + /* #61624# dito */ + endmntent( fp ); +# else + fclose (fp); +# endif + return FALSE; +} + +#endif + +/************************************************************************ +|* +|* DirEntry::IsCaseSensitive() +|* +|* Beschreibung +|* Ersterstellung TPF 25.02.1999 +|* Letzte Aenderung TPF 25.02.1999 +|* +*************************************************************************/ + +BOOL DirEntry::IsCaseSensitive( FSysPathStyle eFormatter ) const +{ + + if (eFormatter==FSYS_STYLE_HOST) + { +#ifdef NETBSD + return TRUE; +#else + struct stat buf; + DirEntry aPath(*this); + aPath.ToAbs(); + + while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf)) + { + if (aPath.Level() == 1) + { + return TRUE; // ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv + } + aPath = aPath [1]; + } + + struct mymnttab fsmnt; + GetMountEntry(buf.st_dev, &fsmnt); + if ((fsmnt.mymnttab_filesystem.CompareTo("msdos")==COMPARE_EQUAL) || + (fsmnt.mymnttab_filesystem.CompareTo("umsdos")==COMPARE_EQUAL) || + (fsmnt.mymnttab_filesystem.CompareTo("vfat")==COMPARE_EQUAL) || + (fsmnt.mymnttab_filesystem.CompareTo("hpfs")==COMPARE_EQUAL) || + (fsmnt.mymnttab_filesystem.CompareTo("smb") ==COMPARE_EQUAL) || + (fsmnt.mymnttab_filesystem.CompareTo("ncpfs")==COMPARE_EQUAL)) + { + return FALSE; + } + else + { + return TRUE; + } +#endif + } + else + { + BOOL isCaseSensitive = TRUE; // ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv + switch ( eFormatter ) + { + case FSYS_STYLE_MAC: + case FSYS_STYLE_FAT: + case FSYS_STYLE_VFAT: + case FSYS_STYLE_NTFS: + case FSYS_STYLE_NWFS: + case FSYS_STYLE_HPFS: + { + isCaseSensitive = FALSE; + break; + } + case FSYS_STYLE_SYSV: + case FSYS_STYLE_BSD: + case FSYS_STYLE_DETECT: + { + isCaseSensitive = TRUE; + break; + } + default: + { + isCaseSensitive = TRUE; // ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv + break; + } + } + return isCaseSensitive; + } +} + +/************************************************************************ +|* +|* DirEntry::ToAbs() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 13:30 +|* +*************************************************************************/ + +BOOL DirEntry::ToAbs() +{ + if ( FSYS_FLAG_VOLUME == eFlag ) + { + eFlag = FSYS_FLAG_ABSROOT; + return TRUE; + } + + if ( IsAbs() ) + return TRUE; + + char sBuf[MAXPATHLEN + 1]; + *this = DirEntry( String( getcwd( sBuf, MAXPATHLEN ), osl_getThreadTextEncoding() ) ) + *this; + return IsAbs(); +} + +/************************************************************************* +|* +|* DirEntry::GetVolume() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 04.03.92 +|* Letzte Aenderung +|* +*************************************************************************/ + +namespace { struct mymnt : public rtl::Static< mymnttab, mymnt > {}; } + +String DirEntry::GetVolume() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntry aPath( *this ); + aPath.ToAbs(); + + struct stat buf; + while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf)) + { + if (aPath.Level() <= 1) + return String(); + aPath = aPath [1]; + } + mymnttab &rMnt = mymnt::get(); + return ((buf.st_dev == rMnt.mountdevice || + GetMountEntry(buf.st_dev, &rMnt)) ? + String(rMnt.mountspecial, osl_getThreadTextEncoding()) : + String()); +} + +DirEntry DirEntry::GetDevice() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + DirEntry aPath( *this ); + aPath.ToAbs(); + + struct stat buf; + while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf)) + { + if (aPath.Level() <= 1) + return String(); + aPath = aPath [1]; + } + mymnttab &rMnt = mymnt::get(); + return ((buf.st_dev == rMnt.mountdevice || + GetMountEntry(buf.st_dev, &rMnt)) ? + String( rMnt.mountpoint, osl_getThreadTextEncoding()) : + String()); +} + +/************************************************************************* +|* +|* DirEntry::SetCWD() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung DV 04.11.92 +|* +*************************************************************************/ + +BOOL DirEntry::SetCWD( BOOL bSloppy ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + + ByteString aPath( GetFull(), osl_getThreadTextEncoding()); + if ( !chdir( aPath.GetBuffer() ) ) + { + return TRUE; + } + else + { + if ( bSloppy && !chdir(aPath.GetBuffer()) ) + { + return TRUE; + } + else + { + return FALSE; + } + } +} + +//------------------------------------------------------------------------- + +USHORT DirReader_Impl::Init() +{ + return 0; +} + +//------------------------------------------------------------------------- + +USHORT DirReader_Impl::Read() +{ + if (!pDosDir) + { + pDosDir = opendir( (char*) ByteString(aPath, osl_getThreadTextEncoding()).GetBuffer() ); + } + + if (!pDosDir) + { + bReady = TRUE; + return 0; + } + + // Directories und Files auflisten? + if ( ( pDir->eAttrMask & FSYS_KIND_DIR || pDir->eAttrMask & FSYS_KIND_FILE ) && + ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) ) + { + String aD_Name(pDosEntry->d_name, osl_getThreadTextEncoding()); + if ( pDir->aNameMask.Matches( aD_Name ) ) + { + DirEntryFlag eFlag = + 0 == strcmp( pDosEntry->d_name, "." ) ? FSYS_FLAG_CURRENT + : 0 == strcmp( pDosEntry->d_name, ".." ) ? FSYS_FLAG_PARENT + : FSYS_FLAG_NORMAL; + DirEntry *pTemp = new DirEntry( ByteString(pDosEntry->d_name), eFlag, FSYS_STYLE_UNX ); + if ( pParent ) + pTemp->ImpChangeParent( new DirEntry( *pParent ), FALSE); + FileStat aStat( *pTemp ); + if ( ( ( ( pDir->eAttrMask & FSYS_KIND_DIR ) && + ( aStat.IsKind( FSYS_KIND_DIR ) ) ) || + ( ( pDir->eAttrMask & FSYS_KIND_FILE ) && + !( aStat.IsKind( FSYS_KIND_DIR ) ) ) ) && + !( pDir->eAttrMask & FSYS_KIND_VISIBLE && + pDosEntry->d_name[0] == '.' ) ) + { + if ( pDir->pStatLst ) //Status fuer Sort gewuenscht? + pDir->ImpSortedInsert( pTemp, new FileStat( aStat ) ); + else + pDir->ImpSortedInsert( pTemp, NULL );; + return 1; + } + else + delete pTemp; + } + } + else + bReady = TRUE; + return 0; +} + +/************************************************************************* +|* +|* FileStat::FileStat() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MA 05.11.91 +|* Letzte Aenderung MA 07.11.91 +|* +*************************************************************************/ + +FileStat::FileStat( const void *, const void * ): + aDateCreated(0), + aTimeCreated(0), + aDateModified(0), + aTimeModified(0), + aDateAccessed(0), + aTimeAccessed(0) +{ +} + +/************************************************************************* +|* +|* FileStat::Update() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 11.06.91 +|* Letzte Aenderung MA 07.11.91 +|* +*************************************************************************/ +BOOL FileStat::Update( const DirEntry& rDirEntry, BOOL ) +{ + + nSize = 0; + nKindFlags = 0; + aCreator.Erase(); + aType.Erase(); + aDateCreated = Date(0); + aTimeCreated = Time(0); + aDateModified = Date(0); + aTimeModified = Time(0); + aDateAccessed = Date(0); + aTimeAccessed = Time(0); + + if ( !rDirEntry.IsValid() ) + { + nError = FSYS_ERR_NOTEXISTS; + return FALSE; + } + + // Sonderbehandlung falls es sich um eine Root handelt + if ( rDirEntry.eFlag == FSYS_FLAG_ABSROOT ) + { + nKindFlags = FSYS_KIND_DIR; + nError = FSYS_ERR_OK; + return TRUE; + } + + struct stat aStat; + ByteString aPath( rDirEntry.GetFull(), osl_getThreadTextEncoding() ); + if ( stat( (char*) aPath.GetBuffer(), &aStat ) ) + { + // pl: #67851# + // do this here, because an existing filename containing "wildcards" + // should be handled as a file, not a wildcard + // note that this is not a solution, since filenames containing special characters + // are handled badly across the whole Office + + // Sonderbehandlung falls es sich um eine Wildcard handelt + ByteString aTempName( rDirEntry.GetName(), osl_getThreadTextEncoding() ); + if ( strchr( (char*) aTempName.GetBuffer(), '?' ) || + strchr( (char*) aTempName.GetBuffer(), '*' ) || + strchr( (char*) aTempName.GetBuffer(), ';' ) ) + { + nKindFlags = FSYS_KIND_WILD; + nError = FSYS_ERR_OK; + return TRUE; + } + + nError = FSYS_ERR_NOTEXISTS; + return FALSE; + } + + nError = FSYS_ERR_OK; + nSize = aStat.st_size; + + nKindFlags = FSYS_KIND_UNKNOWN; + if ( ( aStat.st_mode & S_IFDIR ) == S_IFDIR ) + nKindFlags = nKindFlags | FSYS_KIND_DIR; + if ( ( aStat.st_mode & S_IFREG ) == S_IFREG ) + nKindFlags = nKindFlags | FSYS_KIND_FILE; + if ( ( aStat.st_mode & S_IFCHR ) == S_IFCHR ) + nKindFlags = nKindFlags | FSYS_KIND_DEV | FSYS_KIND_CHAR; + if ( ( aStat.st_mode & S_IFBLK ) == S_IFBLK ) + nKindFlags = nKindFlags | FSYS_KIND_DEV | FSYS_KIND_BLOCK; + if ( nKindFlags == FSYS_KIND_UNKNOWN ) + nKindFlags = nKindFlags | FSYS_KIND_FILE; + + Unx2DateAndTime( aStat.st_ctime, aTimeCreated, aDateCreated ); + Unx2DateAndTime( aStat.st_mtime, aTimeModified, aDateModified ); + Unx2DateAndTime( aStat.st_atime, aTimeAccessed, aDateAccessed ); + + return TRUE; +} + +//==================================================================== + +const char *TempDirImpl( char *pBuf ) +{ +#ifdef MACOSX + // P_tmpdir is /var/tmp on Mac OS X, and it is not cleaned up on system + // startup + strcpy( pBuf, "/tmp" ); +#else + const char *pValue = getenv( "TEMP" ); + if ( !pValue ) + pValue = getenv( "TMP" ); + if ( pValue ) + strcpy( pBuf, pValue ); + else + // auf Solaris und Linux ist P_tmpdir vorgesehen + strcpy( pBuf, P_tmpdir ); + // hart auf "/tmp" sollte wohl nur im Notfall verwendet werden + //strcpy( pBuf, "/tmp" ); +#endif /* MACOSX */ + + return pBuf; +} + +/************************************************************************* +|* +|* DirEntry::GetPathStyle() const +|* +|* Beschreibung +|* Ersterstellung MI 11.05.95 +|* Letzte Aenderung MI 11.05.95 +|* +*************************************************************************/ + +FSysPathStyle DirEntry::GetPathStyle( const String & ) +{ + return FSYS_STYLE_UNX; +} + +/************************************************************************* +|* +|* FileStat::SetDateTime +|* +|* Ersterstellung PB 27.06.97 +|* Letzte Aenderung +|* +*************************************************************************/ + +void FileStat::SetDateTime( const String& rFileName, + const DateTime& rNewDateTime ) +{ + tm times; + + times.tm_year = rNewDateTime.GetYear() - 1900; // 1997 -> 97 + times.tm_mon = rNewDateTime.GetMonth() - 1; // 0 == Januar! + times.tm_mday = rNewDateTime.GetDay(); + + times.tm_hour = rNewDateTime.GetHour(); + times.tm_min = rNewDateTime.GetMin(); + times.tm_sec = rNewDateTime.GetSec(); + + times.tm_wday = 0; + times.tm_yday = 0; +#ifdef SOLARIS + times.tm_isdst = -1; +#else + times.tm_isdst = 0; +#endif + + time_t time = mktime (×); + + if (time != (time_t) -1) + { + struct utimbuf u_time; + u_time.actime = time; + u_time.modtime = time; + utime (ByteString(rFileName, osl_getThreadTextEncoding()).GetBuffer(), &u_time); + } +} + +//========================================================================= + +ErrCode FileStat::QueryDiskSpace( const String &, BigInt &, BigInt & ) +{ + return ERRCODE_IO_NOTSUPPORTED; +} + +//========================================================================= + +void FSysEnableSysErrorBox( BOOL ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/unx.hxx b/tools/source/fsys/unx.hxx new file mode 100644 index 000000000000..0436c9284006 --- /dev/null +++ b/tools/source/fsys/unx.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _unx_hxx +#define _unx_hxx + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <dirent.h> +#include <unistd.h> +/* #include <sysent.h> */ + +#define FSYS_UNIX TRUE +#define DRIVE_EXISTS(c) ( TRUE ) + +#define _mkdir(p) mkdir(p, 0777) +#define _rmdir rmdir +#define _chdir chdir +#define _unlink unlink +#define _getcwd getcwd +#define _access access + +#ifdef SYSV3 +#define DEFSTYLE FSYS_STYLE_SYSV +#else +#define DEFSTYLE FSYS_STYLE_BSD +#endif + +#define CMP_LOWER(s) (s) +#define TEMPNAME() tmpnam(0) +#define LOWER(aString) (aString.Lower()) + +#include <time.h> +#include <tools/datetime.hxx> + +inline Time Unx2Time( time_t nTime ) +{ + tm atm; + tm *pTime; + pTime = localtime_r( &nTime, &atm ); + return Time( pTime->tm_hour, + pTime->tm_min, + pTime->tm_sec ); +} + +inline Date Unx2Date( time_t nDate ) +{ + tm atm; + tm *pTime; + pTime = localtime_r( &nDate, &atm ); + return Date( pTime->tm_mday, + pTime->tm_mon + 1, + pTime->tm_year + 1900 ); +} + +inline void Unx2DateAndTime( time_t nDate, Time& rTime, Date& rDate ) +{ + tm atm; + tm *pTime; + pTime = localtime_r( &nDate, &atm ); + rTime = Time( pTime->tm_hour, pTime->tm_min, pTime->tm_sec ); + rDate = Date( pTime->tm_mday, pTime->tm_mon + 1, pTime->tm_year + 1900 ); +} + +const char* TempDirImpl( char *pBuf ); + +#define FSysFailOnErrorImpl() + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/urlobj.cxx b/tools/source/fsys/urlobj.cxx new file mode 100644 index 000000000000..1f4b67518afe --- /dev/null +++ b/tools/source/fsys/urlobj.cxx @@ -0,0 +1,5575 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" +#include <tools/urlobj.hxx> +#include <tools/debug.hxx> +#include <tools/inetmime.hxx> +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/util/XStringWidth.hpp" +#include "osl/diagnose.h" +#include "osl/file.hxx" +#include "rtl/string.h" +#include "rtl/textenc.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" + +#ifndef INCLUDED_ALGORITHM +#include <algorithm> +#define INCLUDED_ALGORITHM +#endif +#ifndef INCLUDED_LIMITS +#include <limits> +#define INCLUDED_LIMITS +#endif + +#include <string.h> + +namespace unnamed_tools_urlobj {} using namespace unnamed_tools_urlobj; + // unnamed namespaces don't work well yet... + +using namespace com::sun; + +//============================================================================ +// +// INetURLObject +// +//============================================================================ + +/* The URI grammar (using RFC 2234 conventions). + + Constructs of the form + {reference <rule1> using rule2} + stand for a rule matching the given rule1 specified in the given reference, + encoded to URI syntax using rule2 (as specified in this URI grammar). + + + ; RFC 1738, RFC 2396, RFC 2732, private + login = [user [":" password] "@"] hostport + user = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~") + password = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~") + hostport = host [":" port] + host = incomplete-hostname / hostname / IPv4address / IPv6reference + incomplete-hostname = *(domainlabel ".") domainlabel + hostname = *(domainlabel ".") toplabel ["."] + domainlabel = alphanum [*(alphanum / "-") alphanum] + toplabel = ALPHA [*(alphanum / "-") alphanum] + IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT + IPv6reference = "[" hexpart [":" IPv4address] "]" + hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq]) + hexseq = hex4 *(":" hex4) + hex4 = 1*4HEXDIG + port = *DIGIT + escaped = "%" HEXDIG HEXDIG + reserved = "$" / "&" / "+" / "," / "/" / ":" / ";" / "=" / "?" / "@" / "[" / "]" + mark = "!" / "'" / "(" / ")" / "*" / "-" / "." / "_" / "~" + alphanum = ALPHA / DIGIT + unreserved = alphanum / mark + uric = escaped / reserved / unreserved + pchar = escaped / unreserved / "$" / "&" / "+" / "," / ":" / "=" / "@" + + + ; RFC 1738, RFC 2396 + ftp-url = "FTP://" login ["/" segment *("/" segment) [";TYPE=" ("A" / "D" / "I")]] + segment = *pchar + + + ; RFC 1738, RFC 2396 + http-url = "HTTP://" hostport ["/" segment *("/" segment) ["?" *uric]] + segment = *(pchar / ";") + + + ; RFC 1738, RFC 2396, <http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q188997&> + file-url = "FILE://" [host / "LOCALHOST" / netbios-name] ["/" segment *("/" segment)] + segment = *pchar + netbios-name = 1*{<alphanum / "!" / "#" / "$" / "%" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "^" / "_" / "{" / "}" / "~"> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "_" / "~")} + + + ; RFC 2368, RFC 2396 + mailto-url = "MAILTO:" [to] [headers] + to = {RFC 822 <#mailbox> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} + headers = "?" header *("&" header) + header = hname "=" hvalue + hname = {RFC 822 <field-name> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} / "BODY" + hvalue = {RFC 822 <field-body> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} + + + ; private (see RFC 1738, RFC 2396) + vnd-sun-star-webdav-url = "VND.SUN.STAR.WEBDAV://" hostport ["/" segment *("/" segment) ["?" *uric]] + segment = *(pchar / ";") + + + ; RFC 1738, RFC 2396, RFC 2732 + news-url = "NEWS:" grouppart + grouppart = "*" / group / article + group = alpha *(alphanum / "+" / "-" / "." / "_") + article = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "?" / "_" / "~") "@" host + + + ; private + private-url = "PRIVATE:" path ["?" *uric] + path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") + + + ; private + vnd-sun-star-help-url = "VND.SUN.STAR.HELP://" name *("/" segment) ["?" *uric] + name = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") + segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") + + + ; private + https-url = "HTTPS://" hostport ["/" segment *("/" segment) ["?" *uric]] + segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") + + + ; private + slot-url = "SLOT:" path ["?" *uric] + path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") + + + ; private + macro-url = "MACRO:" path ["?" *uric] + path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") + + + ; private + javascript-url = "JAVASCRIPT:" *uric + + + ; private (see RFC 2192) + imap-url = "IMAP://" user [";AUTH=" auth] "@" hostport "/" segment *("/" segment) ["/;UID=" nz_number] + user = 1*{RFC 2060 <CHAR8> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "=" / "_" / "~")} + auth = {RFC 2060 <atom> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "+" / "," / "-" / "." / "=" / "_" / "~")} + segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / "=" / "@" / "_" / "~") + nz_number = {RFC 2060 <nz_number> using *DIGIT} + + + ; private + pop3-url = "POP3://" login ["/" ["<" *uric ">"]] + + + ; RFC 2397 + data-url = "DATA:" [mediatype] [";BASE64"] "," *uric + mediatype = [type "/" subtype] *(";" attribute "=" value) + type = {RFC 2045 <type> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} + subtype = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} + attribute = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} + value = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} + + + ; RFC 2392, RFC 2396 + cid-url = "CID:" {RFC 822 <addr-spec> using *uric} + + + ; private + out-url = "OUT:///~" name ["/" *uric] + name = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "?" / "@" / "_" / "~" + + + ; private + vnd-sun-star-hier-url = "VND.SUN.STAR.HIER:" ["//"reg_name] *("/" *pchar) + reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") + + ; private + vim-url = "VIM://" +vimc [":" *vimc] ["/" [("INBOX" message) / ("NEWSGROUPS" ["/" [+vimc message]])]] + message = ["/" [+vimc [":" +DIGIT "." +DIGIT "." +DIGIT]]] + vimc = ("=" HEXDIG HEXDIG) / alphanum + + + ; private + uno-url = ".UNO:" path ["?" *uric] + path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") + + + ; private + component-url = ".COMPONENT:" path ["?" *uric] + path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") + + + ; private + vnd-sun-star-pkg-url = "VND.SUN.STAR.PKG://" reg_name *("/" *pchar) ["?" *uric] + reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") + + + ; RFC 2255 + ldap-url = "LDAP://" [hostport] ["/" [dn ["?" [attrdesct *("," attrdesc)] ["?" ["base" / "one" / "sub"] ["?" [filter] ["?" extension *("," extension)]]]]]] + dn = {RFC 2253 <distinguishedName> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} + attrdesc = {RFC 2251 <AttributeDescription> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} + filter = {RFC 2254 <filter> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} + extension = ["!"] ["X-"] extoken ["=" exvalue] + extoken = {RFC 2252 <oid> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} + exvalue = {RFC 2251 <LDAPString> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} + + + ; private + db-url = "DB:" *uric + + + ; private + vnd-sun-star-cmd-url = "VND.SUN.STAR.CMD:" opaque_part + opaque_part = uric_no_slash *uric + uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," + + + ; private + vnd-sun-star-url = "VND.SUN.STAR.ODMA:" ["/" *uric_no_slash] + uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," + + + ; RFC 1738 + telnet-url = "TELNET://" login ["/"] + + + ; private + vnd-sun-star-expand-url = "VND.SUN.STAR.EXPAND:" opaque_part + opaque_part = uric_no_slash *uric + uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," + + + ; private + vnd-sun-star-tdoc-url = "VND.SUN.STAR.TDOC:/" segment *("/" segment) + segment = *pchar + + + ; private + unknown-url = scheme ":" 1*uric + scheme = ALPHA *(alphanum / "+" / "-" / ".") + + + ; private (http://ubiqx.org/cifs/Appendix-D.html): + smb-url = "SMB://" login ["/" segment *("/" segment) ["?" *uric]] + segment = *(pchar / ";") + */ + +//============================================================================ +inline sal_Int32 INetURLObject::SubString::clear() +{ + sal_Int32 nDelta = -m_nLength; + m_nBegin = -1; + m_nLength = 0; + return nDelta; +} + +inline sal_Int32 INetURLObject::SubString::set(rtl::OUStringBuffer & rString, + rtl::OUString const & rSubString) +{ + rtl::OUString sTemp(rString.makeStringAndClear()); + sal_Int32 nDelta = set(sTemp, rSubString); + rString.append(sTemp); + return nDelta; +} + +inline sal_Int32 INetURLObject::SubString::set(rtl::OUString & rString, + rtl::OUString const & rSubString) +{ + sal_Int32 nDelta = rSubString.getLength() - m_nLength; + + rString = rString.replaceAt(m_nBegin, m_nLength, rSubString); + + m_nLength = rSubString.getLength(); + return nDelta; +} + +inline sal_Int32 INetURLObject::SubString::set(rtl::OUStringBuffer & rString, + rtl::OUString const & rSubString, + sal_Int32 nTheBegin) +{ + m_nBegin = nTheBegin; + return set(rString, rSubString); +} + +//============================================================================ +inline void INetURLObject::SubString::operator +=(sal_Int32 nDelta) +{ + if (isPresent()) + m_nBegin = m_nBegin + nDelta; +} + +//============================================================================ +int INetURLObject::SubString::compare(SubString const & rOther, + rtl::OUStringBuffer const & rThisString, + rtl::OUStringBuffer const & rOtherString) const +{ + sal_Int32 len = std::min(m_nLength, rOther.m_nLength); + sal_Unicode const * p1 = rThisString.getStr() + m_nBegin; + sal_Unicode const * end = p1 + len; + sal_Unicode const * p2 = rOtherString.getStr() + rOther.m_nBegin; + while (p1 != end) { + if (*p1 < *p2) { + return -1; + } else if (*p1 > *p2) { + return 1; + } + ++p1; + ++p2; + } + return m_nLength < rOther.m_nLength ? -1 + : m_nLength > rOther.m_nLength ? 1 + : 0; +} + +//============================================================================ +struct INetURLObject::SchemeInfo +{ + sal_Char const * m_pScheme; + sal_Char const * m_pPrefix; + sal_uInt16 m_nDefaultPort; + bool m_bAuthority; + bool m_bUser; + bool m_bAuth; + bool m_bPassword; + bool m_bHost; + bool m_bPort; + bool m_bHierarchical; + bool m_bQuery; +}; + +//============================================================================ +struct INetURLObject::PrefixInfo +{ + enum Kind { OFFICIAL, INTERNAL, EXTERNAL, ALIAS }; // order is important! + + sal_Char const * m_pPrefix; + sal_Char const * m_pTranslatedPrefix; + INetProtocol m_eScheme; + Kind m_eKind; +}; + +//============================================================================ +static INetURLObject::SchemeInfo const aSchemeInfoMap[INET_PROT_END] + = { { "", "", 0, false, false, false, false, false, false, false, + false }, + { "ftp", "ftp://", 21, true, true, false, true, true, true, true, + false }, + { "http", "http://", 80, true, false, false, false, true, true, + true, true }, + { "file", "file://", 0, true, false, false, false, true, false, + true, false }, + { "mailto", "mailto:", 0, false, false, false, false, false, + false, false, true }, + { "vnd.sun.star.webdav", "vnd.sun.star.webdav://", 80, true, false, + false, false, true, true, true, true }, + { "news", "news:", 0, false, false, false, false, false, false, false, + false }, + { "private", "private:", 0, false, false, false, false, false, + false, false, true }, + { "vnd.sun.star.help", "vnd.sun.star.help://", 0, true, false, false, + false, false, false, true, true }, + { "https", "https://", 443, true, false, false, false, true, true, + true, true }, + { "slot", "slot:", 0, false, false, false, false, false, false, + false, true }, + { "macro", "macro:", 0, false, false, false, false, false, false, + false, true }, + { "javascript", "javascript:", 0, false, false, false, false, + false, false, false, false }, + { "imap", "imap://", 143, true, true, true, false, true, true, + true, false }, + { "pop3", "pop3://", 110, true, true, false, true, true, true, + false, false }, + { "data", "data:", 0, false, false, false, false, false, false, + false, false }, + { "cid", "cid:", 0, false, false, false, false, false, false, + false, false }, + { "out", "out://", 0, true, false, false, false, false, false, + false, false }, + { "vnd.sun.star.hier", "vnd.sun.star.hier:", 0, true, false, false, + false, false, false, true, false }, + { "vim", "vim://", 0, true, true, false, true, false, false, true, + false }, + { ".uno", ".uno:", 0, false, false, false, false, false, false, + false, true }, + { ".component", ".component:", 0, false, false, false, false, + false, false, false, true }, + { "vnd.sun.star.pkg", "vnd.sun.star.pkg://", 0, true, false, false, + false, false, false, true, true }, + { "ldap", "ldap://", 389, true, false, false, false, true, true, + false, true }, + { "db", "db:", 0, false, false, false, false, false, false, false, + false }, + { "vnd.sun.star.cmd", "vnd.sun.star.cmd:", 0, false, false, false, + false, false, false, false, false }, + { "vnd.sun.star.odma", "vnd.sun.star.odma:", 0, false, false, false, + false, false, false, true, false }, + { "telnet", "telnet://", 23, true, true, false, true, true, true, true, + false }, + { "vnd.sun.star.expand", "vnd.sun.star.expand:", 0, false, false, false, + false, false, false, false, false }, + { "vnd.sun.star.tdoc", "vnd.sun.star.tdoc:", 0, false, false, false, + false, false, false, true, false }, + { "", "", 0, false, false, false, false, true, true, true, false }, + { "smb", "smb://", 139, true, true, false, true, true, true, true, + true } }; + +// static +inline INetURLObject::SchemeInfo const & +INetURLObject::getSchemeInfo(INetProtocol eTheScheme) +{ + return aSchemeInfoMap[eTheScheme]; +}; + +//============================================================================ +inline INetURLObject::SchemeInfo const & INetURLObject::getSchemeInfo() const +{ + return getSchemeInfo(m_eScheme); +} + +//============================================================================ +// static +inline void INetURLObject::appendEscape(rtl::OUStringBuffer & rTheText, + sal_Char cEscapePrefix, + sal_uInt32 nOctet) +{ + rTheText.append(sal_Unicode(cEscapePrefix)); + rTheText.append(sal_Unicode(INetMIME::getHexDigit(int(nOctet >> 4)))); + rTheText.append(sal_Unicode(INetMIME::getHexDigit(int(nOctet & 15)))); +} + +//============================================================================ +namespace unnamed_tools_urlobj { + +enum +{ + PA = INetURLObject::PART_OBSOLETE_NORMAL, + PB = INetURLObject::PART_OBSOLETE_FILE, + PC = INetURLObject::PART_OBSOLETE_PARAM, + PD = INetURLObject::PART_USER_PASSWORD, + PE = INetURLObject::PART_IMAP_ACHAR, + PF = INetURLObject::PART_VIM, + PG = INetURLObject::PART_HOST_EXTRA, + PH = INetURLObject::PART_FPATH, + PI = INetURLObject::PART_AUTHORITY, + PJ = INetURLObject::PART_PATH_SEGMENTS_EXTRA, + PK = INetURLObject::PART_REL_SEGMENT_EXTRA, + PL = INetURLObject::PART_URIC, + PM = INetURLObject::PART_HTTP_PATH, + PN = INetURLObject::PART_FILE_SEGMENT_EXTRA, + PO = INetURLObject::PART_MESSAGE_ID, + PP = INetURLObject::PART_MESSAGE_ID_PATH, + PQ = INetURLObject::PART_MAILTO, + PR = INetURLObject::PART_PATH_BEFORE_QUERY, + PS = INetURLObject::PART_PCHAR, + PT = INetURLObject::PART_FRAGMENT, + PU = INetURLObject::PART_VISIBLE, + PV = INetURLObject::PART_VISIBLE_NONSPECIAL, + PW = INetURLObject::PART_CREATEFRAGMENT, + PX = INetURLObject::PART_UNO_PARAM_VALUE, + PY = INetURLObject::PART_UNAMBIGUOUS, + PZ = INetURLObject::PART_URIC_NO_SLASH, + P1 = INetURLObject::PART_HTTP_QUERY, + P2 = INetURLObject::PART_NEWS_ARTICLE_LOCALPART +}; + +static sal_uInt32 const aMustEncodeMap[128] + = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* */ PY, +/* ! */ PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* " */ PU+PV +PY, +/* # */ PU, +/* $ */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* % */ PU, +/* & */ PA+PB+PC+PD+PE +PH+PI+PJ+PK+PL+PM+PN+PO+PP +PR+PS+PT+PU+PV+PW+PX +PZ+P1+P2, +/* ' */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* ( */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* ) */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* * */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* + */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX +PZ+P1+P2, +/* , */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW +PZ+P1+P2, +/* - */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* . */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* / */ PA+PB+PC +PH +PJ +PL+PM +PP+PQ+PR +PT+PU+PV +PX +P2, +/* 0 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 1 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 2 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 3 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 4 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 5 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 6 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 7 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 8 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* 9 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* : */ PB+PC +PH+PI+PJ +PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX +PZ+P1+P2, +/* ; */ PC+PD +PI+PJ+PK+PL+PM +PO+PP+PQ+PR +PT+PU +PW +PZ+P1+P2, +/* < */ PC +PO+PP +PU+PV +PY, +/* = */ PA+PB+PC+PD+PE +PH+PI+PJ+PK+PL+PM+PN +PR+PS+PT+PU+PV+PW +PZ+P1+P2, +/* > */ PC +PO+PP +PU+PV +PY, +/* ? */ PC +PL +PT+PU +PW+PX +PZ +P2, +/* @ */ PC +PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1, +/* A */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* B */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* C */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* D */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* E */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* F */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* G */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* H */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* I */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* J */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* K */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* L */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* M */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* N */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* O */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* P */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* Q */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* R */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* S */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* T */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* U */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* V */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* W */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* X */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* Y */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* Z */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* [ */ PL +PU+PV +PX, +/* \ */ PB +PU+PV +PY, +/* ] */ PL +PU+PV +PX, +/* ^ */ PU+PV +PY, +/* _ */ PA+PB+PC+PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* ` */ PU+PV +PY, +/* a */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* b */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* c */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* d */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* e */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* f */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* g */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* h */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* i */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* j */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* k */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* l */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* m */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* n */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* o */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* p */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* q */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* r */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* s */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* t */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* u */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* v */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* w */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* x */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* y */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* z */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, +/* { */ PU+PV +PY, +/* | */ PB+PC +PN +PT+PU+PV +PY, +/* } */ PU+PV +PY, +/* ~ */ PA+PB+PC+PD+PE +PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ +P2, + 0 }; + +inline bool mustEncode(sal_uInt32 nUTF32, INetURLObject::Part ePart) +{ + return !INetMIME::isUSASCII(nUTF32) || !(aMustEncodeMap[nUTF32] & ePart); +} + +} + +//============================================================================ +void INetURLObject::setInvalid() +{ + m_aAbsURIRef.setLength(0); + m_eScheme = INET_PROT_NOT_VALID; + m_aScheme.clear(); + m_aUser.clear(); + m_aAuth.clear(); + m_aHost.clear(); + m_aPort.clear(); + m_aPath.clear(); + m_aQuery.clear(); + m_aFragment.clear(); +} + +//============================================================================ + +namespace unnamed_tools_urlobj { + +INetURLObject::FSysStyle +guessFSysStyleByCounting(sal_Unicode const * pBegin, + sal_Unicode const * pEnd, + INetURLObject::FSysStyle eStyle) +{ + DBG_ASSERT(eStyle + & (INetURLObject::FSYS_UNX + | INetURLObject::FSYS_DOS + | INetURLObject::FSYS_MAC), + "guessFSysStyleByCounting(): Bad style"); + DBG_ASSERT(std::numeric_limits< sal_Int32 >::min() < pBegin - pEnd + && pEnd - pBegin <= std::numeric_limits< sal_Int32 >::max(), + "guessFSysStyleByCounting(): Too big"); + sal_Int32 nSlashCount + = eStyle & INetURLObject::FSYS_UNX ? + 0 : std::numeric_limits< sal_Int32 >::min(); + sal_Int32 nBackslashCount + = eStyle & INetURLObject::FSYS_DOS ? + 0 : std::numeric_limits< sal_Int32 >::min(); + sal_Int32 nColonCount + = eStyle & INetURLObject::FSYS_MAC ? + 0 : std::numeric_limits< sal_Int32 >::min(); + while (pBegin != pEnd) + switch (*pBegin++) + { + case '/': + ++nSlashCount; + break; + + case '\\': + ++nBackslashCount; + break; + + case ':': + ++nColonCount; + break; + } + return nSlashCount >= nBackslashCount ? + nSlashCount >= nColonCount ? + INetURLObject::FSYS_UNX : INetURLObject::FSYS_MAC : + nBackslashCount >= nColonCount ? + INetURLObject::FSYS_DOS : INetURLObject::FSYS_MAC; +} + +rtl::OUString parseScheme( + sal_Unicode const ** begin, sal_Unicode const * end, + sal_uInt32 fragmentDelimiter) +{ + sal_Unicode const * p = *begin; + if (p != end && INetMIME::isAlpha(*p)) { + do { + ++p; + } while (p != end + && (INetMIME::isAlphanumeric(*p) || *p == '+' || *p == '-' + || *p == '.')); + // #i34835# To avoid problems with Windows file paths like "C:\foo", + // do not accept generic schemes that are only one character long: + if (end - p > 1 && p[0] == ':' && p[1] != fragmentDelimiter + && p - *begin >= 2) + { + rtl::OUString scheme( + rtl::OUString(*begin, p - *begin).toAsciiLowerCase()); + *begin = p + 1; + return scheme; + } + } + return rtl::OUString(); +} + +} + +bool INetURLObject::setAbsURIRef(rtl::OUString const & rTheAbsURIRef, + bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, + bool bSmart, + FSysStyle eStyle) +{ + sal_Unicode const * pPos = rTheAbsURIRef.getStr(); + sal_Unicode const * pEnd = pPos + rTheAbsURIRef.getLength(); + + setInvalid(); + + sal_uInt32 nFragmentDelimiter = '#'; + + rtl::OUStringBuffer aSynAbsURIRef; + + // Parse <scheme>: + sal_Unicode const * p = pPos; + PrefixInfo const * pPrefix = getPrefix(p, pEnd); + if (pPrefix) + { + pPos = p; + m_eScheme = pPrefix->m_eScheme; + + rtl::OUString sTemp(rtl::OUString::createFromAscii(pPrefix->m_eKind + >= PrefixInfo::EXTERNAL ? + pPrefix->m_pTranslatedPrefix : + pPrefix->m_pPrefix)); + aSynAbsURIRef.append(sTemp); + m_aScheme = SubString( 0, sTemp.indexOf(static_cast< sal_Unicode >(':')) ); + } + else + { + if (bSmart) + { + // For scheme detection, the first (if any) of the following + // productions that matches the input string (and for which the + // appropriate style bit is set in eStyle, if applicable) + // determines the scheme. The productions use the auxiliary rules + // + // domain = label *("." label) + // label = alphanum [*(alphanum / "-") alphanum] + // alphanum = ALPHA / DIGIT + // IPv6reference = "[" IPv6address "]" + // IPv6address = hexpart [":" IPv4address] + // IPv4address = 1*3DIGIT 3("." 1*3DIGIT) + // hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq]) + // hexseq = hex4 *(":" hex4) + // hex4 = 1*4HEXDIG + // UCS4 = <any UCS4 character> + // + // 1st Production (known scheme): + // <one of the known schemes, ignoring case> ":" *UCS4 + // + // 2nd Production (mailto): + // domain "@" domain + // + // 3rd Production (ftp): + // "FTP" 2*("." label) ["/" *UCS4] + // + // 4th Production (http): + // label 2*("." label) ["/" *UCS4] + // + // 5th Production (file): + // "//" (domain / IPv6reference) ["/" *UCS4] + // + // 6th Production (Unix file): + // "/" *UCS4 + // + // 7th Production (UNC file; FSYS_DOS only): + // "\\" domain ["\" *UCS4] + // + // 8th Production (Unix-like DOS file; FSYS_DOS only): + // ALPHA ":" ["/" *UCS4] + // + // 9th Production (DOS file; FSYS_DOS only): + // ALPHA ":" ["\" *UCS4] + // + // For the 'non URL' file productions 6--9, the interpretation of + // the input as a (degenerate) URI is turned off, i.e., escape + // sequences and fragments are never detected as such, but are + // taken as literal characters. + + sal_Unicode const * p1 = pPos; + if (eStyle & FSYS_DOS + && pEnd - p1 >= 2 + && INetMIME::isAlpha(p1[0]) + && p1[1] == ':' + && (pEnd - p1 == 2 || p1[2] == '/' || p1[2] == '\\')) + { + m_eScheme = INET_PROT_FILE; // 8th, 9th + eMechanism = ENCODE_ALL; + nFragmentDelimiter = 0x80000000; + } + else if (pEnd - p1 >= 2 && p1[0] == '/' && p1[1] == '/') + { + p1 += 2; + if ((scanDomain(p1, pEnd) > 0 || scanIPv6reference(p1, pEnd)) + && (p1 == pEnd || *p1 == '/')) + m_eScheme = INET_PROT_FILE; // 5th + } + else if (p1 != pEnd && *p1 == '/') + { + m_eScheme = INET_PROT_FILE; // 6th + eMechanism = ENCODE_ALL; + nFragmentDelimiter = 0x80000000; + } + else if (eStyle & FSYS_DOS + && pEnd - p1 >= 2 + && p1[0] == '\\' + && p1[1] == '\\') + { + p1 += 2; + sal_Int32 n = rtl_ustr_indexOfChar_WithLength( + p1, pEnd - p1, '\\'); + sal_Unicode const * pe = n == -1 ? pEnd : p1 + n; + if ( + parseHostOrNetBiosName( + p1, pe, bOctets, ENCODE_ALL, RTL_TEXTENCODING_DONTKNOW, + true, NULL) || + (scanDomain(p1, pe) > 0 && p1 == pe) + ) + { + m_eScheme = INET_PROT_FILE; // 7th + eMechanism = ENCODE_ALL; + nFragmentDelimiter = 0x80000000; + } + } + else + { + sal_Unicode const * pDomainEnd = p1; + sal_uInt32 nLabels = scanDomain(pDomainEnd, pEnd); + if (nLabels > 0 && pDomainEnd != pEnd && *pDomainEnd == '@') + { + ++pDomainEnd; + if (scanDomain(pDomainEnd, pEnd) > 0 + && pDomainEnd == pEnd) + m_eScheme = INET_PROT_MAILTO; // 2nd + } + else if (nLabels >= 3 + && (pDomainEnd == pEnd || *pDomainEnd == '/')) + m_eScheme + = pDomainEnd - p1 >= 4 + && (p1[0] == 'f' || p1[0] == 'F') + && (p1[1] == 't' || p1[1] == 'T') + && (p1[2] == 'p' || p1[2] == 'P') + && p1[3] == '.' ? + INET_PROT_FTP : INET_PROT_HTTP; // 3rd, 4th + } + } + + rtl::OUString aSynScheme; + if (m_eScheme == INET_PROT_NOT_VALID) { + sal_Unicode const * p1 = pPos; + aSynScheme = parseScheme(&p1, pEnd, nFragmentDelimiter); + if (aSynScheme.getLength() > 0) + { + m_eScheme = INET_PROT_GENERIC; + pPos = p1; + } + } + + if (bSmart && m_eScheme == INET_PROT_NOT_VALID && pPos != pEnd + && *pPos != nFragmentDelimiter) + { + m_eScheme = m_eSmartScheme; + } + + if (m_eScheme == INET_PROT_NOT_VALID) + { + setInvalid(); + return false; + } + + if (m_eScheme != INET_PROT_GENERIC) { + aSynScheme = rtl::OUString::createFromAscii(getSchemeInfo().m_pScheme); + } + m_aScheme.set(aSynAbsURIRef, aSynScheme, aSynAbsURIRef.getLength()); + aSynAbsURIRef.append(sal_Unicode(':')); + } + + sal_Char cEscapePrefix = getEscapePrefix(); + sal_uInt32 nSegmentDelimiter = '/'; + sal_uInt32 nAltSegmentDelimiter = 0x80000000; + bool bSkippedInitialSlash = false; + + // Parse //<user>;AUTH=<auth>@<host>:<port> or + // //<user>:<password>@<host>:<port> or + // //<reg_name> + if (getSchemeInfo().m_bAuthority) + { + sal_Unicode const * pUserInfoBegin = 0; + sal_Unicode const * pUserInfoEnd = 0; + sal_Unicode const * pHostPortBegin = 0; + sal_Unicode const * pHostPortEnd = 0; + + switch (m_eScheme) + { + case INET_PROT_VND_SUN_STAR_HELP: + { + if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/') + { + setInvalid(); + return false; + } + aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + rtl::OUStringBuffer aSynAuthority; + while (pPos < pEnd + && *pPos != '/' && *pPos != '?' + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aSynAuthority, nUTF32, eEscapeType, bOctets, + PART_AUTHORITY, cEscapePrefix, eCharset, + false); + } + m_aHost.set(aSynAbsURIRef, + aSynAuthority.makeStringAndClear(), + aSynAbsURIRef.getLength()); + // misusing m_aHost to store the authority + break; + } + + case INET_PROT_VND_SUN_STAR_HIER: + { + if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') + { + pPos += 2; + aSynAbsURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + rtl::OUStringBuffer aSynAuthority; + while (pPos < pEnd + && *pPos != '/' && *pPos != '?' + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, + pEnd, + bOctets, + cEscapePrefix, + eMechanism, + eCharset, + eEscapeType); + appendUCS4(aSynAuthority, + nUTF32, + eEscapeType, + bOctets, + PART_AUTHORITY, + cEscapePrefix, + eCharset, + false); + } + if (aSynAuthority.getLength() == 0) + { + setInvalid(); + return false; + } + m_aHost.set(aSynAbsURIRef, + aSynAuthority.makeStringAndClear(), + aSynAbsURIRef.getLength()); + // misusing m_aHost to store the authority + } + break; + } + + case INET_PROT_VND_SUN_STAR_PKG: + { + if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/') + { + setInvalid(); + return false; + } + aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + rtl::OUStringBuffer aSynAuthority; + while (pPos < pEnd + && *pPos != '/' && *pPos != '?' + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aSynAuthority, nUTF32, eEscapeType, bOctets, + PART_AUTHORITY, cEscapePrefix, eCharset, + false); + } + if (aSynAuthority.getLength() == 0) + { + setInvalid(); + return false; + } + m_aHost.set(aSynAbsURIRef, + aSynAuthority.makeStringAndClear(), + aSynAbsURIRef.getLength()); + // misusing m_aHost to store the authority + break; + } + + case INET_PROT_FILE: + if (bSmart) + { + // The first of the following seven productions that + // matches the rest of the input string (and for which the + // appropriate style bit is set in eStyle, if applicable) + // determines the used notation. The productions use the + // auxiliary rules + // + // domain = label *("." label) + // label = alphanum [*(alphanum / "-") alphanum] + // alphanum = ALPHA / DIGIT + // IPv6reference = "[" IPv6address "]" + // IPv6address = hexpart [":" IPv4address] + // IPv4address = 1*3DIGIT 3("." 1*3DIGIT) + // hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq]) + // hexseq = hex4 *(":" hex4) + // hex4 = 1*4HEXDIG + // path = <any UCS4 character except "#"> + // UCS4 = <any UCS4 character> + + // 1st Production (URL): + // "//" [domain / IPv6reference] ["/" *path] + // ["#" *UCS4] + // becomes + // "file://" domain "/" *path ["#" *UCS4] + if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') + { + sal_Unicode const * p1 = pPos + 2; + while (p1 != pEnd && *p1 != '/' && + *p1 != nFragmentDelimiter) + { + ++p1; + } + if (parseHostOrNetBiosName( + pPos + 2, p1, bOctets, ENCODE_ALL, + RTL_TEXTENCODING_DONTKNOW, true, NULL)) + { + aSynAbsURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + pHostPortBegin = pPos + 2; + pHostPortEnd = p1; + pPos = p1; + break; + } + } + + // 2nd Production (MS IE generated 1; FSYS_DOS only): + // "//" ALPHA ":" ["/" *path] ["#" *UCS4] + // becomes + // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] + // replacing "\" by "/" within <*path> + // + // 3rd Production (MS IE generated 2; FSYS_DOS only): + // "//" ALPHA ":" ["\" *path] ["#" *UCS4] + // becomes + // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] + // replacing "\" by "/" within <*path> + // + // 4th Production (misscounted slashes): + // "//" *path ["#" *UCS4] + // becomes + // "file:///" *path ["#" *UCS4] + if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') + { + aSynAbsURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + pPos += 2; + bSkippedInitialSlash = true; + if ((eStyle & FSYS_DOS) != 0 + && pEnd - pPos >= 2 + && INetMIME::isAlpha(pPos[0]) + && pPos[1] == ':' + && (pEnd - pPos == 2 + || pPos[2] == '/' || pPos[2] == '\\')) + nAltSegmentDelimiter = '\\'; + break; + } + + // 5th Production (Unix): + // "/" *path ["#" *UCS4] + // becomes + // "file:///" *path ["#" *UCS4] + if (pPos < pEnd && *pPos == '/') + { + aSynAbsURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + break; + } + + // 6th Production (UNC; FSYS_DOS only): + // "\\" domain ["\" *path] ["#" *UCS4] + // becomes + // "file://" domain "/" *path ["#" *UCS4] + // replacing "\" by "/" within <*path> + if (eStyle & FSYS_DOS + && pEnd - pPos >= 2 + && pPos[0] == '\\' + && pPos[1] == '\\') + { + sal_Unicode const * p1 = pPos + 2; + sal_Unicode const * pe = p1; + while (pe < pEnd && *pe != '\\' && + *pe != nFragmentDelimiter) + { + ++pe; + } + if ( + parseHostOrNetBiosName( + p1, pe, bOctets, ENCODE_ALL, + RTL_TEXTENCODING_DONTKNOW, true, NULL) || + (scanDomain(p1, pe) > 0 && p1 == pe) + ) + { + aSynAbsURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + pHostPortBegin = pPos + 2; + pHostPortEnd = pe; + pPos = pe; + nSegmentDelimiter = '\\'; + break; + } + } + + // 7th Production (Unix-like DOS; FSYS_DOS only): + // ALPHA ":" ["/" *path] ["#" *UCS4] + // becomes + // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] + // replacing "\" by "/" within <*path> + // + // 8th Production (DOS; FSYS_DOS only): + // ALPHA ":" ["\" *path] ["#" *UCS4] + // becomes + // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] + // replacing "\" by "/" within <*path> + if (eStyle & FSYS_DOS + && pEnd - pPos >= 2 + && INetMIME::isAlpha(pPos[0]) + && pPos[1] == ':' + && (pEnd - pPos == 2 + || pPos[2] == '/' + || pPos[2] == '\\')) + { + aSynAbsURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + nAltSegmentDelimiter = '\\'; + bSkippedInitialSlash = true; + break; + } + + // 9th Production (any): + // *path ["#" *UCS4] + // becomes + // "file:///" *path ["#" *UCS4] + // replacing the delimiter by "/" within <*path>. The + // delimiter is that character from the set { "/", "\", + // ":" } which appears most often in <*path> (if FSYS_UNX + // is not among the style bits, "/" is removed from the + // set; if FSYS_DOS is not among the style bits, "\" is + // removed from the set; if FSYS_MAC is not among the + // style bits, ":" is removed from the set). If two or + // more characters appear the same number of times, the + // character mentioned first in that set is chosen. If + // the first character of <*path> is the delimiter, that + // character is not copied. + if (eStyle & (FSYS_UNX | FSYS_DOS | FSYS_MAC)) + { + aSynAbsURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + switch (guessFSysStyleByCounting(pPos, pEnd, eStyle)) + { + case FSYS_UNX: + nSegmentDelimiter = '/'; + break; + + case FSYS_DOS: + nSegmentDelimiter = '\\'; + break; + + case FSYS_MAC: + nSegmentDelimiter = ':'; + break; + + default: + DBG_ERROR( + "INetURLObject::setAbsURIRef():" + " Bad guessFSysStyleByCounting"); + break; + } + bSkippedInitialSlash + = pPos != pEnd && *pPos != nSegmentDelimiter; + break; + } + } + default: + { + // For INET_PROT_FILE, allow an empty authority ("//") to be + // missing if the following path starts with an explicit "/" + // (Java is notorious in generating such file URLs, so be + // liberal here): + if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') + pPos += 2; + else if (!bSmart + && !(m_eScheme == INET_PROT_FILE + && pPos != pEnd && *pPos == '/')) + { + setInvalid(); + return false; + } + aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + + sal_Unicode const * pAuthority = pPos; + sal_uInt32 c = getSchemeInfo().m_bQuery ? '?' : 0x80000000; + while (pPos < pEnd && *pPos != '/' && *pPos != c + && *pPos != nFragmentDelimiter) + ++pPos; + if (getSchemeInfo().m_bUser) + if (getSchemeInfo().m_bHost) + { + sal_Unicode const * p1 = pAuthority; + while (p1 < pPos && *p1 != '@') + ++p1; + if (p1 == pPos) + { + pHostPortBegin = pAuthority; + pHostPortEnd = pPos; + } + else + { + pUserInfoBegin = pAuthority; + pUserInfoEnd = p1; + pHostPortBegin = p1 + 1; + pHostPortEnd = pPos; + } + } + else + { + pUserInfoBegin = pAuthority; + pUserInfoEnd = pPos; + } + else if (getSchemeInfo().m_bHost) + { + pHostPortBegin = pAuthority; + pHostPortEnd = pPos; + } + else if (pPos != pAuthority) + { + setInvalid(); + return false; + } + break; + } + } + + if (pUserInfoBegin) + { + Part ePart = m_eScheme == INET_PROT_IMAP ? + PART_IMAP_ACHAR : + m_eScheme == INET_PROT_VIM ? + PART_VIM : + PART_USER_PASSWORD; + bool bSupportsPassword = getSchemeInfo().m_bPassword; + bool bSupportsAuth + = !bSupportsPassword && getSchemeInfo().m_bAuth; + bool bHasAuth = false; + rtl::OUStringBuffer aSynUser; + sal_Unicode const * p1 = pUserInfoBegin; + while (p1 < pUserInfoEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets, + cEscapePrefix, eMechanism, + eCharset, eEscapeType); + if (eEscapeType == ESCAPE_NO) + { + if (nUTF32 == ':' && bSupportsPassword) + { + bHasAuth = true; + break; + } + else if (nUTF32 == ';' && bSupportsAuth + && pUserInfoEnd - p1 + > RTL_CONSTASCII_LENGTH("auth=") + && INetMIME::equalIgnoreCase( + p1, + p1 + RTL_CONSTASCII_LENGTH("auth="), + "auth=")) + { + p1 += RTL_CONSTASCII_LENGTH("auth="); + bHasAuth = true; + break; + } + } + appendUCS4(aSynUser, nUTF32, eEscapeType, bOctets, ePart, + cEscapePrefix, eCharset, false); + } + m_aUser.set(aSynAbsURIRef, aSynUser.makeStringAndClear(), + aSynAbsURIRef.getLength()); + if (bHasAuth) + { + if (bSupportsPassword) + { + aSynAbsURIRef.append(sal_Unicode(':')); + rtl::OUStringBuffer aSynAuth; + while (p1 < pUserInfoEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets, + cEscapePrefix, + eMechanism, eCharset, + eEscapeType); + appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets, + ePart, cEscapePrefix, eCharset, false); + } + m_aAuth.set(aSynAbsURIRef, aSynAuth.makeStringAndClear(), + aSynAbsURIRef.getLength()); + } + else + { + aSynAbsURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM(";AUTH=")); + rtl::OUStringBuffer aSynAuth; + while (p1 < pUserInfoEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets, + cEscapePrefix, + eMechanism, eCharset, + eEscapeType); + if (!INetMIME::isIMAPAtomChar(nUTF32)) + { + setInvalid(); + return false; + } + appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets, + ePart, cEscapePrefix, eCharset, false); + } + m_aAuth.set(aSynAbsURIRef, aSynAuth.makeStringAndClear(), + aSynAbsURIRef.getLength()); + } + } + if (pHostPortBegin) + aSynAbsURIRef.append(sal_Unicode('@')); + } + + if (pHostPortBegin) + { + sal_Unicode const * pPort = pHostPortEnd; + if ( getSchemeInfo().m_bPort && pHostPortBegin < pHostPortEnd ) + { + sal_Unicode const * p1 = pHostPortEnd - 1; + while (p1 > pHostPortBegin && INetMIME::isDigit(*p1)) + --p1; + if (*p1 == ':') + pPort = p1; + } + bool bNetBiosName = false; + switch (m_eScheme) + { + case INET_PROT_FILE: + // If the host equals "LOCALHOST" (unencoded and ignoring + // case), turn it into an empty host: + if (INetMIME::equalIgnoreCase(pHostPortBegin, pPort, + "localhost")) + pHostPortBegin = pPort; + bNetBiosName = true; + break; + + case INET_PROT_LDAP: + case INET_PROT_SMB: + if (pHostPortBegin == pPort && pPort != pHostPortEnd) + { + setInvalid(); + return false; + } + break; + default: + if (pHostPortBegin == pPort) + { + setInvalid(); + return false; + } + break; + } + rtl::OUStringBuffer aSynHost; + if (!parseHostOrNetBiosName( + pHostPortBegin, pPort, bOctets, eMechanism, eCharset, + bNetBiosName, &aSynHost)) + { + setInvalid(); + return false; + } + m_aHost.set(aSynAbsURIRef, aSynHost.makeStringAndClear(), + aSynAbsURIRef.getLength()); + if (pPort != pHostPortEnd) + { + aSynAbsURIRef.append(sal_Unicode(':')); + m_aPort.set(aSynAbsURIRef, + rtl::OUString(pPort + 1, pHostPortEnd - (pPort + 1)), + aSynAbsURIRef.getLength()); + } + } + } + + // Parse <path> + rtl::OUStringBuffer aSynPath; + if (!parsePath(m_eScheme, &pPos, pEnd, bOctets, eMechanism, eCharset, + bSkippedInitialSlash, nSegmentDelimiter, + nAltSegmentDelimiter, + getSchemeInfo().m_bQuery ? '?' : 0x80000000, + nFragmentDelimiter, aSynPath)) + { + setInvalid(); + return false; + } + m_aPath.set(aSynAbsURIRef, aSynPath.makeStringAndClear(), + aSynAbsURIRef.getLength()); + + // Parse ?<query> + if (getSchemeInfo().m_bQuery && pPos < pEnd && *pPos == '?') + { + aSynAbsURIRef.append(sal_Unicode('?')); + rtl::OUStringBuffer aSynQuery; + for (++pPos; pPos < pEnd && *pPos != nFragmentDelimiter;) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, cEscapePrefix, + eMechanism, eCharset, eEscapeType); + appendUCS4(aSynQuery, nUTF32, eEscapeType, bOctets, + PART_URIC, cEscapePrefix, eCharset, true); + } + m_aQuery.set(aSynAbsURIRef, aSynQuery.makeStringAndClear(), + aSynAbsURIRef.getLength()); + } + + // Parse #<fragment> + if (pPos < pEnd && *pPos == nFragmentDelimiter) + { + aSynAbsURIRef.append(sal_Unicode(nFragmentDelimiter)); + rtl::OUStringBuffer aSynFragment; + for (++pPos; pPos < pEnd;) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, cEscapePrefix, + eMechanism, eCharset, eEscapeType); + appendUCS4(aSynFragment, nUTF32, eEscapeType, bOctets, PART_URIC, + cEscapePrefix, eCharset, true); + } + m_aFragment.set(aSynAbsURIRef, aSynFragment.makeStringAndClear(), + aSynAbsURIRef.getLength()); + } + + if (pPos != pEnd) + { + setInvalid(); + return false; + } + + m_aAbsURIRef = aSynAbsURIRef; + + return true; +} + +//============================================================================ +bool INetURLObject::convertRelToAbs(rtl::OUString const & rTheRelURIRef, + bool bOctets, + INetURLObject & rTheAbsURIRef, + bool & rWasAbsolute, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, + bool bIgnoreFragment, bool bSmart, + bool bRelativeNonURIs, FSysStyle eStyle) + const +{ + sal_Unicode const * p = rTheRelURIRef.getStr(); + sal_Unicode const * pEnd = p + rTheRelURIRef.getLength(); + + sal_Unicode const * pPrefixBegin = p; + PrefixInfo const * pPrefix = getPrefix(pPrefixBegin, pEnd); + bool hasScheme = pPrefix != 0; + if (!hasScheme) { + pPrefixBegin = p; + hasScheme = parseScheme(&pPrefixBegin, pEnd, '#').getLength() > 0; + } + + sal_uInt32 nSegmentDelimiter = '/'; + sal_uInt32 nQueryDelimiter + = !bSmart || getSchemeInfo().m_bQuery ? '?' : 0x80000000; + sal_uInt32 nFragmentDelimiter = '#'; + Part ePart = PART_VISIBLE; + + if (!hasScheme && bSmart) + { + // If the input matches any of the following productions (for which + // the appropriate style bit is set in eStyle), it is assumed to be an + // absolute file system path, rather than a relative URI reference. + // (This is only a subset of the productions used for scheme detection + // in INetURLObject::setAbsURIRef(), because most of those productions + // interfere with the syntax of relative URI references.) The + // productions use the auxiliary rules + // + // domain = label *("." label) + // label = alphanum [*(alphanum / "-") alphanum] + // alphanum = ALPHA / DIGIT + // UCS4 = <any UCS4 character> + // + // 1st Production (UNC file; FSYS_DOS only): + // "\\" domain ["\" *UCS4] + // + // 2nd Production (Unix-like DOS file; FSYS_DOS only): + // ALPHA ":" ["/" *UCS4] + // + // 3rd Production (DOS file; FSYS_DOS only): + // ALPHA ":" ["\" *UCS4] + if (eStyle & FSYS_DOS) + { + bool bFSys = false; + sal_Unicode const * q = p; + if (pEnd - q >= 2 + && INetMIME::isAlpha(q[0]) + && q[1] == ':' + && (pEnd - q == 2 || q[2] == '/' || q[2] == '\\')) + bFSys = true; // 2nd, 3rd + else if (pEnd - q >= 2 && q[0] == '\\' && q[1] == '\\') + { + q += 2; + sal_Int32 n = rtl_ustr_indexOfChar_WithLength( + q, pEnd - q, '\\'); + sal_Unicode const * qe = n == -1 ? pEnd : q + n; + if (parseHostOrNetBiosName( + q, qe, bOctets, ENCODE_ALL, RTL_TEXTENCODING_DONTKNOW, + true, NULL)) + { + bFSys = true; // 1st + } + } + if (bFSys) + { + INetURLObject aNewURI; + aNewURI.setAbsURIRef(rTheRelURIRef, bOctets, eMechanism, + eCharset, true, eStyle); + if (!aNewURI.HasError()) + { + rTheAbsURIRef = aNewURI; + rWasAbsolute = true; + return true; + } + } + } + + // When the base URL is a file URL, accept relative file system paths + // using "\" or ":" as delimiter (and ignoring URI conventions for "%" + // and "#"), as well as relative URIs using "/" as delimiter: + if (m_eScheme == INET_PROT_FILE) + switch (guessFSysStyleByCounting(p, pEnd, eStyle)) + { + case FSYS_UNX: + nSegmentDelimiter = '/'; + break; + + case FSYS_DOS: + nSegmentDelimiter = '\\'; + bRelativeNonURIs = true; + break; + + case FSYS_MAC: + nSegmentDelimiter = ':'; + bRelativeNonURIs = true; + break; + + default: + DBG_ERROR("INetURLObject::convertRelToAbs():" + " Bad guessFSysStyleByCounting"); + break; + } + + if (bRelativeNonURIs) + { + eMechanism = ENCODE_ALL; + nQueryDelimiter = 0x80000000; + nFragmentDelimiter = 0x80000000; + ePart = PART_VISIBLE_NONSPECIAL; + } + } + + // If the relative URI has the same scheme as the base URI, and that + // scheme is hierarchical, then ignore its presence in the relative + // URI in order to be backward compatible (cf. RFC 2396 section 5.2 + // step 3): + if (pPrefix && pPrefix->m_eScheme == m_eScheme + && getSchemeInfo().m_bHierarchical) + { + hasScheme = false; + while (p != pEnd && *p++ != ':') ; + } + rWasAbsolute = hasScheme; + + // Fast solution for non-relative URIs: + if (hasScheme) + { + INetURLObject aNewURI(rTheRelURIRef, eMechanism, eCharset); + if (aNewURI.HasError()) + { + rWasAbsolute = false; + return false; + } + + if (bIgnoreFragment) + aNewURI.clearFragment(); + rTheAbsURIRef = aNewURI; + return true; + } + + enum State { STATE_AUTH, STATE_ABS_PATH, STATE_REL_PATH, STATE_FRAGMENT, + STATE_DONE }; + + rtl::OUStringBuffer aSynAbsURIRef; + // make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme + // is empty ("") in that case, so take the scheme from m_aAbsURIRef + if (m_eScheme != INET_PROT_GENERIC) + { + aSynAbsURIRef.appendAscii(getSchemeInfo().m_pScheme); + } + else + { + sal_Unicode const * pSchemeBegin + = m_aAbsURIRef.getStr(); + sal_Unicode const * pSchemeEnd = pSchemeBegin; + while (pSchemeEnd[0] != ':') + { + ++pSchemeEnd; + } + aSynAbsURIRef.append(pSchemeBegin, pSchemeEnd - pSchemeBegin); + } + aSynAbsURIRef.append(sal_Unicode(':')); + + sal_Char cEscapePrefix = getEscapePrefix(); + + State eState = STATE_AUTH; + bool bSameDoc = true; + + if (getSchemeInfo().m_bAuthority) + { + if (pEnd - p >= 2 && p[0] == '/' && p[1] == '/') + { + aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + p += 2; + eState = STATE_ABS_PATH; + bSameDoc = false; + while (p != pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 + = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, + eCharset, eEscapeType); + if (eEscapeType == ESCAPE_NO) + { + if (nUTF32 == nSegmentDelimiter) + break; + else if (nUTF32 == nFragmentDelimiter) + { + eState = STATE_FRAGMENT; + break; + } + } + appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, + PART_VISIBLE, cEscapePrefix, eCharset, true); + } + } + else + { + SubString aAuthority(getAuthority()); + aSynAbsURIRef.append(m_aAbsURIRef.getStr() + + aAuthority.getBegin(), + aAuthority.getLength()); + } + } + + if (eState == STATE_AUTH) + { + if (p == pEnd) + eState = STATE_DONE; + else if (*p == nFragmentDelimiter) + { + ++p; + eState = STATE_FRAGMENT; + } + else if (*p == nSegmentDelimiter) + { + ++p; + eState = STATE_ABS_PATH; + bSameDoc = false; + } + else + { + eState = STATE_REL_PATH; + bSameDoc = false; + } + } + + if (eState == STATE_ABS_PATH) + { + aSynAbsURIRef.append(sal_Unicode('/')); + eState = STATE_DONE; + while (p != pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 + = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, + eCharset, eEscapeType); + if (eEscapeType == ESCAPE_NO) + { + if (nUTF32 == nFragmentDelimiter) + { + eState = STATE_FRAGMENT; + break; + } + else if (nUTF32 == nSegmentDelimiter) + nUTF32 = '/'; + } + appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart, + cEscapePrefix, eCharset, true); + } + } + else if (eState == STATE_REL_PATH) + { + if (!getSchemeInfo().m_bHierarchical) + { + // Detect cases where a relative input could not be made absolute + // because the given base URL is broken (most probably because it is + // empty): + OSL_ASSERT(!HasError()); + rWasAbsolute = false; + return false; + } + + sal_Unicode const * pBasePathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pBasePathEnd + = pBasePathBegin + m_aPath.getLength(); + while (pBasePathEnd != pBasePathBegin) + if (*(--pBasePathEnd) == '/') + { + ++pBasePathEnd; + break; + } + + sal_Int32 nPathBegin = aSynAbsURIRef.getLength(); + aSynAbsURIRef.append(pBasePathBegin, pBasePathEnd - pBasePathBegin); + DBG_ASSERT(aSynAbsURIRef.getLength() > nPathBegin + && aSynAbsURIRef.charAt(aSynAbsURIRef.getLength() - 1) == '/', + "INetURLObject::convertRelToAbs(): Bad base path"); + + while (p != pEnd && *p != nQueryDelimiter && *p != nFragmentDelimiter) + { + if (*p == '.') + { + if (pEnd - p == 1 + || p[1] == nSegmentDelimiter + || p[1] == nQueryDelimiter + || p[1] == nFragmentDelimiter) + { + ++p; + if (p != pEnd && *p == nSegmentDelimiter) + ++p; + continue; + } + else if (pEnd - p >= 2 + && p[1] == '.' + && (pEnd - p == 2 + || p[2] == nSegmentDelimiter + || p[2] == nQueryDelimiter + || p[2] == nFragmentDelimiter) + && aSynAbsURIRef.getLength() - nPathBegin > 1) + { + p += 2; + if (p != pEnd && *p == nSegmentDelimiter) + ++p; + + sal_Int32 i = aSynAbsURIRef.getLength() - 2; + while (i > nPathBegin && aSynAbsURIRef.charAt(i) != '/') + --i; + aSynAbsURIRef.setLength(i + 1); + DBG_ASSERT( + aSynAbsURIRef.getLength() > nPathBegin + && aSynAbsURIRef.charAt(aSynAbsURIRef.getLength() - 1) + == '/', + "INetURLObject::convertRelToAbs(): Bad base path"); + continue; + } + } + + while (p != pEnd + && *p != nSegmentDelimiter + && *p != nQueryDelimiter + && *p != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 + = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart, + cEscapePrefix, eCharset, true); + } + if (p != pEnd && *p == nSegmentDelimiter) + { + aSynAbsURIRef.append(sal_Unicode('/')); + ++p; + } + } + + while (p != pEnd && *p != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 + = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart, + cEscapePrefix, eCharset, true); + } + + if (p == pEnd) + eState = STATE_DONE; + else + { + ++p; + eState = STATE_FRAGMENT; + } + } + else if (bSameDoc) + { + aSynAbsURIRef.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(), + m_aPath.getLength()); + if (m_aQuery.isPresent()) + aSynAbsURIRef.append(m_aAbsURIRef.getStr() + + m_aQuery.getBegin() - 1, + m_aQuery.getLength() + 1); + } + + if (eState == STATE_FRAGMENT && !bIgnoreFragment) + { + aSynAbsURIRef.append(sal_Unicode('#')); + while (p != pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 + = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, + eCharset, eEscapeType); + appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, + PART_VISIBLE, cEscapePrefix, eCharset, true); + } + } + + INetURLObject aNewURI(aSynAbsURIRef.makeStringAndClear()); + if (aNewURI.HasError()) + { + // Detect cases where a relative input could not be made absolute + // because the given base URL is broken (most probably because it is + // empty): + OSL_ASSERT(!HasError()); + rWasAbsolute = false; + return false; + } + + rTheAbsURIRef = aNewURI; + return true; +} + +//============================================================================ +bool INetURLObject::convertAbsToRel(rtl::OUString const & rTheAbsURIRef, + bool bOctets, rtl::OUString & rTheRelURIRef, + EncodeMechanism eEncodeMechanism, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset, + FSysStyle eStyle) const +{ + // Check for hierarchical base URL: + if (!getSchemeInfo().m_bHierarchical) + { + rTheRelURIRef + = decode(rTheAbsURIRef, + getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)), + eDecodeMechanism, eCharset); + return false; + } + + // Convert the input (absolute or relative URI ref) to an absolute URI + // ref: + INetURLObject aSubject; + bool bWasAbsolute; + if (!convertRelToAbs(rTheAbsURIRef, bOctets, aSubject, bWasAbsolute, + eEncodeMechanism, eCharset, false, false, false, + eStyle)) + { + rTheRelURIRef + = decode(rTheAbsURIRef, + getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)), + eDecodeMechanism, eCharset); + return false; + } + + // Check for differing scheme or authority parts: + if ((m_aScheme.compare( + aSubject.m_aScheme, m_aAbsURIRef, aSubject.m_aAbsURIRef) + != 0) + || (m_aUser.compare( + aSubject.m_aUser, m_aAbsURIRef, aSubject.m_aAbsURIRef) + != 0) + || (m_aAuth.compare( + aSubject.m_aAuth, m_aAbsURIRef, aSubject.m_aAbsURIRef) + != 0) + || (m_aHost.compare( + aSubject.m_aHost, m_aAbsURIRef, aSubject.m_aAbsURIRef) + != 0) + || (m_aPort.compare( + aSubject.m_aPort, m_aAbsURIRef, aSubject.m_aAbsURIRef) + != 0)) + { + rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset); + return false; + } + + sal_Unicode const * pBasePathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pBasePathEnd = pBasePathBegin + m_aPath.getLength(); + sal_Unicode const * pSubjectPathBegin + = aSubject.m_aAbsURIRef.getStr() + aSubject.m_aPath.getBegin(); + sal_Unicode const * pSubjectPathEnd + = pSubjectPathBegin + aSubject.m_aPath.getLength(); + + // Make nMatch point past the last matching slash, or past the end of the + // paths, in case they are equal: + sal_Unicode const * pSlash = 0; + sal_Unicode const * p1 = pBasePathBegin; + sal_Unicode const * p2 = pSubjectPathBegin; + for (;;) + { + if (p1 == pBasePathEnd || p2 == pSubjectPathEnd) + { + if (p1 == pBasePathEnd && p2 == pSubjectPathEnd) + pSlash = p1; + break; + } + + sal_Unicode c = *p1++; + if (c != *p2++) + break; + if (c == '/') + pSlash = p1; + } + if (!pSlash) + { + // One of the paths does not start with '/': + rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset); + return false; + } + sal_Int32 nMatch = pSlash - pBasePathBegin; + + // If the two URLs are DOS file URLs starting with different volumes + // (e.g., file:///a:/... and file:///b:/...), the subject is not made + // relative (it could be, but some people do not like that): + if (m_eScheme == INET_PROT_FILE + && nMatch <= 1 + && hasDosVolume(eStyle) + && aSubject.hasDosVolume(eStyle)) //TODO! ok to use eStyle for these? + { + rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset); + return false; + } + + // For every slash in the base path after nMatch, a prefix of "../" is + // added to the new relative URL (if the common prefix of the two paths is + // only "/"---but see handling of file URLs above---, the complete subject + // path could go into the new relative URL instead, but some people don't + // like that): + rtl::OUStringBuffer aSynRelURIRef; +// if (nMatch <= 1) nMatch = 0; else // see comment above + for (sal_Unicode const * p = pBasePathBegin + nMatch; p != pBasePathEnd; + ++p) + { + if (*p == '/') + aSynRelURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("../")); + } + + // If the new relative URL would start with "//" (i.e., it would be + // mistaken for a relative URL starting with an authority part), or if the + // new relative URL would neither be empty nor start with <"/"> nor start + // with <1*rseg> (i.e., it could be mistaken for an absolute URL starting + // with a scheme part), then the new relative URL is prefixed with "./": + if (aSynRelURIRef.getLength() == 0) + { + if (pSubjectPathEnd - pSubjectPathBegin >= nMatch + 2 + && pSubjectPathBegin[nMatch] == '/' + && pSubjectPathBegin[nMatch + 1] == '/') + { + aSynRelURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("./")); + } + else + { + for (sal_Unicode const * p = pSubjectPathBegin + nMatch; + p != pSubjectPathEnd && *p != '/'; ++p) + { + if (mustEncode(*p, PART_REL_SEGMENT_EXTRA)) + { + aSynRelURIRef. + appendAscii(RTL_CONSTASCII_STRINGPARAM("./")); + break; + } + } + } + } + + // The remainder of the subject path, starting at nMatch, is appended to + // the new relative URL: + sal_Char cEscapePrefix = getEscapePrefix(); + aSynRelURIRef.append(decode(pSubjectPathBegin + nMatch, pSubjectPathEnd, + cEscapePrefix, eDecodeMechanism, eCharset)); + + // If the subject has defined query or fragment parts, they are appended + // to the new relative URL: + if (aSubject.m_aQuery.isPresent()) + { + aSynRelURIRef.append(sal_Unicode('?')); + aSynRelURIRef.append(aSubject.decode(aSubject.m_aQuery, cEscapePrefix, + eDecodeMechanism, eCharset)); + } + if (aSubject.m_aFragment.isPresent()) + { + aSynRelURIRef.append(sal_Unicode('#')); + aSynRelURIRef.append(aSubject.decode(aSubject.m_aFragment, + cEscapePrefix, eDecodeMechanism, eCharset)); + } + + rTheRelURIRef = aSynRelURIRef.makeStringAndClear(); + return true; +} + +//============================================================================ +// static +bool INetURLObject::convertIntToExt(rtl::OUString const & rTheIntURIRef, + bool bOctets, rtl::OUString & rTheExtURIRef, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset) +{ + sal_Char cEscapePrefix + = getEscapePrefix(CompareProtocolScheme(rTheIntURIRef)); + rtl::OUString aSynExtURIRef(encodeText(rTheIntURIRef, bOctets, PART_VISIBLE, + cEscapePrefix, NOT_CANONIC, eCharset, + true)); + sal_Unicode const * pBegin = aSynExtURIRef.getStr(); + sal_Unicode const * pEnd = pBegin + aSynExtURIRef.getLength(); + sal_Unicode const * p = pBegin; + PrefixInfo const * pPrefix = getPrefix(p, pEnd); + bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::INTERNAL; + if (bConvert) + { + aSynExtURIRef = + aSynExtURIRef.replaceAt(0, p - pBegin, + rtl::OUString::createFromAscii(pPrefix->m_pTranslatedPrefix)); + } + rTheExtURIRef = decode(aSynExtURIRef, cEscapePrefix, eDecodeMechanism, + eCharset); + return bConvert; +} + +//============================================================================ +// static +bool INetURLObject::convertExtToInt(rtl::OUString const & rTheExtURIRef, + bool bOctets, rtl::OUString & rTheIntURIRef, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset) +{ + sal_Char cEscapePrefix + = getEscapePrefix(CompareProtocolScheme(rTheExtURIRef)); + rtl::OUString aSynIntURIRef(encodeText(rTheExtURIRef, bOctets, PART_VISIBLE, + cEscapePrefix, NOT_CANONIC, eCharset, + true)); + sal_Unicode const * pBegin = aSynIntURIRef.getStr(); + sal_Unicode const * pEnd = pBegin + aSynIntURIRef.getLength(); + sal_Unicode const * p = pBegin; + PrefixInfo const * pPrefix = getPrefix(p, pEnd); + bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::EXTERNAL; + if (bConvert) + { + aSynIntURIRef = + aSynIntURIRef.replaceAt(0, p - pBegin, + rtl::OUString::createFromAscii(pPrefix->m_pTranslatedPrefix)); + } + rTheIntURIRef = decode(aSynIntURIRef, cEscapePrefix, eDecodeMechanism, + eCharset); + return bConvert; +} + +//============================================================================ +// static +INetURLObject::PrefixInfo const * +INetURLObject::getPrefix(sal_Unicode const *& rBegin, + sal_Unicode const * pEnd) +{ + static PrefixInfo const aMap[] + = { // dummy entry at front needed, because pLast may point here: + { 0, 0, INET_PROT_NOT_VALID, PrefixInfo::INTERNAL }, + { ".component:", "staroffice.component:", INET_PROT_COMPONENT, + PrefixInfo::INTERNAL }, + { ".uno:", "staroffice.uno:", INET_PROT_UNO, + PrefixInfo::INTERNAL }, + { "cid:", 0, INET_PROT_CID, PrefixInfo::OFFICIAL }, + { "data:", 0, INET_PROT_DATA, PrefixInfo::OFFICIAL }, + { "db:", "staroffice.db:", INET_PROT_DB, PrefixInfo::INTERNAL }, + { "file:", 0, INET_PROT_FILE, PrefixInfo::OFFICIAL }, + { "ftp:", 0, INET_PROT_FTP, PrefixInfo::OFFICIAL }, + { "http:", 0, INET_PROT_HTTP, PrefixInfo::OFFICIAL }, + { "https:", 0, INET_PROT_HTTPS, PrefixInfo::OFFICIAL }, + { "imap:", 0, INET_PROT_IMAP, PrefixInfo::OFFICIAL }, + { "javascript:", 0, INET_PROT_JAVASCRIPT, PrefixInfo::OFFICIAL }, + { "ldap:", 0, INET_PROT_LDAP, PrefixInfo::OFFICIAL }, + { "macro:", "staroffice.macro:", INET_PROT_MACRO, + PrefixInfo::INTERNAL }, + { "mailto:", 0, INET_PROT_MAILTO, PrefixInfo::OFFICIAL }, + { "news:", 0, INET_PROT_NEWS, PrefixInfo::OFFICIAL }, + { "out:", "staroffice.out:", INET_PROT_OUT, + PrefixInfo::INTERNAL }, + { "pop3:", "staroffice.pop3:", INET_PROT_POP3, + PrefixInfo::INTERNAL }, + { "private:", "staroffice.private:", INET_PROT_PRIV_SOFFICE, + PrefixInfo::INTERNAL }, + { "private:factory/", "staroffice.factory:", + INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL }, + { "private:helpid/", "staroffice.helpid:", INET_PROT_PRIV_SOFFICE, + PrefixInfo::INTERNAL }, + { "private:java/", "staroffice.java:", INET_PROT_PRIV_SOFFICE, + PrefixInfo::INTERNAL }, + { "private:searchfolder:", "staroffice.searchfolder:", + INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL }, + { "private:trashcan:", "staroffice.trashcan:", + INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL }, + { "slot:", "staroffice.slot:", INET_PROT_SLOT, + PrefixInfo::INTERNAL }, + { "smb:", 0, INET_PROT_SMB, PrefixInfo::OFFICIAL }, + { "staroffice.component:", ".component:", INET_PROT_COMPONENT, + PrefixInfo::EXTERNAL }, + { "staroffice.db:", "db:", INET_PROT_DB, PrefixInfo::EXTERNAL }, + { "staroffice.factory:", "private:factory/", + INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL }, + { "staroffice.helpid:", "private:helpid/", INET_PROT_PRIV_SOFFICE, + PrefixInfo::EXTERNAL }, + { "staroffice.java:", "private:java/", INET_PROT_PRIV_SOFFICE, + PrefixInfo::EXTERNAL }, + { "staroffice.macro:", "macro:", INET_PROT_MACRO, + PrefixInfo::EXTERNAL }, + { "staroffice.out:", "out:", INET_PROT_OUT, + PrefixInfo::EXTERNAL }, + { "staroffice.pop3:", "pop3:", INET_PROT_POP3, + PrefixInfo::EXTERNAL }, + { "staroffice.private:", "private:", INET_PROT_PRIV_SOFFICE, + PrefixInfo::EXTERNAL }, + { "staroffice.searchfolder:", "private:searchfolder:", + INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL }, + { "staroffice.slot:", "slot:", INET_PROT_SLOT, + PrefixInfo::EXTERNAL }, + { "staroffice.trashcan:", "private:trashcan:", + INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL }, + { "staroffice.uno:", ".uno:", INET_PROT_UNO, + PrefixInfo::EXTERNAL }, + { "staroffice.vim:", "vim:", INET_PROT_VIM, + PrefixInfo::EXTERNAL }, + { "staroffice:", "private:", INET_PROT_PRIV_SOFFICE, + PrefixInfo::EXTERNAL }, + { "telnet:", 0, INET_PROT_TELNET, PrefixInfo::OFFICIAL }, + { "vim:", "staroffice.vim:", INET_PROT_VIM, + PrefixInfo::INTERNAL }, + { "vnd.sun.star.cmd:", 0, INET_PROT_VND_SUN_STAR_CMD, + PrefixInfo::OFFICIAL }, + { "vnd.sun.star.expand:", 0, INET_PROT_VND_SUN_STAR_EXPAND, + PrefixInfo::OFFICIAL }, + { "vnd.sun.star.help:", 0, INET_PROT_VND_SUN_STAR_HELP, + PrefixInfo::OFFICIAL }, + { "vnd.sun.star.hier:", 0, INET_PROT_VND_SUN_STAR_HIER, + PrefixInfo::OFFICIAL }, + { "vnd.sun.star.odma:", 0, INET_PROT_VND_SUN_STAR_ODMA, + PrefixInfo::OFFICIAL }, + { "vnd.sun.star.pkg:", 0, INET_PROT_VND_SUN_STAR_PKG, + PrefixInfo::OFFICIAL }, + { "vnd.sun.star.tdoc:", 0, INET_PROT_VND_SUN_STAR_TDOC, + PrefixInfo::OFFICIAL }, + { "vnd.sun.star.webdav:", 0, INET_PROT_VND_SUN_STAR_WEBDAV, + PrefixInfo::OFFICIAL } }; + PrefixInfo const * pFirst = aMap + 1; + PrefixInfo const * pLast = aMap + sizeof aMap / sizeof (PrefixInfo) - 1; + PrefixInfo const * pMatch = 0; + sal_Unicode const * pMatched = rBegin; + sal_Unicode const * p = rBegin; + sal_Int32 i = 0; + for (; pFirst < pLast; ++i) + { + if (pFirst->m_pPrefix[i] == '\0') + { + pMatch = pFirst++; + pMatched = p; + } + if (p >= pEnd) + break; + sal_uInt32 nChar = INetMIME::toLowerCase(*p++); + while (pFirst <= pLast && sal_uChar(pFirst->m_pPrefix[i]) < nChar) + ++pFirst; + while (pFirst <= pLast && sal_uChar(pLast->m_pPrefix[i]) > nChar) + --pLast; + } + if (pFirst == pLast) + { + sal_Char const * q = pFirst->m_pPrefix + i; + while (p < pEnd && *q != '\0' + && INetMIME::toLowerCase(*p) == sal_uChar(*q)) + { + ++p; + ++q; + } + if (*q == '\0') + { + rBegin = p; + return pFirst; + } + } + rBegin = pMatched; + return pMatch; +} + +//============================================================================ +sal_Int32 INetURLObject::getAuthorityBegin() const +{ + DBG_ASSERT(getSchemeInfo().m_bAuthority, + "INetURLObject::getAuthority(): Bad scheme"); + sal_Int32 nBegin; + if (m_aUser.isPresent()) + nBegin = m_aUser.getBegin(); + else if (m_aHost.isPresent()) + nBegin = m_aHost.getBegin(); + else + nBegin = m_aPath.getBegin(); + nBegin -= RTL_CONSTASCII_LENGTH("//"); + DBG_ASSERT(m_aAbsURIRef.charAt(nBegin) == '/' + && m_aAbsURIRef.charAt(nBegin + 1) == '/', + "INetURLObject::getAuthority(): Bad authority"); + return nBegin; +} + +//============================================================================ +INetURLObject::SubString INetURLObject::getAuthority() const +{ + sal_Int32 nBegin = getAuthorityBegin(); + sal_Int32 nEnd = m_aPort.isPresent() ? m_aPort.getEnd() : + m_aHost.isPresent() ? m_aHost.getEnd() : + m_aAuth.isPresent() ? m_aAuth.getEnd() : + m_aUser.isPresent() ? m_aUser.getEnd() : + nBegin + RTL_CONSTASCII_LENGTH("//"); + return SubString(nBegin, nEnd - nBegin); +} + +//============================================================================ +bool INetURLObject::setUser(rtl::OUString const & rTheUser, + bool bOctets, EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if ( + !getSchemeInfo().m_bUser || + (m_eScheme == INET_PROT_IMAP && rTheUser.getLength() == 0) + ) + { + return false; + } + + rtl::OUString aNewUser(encodeText(rTheUser, bOctets, + m_eScheme == INET_PROT_IMAP ? + PART_IMAP_ACHAR : + m_eScheme == INET_PROT_VIM ? + PART_VIM : + PART_USER_PASSWORD, + getEscapePrefix(), eMechanism, eCharset, + false)); + sal_Int32 nDelta; + if (m_aUser.isPresent()) + nDelta = m_aUser.set(m_aAbsURIRef, aNewUser); + else if (m_aHost.isPresent()) + { + m_aAbsURIRef.insert(m_aHost.getBegin(), sal_Unicode('@')); + nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aHost.getBegin()) + 1; + } + else if (getSchemeInfo().m_bHost) + return false; + else + nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aPath.getBegin()); + m_aAuth += nDelta; + m_aHost += nDelta; + m_aPort += nDelta; + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + return true; +} + +namespace +{ + void lcl_Erase(rtl::OUStringBuffer &rBuf, sal_Int32 index, sal_Int32 count) + { + rtl::OUString sTemp(rBuf.makeStringAndClear()); + rBuf.append(sTemp.replaceAt(index, count, rtl::OUString())); + } +} + +//============================================================================ +bool INetURLObject::clearPassword() +{ + if (!getSchemeInfo().m_bPassword) + return false; + if (m_aAuth.isPresent()) + { + lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin() - 1, + m_aAuth.getLength() + 1); + sal_Int32 nDelta = m_aAuth.clear() - 1; + m_aHost += nDelta; + m_aPort += nDelta; + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + } + return true; +} + +//============================================================================ +bool INetURLObject::setPassword(rtl::OUString const & rThePassword, + bool bOctets, EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (!getSchemeInfo().m_bPassword) + return false; + rtl::OUString aNewAuth(encodeText(rThePassword, bOctets, + m_eScheme == INET_PROT_VIM ? + PART_VIM : PART_USER_PASSWORD, + getEscapePrefix(), eMechanism, eCharset, + false)); + sal_Int32 nDelta; + if (m_aAuth.isPresent()) + nDelta = m_aAuth.set(m_aAbsURIRef, aNewAuth); + else if (m_aUser.isPresent()) + { + m_aAbsURIRef.insert(m_aUser.getEnd(), sal_Unicode(':')); + nDelta + = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aUser.getEnd() + 1) + 1; + } + else if (m_aHost.isPresent()) + { + m_aAbsURIRef.insert(m_aHost.getBegin(), + rtl::OUString::createFromAscii(":@")); + m_aUser.set(m_aAbsURIRef, rtl::OUString(), m_aHost.getBegin()); + nDelta + = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aHost.getBegin() + 1) + 2; + } + else if (getSchemeInfo().m_bHost) + return false; + else + { + m_aAbsURIRef.insert(m_aPath.getBegin(), sal_Unicode(':')); + m_aUser.set(m_aAbsURIRef, rtl::OUString(), m_aPath.getBegin()); + nDelta + = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aPath.getBegin() + 1) + 1; + } + m_aHost += nDelta; + m_aPort += nDelta; + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + return true; +} + +//============================================================================ +// static +bool INetURLObject::parseHost( + sal_Unicode const *& rBegin, sal_Unicode const * pEnd, + rtl::OUString & rCanonic) +{ + // RFC 2373 is inconsistent about how to write an IPv6 address in which an + // IPv4 address directly follows the abbreviating "::". The ABNF in + // Appendix B suggests ":::13.1.68.3", while an example in 2.2/3 explicitly + // mentions "::13:1.68.3". This algorithm accepts both variants: + enum State { STATE_INITIAL, STATE_LABEL, STATE_LABEL_HYPHEN, + STATE_LABEL_DOT, STATE_TOPLABEL, STATE_TOPLABEL_HYPHEN, + STATE_TOPLABEL_DOT, STATE_IP4, STATE_IP4_DOT, STATE_IP6, + STATE_IP6_COLON, STATE_IP6_2COLON, STATE_IP6_3COLON, + STATE_IP6_HEXSEQ1, STATE_IP6_HEXSEQ1_COLON, + STATE_IP6_HEXSEQ1_MAYBE_IP4, STATE_IP6_HEXSEQ2, + STATE_IP6_HEXSEQ2_COLON, STATE_IP6_HEXSEQ2_MAYBE_IP4, + STATE_IP6_IP4, STATE_IP6_IP4_DOT, STATE_IP6_DONE }; + rtl::OUStringBuffer aTheCanonic; + sal_uInt32 nNumber = 0; + int nDigits = 0; + int nOctets = 0; + State eState = STATE_INITIAL; + sal_Unicode const * p = rBegin; + for (; p != pEnd; ++p) + switch (eState) + { + case STATE_INITIAL: + if (*p == '[') + { + aTheCanonic.append(sal_Unicode('[')); + eState = STATE_IP6; + } + else if (INetMIME::isAlpha(*p) || *p == '_') + eState = STATE_TOPLABEL; + else if (INetMIME::isDigit(*p)) + { + nNumber = INetMIME::getWeight(*p); + nDigits = 1; + nOctets = 1; + eState = STATE_IP4; + } + else + goto done; + break; + + case STATE_LABEL: + if (*p == '.') + eState = STATE_LABEL_DOT; + else if (*p == '-') + eState = STATE_LABEL_HYPHEN; + else if (!INetMIME::isAlphanumeric(*p) && *p != '_') + goto done; + break; + + case STATE_LABEL_HYPHEN: + if (INetMIME::isAlphanumeric(*p) || *p == '_') + eState = STATE_LABEL; + else if (*p != '-') + goto done; + break; + + case STATE_LABEL_DOT: + if (INetMIME::isAlpha(*p) || *p == '_') + eState = STATE_TOPLABEL; + else if (INetMIME::isDigit(*p)) + eState = STATE_LABEL; + else + goto done; + break; + + case STATE_TOPLABEL: + if (*p == '.') + eState = STATE_TOPLABEL_DOT; + else if (*p == '-') + eState = STATE_TOPLABEL_HYPHEN; + else if (!INetMIME::isAlphanumeric(*p) && *p != '_') + goto done; + break; + + case STATE_TOPLABEL_HYPHEN: + if (INetMIME::isAlphanumeric(*p) || *p == '_') + eState = STATE_TOPLABEL; + else if (*p != '-') + goto done; + break; + + case STATE_TOPLABEL_DOT: + if (INetMIME::isAlpha(*p) || *p == '_') + eState = STATE_TOPLABEL; + else if (INetMIME::isDigit(*p)) + eState = STATE_LABEL; + else + goto done; + break; + + case STATE_IP4: + if (*p == '.') + if (nOctets < 4) + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber))); + aTheCanonic.append(sal_Unicode('.')); + ++nOctets; + eState = STATE_IP4_DOT; + } + else + eState = STATE_LABEL_DOT; + else if (*p == '-') + eState = STATE_LABEL_HYPHEN; + else if (INetMIME::isAlpha(*p) || *p == '_') + eState = STATE_LABEL; + else if (INetMIME::isDigit(*p)) + if (nDigits < 3) + { + nNumber = 10 * nNumber + INetMIME::getWeight(*p); + ++nDigits; + } + else + eState = STATE_LABEL; + else + goto done; + break; + + case STATE_IP4_DOT: + if (INetMIME::isAlpha(*p) || *p == '_') + eState = STATE_TOPLABEL; + else if (INetMIME::isDigit(*p)) + { + nNumber = INetMIME::getWeight(*p); + nDigits = 1; + eState = STATE_IP4; + } + else + goto done; + break; + + case STATE_IP6: + if (*p == ':') + eState = STATE_IP6_COLON; + else if (INetMIME::isHexDigit(*p)) + { + nNumber = INetMIME::getHexWeight(*p); + nDigits = 1; + eState = STATE_IP6_HEXSEQ1; + } + else + goto done; + break; + + case STATE_IP6_COLON: + if (*p == ':') + { + aTheCanonic.appendAscii(RTL_CONSTASCII_STRINGPARAM("::")); + eState = STATE_IP6_2COLON; + } + else + goto done; + break; + + case STATE_IP6_2COLON: + if (*p == ']') + eState = STATE_IP6_DONE; + else if (*p == ':') + { + aTheCanonic.append(sal_Unicode(':')); + eState = STATE_IP6_3COLON; + } + else if (INetMIME::isDigit(*p)) + { + nNumber = INetMIME::getWeight(*p); + nDigits = 1; + eState = STATE_IP6_HEXSEQ2_MAYBE_IP4; + } + else if (INetMIME::isHexDigit(*p)) + { + nNumber = INetMIME::getHexWeight(*p); + nDigits = 1; + eState = STATE_IP6_HEXSEQ2; + } + else + goto done; + break; + + case STATE_IP6_3COLON: + if (INetMIME::isDigit(*p)) + { + nNumber = INetMIME::getWeight(*p); + nDigits = 1; + nOctets = 1; + eState = STATE_IP6_IP4; + } + else + goto done; + break; + + case STATE_IP6_HEXSEQ1: + if (*p == ']') + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber), 16)); + eState = STATE_IP6_DONE; + } + else if (*p == ':') + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber), 16)); + aTheCanonic.append(sal_Unicode(':')); + eState = STATE_IP6_HEXSEQ1_COLON; + } + else if (INetMIME::isHexDigit(*p) && nDigits < 4) + { + nNumber = 16 * nNumber + INetMIME::getHexWeight(*p); + ++nDigits; + } + else + goto done; + break; + + case STATE_IP6_HEXSEQ1_COLON: + if (*p == ':') + { + aTheCanonic.append(sal_Unicode(':')); + eState = STATE_IP6_2COLON; + } + else if (INetMIME::isDigit(*p)) + { + nNumber = INetMIME::getWeight(*p); + nDigits = 1; + eState = STATE_IP6_HEXSEQ1_MAYBE_IP4; + } + else if (INetMIME::isHexDigit(*p)) + { + nNumber = INetMIME::getHexWeight(*p); + nDigits = 1; + eState = STATE_IP6_HEXSEQ1; + } + else + goto done; + break; + + case STATE_IP6_HEXSEQ1_MAYBE_IP4: + if (*p == ']') + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber), 16)); + eState = STATE_IP6_DONE; + } + else if (*p == ':') + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber), 16)); + aTheCanonic.append(sal_Unicode(':')); + eState = STATE_IP6_HEXSEQ1_COLON; + } + else if (*p == '.') + { + nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15) + + (nNumber & 15); + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber))); + aTheCanonic.append(sal_Unicode('.')); + nOctets = 2; + eState = STATE_IP6_IP4_DOT; + } + else if (INetMIME::isDigit(*p) && nDigits < 3) + { + nNumber = 16 * nNumber + INetMIME::getWeight(*p); + ++nDigits; + } + else if (INetMIME::isHexDigit(*p) && nDigits < 4) + { + nNumber = 16 * nNumber + INetMIME::getHexWeight(*p); + ++nDigits; + eState = STATE_IP6_HEXSEQ1; + } + else + goto done; + break; + + case STATE_IP6_HEXSEQ2: + if (*p == ']') + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber), 16)); + eState = STATE_IP6_DONE; + } + else if (*p == ':') + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber), 16)); + aTheCanonic.append(sal_Unicode(':')); + eState = STATE_IP6_HEXSEQ2_COLON; + } + else if (INetMIME::isHexDigit(*p) && nDigits < 4) + { + nNumber = 16 * nNumber + INetMIME::getHexWeight(*p); + ++nDigits; + } + else + goto done; + break; + + case STATE_IP6_HEXSEQ2_COLON: + if (INetMIME::isDigit(*p)) + { + nNumber = INetMIME::getWeight(*p); + nDigits = 1; + eState = STATE_IP6_HEXSEQ2_MAYBE_IP4; + } + else if (INetMIME::isHexDigit(*p)) + { + nNumber = INetMIME::getHexWeight(*p); + nDigits = 1; + eState = STATE_IP6_HEXSEQ2; + } + else + goto done; + break; + + case STATE_IP6_HEXSEQ2_MAYBE_IP4: + if (*p == ']') + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber), 16)); + eState = STATE_IP6_DONE; + } + else if (*p == ':') + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber), 16)); + aTheCanonic.append(sal_Unicode(':')); + eState = STATE_IP6_HEXSEQ2_COLON; + } + else if (*p == '.') + { + nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15) + + (nNumber & 15); + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber))); + aTheCanonic.append(sal_Unicode('.')); + nOctets = 2; + eState = STATE_IP6_IP4_DOT; + } + else if (INetMIME::isDigit(*p) && nDigits < 3) + { + nNumber = 16 * nNumber + INetMIME::getWeight(*p); + ++nDigits; + } + else if (INetMIME::isHexDigit(*p) && nDigits < 4) + { + nNumber = 16 * nNumber + INetMIME::getHexWeight(*p); + ++nDigits; + eState = STATE_IP6_HEXSEQ2; + } + else + goto done; + break; + + case STATE_IP6_IP4: + if (*p == ']') + if (nOctets == 4) + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber))); + eState = STATE_IP6_DONE; + } + else + goto done; + else if (*p == '.') + if (nOctets < 4) + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber))); + aTheCanonic.append(sal_Unicode('.')); + ++nOctets; + eState = STATE_IP6_IP4_DOT; + } + else + goto done; + else if (INetMIME::isDigit(*p) && nDigits < 3) + { + nNumber = 10 * nNumber + INetMIME::getWeight(*p); + ++nDigits; + } + else + goto done; + break; + + case STATE_IP6_IP4_DOT: + if (INetMIME::isDigit(*p)) + { + nNumber = INetMIME::getWeight(*p); + nDigits = 1; + eState = STATE_IP6_IP4; + } + else + goto done; + break; + + case STATE_IP6_DONE: + goto done; + } + done: + switch (eState) + { + case STATE_LABEL: + case STATE_TOPLABEL: + case STATE_TOPLABEL_DOT: + aTheCanonic.setLength(0); + aTheCanonic.append(rBegin, p - rBegin); + rBegin = p; + rCanonic = aTheCanonic.makeStringAndClear(); + return true; + + case STATE_IP4: + if (nOctets == 4) + { + aTheCanonic.append( + rtl::OUString::valueOf(sal_Int32(nNumber))); + rBegin = p; + rCanonic = aTheCanonic.makeStringAndClear(); + return true; + } + return false; + + case STATE_IP6_DONE: + aTheCanonic.append(sal_Unicode(']')); + rBegin = p; + rCanonic = aTheCanonic.makeStringAndClear(); + return true; + + default: + return false; + } +} + +//============================================================================ +// static +bool INetURLObject::parseHostOrNetBiosName( + sal_Unicode const * pBegin, sal_Unicode const * pEnd, bool bOctets, + EncodeMechanism eMechanism, rtl_TextEncoding eCharset, bool bNetBiosName, + rtl::OUStringBuffer* pCanonic) +{ + rtl::OUString aTheCanonic; + if (pBegin < pEnd) + { + sal_Unicode const * p = pBegin; + if (!parseHost(p, pEnd, aTheCanonic) || p != pEnd) + { + if (bNetBiosName) + { + rtl::OUStringBuffer buf; + while (pBegin < pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, bOctets, '%', + eMechanism, eCharset, + eEscapeType); + if (!INetMIME::isVisible(nUTF32)) + return false; + if (!INetMIME::isAlphanumeric(nUTF32)) + switch (nUTF32) + { + case '"': + case '*': + case '+': + case ',': + case '/': + case ':': + case ';': + case '<': + case '=': + case '>': + case '?': + case '[': + case '\\': + case ']': + case '`': + case '|': + return false;; + } + if (pCanonic != NULL) { + appendUCS4( + buf, nUTF32, eEscapeType, bOctets, PART_URIC, '%', + eCharset, true); + } + } + aTheCanonic = buf.makeStringAndClear(); + } + else + return false; + } + } + if (pCanonic != NULL) { + *pCanonic = aTheCanonic; + } + return true; +} + +//============================================================================ +// static +rtl::OUString INetURLObject::encodeHostPort(rtl::OUString const & rTheHostPort, + bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + sal_Int32 nPort = rTheHostPort.getLength(); + if (nPort != 0) + { + sal_Int32 i = nPort - 1; + while (i != 0 && INetMIME::isDigit(rTheHostPort.getStr()[i])) + --i; + if (rTheHostPort.getStr()[i] == ':') + nPort = i; + } + rtl::OUString aResult(encodeText(rTheHostPort.copy(0, nPort), bOctets, + PART_HOST_EXTRA, '%', eMechanism, eCharset, + true)); + aResult += rTheHostPort.copy(nPort); + return aResult; +} + +//============================================================================ +bool INetURLObject::setHost(rtl::OUString const & rTheHost, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (!getSchemeInfo().m_bHost) + return false; + rtl::OUStringBuffer aSynHost(rTheHost); + bool bNetBiosName = false; + switch (m_eScheme) + { + case INET_PROT_FILE: + { + rtl::OUString sTemp(aSynHost); + if (sTemp.equalsIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM("localhost"))) + { + aSynHost.setLength(0); + } + bNetBiosName = true; + } + break; + case INET_PROT_LDAP: + if (aSynHost.getLength() == 0 && m_aPort.isPresent()) + return false; + break; + + default: + if (aSynHost.getLength() == 0) + return false; + break; + } + if (!parseHostOrNetBiosName( + aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(), + bOctets, eMechanism, eCharset, bNetBiosName, &aSynHost)) + return false; + sal_Int32 nDelta = m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear()); + m_aPort += nDelta; + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + return true; +} + +//============================================================================ +// static +bool INetURLObject::parsePath(INetProtocol eScheme, + sal_Unicode const ** pBegin, + sal_Unicode const * pEnd, + bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, + bool bSkippedInitialSlash, + sal_uInt32 nSegmentDelimiter, + sal_uInt32 nAltSegmentDelimiter, + sal_uInt32 nQueryDelimiter, + sal_uInt32 nFragmentDelimiter, + rtl::OUStringBuffer &rSynPath) +{ + DBG_ASSERT(pBegin, "INetURLObject::parsePath(): Null output param"); + + sal_Unicode const * pPos = *pBegin; + rtl::OUStringBuffer aTheSynPath; + + switch (eScheme) + { + case INET_PROT_NOT_VALID: + return false; + + case INET_PROT_FTP: + case INET_PROT_IMAP: + if (pPos < pEnd && *pPos != '/') + return false; + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_HTTP_PATH, '%', eCharset, true); + } + if (aTheSynPath.getLength() == 0) + aTheSynPath.append(sal_Unicode('/')); + break; + + case INET_PROT_HTTP: + case INET_PROT_VND_SUN_STAR_WEBDAV: + case INET_PROT_HTTPS: + case INET_PROT_SMB: + if (pPos < pEnd && *pPos != '/') + return false; + while (pPos < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_HTTP_PATH, '%', eCharset, true); + } + if (aTheSynPath.getLength() == 0) + aTheSynPath.append(sal_Unicode('/')); + break; + + case INET_PROT_FILE: + { + if (bSkippedInitialSlash) + aTheSynPath.append(sal_Unicode('/')); + else if (pPos < pEnd + && *pPos != nSegmentDelimiter + && *pPos != nAltSegmentDelimiter) + return false; + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + if (eEscapeType == ESCAPE_NO) + { + if (nUTF32 == nSegmentDelimiter + || nUTF32 == nAltSegmentDelimiter) + { + aTheSynPath.append(sal_Unicode('/')); + continue; + } + else if (nUTF32 == '|' + && (pPos == pEnd + || *pPos == nFragmentDelimiter + || *pPos == nSegmentDelimiter + || *pPos == nAltSegmentDelimiter) + && aTheSynPath.getLength() == 2 + && INetMIME::isAlpha(aTheSynPath.charAt(1))) + { + // A first segment of <ALPHA "|"> is translated to + // <ALPHA ":">: + aTheSynPath.append(sal_Unicode(':')); + continue; + } + } + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_PCHAR, '%', eCharset, true); + } + if (aTheSynPath.getLength() == 0) + aTheSynPath.append(sal_Unicode('/')); + break; + } + + case INET_PROT_MAILTO: + while (pPos < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_MAILTO, '%', eCharset, true); + } + break; + + case INET_PROT_NEWS: + if (pPos == pEnd || *pPos == nQueryDelimiter + || *pPos == nFragmentDelimiter) + return false; + + // Match <"*">: + if (*pPos == '*' + && (pEnd - pPos == 1 || pPos[1] == nQueryDelimiter + || pPos[1] == nFragmentDelimiter)) + { + ++pPos; + aTheSynPath.append(sal_Unicode('*')); + break; + } + + // Match <group>: + if (INetMIME::isAlpha(*pPos)) + for (sal_Unicode const * p = pPos + 1;; ++p) + if (p == pEnd || *p == nQueryDelimiter + || *p == nFragmentDelimiter) + { + aTheSynPath.setLength(0); + aTheSynPath.append(pPos, p - pPos); + pPos = p; + goto done; + } + else if (!INetMIME::isAlphanumeric(*p) && *p != '+' + && *p != '-' && *p != '.' && *p != '_') + break; + + // Match <article>: + for (;;) + { + if (pPos == pEnd || *pPos == nQueryDelimiter + || *pPos == nFragmentDelimiter) + return false; + if (*pPos == '@') + break; + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, '%', + eMechanism, eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_NEWS_ARTICLE_LOCALPART, '%', eCharset, true); + } + if (aTheSynPath.getLength() == 0) + return false; + ++pPos; + aTheSynPath.append(sal_Unicode('@')); + { + sal_Unicode const * p = pPos; + while (p < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + ++p; + rtl::OUString aCanonic; + if (!parseHost(pPos, p, aCanonic)) + return false; + aTheSynPath.append(aCanonic); + } + + done: + break; + + case INET_PROT_POP3: + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_MESSAGE_ID_PATH, '%', eCharset, + true); + } + break; + + case INET_PROT_PRIV_SOFFICE: + case INET_PROT_SLOT: + case INET_PROT_MACRO: + case INET_PROT_UNO: + case INET_PROT_COMPONENT: + case INET_PROT_LDAP: + while (pPos < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_PATH_BEFORE_QUERY, '%', eCharset, + true); + } + break; + + case INET_PROT_VND_SUN_STAR_HELP: + if (pPos == pEnd + || *pPos == nQueryDelimiter + || *pPos == nFragmentDelimiter) + aTheSynPath.append(sal_Unicode('/')); + else + { + if (*pPos != '/') + return false; + while (pPos < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_HTTP_PATH, '%', eCharset, true); + } + } + break; + + case INET_PROT_JAVASCRIPT: + case INET_PROT_DATA: + case INET_PROT_CID: + case INET_PROT_DB: + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_URIC, '%', eCharset, true); + } + break; + + case INET_PROT_OUT: + if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '~') + return false; + aTheSynPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("/~")); + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_URIC, '%', eCharset, true); + } + break; + + case INET_PROT_VND_SUN_STAR_HIER: + case INET_PROT_VND_SUN_STAR_PKG: + if (pPos < pEnd && *pPos != '/' + && *pPos != nQueryDelimiter && *pPos != nFragmentDelimiter) + return false; + while (pPos < pEnd && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + if (eEscapeType == ESCAPE_NO && nUTF32 == '/') + aTheSynPath.append(sal_Unicode('/')); + else + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_PCHAR, '%', eCharset, false); + } + if (aTheSynPath.getLength() == 0) + aTheSynPath.append(sal_Unicode('/')); + break; + + case INET_PROT_VIM: + { +/* test had to be taken out to make parsePath static; ok since INET_PROT_VIM is + obsolete, anyway + if (m_aUser.isEmpty()) + return false; +*/ + sal_Unicode const * pPathEnd = pPos; + while (pPathEnd < pEnd && *pPathEnd != nFragmentDelimiter) + ++pPathEnd; + aTheSynPath.append(sal_Unicode('/')); + if (pPos == pPathEnd) + break; + else if (*pPos++ != '/') + return false; + if (pPos == pPathEnd) + break; + while (pPos < pPathEnd && *pPos != '/') + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, + '=', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, + eEscapeType == ESCAPE_NO ? + INetMIME::toLowerCase(nUTF32) : nUTF32, + eEscapeType, bOctets, PART_VIM, '=', + eCharset, false); + } + bool bInbox; + rtl::OUString sCompare(aTheSynPath); + if (sCompare.equalsAscii("/inbox")) + bInbox = true; + else if (sCompare.equalsAscii("/newsgroups")) + bInbox = false; + else + return false; + aTheSynPath.append(sal_Unicode('/')); + if (pPos == pPathEnd) + break; + else if (*pPos++ != '/') + return false; + if (!bInbox) + { + bool bEmpty = true; + while (pPos < pPathEnd && *pPos != '/') + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, + '=', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_VIM, '=', eCharset, false); + bEmpty = false; + } + if (bEmpty) + return false; + aTheSynPath.append(sal_Unicode('/')); + if (pPos == pPathEnd) + break; + else if (*pPos++ != '/') + return false; + } + bool bEmpty = true; + while (pPos < pPathEnd && *pPos != ':') + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, + '=', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_VIM, '=', eCharset, false); + bEmpty = false; + } + if (bEmpty) + return false; + if (pPos == pPathEnd) + break; + else if (*pPos++ != ':') + return false; + aTheSynPath.append(sal_Unicode(':')); + for (int i = 0; i < 3; ++i) + { + if (i != 0) + { + if (pPos == pPathEnd || *pPos++ != '.') + return false; + aTheSynPath.append(sal_Unicode('.')); + } + bEmpty = true; + while (pPos < pPathEnd && *pPos != '.') + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, + '=', eMechanism, + eCharset, eEscapeType); + if (!INetMIME::isDigit(nUTF32)) + return false; + aTheSynPath.append(sal_Unicode(nUTF32)); + bEmpty = false; + } + if (bEmpty) + return false; + } + if (pPos != pPathEnd) + return false; + break; + } + + case INET_PROT_VND_SUN_STAR_CMD: + case INET_PROT_VND_SUN_STAR_EXPAND: + { + if (pPos == pEnd || *pPos == nFragmentDelimiter) + return false; + Part ePart = PART_URIC_NO_SLASH; + while (pPos != pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, ePart, + '%', eCharset, true); + ePart = PART_URIC; + } + break; + } + + case INET_PROT_VND_SUN_STAR_ODMA: + if (pPos < pEnd) + { + if (*pPos == '/') + ++pPos; + else + return false; + } + aTheSynPath.append(sal_Unicode('/')); + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_URIC_NO_SLASH, '%', eCharset, true); + } + break; + + case INET_PROT_TELNET: + if (pPos < pEnd) + { + if (*pPos != '/' || pEnd - pPos > 1) + return false; + ++pPos; + } + aTheSynPath.append(sal_Unicode('/')); + break; + + case INET_PROT_VND_SUN_STAR_TDOC: + if (pPos == pEnd || *pPos != '/') + return false; + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + if (eEscapeType == ESCAPE_NO && nUTF32 == '/') + aTheSynPath.append(sal_Unicode('/')); + else + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_PCHAR, '%', eCharset, false); + } + break; + + case INET_PROT_GENERIC: + while (pPos < pEnd && *pPos != nFragmentDelimiter) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, + '%', eMechanism, + eCharset, eEscapeType); + appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, + PART_URIC, '%', eCharset, true); + } + if (aTheSynPath.getLength() == 0) + return false; + break; + default: + OSL_ASSERT(false); + break; + } + + *pBegin = pPos; + rSynPath = aTheSynPath; + return true; +} + +//============================================================================ +bool INetURLObject::setPath(rtl::OUString const & rThePath, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + rtl::OUStringBuffer aSynPath; + sal_Unicode const * p = rThePath.getStr(); + sal_Unicode const * pEnd = p + rThePath.getLength(); + if (!parsePath(m_eScheme, &p, pEnd, bOctets, eMechanism, eCharset, false, + '/', 0x80000000, 0x80000000, 0x80000000, aSynPath) + || p != pEnd) + return false; + sal_Int32 nDelta = m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear()); + m_aQuery += nDelta; + m_aFragment += nDelta; + return true; +} + +//============================================================================ +bool INetURLObject::checkHierarchical() const { + if (m_eScheme == INET_PROT_VND_SUN_STAR_EXPAND) { + OSL_ENSURE( + false, "INetURLObject::checkHierarchical vnd.sun.star.expand"); + return true; + } else { + return getSchemeInfo().m_bHierarchical; + } +} + +//============================================================================ +bool INetURLObject::appendSegment(rtl::OUString const & rTheSegment, + bool bOctets, EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + return insertName(rTheSegment, bOctets, false, LAST_SEGMENT, true, + eMechanism, eCharset); +} + +//============================================================================ +INetURLObject::SubString INetURLObject::getSegment(sal_Int32 nIndex, + bool bIgnoreFinalSlash) + const +{ + DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT, + "INetURLObject::getSegment(): Bad index"); + + if (!checkHierarchical()) + return SubString(); + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin; + sal_Unicode const * pSegEnd; + if (nIndex == LAST_SEGMENT) + { + pSegEnd = pPathEnd; + if (bIgnoreFinalSlash && pSegEnd > pPathBegin && pSegEnd[-1] == '/') + --pSegEnd; + if (pSegEnd <= pPathBegin) + return SubString(); + pSegBegin = pSegEnd - 1; + while (pSegBegin > pPathBegin && *pSegBegin != '/') + --pSegBegin; + } + else + { + pSegBegin = pPathBegin; + while (nIndex-- > 0) + do + { + ++pSegBegin; + if (pSegBegin >= pPathEnd) + return SubString(); + } + while (*pSegBegin != '/'); + pSegEnd = pSegBegin + 1; + while (pSegEnd < pPathEnd && *pSegEnd != '/') + ++pSegEnd; + } + + return SubString(pSegBegin - m_aAbsURIRef.getStr(), + pSegEnd - pSegBegin); +} + +//============================================================================ +bool INetURLObject::insertName(rtl::OUString const & rTheName, bool bOctets, + bool bAppendFinalSlash, sal_Int32 nIndex, + bool bIgnoreFinalSlash, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT, + "INetURLObject::insertName(): Bad index"); + + if (!checkHierarchical()) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pPrefixEnd; + bool bInsertSlash; + sal_Unicode const * pSuffixBegin; + if (nIndex == LAST_SEGMENT) + { + pPrefixEnd = pPathEnd; + if (bIgnoreFinalSlash && pPrefixEnd > pPathBegin && + pPrefixEnd[-1] == '/') + { + --pPrefixEnd; + } + bInsertSlash = bAppendFinalSlash; + pSuffixBegin = pPathEnd; + } + else if (nIndex == 0) + { + pPrefixEnd = pPathBegin; + bInsertSlash = + (pPathBegin < pPathEnd && *pPathBegin != '/') || + (pPathBegin == pPathEnd && bAppendFinalSlash); + pSuffixBegin = + (pPathEnd - pPathBegin == 1 && *pPathBegin == '/' && + !bAppendFinalSlash && bIgnoreFinalSlash) + ? pPathEnd : pPathBegin; + } + else + { + pPrefixEnd = pPathBegin; + sal_Unicode const * pEnd = pPathEnd; + if (bIgnoreFinalSlash && pEnd > pPathBegin && pEnd[-1] == '/') + --pEnd; + bool bSkip = pPrefixEnd < pEnd && *pPrefixEnd == '/'; + bInsertSlash = false; + pSuffixBegin = pPathEnd; + while (nIndex-- > 0) + for (;;) + { + if (bSkip) + ++pPrefixEnd; + bSkip = true; + if (pPrefixEnd >= pEnd) + { + if (nIndex == 0) + { + bInsertSlash = bAppendFinalSlash; + break; + } + else + return false; + } + if (*pPrefixEnd == '/') + { + pSuffixBegin = pPrefixEnd; + break; + } + } + } + + rtl::OUStringBuffer aNewPath; + aNewPath.append(pPathBegin, pPrefixEnd - pPathBegin); + aNewPath.append(sal_Unicode('/')); + aNewPath.append(encodeText(rTheName, bOctets, PART_PCHAR, getEscapePrefix(), + eMechanism, eCharset, true)); + if (bInsertSlash) { + aNewPath.append(sal_Unicode('/')); + } + aNewPath.append(pSuffixBegin, pPathEnd - pSuffixBegin); + + return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, + RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +bool INetURLObject::clearQuery() +{ + if (HasError()) + return false; + if (m_aQuery.isPresent()) + { + lcl_Erase(m_aAbsURIRef, m_aQuery.getBegin() - 1, + m_aQuery.getLength() + 1); + m_aFragment += m_aQuery.clear() - 1; + } + return false; +} + +//============================================================================ +bool INetURLObject::setQuery(rtl::OUString const & rTheQuery, bool bOctets, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (!getSchemeInfo().m_bQuery) + return false; + rtl::OUString aNewQuery(encodeText(rTheQuery, bOctets, PART_URIC, + getEscapePrefix(), eMechanism, eCharset, + true)); + sal_Int32 nDelta; + if (m_aQuery.isPresent()) + nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery); + else + { + m_aAbsURIRef.insert(m_aPath.getEnd(), sal_Unicode('?')); + nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery, m_aPath.getEnd() + 1) + + 1; + } + m_aFragment += nDelta; + return true; +} + +//============================================================================ +bool INetURLObject::clearFragment() +{ + if (HasError()) + return false; + if (m_aFragment.isPresent()) + { + m_aAbsURIRef.setLength(m_aFragment.getBegin() - 1); + m_aFragment.clear(); + } + return true; +} + +//============================================================================ +bool INetURLObject::setFragment(rtl::OUString const & rTheFragment, + bool bOctets, EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + if (HasError()) + return false; + rtl::OUString aNewFragment(encodeText(rTheFragment, bOctets, PART_URIC, + getEscapePrefix(), eMechanism, + eCharset, true)); + if (m_aFragment.isPresent()) + m_aFragment.set(m_aAbsURIRef, aNewFragment); + else + { + m_aAbsURIRef.append(sal_Unicode('#')); + m_aFragment.set(m_aAbsURIRef, aNewFragment, m_aAbsURIRef.getLength()); + } + return true; +} + +//============================================================================ +INetURLObject::FTPType INetURLObject::getFTPType() const +{ + if (m_eScheme == INET_PROT_FTP + && m_aPath.getLength() >= RTL_CONSTASCII_LENGTH(";type=") + 1 + && rtl::OUString(m_aAbsURIRef).copy( + m_aPath.getEnd() - (RTL_CONSTASCII_LENGTH(";type=") + 1), + RTL_CONSTASCII_LENGTH(";type=")).equalsIgnoreAsciiCaseAscii(";type=")) + switch (m_aAbsURIRef.charAt(m_aPath.getEnd())) + { + case 'A': + case 'a': + return FTP_TYPE_A; + + case 'D': + case 'd': + return FTP_TYPE_D; + + case 'I': + case 'i': + return FTP_TYPE_I; + } + return FTP_TYPE_NONE; +} + +//============================================================================ +bool INetURLObject::hasDosVolume(FSysStyle eStyle) const +{ + sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + return (eStyle & FSYS_DOS) != 0 + && m_aPath.getLength() >= 3 + && p[0] == '/' + && INetMIME::isAlpha(p[1]) + && p[2] == ':' + && (m_aPath.getLength() == 3 || p[3] == '/'); +} + +//============================================================================ +sal_uInt32 INetURLObject::getIMAPUID() const +{ + if (m_eScheme == INET_PROT_IMAP + && m_aPath.getLength() >= RTL_CONSTASCII_LENGTH("/;uid=") + 1) + { + sal_Unicode const * pBegin = m_aAbsURIRef.getStr() + + m_aPath.getBegin() + + RTL_CONSTASCII_LENGTH("/;uid="); + sal_Unicode const * pEnd = pBegin + m_aPath.getLength(); + sal_Unicode const * p = pEnd; + while (p > pBegin && INetMIME::isDigit(p[-1])) + --p; + if (p < pEnd && *--p != '0' + && rtl::OUString(m_aAbsURIRef).copy( + p - RTL_CONSTASCII_LENGTH("/;uid=") - m_aAbsURIRef.getStr(), + RTL_CONSTASCII_LENGTH("/;uid=")).equalsIgnoreAsciiCaseAscii("/;uid=") + ) + { + sal_uInt32 nUID; + if (INetMIME::scanUnsigned(p, pEnd, false, nUID)) + return nUID; + } + } + return 0; +} + +//============================================================================ +// static +rtl::OUString INetURLObject::encodeText(sal_Unicode const * pBegin, + sal_Unicode const * pEnd, bool bOctets, + Part ePart, sal_Char cEscapePrefix, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, + bool bKeepVisibleEscapes) +{ + rtl::OUStringBuffer aResult; + while (pBegin < pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, bOctets, cEscapePrefix, + eMechanism, eCharset, eEscapeType); + appendUCS4(aResult, nUTF32, eEscapeType, bOctets, ePart, + cEscapePrefix, eCharset, bKeepVisibleEscapes); + } + return aResult.makeStringAndClear(); +} + +//============================================================================ +// static +rtl::OUString INetURLObject::decode(sal_Unicode const * pBegin, + sal_Unicode const * pEnd, + sal_Char cEscapePrefix, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + switch (eMechanism) + { + case NO_DECODE: + return rtl::OUString(pBegin, pEnd - pBegin); + + case DECODE_TO_IURI: + eCharset = RTL_TEXTENCODING_UTF8; + break; + + default: + break; + } + rtl::OUStringBuffer aResult; + while (pBegin < pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, false, cEscapePrefix, + WAS_ENCODED, eCharset, eEscapeType); + switch (eEscapeType) + { + case ESCAPE_NO: + aResult.append(sal_Unicode(nUTF32)); + break; + + case ESCAPE_OCTET: + appendEscape(aResult, cEscapePrefix, nUTF32); + break; + + case ESCAPE_UTF32: + if ( + INetMIME::isUSASCII(nUTF32) && + ( + eMechanism == DECODE_TO_IURI || + ( + eMechanism == DECODE_UNAMBIGUOUS && + mustEncode(nUTF32, PART_UNAMBIGUOUS) + ) + ) + ) + { + appendEscape(aResult, cEscapePrefix, nUTF32); + } + else + aResult.append(sal_Unicode(nUTF32)); + break; + } + } + return aResult.makeStringAndClear(); +} + +//============================================================================ +rtl::OUString INetURLObject::GetURLNoPass(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + INetURLObject aTemp(*this); + aTemp.clearPassword(); + return aTemp.GetMainURL(eMechanism, eCharset); +} + +//============================================================================ +rtl::OUString INetURLObject::GetURLNoMark(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + INetURLObject aTemp(*this); + aTemp.clearFragment(); + return aTemp.GetMainURL(eMechanism, eCharset); +} + +//============================================================================ +rtl::OUString +INetURLObject::getAbbreviated( + star::uno::Reference< star::util::XStringWidth > const & rStringWidth, + sal_Int32 nWidth, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) + const +{ + OSL_ENSURE(rStringWidth.is(), "specification violation"); + sal_Char cEscapePrefix = getEscapePrefix(); + rtl::OUStringBuffer aBuffer; + // make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme + // is empty ("") in that case, so take the scheme from m_aAbsURIRef + if (m_eScheme != INET_PROT_GENERIC) + { + aBuffer.appendAscii(getSchemeInfo().m_pScheme); + } + else + { + if (m_aAbsURIRef) + { + sal_Unicode const * pSchemeBegin + = m_aAbsURIRef.getStr(); + sal_Unicode const * pSchemeEnd = pSchemeBegin; + + while (pSchemeEnd[0] != ':') + { + ++pSchemeEnd; + } + aBuffer.append(pSchemeBegin, pSchemeEnd - pSchemeBegin); + } + } + aBuffer.append(static_cast< sal_Unicode >(':')); + bool bAuthority = getSchemeInfo().m_bAuthority; + sal_Unicode const * pCoreBegin + = m_aAbsURIRef.getStr() + (bAuthority ? getAuthorityBegin() : + m_aPath.getBegin()); + sal_Unicode const * pCoreEnd + = m_aAbsURIRef.getStr() + m_aPath.getBegin() + m_aPath.getLength(); + bool bSegment = false; + if (getSchemeInfo().m_bHierarchical) + { + rtl::OUString aRest; + if (m_aQuery.isPresent()) + aRest = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("?...")); + else if (m_aFragment.isPresent()) + aRest = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("#...")); + rtl::OUStringBuffer aTrailer; + sal_Unicode const * pBegin = pCoreBegin; + sal_Unicode const * pEnd = pCoreEnd; + sal_Unicode const * pPrefixBegin = pBegin; + sal_Unicode const * pSuffixEnd = pEnd; + bool bPrefix = true; + bool bSuffix = true; + do + { + if (bSuffix) + { + sal_Unicode const * p = pSuffixEnd - 1; + if (pSuffixEnd == pCoreEnd && *p == '/') + --p; + while (*p != '/') + --p; + if (bAuthority && p == pCoreBegin + 1) + --p; + rtl::OUString + aSegment(decode(p + (p == pBegin && pBegin != pCoreBegin ? + 1 : 0), + pSuffixEnd, + cEscapePrefix, + eMechanism, + eCharset)); + pSuffixEnd = p; + rtl::OUStringBuffer aResult(aBuffer); + if (pSuffixEnd != pBegin) + aResult.appendAscii(RTL_CONSTASCII_STRINGPARAM("...")); + aResult.append(aSegment); + aResult.append(aTrailer); + aResult.append(aRest); + if (rStringWidth-> + queryStringWidth(aResult.makeStringAndClear()) + <= nWidth) + { + aTrailer.insert(0, aSegment); + bSegment = true; + pEnd = pSuffixEnd; + } + else + bSuffix = false; + if (pPrefixBegin > pSuffixEnd) + pPrefixBegin = pSuffixEnd; + if (pBegin == pEnd) + break; + } + if (bPrefix) + { + sal_Unicode const * p + = pPrefixBegin + + (bAuthority && pPrefixBegin == pCoreBegin ? 2 : + 1); + OSL_ASSERT(p <= pEnd); + while (p < pEnd && *p != '/') + ++p; + if (p == pCoreEnd - 1 && *p == '/') + ++p; + rtl::OUString + aSegment(decode(pPrefixBegin + + (pPrefixBegin == pCoreBegin ? 0 : + 1), + p == pEnd ? p : p + 1, + cEscapePrefix, + eMechanism, + eCharset)); + pPrefixBegin = p; + rtl::OUStringBuffer aResult(aBuffer); + aResult.append(aSegment); + if (pPrefixBegin != pEnd) + aResult.appendAscii(RTL_CONSTASCII_STRINGPARAM("...")); + aResult.append(aTrailer); + aResult.append(aRest); + if (rStringWidth-> + queryStringWidth(aResult.makeStringAndClear()) + <= nWidth) + { + aBuffer.append(aSegment); + bSegment = true; + pBegin = pPrefixBegin; + } + else + bPrefix = false; + if (pPrefixBegin > pSuffixEnd) + pSuffixEnd = pPrefixBegin; + if (pBegin == pEnd) + break; + } + } + while (bPrefix || bSuffix); + if (bSegment) + { + if (pPrefixBegin != pBegin || pSuffixEnd != pEnd) + aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("...")); + aBuffer.append(aTrailer); + } + } + if (!bSegment) + aBuffer.append(decode(pCoreBegin, + pCoreEnd, + cEscapePrefix, + eMechanism, + eCharset)); + if (m_aQuery.isPresent()) + { + aBuffer.append(static_cast< sal_Unicode >('?')); + aBuffer.append(decode(m_aQuery, cEscapePrefix, eMechanism, eCharset)); + } + if (m_aFragment.isPresent()) + { + aBuffer.append(static_cast< sal_Unicode >('#')); + aBuffer. + append(decode(m_aFragment, cEscapePrefix, eMechanism, eCharset)); + } + if (aBuffer.getLength() != 0) + { + rtl::OUStringBuffer aResult(aBuffer); + if (rStringWidth->queryStringWidth(aResult.makeStringAndClear()) + > nWidth) + for (sal_Int32 i = aBuffer.getLength();;) + { + if (i == 0) + { + aBuffer.setLength(aBuffer.getLength() - 1); + if (aBuffer.getLength() == 0) + break; + } + else + { + aBuffer.setLength(--i); + aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("...")); + } + aResult = aBuffer; + if (rStringWidth-> + queryStringWidth(aResult.makeStringAndClear()) + <= nWidth) + break; + } + } + return aBuffer.makeStringAndClear(); +} + +//============================================================================ +bool INetURLObject::operator ==(INetURLObject const & rObject) const +{ + if (m_eScheme != rObject.m_eScheme) + return false; + if (m_eScheme == INET_PROT_NOT_VALID) + return (m_aAbsURIRef == rObject.m_aAbsURIRef) != false; + if ((m_aScheme.compare( + rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef) + != 0) + || GetUser(NO_DECODE) != rObject.GetUser(NO_DECODE) + || GetPass(NO_DECODE) != rObject.GetPass(NO_DECODE) + || !GetHost(NO_DECODE).equalsIgnoreAsciiCase( + rObject.GetHost(NO_DECODE)) + || GetPort() != rObject.GetPort() + || HasParam() != rObject.HasParam() + || GetParam(NO_DECODE) != rObject.GetParam(NO_DECODE) + || GetMsgId(NO_DECODE) != rObject.GetMsgId(NO_DECODE)) + return false; + rtl::OUString aPath1(GetURLPath(NO_DECODE)); + rtl::OUString aPath2(rObject.GetURLPath(NO_DECODE)); + switch (m_eScheme) + { + case INET_PROT_FILE: + { + // If the URL paths of two file URLs only differ in that one has a + // final '/' and the other has not, take the two paths as + // equivalent (this could be usefull for other schemes, too): + sal_Int32 nLength = aPath1.getLength(); + switch (nLength - aPath2.getLength()) + { + case -1: + if (aPath2.getStr()[nLength] != '/') + return false; + break; + + case 0: + break; + + case 1: + if (aPath1.getStr()[--nLength] != '/') + return false; + break; + + default: + return false; + } + return aPath1.compareTo(aPath2, nLength) == 0; + } + + default: + return (aPath1 == aPath2) != false; + } +} + +//============================================================================ +bool INetURLObject::operator <(INetURLObject const & rObject) const +{ + sal_Int32 nCompare = m_aScheme.compare( + rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef); + if (nCompare < 0) { + return true; + } else if (nCompare > 0) { + return false; + } + sal_uInt32 nPort1 = GetPort(); + sal_uInt32 nPort2 = rObject.GetPort(); + if (nPort1 < nPort2) + return true; + else if (nPort1 > nPort2) + return false; + nCompare = GetUser(NO_DECODE).compareTo(rObject.GetUser(NO_DECODE)); + if (nCompare < 0) + return true; + else if (nCompare > 0) + return false; + nCompare = GetPass(NO_DECODE).compareTo(rObject.GetPass(NO_DECODE)); + if (nCompare < 0) + return true; + else if (nCompare > 0) + return false; + nCompare = GetHost(NO_DECODE).compareTo(rObject.GetHost(NO_DECODE)); + if (nCompare < 0) + return true; + else if (nCompare > 0) + return false; + const rtl::OUString &rPath1(GetURLPath(NO_DECODE)); + const rtl::OUString &rPath2(rObject.GetURLPath(NO_DECODE)); + nCompare = rPath1.compareTo(rPath2); + if (nCompare < 0) + return true; + else if (nCompare > 0) + return false; + nCompare = GetParam(NO_DECODE).compareTo(rObject.GetParam(NO_DECODE)); + if (nCompare < 0) + return true; + else if (nCompare > 0) + return false; + return GetMsgId(NO_DECODE).compareTo(rObject.GetMsgId(NO_DECODE)) < 0; +} + +//============================================================================ +bool INetURLObject::ConcatData(INetProtocol eTheScheme, + rtl::OUString const & rTheUser, + rtl::OUString const & rThePassword, + rtl::OUString const & rTheHost, + sal_uInt32 nThePort, + rtl::OUString const & rThePath, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + setInvalid(); + m_eScheme = eTheScheme; + if (HasError() || m_eScheme == INET_PROT_GENERIC) + return false; + m_aAbsURIRef.setLength(0); + m_aAbsURIRef.appendAscii(getSchemeInfo().m_pScheme); + m_aAbsURIRef.append(sal_Unicode(':')); + if (getSchemeInfo().m_bAuthority) + { + m_aAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + bool bUserInfo = false; + if (getSchemeInfo().m_bUser) + { + if (m_eScheme == INET_PROT_IMAP && rTheUser.getLength() == 0) + { + setInvalid(); + return false; + } + if (rTheUser.getLength() != 0) + { + m_aUser.set(m_aAbsURIRef, + encodeText(rTheUser, false, + m_eScheme == INET_PROT_IMAP ? + PART_IMAP_ACHAR : + m_eScheme == INET_PROT_VIM ? + PART_VIM : + PART_USER_PASSWORD, + getEscapePrefix(), eMechanism, + eCharset, false), + m_aAbsURIRef.getLength()); + bUserInfo = true; + } + } + else if (rTheUser.getLength() != 0) + { + setInvalid(); + return false; + } + if (rThePassword.getLength() != 0) + { + if (getSchemeInfo().m_bPassword) + { + m_aAbsURIRef.append(sal_Unicode(':')); + m_aAuth.set(m_aAbsURIRef, + encodeText(rThePassword, false, + m_eScheme == INET_PROT_VIM ? + PART_VIM : PART_USER_PASSWORD, + getEscapePrefix(), eMechanism, + eCharset, false), + m_aAbsURIRef.getLength()); + bUserInfo = true; + } + else + { + setInvalid(); + return false; + } + } + if (bUserInfo && getSchemeInfo().m_bHost) + m_aAbsURIRef.append(sal_Unicode('@')); + if (getSchemeInfo().m_bHost) + { + rtl::OUStringBuffer aSynHost(rTheHost); + bool bNetBiosName = false; + switch (m_eScheme) + { + case INET_PROT_FILE: + { + rtl::OUString sTemp(aSynHost); + if (sTemp.equalsIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM("localhost"))) + { + aSynHost.setLength(0); + } + bNetBiosName = true; + } + break; + + case INET_PROT_LDAP: + if (aSynHost.getLength() == 0 && nThePort != 0) + { + setInvalid(); + return false; + } + break; + + default: + if (aSynHost.getLength() == 0) + { + setInvalid(); + return false; + } + break; + } + if (!parseHostOrNetBiosName( + aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(), + false, eMechanism, eCharset, bNetBiosName, &aSynHost)) + { + setInvalid(); + return false; + } + m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear(), + m_aAbsURIRef.getLength()); + if (nThePort != 0) + { + if (getSchemeInfo().m_bPort) + { + m_aAbsURIRef.append(sal_Unicode(':')); + m_aPort.set(m_aAbsURIRef, + rtl::OUString::valueOf(sal_Int64(nThePort)), + m_aAbsURIRef.getLength()); + } + else + { + setInvalid(); + return false; + } + } + } + else if (rTheHost.getLength() != 0 || nThePort != 0) + { + setInvalid(); + return false; + } + } + rtl::OUStringBuffer aSynPath; + sal_Unicode const * p = rThePath.getStr(); + sal_Unicode const * pEnd = p + rThePath.getLength(); + if (!parsePath(m_eScheme, &p, pEnd, false, eMechanism, eCharset, false, '/', + 0x80000000, 0x80000000, 0x80000000, aSynPath) + || p != pEnd) + { + setInvalid(); + return false; + } + m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear(), + m_aAbsURIRef.getLength()); + return true; +} + +//============================================================================ +// static +rtl::OUString INetURLObject::GetAbsURL(rtl::OUString const & rTheBaseURIRef, + rtl::OUString const & rTheRelURIRef, + bool bIgnoreFragment, + EncodeMechanism eEncodeMechanism, + DecodeMechanism eDecodeMechanism, + rtl_TextEncoding eCharset, + FSysStyle eStyle) +{ + // Backwards compatibility: + if (rTheRelURIRef.getLength() == 0 || rTheRelURIRef[0] == '#') + return rTheRelURIRef; + + INetURLObject aTheAbsURIRef; + bool bWasAbsolute; + return INetURLObject(rTheBaseURIRef, eEncodeMechanism, eCharset). + convertRelToAbs(rTheRelURIRef, false, aTheAbsURIRef, + bWasAbsolute, eEncodeMechanism, + eCharset, bIgnoreFragment, false, + false, eStyle) + || eEncodeMechanism != WAS_ENCODED + || eDecodeMechanism != DECODE_TO_IURI + || eCharset != RTL_TEXTENCODING_UTF8 ? + aTheAbsURIRef.GetMainURL(eDecodeMechanism, eCharset) : + rTheRelURIRef; +} + +//============================================================================ +rtl::OUString INetURLObject::getExternalURL(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + rtl::OUString aTheExtURIRef; + translateToExternal( + rtl::OUString(m_aAbsURIRef), aTheExtURIRef, eMechanism, eCharset); + return aTheExtURIRef; +} + +//============================================================================ +// static +rtl::OUString INetURLObject::GetScheme(INetProtocol eTheScheme) +{ + return rtl::OUString::createFromAscii(getSchemeInfo(eTheScheme).m_pPrefix); +} + +//============================================================================ +// static +INetProtocol INetURLObject::CompareProtocolScheme(rtl::OUString const & + rTheAbsURIRef) +{ + sal_Unicode const * p = rTheAbsURIRef.getStr(); + PrefixInfo const * pPrefix = getPrefix(p, p + rTheAbsURIRef.getLength()); + return pPrefix ? pPrefix->m_eScheme : INET_PROT_NOT_VALID; +} + +//============================================================================ +bool INetURLObject::hasPassword() const +{ + return m_aAuth.isPresent() && getSchemeInfo().m_bPassword; +} + +//============================================================================ +void INetURLObject::makeAuthCanonic() +{ + if (m_eScheme == INET_PROT_IMAP && m_aAuth.getLength() == 1 + && m_aAbsURIRef.charAt(m_aAuth.getBegin()) == '*') + { + lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin() + - RTL_CONSTASCII_LENGTH(";AUTH="), + RTL_CONSTASCII_LENGTH(";AUTH=*")); + sal_Int32 nDelta = m_aAuth.clear() - RTL_CONSTASCII_LENGTH(";AUTH="); + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + } +} + +//============================================================================ +rtl::OUString INetURLObject::GetHostPort(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + // Check because PROT_VND_SUN_STAR_HELP, PROT_VND_SUN_STAR_HIER, and + // PROT_VND_SUN_STAR_PKG misuse m_aHost: + if (!getSchemeInfo().m_bHost) + return rtl::OUString(); + rtl::OUStringBuffer aHostPort(decode(m_aHost, getEscapePrefix(), + eMechanism, eCharset)); + if (m_aPort.isPresent()) + { + aHostPort.append(sal_Unicode(':')); + aHostPort.append(decode(m_aPort, getEscapePrefix(), + eMechanism, eCharset)); + } + return aHostPort.makeStringAndClear(); +} + +//============================================================================ +sal_uInt32 INetURLObject::GetPort() const +{ + if (m_aPort.isPresent()) + { + sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin(); + sal_Unicode const * pEnd = p + m_aPort.getLength(); + sal_uInt32 nThePort; + if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd) + return nThePort; + } + return 0; +} + +//============================================================================ +bool INetURLObject::SetPort(sal_uInt32 nThePort) +{ + if (getSchemeInfo().m_bPort && m_aHost.isPresent()) + { + rtl::OUString aNewPort(rtl::OUString::valueOf(sal_Int64(nThePort))); + sal_Int32 nDelta; + if (m_aPort.isPresent()) + nDelta = m_aPort.set(m_aAbsURIRef, aNewPort); + else + { + m_aAbsURIRef.insert(m_aHost.getEnd(), sal_Unicode(':')); + nDelta = m_aPort.set(m_aAbsURIRef, aNewPort, m_aHost.getEnd() + 1) + + 1; + } + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + return true; + } + return false; +} + +//============================================================================ +void INetURLObject::makePortCanonic() +{ + if (m_aPort.isPresent()) + { + sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin(); + sal_Unicode const * pEnd = p + m_aPort.getLength(); + sal_uInt32 nThePort; + if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd) + { + sal_Int32 nDelta; + if (nThePort != 0 && nThePort == getSchemeInfo().m_nDefaultPort) + { + lcl_Erase(m_aAbsURIRef, m_aPort.getBegin() - 1, + m_aPort.getLength() + 1); + nDelta = m_aPort.clear() - 1; + } + else + nDelta = m_aPort.set(m_aAbsURIRef, + rtl::OUString::valueOf(sal_Int64(nThePort))); + m_aPath += nDelta; + m_aQuery += nDelta; + m_aFragment += nDelta; + } + } +} + +//============================================================================ +sal_Int32 INetURLObject::getSegmentCount(bool bIgnoreFinalSlash) const +{ + if (!checkHierarchical()) + return 0; + + sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pEnd = p + m_aPath.getLength(); + if (bIgnoreFinalSlash && pEnd > p && pEnd[-1] == '/') + --pEnd; + sal_Int32 n = p == pEnd || *p == '/' ? 0 : 1; + while (p != pEnd) + if (*p++ == '/') + ++n; + return n; +} + +//============================================================================ +bool INetURLObject::removeSegment(sal_Int32 nIndex, bool bIgnoreFinalSlash) +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return false; + + rtl::OUStringBuffer aNewPath; + aNewPath.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(), + aSegment.getBegin() - m_aPath.getBegin()); + if (bIgnoreFinalSlash && aSegment.getEnd() == m_aPath.getEnd()) + aNewPath.append(sal_Unicode('/')); + else + aNewPath.append(m_aAbsURIRef.getStr() + aSegment.getEnd(), + m_aPath.getEnd() - aSegment.getEnd()); + if (aNewPath.getLength() == 0 && !aSegment.isEmpty() && + m_aAbsURIRef[aSegment.getBegin()] == '/') + { + aNewPath.append(sal_Unicode('/')); + } + + return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, + RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +rtl::OUString INetURLObject::getName(sal_Int32 nIndex, bool bIgnoreFinalSlash, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return rtl::OUString(); + + sal_Unicode const * pSegBegin + = m_aAbsURIRef.getStr() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + if (pSegBegin < pSegEnd && *pSegBegin == '/') + ++pSegBegin; + sal_Unicode const * p = pSegBegin; + while (p != pSegEnd && *p != ';') + ++p; + + return decode(pSegBegin, p, getEscapePrefix(), eMechanism, eCharset); +} + +//============================================================================ +bool INetURLObject::setName(rtl::OUString const & rTheName, sal_Int32 nIndex, + bool bIgnoreFinalSlash, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin + = m_aAbsURIRef.getStr() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + if (pSegBegin < pSegEnd && *pSegBegin == '/') + ++pSegBegin; + sal_Unicode const * p = pSegBegin; + while (p != pSegEnd && *p != ';') + ++p; + + rtl::OUStringBuffer aNewPath; + aNewPath.append(pPathBegin, pSegBegin - pPathBegin); + aNewPath.append(encodeText(rTheName, false, PART_PCHAR, getEscapePrefix(), + eMechanism, eCharset, true)); + aNewPath.append(p, pPathEnd - p); + + return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, + RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +bool INetURLObject::hasExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash) + const +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return false; + + sal_Unicode const * pSegBegin + = m_aAbsURIRef.getStr() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + if (pSegBegin < pSegEnd && *pSegBegin == '/') + ++pSegBegin; + for (sal_Unicode const * p = pSegBegin; p != pSegEnd && *p != ';'; ++p) + if (*p == '.' && p != pSegBegin) + return true; + return false; +} + +//============================================================================ +rtl::OUString INetURLObject::getBase(sal_Int32 nIndex, bool bIgnoreFinalSlash, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return rtl::OUString(); + + sal_Unicode const * pSegBegin + = m_aAbsURIRef.getStr() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + if (pSegBegin < pSegEnd && *pSegBegin == '/') + ++pSegBegin; + sal_Unicode const * pExtension = 0; + sal_Unicode const * p = pSegBegin; + for (; p != pSegEnd && *p != ';'; ++p) + if (*p == '.' && p != pSegBegin) + pExtension = p; + if (!pExtension) + pExtension = p; + + return decode(pSegBegin, pExtension, getEscapePrefix(), eMechanism, + eCharset); +} + +//============================================================================ +bool INetURLObject::setBase(rtl::OUString const & rTheBase, sal_Int32 nIndex, + bool bIgnoreFinalSlash, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin + = m_aAbsURIRef.getStr() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + if (pSegBegin < pSegEnd && *pSegBegin == '/') + ++pSegBegin; + sal_Unicode const * pExtension = 0; + sal_Unicode const * p = pSegBegin; + for (; p != pSegEnd && *p != ';'; ++p) + if (*p == '.' && p != pSegBegin) + pExtension = p; + if (!pExtension) + pExtension = p; + + rtl::OUStringBuffer aNewPath; + aNewPath.append(pPathBegin, pSegBegin - pPathBegin); + aNewPath.append(encodeText(rTheBase, false, PART_PCHAR, getEscapePrefix(), + eMechanism, eCharset, true)); + aNewPath.append(pExtension, pPathEnd - pExtension); + + return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, + RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +rtl::OUString INetURLObject::getExtension(sal_Int32 nIndex, + bool bIgnoreFinalSlash, + DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return rtl::OUString(); + + sal_Unicode const * pSegBegin + = m_aAbsURIRef.getStr() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + if (pSegBegin < pSegEnd && *pSegBegin == '/') + ++pSegBegin; + sal_Unicode const * pExtension = 0; + sal_Unicode const * p = pSegBegin; + for (; p != pSegEnd && *p != ';'; ++p) + if (*p == '.' && p != pSegBegin) + pExtension = p; + + if (!pExtension) + return rtl::OUString(); + + return decode(pExtension + 1, p, getEscapePrefix(), eMechanism, eCharset); +} + +//============================================================================ +bool INetURLObject::setExtension(rtl::OUString const & rTheExtension, + sal_Int32 nIndex, bool bIgnoreFinalSlash, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin + = m_aAbsURIRef.getStr() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + if (pSegBegin < pSegEnd && *pSegBegin == '/') + ++pSegBegin; + sal_Unicode const * pExtension = 0; + sal_Unicode const * p = pSegBegin; + for (; p != pSegEnd && *p != ';'; ++p) + if (*p == '.' && p != pSegBegin) + pExtension = p; + if (!pExtension) + pExtension = p; + + rtl::OUStringBuffer aNewPath; + aNewPath.append(pPathBegin, pExtension - pPathBegin); + aNewPath.append(sal_Unicode('.')); + aNewPath.append(encodeText(rTheExtension, false, PART_PCHAR, + getEscapePrefix(), eMechanism, eCharset, true)); + aNewPath.append(p, pPathEnd - p); + + return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, + RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +bool INetURLObject::removeExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash) +{ + SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); + if (!aSegment.isPresent()) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + sal_Unicode const * pSegBegin + = m_aAbsURIRef.getStr() + aSegment.getBegin(); + sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); + + if (pSegBegin < pSegEnd && *pSegBegin == '/') + ++pSegBegin; + sal_Unicode const * pExtension = 0; + sal_Unicode const * p = pSegBegin; + for (; p != pSegEnd && *p != ';'; ++p) + if (*p == '.' && p != pSegBegin) + pExtension = p; + if (!pExtension) + return true; + + rtl::OUStringBuffer aNewPath; + aNewPath.append(pPathBegin, pExtension - pPathBegin); + aNewPath.append(p, pPathEnd - p); + + return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, + RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +bool INetURLObject::hasFinalSlash() const +{ + if (!checkHierarchical()) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + return pPathEnd > pPathBegin && pPathEnd[-1] == '/'; +} + +//============================================================================ +bool INetURLObject::setFinalSlash() +{ + if (!checkHierarchical()) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + if (pPathEnd > pPathBegin && pPathEnd[-1] == '/') + return true; + + rtl::OUStringBuffer aNewPath; + aNewPath.append(pPathBegin, pPathEnd - pPathBegin); + aNewPath.append(sal_Unicode('/')); + + return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, + RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +bool INetURLObject::removeFinalSlash() +{ + if (!checkHierarchical()) + return false; + + sal_Unicode const * pPathBegin + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); + if (pPathEnd <= pPathBegin || pPathEnd[-1] != '/') + return true; + + --pPathEnd; + if (pPathEnd == pPathBegin && *pPathBegin == '/') + return false; + rtl::OUString aNewPath(pPathBegin, pPathEnd - pPathBegin); + + return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8); +} + +//============================================================================ +// static +rtl::OUString INetURLObject::createFragment(rtl::OUString const & rText) +{ + rtl::OUString aFragment(rText); + for (sal_Int32 i = 0; i < aFragment.getLength();) + { + sal_Unicode c = aFragment.getStr()[i]; + if (mustEncode(c, PART_CREATEFRAGMENT)) + aFragment = aFragment.replaceAt(i, 1, rtl::OUString()); + else + ++i; + } + return aFragment; +} + +//============================================================================ +bool INetURLObject::setFSysPath(rtl::OUString const & rFSysPath, + FSysStyle eStyle) +{ + sal_Unicode const * pFSysBegin = rFSysPath.getStr(); + sal_Unicode const * pFSysEnd = pFSysBegin + rFSysPath.getLength(); + + switch ((eStyle & FSYS_VOS ? 1 : 0) + + (eStyle & FSYS_UNX ? 1 : 0) + + (eStyle & FSYS_DOS ? 1 : 0) + + (eStyle & FSYS_MAC ? 1 : 0)) + { + case 0: + return false; + + case 1: + break; + + default: + if (eStyle & FSYS_VOS + && pFSysEnd - pFSysBegin >= 2 + && pFSysBegin[0] == '/' + && pFSysBegin[1] == '/') + { + if (pFSysEnd - pFSysBegin >= 3 + && pFSysBegin[2] == '.' + && (pFSysEnd - pFSysBegin == 3 || pFSysBegin[3] == '/')) + { + eStyle = FSYS_VOS; // Production T1 + break; + } + + sal_Unicode const * p = pFSysBegin + 2; + rtl::OUString aHost; + if (parseHost(p, pFSysEnd, aHost) + && (p == pFSysEnd || *p == '/')) + { + eStyle = FSYS_VOS; // Production T2 + break; + } + } + + if (eStyle & FSYS_DOS + && pFSysEnd - pFSysBegin >= 2 + && pFSysBegin[0] == '\\' + && pFSysBegin[1] == '\\') + { + sal_Unicode const * p = pFSysBegin + 2; + rtl::OUString aHost; + if (parseHost(p, pFSysEnd, aHost) + && (p == pFSysEnd || *p == '\\')) + { + eStyle = FSYS_DOS; // Production T3 + break; + } + } + + if (eStyle & FSYS_DOS + && pFSysEnd - pFSysBegin >= 2 + && INetMIME::isAlpha(pFSysBegin[0]) + && pFSysBegin[1] == ':' + && (pFSysEnd - pFSysBegin == 2 + || pFSysBegin[2] == '/' + || pFSysBegin[2] == '\\')) + { + eStyle = FSYS_DOS; // Productions T4, T5 + break; + } + + if (!(eStyle & (FSYS_UNX | FSYS_DOS | FSYS_MAC))) + return false; + + eStyle = guessFSysStyleByCounting(pFSysBegin, pFSysEnd, eStyle); + // Production T6 + break; + } + + rtl::OUStringBuffer aSynAbsURIRef(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("file://"))); + + switch (eStyle) + { + case FSYS_VOS: + { + sal_Unicode const * p = pFSysBegin; + if (pFSysEnd - p < 2 || *p++ != '/' || *p++ != '/') + return false; + if (p != pFSysEnd && *p == '.' + && (pFSysEnd - p == 1 || p[1] == '/')) + ++p; + for (; p != pFSysEnd; ++p) + switch (*p) + { + case '#': + case '%': + appendEscape(aSynAbsURIRef, '%', *p); + break; + + default: + aSynAbsURIRef.append(*p); + break; + } + break; + } + + case FSYS_UNX: + { + sal_Unicode const * p = pFSysBegin; + if (p != pFSysEnd && *p != '/') + return false; + for (; p != pFSysEnd; ++p) + switch (*p) + { + case '|': + case '#': + case '%': + appendEscape(aSynAbsURIRef, '%', *p); + break; + + default: + aSynAbsURIRef.append(*p); + break; + } + break; + } + + case FSYS_DOS: + { + sal_uInt32 nAltDelimiter = 0x80000000; + sal_Unicode const * p = pFSysBegin; + if (pFSysEnd - p >= 3 && p[0] == '\\' && p[1] == '\\') + p += 2; + else + { + aSynAbsURIRef.append(sal_Unicode('/')); + if (pFSysEnd - p >= 2 + && INetMIME::isAlpha(p[0]) + && p[1] == ':' + && (pFSysEnd - p == 2 || p[2] == '\\' || p[2] == '/')) + nAltDelimiter = '/'; + } + for (; p != pFSysEnd; ++p) + if (*p == '\\' || *p == nAltDelimiter) + aSynAbsURIRef.append(sal_Unicode('/')); + else + switch (*p) + { + case '/': + case '#': + case '%': + appendEscape(aSynAbsURIRef, '%', *p); + break; + + default: + aSynAbsURIRef.append(*p); + break; + } + break; + } + + case FSYS_MAC: + aSynAbsURIRef.append(sal_Unicode('/')); + {for (sal_Unicode const * p = pFSysBegin; p != pFSysEnd; ++p) + switch (*p) + { + case ':': + aSynAbsURIRef.append(sal_Unicode('/')); + break; + + case '/': + case '|': + case '#': + case '%': + appendEscape(aSynAbsURIRef, '%', *p); + break; + + default: + aSynAbsURIRef.append(*p); + break; + } + } + break; + + default: + OSL_ASSERT(false); + break; + } + + INetURLObject aTemp(aSynAbsURIRef.makeStringAndClear(), WAS_ENCODED, + RTL_TEXTENCODING_UTF8); + if (aTemp.HasError()) + return false; + + *this = aTemp; + return true; +} + +//============================================================================ +rtl::OUString INetURLObject::getFSysPath(FSysStyle eStyle, + sal_Unicode * pDelimiter) const +{ + if (m_eScheme != INET_PROT_FILE) + return rtl::OUString(); + + if ((eStyle & FSYS_VOS ? 1 : 0) + + (eStyle & FSYS_UNX ? 1 : 0) + + (eStyle & FSYS_DOS ? 1 : 0) + + (eStyle & FSYS_MAC ? 1 : 0) + > 1) + { + eStyle = eStyle & FSYS_VOS + && m_aHost.isPresent() + && m_aHost.getLength() > 0 ? + FSYS_VOS : + hasDosVolume(eStyle) + || ((eStyle & FSYS_DOS) != 0 + && m_aHost.isPresent() + && m_aHost.getLength() > 0) ? + FSYS_DOS : + eStyle & FSYS_UNX + && (!m_aHost.isPresent() || m_aHost.getLength() == 0) ? + FSYS_UNX : + FSysStyle(0); + } + + switch (eStyle) + { + case FSYS_VOS: + { + if (pDelimiter) + *pDelimiter = '/'; + + rtl::OUStringBuffer aSynFSysPath; + aSynFSysPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); + if (m_aHost.isPresent() && m_aHost.getLength() > 0) + aSynFSysPath.append(decode(m_aHost, '%', DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8)); + else + aSynFSysPath.append(sal_Unicode('.')); + aSynFSysPath.append(decode(m_aPath, '%', DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8)); + return aSynFSysPath.makeStringAndClear(); + } + + case FSYS_UNX: + { + if (m_aHost.isPresent() && m_aHost.getLength() > 0) + return rtl::OUString(); + + if (pDelimiter) + *pDelimiter = '/'; + + return decode(m_aPath, '%', DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8); + } + + case FSYS_DOS: + { + if (pDelimiter) + *pDelimiter = '\\'; + + rtl::OUStringBuffer aSynFSysPath; + if (m_aHost.isPresent() && m_aHost.getLength() > 0) + { + aSynFSysPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("\\\\")); + aSynFSysPath.append(decode(m_aHost, '%', DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8)); + aSynFSysPath.append(sal_Unicode('\\')); + } + sal_Unicode const * p + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pEnd = p + m_aPath.getLength(); + DBG_ASSERT(p < pEnd && *p == '/', + "INetURLObject::getFSysPath(): Bad path"); + ++p; + while (p < pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(p, pEnd, false, '%', WAS_ENCODED, + RTL_TEXTENCODING_UTF8, + eEscapeType); + if (eEscapeType == ESCAPE_NO && nUTF32 == '/') + aSynFSysPath.append(sal_Unicode('\\')); + else + aSynFSysPath.appendUtf32(nUTF32); + } + return aSynFSysPath.makeStringAndClear(); + } + + case FSYS_MAC: + { + if (m_aHost.isPresent() && m_aHost.getLength() > 0) + return rtl::OUString(); + + if (pDelimiter) + *pDelimiter = ':'; + + rtl::OUStringBuffer aSynFSysPath; + sal_Unicode const * p + = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pEnd = p + m_aPath.getLength(); + DBG_ASSERT(p < pEnd && *p == '/', + "INetURLObject::getFSysPath(): Bad path"); + ++p; + while (p < pEnd) + { + EscapeType eEscapeType; + sal_uInt32 nUTF32 = getUTF32(p, pEnd, false, '%', WAS_ENCODED, + RTL_TEXTENCODING_UTF8, + eEscapeType); + if (eEscapeType == ESCAPE_NO && nUTF32 == '/') + aSynFSysPath.append(sal_Unicode(':')); + else + aSynFSysPath.appendUtf32(nUTF32); + } + return aSynFSysPath.makeStringAndClear(); + } + + default: + return rtl::OUString(); + } +} + +//============================================================================ +bool INetURLObject::HasMsgId() const +{ + if (m_eScheme != INET_PROT_POP3) + return false; + sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pEnd = p + m_aPath.getLength(); + for (; p < pEnd; ++p) + if (*p == '<') + return true; + return false; +} + +//============================================================================ +rtl::OUString INetURLObject::GetMsgId(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + if (m_eScheme != INET_PROT_POP3) + return rtl::OUString(); + sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); + sal_Unicode const * pEnd = p + m_aPath.getLength(); + for (; p < pEnd; ++p) + if (*p == '<') + return decode(p, pEnd, getEscapePrefix(), eMechanism, eCharset); + return rtl::OUString(); +} + +//============================================================================ +// static +void INetURLObject::appendUCS4Escape(rtl::OUStringBuffer & rTheText, + sal_Char cEscapePrefix, sal_uInt32 nUCS4) +{ + DBG_ASSERT(nUCS4 < 0x80000000, + "INetURLObject::appendUCS4Escape(): Bad char"); + if (nUCS4 < 0x80) + appendEscape(rTheText, cEscapePrefix, nUCS4); + else if (nUCS4 < 0x800) + { + appendEscape(rTheText, cEscapePrefix, nUCS4 >> 6 | 0xC0); + appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); + } + else if (nUCS4 < 0x10000) + { + appendEscape(rTheText, cEscapePrefix, nUCS4 >> 12 | 0xE0); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); + } + else if (nUCS4 < 0x200000) + { + appendEscape(rTheText, cEscapePrefix, nUCS4 >> 18 | 0xF0); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); + } + else if (nUCS4 < 0x4000000) + { + appendEscape(rTheText, cEscapePrefix, nUCS4 >> 24 | 0xF8); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 18 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); + } + else + { + appendEscape(rTheText, cEscapePrefix, nUCS4 >> 30 | 0xFC); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 24 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 18 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80); + appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); + } +} + +//============================================================================ +// static +void INetURLObject::appendUCS4(rtl::OUStringBuffer& rTheText, sal_uInt32 nUCS4, + EscapeType eEscapeType, bool bOctets, + Part ePart, sal_Char cEscapePrefix, + rtl_TextEncoding eCharset, + bool bKeepVisibleEscapes) +{ + bool bEscape; + rtl_TextEncoding eTargetCharset = RTL_TEXTENCODING_DONTKNOW; + switch (eEscapeType) + { + case ESCAPE_NO: + if (mustEncode(nUCS4, ePart)) + { + bEscape = true; + eTargetCharset = bOctets ? RTL_TEXTENCODING_ISO_8859_1 : + RTL_TEXTENCODING_UTF8; + } + else + bEscape = false; + break; + + case ESCAPE_OCTET: + bEscape = true; + eTargetCharset = RTL_TEXTENCODING_ISO_8859_1; + break; + + case ESCAPE_UTF32: + if (mustEncode(nUCS4, ePart)) + { + bEscape = true; + eTargetCharset = eCharset; + } + else if (bKeepVisibleEscapes && INetMIME::isVisible(nUCS4)) + { + bEscape = true; + eTargetCharset = RTL_TEXTENCODING_ASCII_US; + } + else + bEscape = false; + break; + default: + bEscape = false; + } + + if (bEscape) + { + switch (eTargetCharset) + { + default: + DBG_ERROR("INetURLObject::appendUCS4(): Unsupported charset"); + case RTL_TEXTENCODING_ASCII_US: + case RTL_TEXTENCODING_ISO_8859_1: + appendEscape(rTheText, cEscapePrefix, nUCS4); + break; + + case RTL_TEXTENCODING_UTF8: + appendUCS4Escape(rTheText, cEscapePrefix, nUCS4); + break; + } + } + else + rTheText.append(sal_Unicode(nUCS4)); +} + +//============================================================================ +// static +sal_uInt32 INetURLObject::getUTF32(sal_Unicode const *& rBegin, + sal_Unicode const * pEnd, bool bOctets, + sal_Char cEscapePrefix, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, + EscapeType & rEscapeType) +{ + DBG_ASSERT(rBegin < pEnd, "INetURLObject::getUTF32(): Bad sequence"); + sal_uInt32 nUTF32 = bOctets ? *rBegin++ : + INetMIME::getUTF32Character(rBegin, pEnd); + switch (eMechanism) + { + case ENCODE_ALL: + rEscapeType = ESCAPE_NO; + break; + + case WAS_ENCODED: + { + int nWeight1; + int nWeight2; + if (nUTF32 == sal_uChar(cEscapePrefix) && rBegin + 1 < pEnd + && (nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0 + && (nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0) + { + rBegin += 2; + nUTF32 = nWeight1 << 4 | nWeight2; + switch (eCharset) + { + default: + DBG_ERROR( + "INetURLObject::getUTF32(): Unsupported charset"); + case RTL_TEXTENCODING_ASCII_US: + rEscapeType = INetMIME::isUSASCII(nUTF32) ? + ESCAPE_UTF32 : ESCAPE_OCTET; + break; + + case RTL_TEXTENCODING_ISO_8859_1: + rEscapeType = ESCAPE_UTF32; + break; + + case RTL_TEXTENCODING_UTF8: + if (INetMIME::isUSASCII(nUTF32)) + rEscapeType = ESCAPE_UTF32; + else + { + if (nUTF32 >= 0xC0 && nUTF32 <= 0xF4) + { + sal_uInt32 nEncoded; + int nShift; + sal_uInt32 nMin; + if (nUTF32 <= 0xDF) + { + nEncoded = (nUTF32 & 0x1F) << 6; + nShift = 0; + nMin = 0x80; + } + else if (nUTF32 <= 0xEF) + { + nEncoded = (nUTF32 & 0x0F) << 12; + nShift = 6; + nMin = 0x800; + } + else + { + nEncoded = (nUTF32 & 0x07) << 18; + nShift = 12; + nMin = 0x10000; + } + sal_Unicode const * p = rBegin; + bool bUTF8 = true; + for (;;) + { + if (pEnd - p < 3 + || p[0] != cEscapePrefix + || (nWeight1 + = INetMIME::getHexWeight(p[1])) + < 8 + || nWeight1 > 11 + || (nWeight2 + = INetMIME::getHexWeight(p[2])) + < 0) + { + bUTF8 = false; + break; + } + p += 3; + nEncoded + |= ((nWeight1 & 3) << 4 | nWeight2) + << nShift; + if (nShift == 0) + break; + nShift -= 6; + } + if (bUTF8 && nEncoded >= nMin + && !INetMIME::isHighSurrogate(nEncoded) + && !INetMIME::isLowSurrogate(nEncoded) + && nEncoded <= 0x10FFFF) + { + rBegin = p; + nUTF32 = nEncoded; + rEscapeType = ESCAPE_UTF32; + break; + } + } + rEscapeType = ESCAPE_OCTET; + } + break; + } + } + else + rEscapeType = ESCAPE_NO; + break; + } + + case NOT_CANONIC: + { + int nWeight1; + int nWeight2; + if (nUTF32 == sal_uChar(cEscapePrefix) && rBegin + 1 < pEnd + && ((nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0) + && ((nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0)) + { + rBegin += 2; + nUTF32 = nWeight1 << 4 | nWeight2; + rEscapeType = ESCAPE_OCTET; + } + else + rEscapeType = ESCAPE_NO; + break; + } + } + return nUTF32; +} + +//============================================================================ +// static +sal_uInt32 INetURLObject::scanDomain(sal_Unicode const *& rBegin, + sal_Unicode const * pEnd, + bool bEager) +{ + enum State { STATE_DOT, STATE_LABEL, STATE_HYPHEN }; + State eState = STATE_DOT; + sal_Int32 nLabels = 0; + sal_Unicode const * pLastAlphanumeric = 0; + for (sal_Unicode const * p = rBegin;; ++p) + switch (eState) + { + case STATE_DOT: + if (p != pEnd && (INetMIME::isAlphanumeric(*p) || *p == '_')) + { + ++nLabels; + eState = STATE_LABEL; + break; + } + if (bEager || nLabels == 0) + return 0; + rBegin = p - 1; + return nLabels; + + case STATE_LABEL: + if (p != pEnd) + { + if (INetMIME::isAlphanumeric(*p) || *p == '_') + break; + else if (*p == '.') + { + eState = STATE_DOT; + break; + } + else if (*p == '-') + { + pLastAlphanumeric = p; + eState = STATE_HYPHEN; + break; + } + } + rBegin = p; + return nLabels; + + case STATE_HYPHEN: + if (p != pEnd) + { + if (INetMIME::isAlphanumeric(*p) || *p == '_') + { + eState = STATE_LABEL; + break; + } + else if (*p == '-') + break; + } + if (bEager) + return 0; + rBegin = pLastAlphanumeric; + return nLabels; + } +} + +//============================================================================ +// static +bool INetURLObject::scanIPv6reference(sal_Unicode const *& rBegin, + sal_Unicode const * pEnd) +{ + if (rBegin != pEnd && *rBegin == '[') { + sal_Unicode const * p = rBegin + 1; + //TODO: check for valid IPv6address (RFC 2373): + while (p != pEnd && (INetMIME::isHexDigit(*p) || *p == ':' || *p == '.')) + { + ++p; + } + if (p != pEnd && *p == ']') { + rBegin = p + 1; + return true; + } + } + return false; +} + +//============================================================================ +rtl::OUString INetURLObject::GetPartBeforeLastName(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) + const +{ + if (!checkHierarchical()) + return rtl::OUString(); + INetURLObject aTemp(*this); + aTemp.clearFragment(); + aTemp.clearQuery(); + aTemp.removeSegment(LAST_SEGMENT, false); + aTemp.setFinalSlash(); + return aTemp.GetMainURL(eMechanism, eCharset); +} + +//============================================================================ +rtl::OUString INetURLObject::GetLastName(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + return getName(LAST_SEGMENT, true, eMechanism, eCharset); +} + +//============================================================================ +rtl::OUString INetURLObject::GetFileExtension(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) const +{ + return getExtension(LAST_SEGMENT, false, eMechanism, eCharset); +} + +//============================================================================ +bool INetURLObject::CutLastName() +{ + INetURLObject aTemp(*this); + aTemp.clearFragment(); + aTemp.clearQuery(); + if (!aTemp.removeSegment(LAST_SEGMENT, false)) + return false; + *this = aTemp; + return true; +} + +//============================================================================ +rtl::OUString INetURLObject::PathToFileName() const +{ + if (m_eScheme != INET_PROT_FILE) + return rtl::OUString(); + rtl::OUString aSystemPath; + if (osl::FileBase::getSystemPathFromFileURL( + decode(m_aAbsURIRef.getStr(), + m_aAbsURIRef.getStr() + m_aPath.getEnd(), + getEscapePrefix(), NO_DECODE, RTL_TEXTENCODING_UTF8), + aSystemPath) + != osl::FileBase::E_None) + return rtl::OUString(); + return aSystemPath; +} + +//============================================================================ +rtl::OUString INetURLObject::GetFull() const +{ + INetURLObject aTemp(*this); + aTemp.removeFinalSlash(); + return aTemp.PathToFileName(); +} + +//============================================================================ +rtl::OUString INetURLObject::GetPath() const +{ + INetURLObject aTemp(*this); + aTemp.removeSegment(LAST_SEGMENT, true); + aTemp.removeFinalSlash(); + return aTemp.PathToFileName(); +} + +//============================================================================ +void INetURLObject::SetBase(rtl::OUString const & rTheBase) +{ + setBase(rTheBase, LAST_SEGMENT, true, ENCODE_ALL); +} + +//============================================================================ +rtl::OUString INetURLObject::GetBase() const +{ + return getBase(LAST_SEGMENT, true, DECODE_WITH_CHARSET); +} + +//============================================================================ +void INetURLObject::SetName(rtl::OUString const & rTheName, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + INetURLObject aTemp(*this); + if (aTemp.removeSegment(LAST_SEGMENT, true) + && aTemp.insertName(rTheName, false, LAST_SEGMENT, true, eMechanism, + eCharset)) + *this = aTemp; +} + +//============================================================================ +rtl::OUString INetURLObject::CutName(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + rtl::OUString aTheName(getName(LAST_SEGMENT, true, eMechanism, eCharset)); + return removeSegment(LAST_SEGMENT, true) ? aTheName : rtl::OUString(); +} + +//============================================================================ +void INetURLObject::SetExtension(rtl::OUString const & rTheExtension, + EncodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + setExtension(rTheExtension, LAST_SEGMENT, false, eMechanism, eCharset); +} + +//============================================================================ +rtl::OUString INetURLObject::CutExtension(DecodeMechanism eMechanism, + rtl_TextEncoding eCharset) +{ + rtl::OUString aTheExtension(getExtension(LAST_SEGMENT, false, eMechanism, + eCharset)); + return removeExtension(LAST_SEGMENT, false) + ? aTheExtension : rtl::OUString(); +} + +//============================================================================ +bool INetURLObject::IsCaseSensitive() const +{ + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/wldcrd.cxx b/tools/source/fsys/wldcrd.cxx new file mode 100644 index 000000000000..183f07d3d6fb --- /dev/null +++ b/tools/source/fsys/wldcrd.cxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" +#include <tools/wldcrd.hxx> + +/************************************************************************* +|* +|* WildCard::Match() +|* +|* Beschreibung WLDCRD.SDW +|* Ersterstellung MA 19.06.91 +|* Letzte Aenderung MA 03.07.91 +|* +*************************************************************************/ + +/* Diese Methode ueberprueft, ob die Wilde Karte in pWild mit dem String + * in pStr matscht. + * Vertragen sich die beiden, so wird 1 zurueckgegeben, sonst 0. + * + * ein '*' in pWild bedeutet n beliebige Zeichen, mit n>=0 + * ein '?' in pWild bedeutet genau ein beliebiges Zeichen + * + */ + +USHORT WildCard::ImpMatch( const char *pWild, const char *pStr ) const +{ + int pos=0; + int flag=0; + + while ( *pWild || flag ) + { + switch (*pWild) + { + case '?': + if ( *pStr == '\0' ) + return 0; + break; + + default: + if ( (*pWild == '\\') && ((*(pWild+1)=='?') || (*(pWild+1) == '*')) ) + pWild++; + if ( *pWild != *pStr ) + if ( !pos ) + return 0; + else + pWild += pos; + else + break; // ACHTUNG laeuft unter bestimmten + // Umstaenden in den nachsten case rein!! + case '*': + while ( *pWild == '*' ) + pWild++; + if ( *pWild == '\0' ) + return 1; + flag = 1; + pos = 0; + if ( *pStr == '\0' ) + return ( *pWild == '\0' ); + while ( *pStr && *pStr != *pWild ) + { + if ( *pWild == '?' ) { + pWild++; + while ( *pWild == '*' ) + pWild++; + } + pStr++; + if ( *pStr == '\0' ) + return ( *pWild == '\0' ); + } + break; + } + if ( *pWild != '\0' ) + pWild++; + if ( *pStr != '\0' ) + pStr++; + else + flag = 0; + if ( flag ) + pos--; + } + return ( *pStr == '\0' ) && ( *pWild == '\0' ); +} + +/************************************************************************* +|* +|* WildCard::Matches() +|* +|* Beschreibung WLDCRD.SDW +|* Ersterstellung MA 19.06.91 +|* Letzte Aenderung TH 02.02.96 +|* +*************************************************************************/ + +BOOL WildCard::Matches( const String& rString ) const +{ + ByteString aTmpWild = aWildString; + ByteString aString(rString, osl_getThreadTextEncoding()); + + USHORT nSepPos; + + if ( cSepSymbol != '\0' ) + { + while ( (nSepPos = aTmpWild.Search( cSepSymbol )) != STRING_NOTFOUND ) + { + // alle getrennten WildCard's pruefen + if ( ImpMatch( aTmpWild.Copy( 0, nSepPos ).GetBuffer(), aString.GetBuffer() ) ) + return TRUE; + aTmpWild.Erase( 0, nSepPos + 1 ); // Trennsymbol entfernen + } + // und noch den hinter dem letzen Trennsymbol bzw. den einzigen + } + + if ( ImpMatch( aTmpWild.GetBuffer(), aString.GetBuffer() ) ) + return TRUE; + else + return FALSE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/wntmsc.cxx b/tools/source/fsys/wntmsc.cxx new file mode 100644 index 000000000000..4d78b575cfdc --- /dev/null +++ b/tools/source/fsys/wntmsc.cxx @@ -0,0 +1,1083 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_tools.hxx" + +#ifdef _MSC_VER +#pragma warning (push,1) +#endif +#include <stdio.h> +#include <ctype.h> +#include <limits.h> +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +#include "wntmsc.hxx" +#include <tools/errinf.hxx> +#include <tools/debug.hxx> +#include <tools/list.hxx> +#include <tools/wldcrd.hxx> +#include <tools/fsys.hxx> +#include <tools/bigint.hxx> + +DECLARE_LIST( DirEntryList, DirEntry* ); +DECLARE_LIST( FSysSortList, FSysSort* ); +DECLARE_LIST( FileStatList, FileStat* ); + +int Sys2SolarError_Impl( int nSysErr ); + +static BOOL bLastCaseSensitive = FALSE; + +//-------------------------------------------------------------------- + +ByteString Upper_Impl( const ByteString &rStr ) +{ + ByteString aRet( rStr.GetBuffer() ); // es muss ein neuer String entstehen! + CharUpperBuff( (char*) aRet.GetBuffer(), aRet.Len() ); + return aRet; +} + +//-------------------------------------------------------------------- + +DIR *opendir( const char* pPfad ) +{ + DIR *pDir = new DIR; + if ( pDir ) + pDir->p = (char*) pPfad; + return pDir; +} + +struct dirent *readdir( DIR *pDir ) +{ + bool bOk = false; + if ( pDir->p ) + { + char *pBuf = new char[ strlen( pDir->p ) + 5 ]; + if ( pBuf ) + { + // *.* dahinter, ggf mit "\\" abtrennen (falls nicht schon da) + strcpy( pBuf, pDir->p ); + strcat( pBuf, "\\*.*" + ( *(pBuf + strlen( pBuf ) - 1 ) == '\\' ) ); + CharUpperBuff( pBuf, strlen(pBuf) ); + pDir->h = FindFirstFile( pBuf, &pDir->aDirEnt ); + bOk = pDir->h != INVALID_HANDLE_VALUE; + pDir->p = NULL; + delete [] pBuf; + } + else + pDir->h = INVALID_HANDLE_VALUE; + } + else + { + bOk = FindNextFile( pDir->h, &pDir->aDirEnt ); + } + + return bOk ? &pDir->aDirEnt : NULL; +} + +int closedir( DIR *pDir ) +{ + BOOL bOk = FALSE; + if ( pDir ) + { + bOk = 0 != pDir->p || FindClose( pDir->h ); + delete pDir; + } + return bOk; +} + +/************************************************************************* +|* +|* DirEntry::GetPathStyle() const +|* +|* Beschreibung +|* Ersterstellung MI 11.05.95 +|* Letzte Aenderung MI 11.05.95 +|* +*************************************************************************/ + +ErrCode GetPathStyle_Impl( const String &rDevice, FSysPathStyle &rStyle ) +{ + ByteString aRootDir(rDevice, osl_getThreadTextEncoding()); + if ( aRootDir.Len() && aRootDir.GetBuffer()[aRootDir.Len()-1] != '\\' ) + aRootDir += '\\'; + + char sVolumeName[256]; + char sFileSysName[16]; + DWORD nSerial[2]; + DWORD nMaxCompLen[2]; + DWORD nFlags[2]; + + // Windows95 hat VFAT, WindowsNT nicht + DWORD nVer = GetVersion(); + BOOL bW95 = ( nVer & 0xFF ) >= 4; + + FSysFailOnErrorImpl(); + rStyle = FSYS_STYLE_UNKNOWN; + if ( GetVolumeInformation( + (char*) aRootDir.GetBuffer(), + sVolumeName, 256, (LPDWORD) &nSerial, (LPDWORD) &nMaxCompLen, + (LPDWORD) &nFlags, sFileSysName, 16 ) ) + { + // FAT/VFAT? + if ( 0 == strcmp( "FAT", sFileSysName ) ) + rStyle = bW95 ? FSYS_STYLE_VFAT : FSYS_STYLE_FAT; + + // NTFS? + else if ( 0 == strcmp( "NTFS", sFileSysName ) ) + rStyle = FSYS_STYLE_NTFS; + + // HPFS? + else if ( 0 == strcmp( "HPFS", sFileSysName ) ) + rStyle = FSYS_STYLE_HPFS; + + // NWCOMPA/NWFS? + else if ( 0 == strncmp( "NW", sFileSysName, 2 ) ) + rStyle = FSYS_STYLE_NWFS; + + return ERRCODE_NONE; + } + + return ERRCODE_IO_INVALIDDEVICE; +} + +FSysPathStyle DirEntry::GetPathStyle( const String &rDevice ) +{ + + FSysPathStyle eStyle; + GetPathStyle_Impl( rDevice, eStyle ); + return eStyle; +} + +/************************************************************************* +|* +|* DirEntry::IsCaseSensitive() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 10.06.93 +|* Letzte Aenderung TPF 26.02.1999 +|* +*************************************************************************/ + +BOOL DirEntry::IsCaseSensitive( FSysPathStyle eFormatter ) const +{ + + if (eFormatter==FSYS_STYLE_HOST) + { +/* + DirEntry aRoot(*this); + aRoot.ToAbs(); + aRoot = aRoot[Level()-1]; + String aRootDir = aRoot.GetFull(FSYS_STYLE_HOST, TRUE); + + char sVolumeName[256]; + DWORD nVolumeSerial; + DWORD nMaxCompLen; + DWORD nFlags; + char sFileSysName[16]; + + if ( GetVolumeInformation( (char*) aRootDir.GetStr(), + sVolumeName, + 256, + (LPDWORD) &nVolumeSerial, + (LPDWORD) &nMaxCompLen, + (LPDWORD) &nFlags, + sFileSysName, + 16 )) + { + return (nFlags & FS_CASE_SENSITIVE) ? TRUE : FALSE; + } + else + { + return FALSE; + } +*/ + // + // guter versuch, aber FS_CASE_SENSITIVE ist D?nnsinn in T?ten: + // + // sFileSysName FS_CASE_SENSITIVE + // FAT FALSE + // NTFS TRUE !!! + // NWCompat FALSE + // Samba FALSE + // + // NT spricht auch NTFS lediglich case preserving an, also ist unter NT alles case insensitiv + // + + return FALSE; + } + else + { + BOOL isCaseSensitive = FALSE; // ich bin unter win32, also ist der default case insensitiv + switch ( eFormatter ) + { + case FSYS_STYLE_MAC: + case FSYS_STYLE_FAT: + case FSYS_STYLE_VFAT: + case FSYS_STYLE_NTFS: + case FSYS_STYLE_NWFS: + case FSYS_STYLE_HPFS: + case FSYS_STYLE_DETECT: + { + isCaseSensitive = FALSE; + break; + } + case FSYS_STYLE_SYSV: + case FSYS_STYLE_BSD: + { + isCaseSensitive = TRUE; + break; + } + default: + { + isCaseSensitive = FALSE; // ich bin unter win32, also ist der default case insensitiv + break; + } + } + return isCaseSensitive; + } +} + +/************************************************************************* +|* +|* DirEntry::ToAbs() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MA 02.12.91 +|* +*************************************************************************/ + +BOOL DirEntry::ToAbs() +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + if ( FSYS_FLAG_VOLUME == eFlag ) + { + eFlag = FSYS_FLAG_ABSROOT; + return TRUE; + } + + if ( IsAbs() ) + { + return TRUE; + } + + + char sBuf[256]; + char *pOld; + ByteString aFullName( GetFull(), osl_getThreadTextEncoding() ); + FSysFailOnErrorImpl(); + if ( GetFullPathName((char*)aFullName.GetBuffer(),256,sBuf,&pOld) > 511 ) + return FALSE; + + *this = DirEntry( String(sBuf, osl_getThreadTextEncoding() )); + return TRUE; +} + + +/************************************************************************* +|* +|* DirEntry::GetVolume() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 27.08.92 +|* Letzte Aenderung MI 28.08.92 +|* +*************************************************************************/ + +String DirEntry::GetVolume() const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + String aRet; + const DirEntry *pTop = ImpGetTopPtr(); + ByteString aName = ByteString( pTop->aName ).ToLowerAscii(); + + if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT || + pTop->eFlag == FSYS_FLAG_RELROOT || + pTop->eFlag == FSYS_FLAG_VOLUME ) + && aName != "a:" && aName != "b:" && Exists() ) + { + char sFileSysName[256]; + char sVolumeName[256]; + DWORD nVolumeNameLen = 256; + DWORD nSerial[2]; + DWORD nMaxCompLen[2]; + DWORD nFlags[2]; + ByteString aRootDir = pTop->aName; + FSysFailOnErrorImpl(); + + // Network-Device zuerst probieren wegen langsamer Samba-Drives + if ( !WNetGetConnection( (char*) aRootDir.GetBuffer(), + sVolumeName, &nVolumeNameLen ) ) + aRet = String( sVolumeName, osl_getThreadTextEncoding()); + + // dann den VolumeNamen fuer lokale Drives + if ( aRet.Len() == 0 ) + { + aRootDir += "\\"; + if ( GetVolumeInformation( (char*) aRootDir.GetBuffer(), + sVolumeName, 256, + (LPDWORD) &nSerial, (LPDWORD) &nMaxCompLen, + (LPDWORD) &nFlags, sFileSysName, 256 ) ) + aRet = String( sVolumeName, osl_getThreadTextEncoding()); + } + } + + return aRet; +} + +/************************************************************************* +|* +|* DirEntry::SetCWD() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 26.04.91 +|* Letzte Aenderung MI 21.05.92 +|* +*************************************************************************/ + +BOOL DirEntry::SetCWD( BOOL bSloppy ) const +{ + DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); + + FSysFailOnErrorImpl(); + + if ( eFlag == FSYS_FLAG_CURRENT && !aName.Len() ) + return TRUE; + + if ( SetCurrentDirectory(ByteString(GetFull(), osl_getThreadTextEncoding()).GetBuffer()) ) + { + return TRUE; + } + + if ( bSloppy && pParent && + SetCurrentDirectory(ByteString(pParent->GetFull(), osl_getThreadTextEncoding()).GetBuffer()) ) + { + return TRUE; + } + + return FALSE; +} + +//------------------------------------------------------------------------- + +USHORT DirReader_Impl::Init() +{ + // Block-Devices auflisten? + if ( pDir->eAttrMask & FSYS_KIND_BLOCK ) + { + // CWD merken + DirEntry aCurrentDir; + aCurrentDir.ToAbs(); + + // einzeln auf Existenz und Masken-konformit"at pr"ufen + USHORT nRead = 0; + char sDrive[3] = { '?', ':', 0 }; + char sRoot[4] = { '?', ':', '\\', 0 }; + for ( char c = 'a'; c <= 'z'; c++ ) + { + sDrive[0] = c; + sRoot[0] = c; + DirEntry* pDrive = new DirEntry( sDrive, FSYS_FLAG_VOLUME, FSYS_STYLE_HOST ); + if ( pDir->aNameMask.Matches( String( ByteString(sDrive), osl_getThreadTextEncoding())) && GetDriveType( sRoot ) != 1 ) + { + if ( pDir->pStatLst ) //Status fuer Sort gewuenscht? + { + FileStat *pNewStat = new FileStat( *pDrive ); + pDir->ImpSortedInsert( pDrive, pNewStat ); + } + else + pDir->ImpSortedInsert( pDrive, NULL ); + ++nRead; + } + else + delete pDrive; + } + + // CWD restaurieren + aCurrentDir.SetCWD(); + return nRead; + } + + return 0; +} + +//------------------------------------------------------------------------- + +USHORT DirReader_Impl::Read() +{ + // Directories und Files auflisten? + if ( ( pDir->eAttrMask & FSYS_KIND_DIR || + pDir->eAttrMask & FSYS_KIND_FILE ) && + ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) ) + { + // Gross/Kleinschreibung nicht beruecksichtigen + ByteString aLowerName = pDosEntry->d_name; + CharLowerBuff( (char*) aLowerName.GetBuffer(), aLowerName.Len() ); + + // Flags pruefen + BOOL bIsDirAndWantsDir = + ( ( pDir->eAttrMask & FSYS_KIND_DIR ) && +#ifdef ICC + ( pDosEntry->d_type & ( strcmp(pDosEntry->d_name,".") || + strcmp(pDosEntry->d_name,"..")) ) ); +#else + ( pDosEntry->d_type & DOS_DIRECT ) ); +#endif + BOOL bIsFileAndWantsFile = + ( ( pDir->eAttrMask & FSYS_KIND_FILE ) && +#ifdef ICC + !( pDosEntry->d_type & ( strcmp(pDosEntry->d_name,".") || + strcmp(pDosEntry->d_name,"..")) ) && +#else + !( pDosEntry->d_type & DOS_DIRECT ) && +#endif + !( pDosEntry->d_type & DOS_VOLUMEID ) ); + BOOL bIsHidden = (pDosEntry->d_type & _A_HIDDEN) != 0; + BOOL bWantsHidden = 0 == ( pDir->eAttrMask & FSYS_KIND_VISIBLE ); + if ( ( bIsDirAndWantsDir || bIsFileAndWantsFile ) && + ( bWantsHidden || !bIsHidden ) && + pDir->aNameMask.Matches( String(aLowerName, osl_getThreadTextEncoding()) ) ) + { +#ifdef DBG_UTIL + DbgOutf( "%s %s flags:%x found", + pDosEntry->d_name, + bIsFileAndWantsFile ? "file" : "dir", + pDosEntry->d_type ); +#endif + DirEntryFlag eFlag = + 0 == strcmp( pDosEntry->d_name, "." ) ? FSYS_FLAG_CURRENT + : 0 == strcmp( pDosEntry->d_name, ".." ) ? FSYS_FLAG_PARENT + : FSYS_FLAG_NORMAL; + DirEntry *pTemp = new DirEntry( ByteString(pDosEntry->d_name), + eFlag, FSYS_STYLE_NTFS ); +#ifdef FEAT_FSYS_DOUBLESPEED + pTemp->ImpSetStat( new FileStat( (void*) pDosDir, (void*) 0 ) ); +#endif + if ( pParent ) + pTemp->ImpChangeParent( new DirEntry( *pParent ), FALSE ); + if ( pDir->pStatLst ) //Status fuer Sort gewuenscht? + { + FileStat *pNewStat = new FileStat( (void*) pDosDir, (void*) 0 ); + pDir->ImpSortedInsert( pTemp, pNewStat ); + } + else + pDir->ImpSortedInsert( pTemp, NULL ); + return 1; + } +#ifdef DBG_UTIL + else + DbgOutf( "%s flags:%x skipped", + pDosEntry->d_name, + pDosEntry->d_type ); +#endif + + } + else + bReady = TRUE; + return 0; +} + +/************************************************************************* +|* +|* InitFileStat() +|* +|* Beschreibung gemeinsamer Teil der Ctoren fuer FileStat +|* Ersterstellung MI 28.08.92 +|* Letzte Aenderung MI 28.08.92 +|* +*************************************************************************/ + +void FileStat::ImpInit( void* p ) +{ + _WIN32_FIND_DATAA *pDirEnt = (_WIN32_FIND_DATAA*) p; + + nError = FSYS_ERR_OK; + nSize = pDirEnt->nFileSizeLow; + + SYSTEMTIME aSysTime; + FILETIME aLocTime; + + // use the last write date / time when the creation date / time isn't set + if ( ( pDirEnt->ftCreationTime.dwLowDateTime == 0 ) && + ( pDirEnt->ftCreationTime.dwHighDateTime == 0 ) ) + { + pDirEnt->ftCreationTime.dwLowDateTime = pDirEnt->ftLastWriteTime.dwLowDateTime; + pDirEnt->ftCreationTime.dwHighDateTime = pDirEnt->ftLastWriteTime.dwHighDateTime; + } + + // use the last write date / time when the last accessed date / time isn't set + if ( ( pDirEnt->ftLastAccessTime.dwLowDateTime == 0 ) && + ( pDirEnt->ftLastAccessTime.dwHighDateTime == 0 ) ) + { + pDirEnt->ftLastAccessTime.dwLowDateTime = pDirEnt->ftLastWriteTime.dwLowDateTime; + pDirEnt->ftLastAccessTime.dwHighDateTime = pDirEnt->ftLastWriteTime.dwHighDateTime; + } + + FileTimeToLocalFileTime( &pDirEnt->ftCreationTime, &aLocTime ); + FileTimeToSystemTime( &aLocTime, &aSysTime ); + aDateCreated = Date( aSysTime.wDay, aSysTime.wMonth, aSysTime.wYear ); + aTimeCreated = Time( aSysTime.wHour, aSysTime.wMinute, + aSysTime.wSecond, 0 ); + + FileTimeToLocalFileTime( &pDirEnt->ftLastWriteTime, &aLocTime ); + FileTimeToSystemTime( &aLocTime, &aSysTime ); + aDateModified = Date( aSysTime.wDay, aSysTime.wMonth, aSysTime.wYear ); + aTimeModified = Time( aSysTime.wHour, aSysTime.wMinute, + aSysTime.wSecond, 0 ); + + FileTimeToLocalFileTime( &pDirEnt->ftLastAccessTime, &aLocTime ); + FileTimeToSystemTime( &aLocTime, &aSysTime ); + aDateAccessed = Date( aSysTime.wDay, aSysTime.wMonth, aSysTime.wYear ); + aTimeAccessed = Time( aSysTime.wHour, aSysTime.wMinute, + aSysTime.wSecond, 0 ); + + nKindFlags = FSYS_KIND_FILE; + if ( pDirEnt->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + nKindFlags = FSYS_KIND_DIR; +} + +/************************************************************************* +|* +|* FileStat::FileStat() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 27.08.92 +|* Letzte Aenderung MI 28.08.92 +|* +*************************************************************************/ + +FileStat::FileStat( const void *pInfo, // struct dirent + const void * ): // dummy + aDateCreated(0), + aTimeCreated(0), + aDateModified(0), + aTimeModified(0), + aDateAccessed(0), + aTimeAccessed(0) +{ + ImpInit( ( (dirent*) pInfo ) ); +} + +/************************************************************************* +|* +|* FileStat::Update() +|* +|* Beschreibung FSYS.SDW +|* Ersterstellung MI 27.08.92 +|* Letzte Aenderung MI 28.08.92 +|* +*************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(push, 1) +#pragma warning(disable: 4917) +#endif +#include <shlobj.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef UNICODE +#define lstrchr wcschr +#define lstrncmp wcsncmp +#else +#define lstrchr strchr +#define lstrncmp strncmp +#endif + +//--------------------------------------------------------------------------- + +void SHFreeMem( void *p ) +{ + LPMALLOC pMalloc = NULL; + + if ( SUCCEEDED(SHGetMalloc(&pMalloc)) ) + { + pMalloc->Free( p ); + pMalloc->Release(); + } +} + +//--------------------------------------------------------------------------- + +HRESULT SHGetIDListFromPath( HWND hwndOwner, LPCTSTR pszPath, LPITEMIDLIST *ppidl ) +{ + if ( IsBadWritePtr(ppidl, sizeof(LPITEMIDLIST)) ) + return E_INVALIDARG; + + LPSHELLFOLDER pDesktopFolder = NULL; + + HRESULT hResult = SHGetDesktopFolder( &pDesktopFolder ); + if ( FAILED(hResult) ) + return hResult; + + ULONG chEaten = lstrlen( pszPath ); + DWORD dwAttributes = FILE_ATTRIBUTE_DIRECTORY; + +#ifdef UNICODE + LPOLESTR wszPath = pszPath; +#else + WCHAR wszPath[MAX_PATH]; + MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszPath, -1, wszPath, MAX_PATH ); +#endif + + hResult = pDesktopFolder->ParseDisplayName( hwndOwner, (LPBC)NULL, wszPath, &chEaten, ppidl, &dwAttributes ); + pDesktopFolder->Release(); + + return hResult; +} + +//--------------------------------------------------------------------------- + +HRESULT SHGetFolderFromIDList( LPCITEMIDLIST pidl, LPSHELLFOLDER *ppFolder ) +{ + if ( IsBadWritePtr(ppFolder, sizeof(LPSHELLFOLDER)) ) + return E_INVALIDARG; + + *ppFolder = NULL; + + LPSHELLFOLDER pDesktopFolder = NULL; + + HRESULT hResult = SHGetDesktopFolder( &pDesktopFolder ); + if ( FAILED(hResult) ) + return hResult; + + hResult = pDesktopFolder->BindToObject( pidl, (LPBC)NULL, IID_IShellFolder, (LPVOID *)ppFolder ); + pDesktopFolder->Release(); + + return hResult; +} + +//--------------------------------------------------------------------------- + +HRESULT SHResolvePath( HWND hwndOwner, LPCTSTR pszPath, LPITEMIDLIST *ppidl ) +{ + // If hwndOwner is NULL, use the desktop window, because dialogs need a parent + +#ifdef BOOTSTRAP + return NO_ERROR; +#else + if ( !hwndOwner ) + hwndOwner = GetDesktopWindow(); + + HRESULT hResult = NOERROR; + LPTSTR pszPathCopy; + LPTSTR pszTrailingPath; + TCHAR cBackup = 0; + + // First make a copy of the path + + pszPathCopy = new TCHAR[lstrlen(pszPath) + 1]; + if ( pszPathCopy ) + lstrcpy( pszPathCopy, pszPath ); + else + return E_OUTOFMEMORY; + + // Determine the first token + + if ( !lstrncmp( pszPathCopy, "\\\\", 2 ) ) + pszTrailingPath = lstrchr( pszPathCopy + 2, '\\' ); + else + pszTrailingPath = lstrchr( pszPathCopy, '\\' ); + + // Now scan the path tokens + + while ( SUCCEEDED(hResult) ) + { + if ( pszTrailingPath ) + { + cBackup = *(++pszTrailingPath); + *pszTrailingPath = 0; + } + + LPITEMIDLIST pidl = NULL; + + // Make item ID list from leading path + + hResult = SHGetIDListFromPath( hwndOwner, pszPathCopy, &pidl ); + + // if path exists try to open it as folder + + if ( SUCCEEDED(hResult) ) + { + // Only open the folder if it was not the last token + + if ( pszTrailingPath ) + { + LPSHELLFOLDER pFolder; + + // Create a folder instance + hResult = SHGetFolderFromIDList( pidl, &pFolder); + + // Is it a folder ? + if ( SUCCEEDED(hResult) ) + { + // No try to instantiate an enumerator. + // This should popup a login dialog if any + + LPENUMIDLIST pEnum = NULL; + + hResult = pFolder->EnumObjects( hwndOwner, + SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN, + &pEnum ); + + // Release the enumerator interface + if ( SUCCEEDED(hResult) ) + pEnum->Release(); + + // Release the folder interface + pFolder->Release(); + } + + SHFreeMem( pidl ); + } + else // It was the last token + { + if ( ppidl ) + *ppidl = pidl; + else + SHFreeMem( pidl ); + } + } + + + // Forward to next token + + if ( pszTrailingPath ) + { + *pszTrailingPath = cBackup; + pszTrailingPath = lstrchr( pszTrailingPath, '\\' ); + } + else + break; + } + + // Free the working copy of the path + delete pszPathCopy; + + // NOERROR or OLE error code + return hResult; +#endif +} + +//--------------------------------------------------------------------------- +// The Wrapper +//--------------------------------------------------------------------------- + +BOOL Exists_Impl( const ByteString & crPath ) +{ + // We do not know if OLE was initialized for this thread + + CoInitialize( NULL ); + + BOOL bSuccess = SUCCEEDED( SHResolvePath(NULL, crPath.GetBuffer(), NULL) ); + + CoUninitialize(); + + return bSuccess; +} + +//--------------------------------------------------------------------------- + +BOOL FileStat::Update( const DirEntry& rDirEntry, BOOL bForceAccess ) +{ + nSize = 0; + nKindFlags = 0; + aCreator.Erase(); + aType.Erase(); + aDateCreated = Date(0); + aTimeCreated = Time(0); + aDateModified = Date(0); + aTimeModified = Time(0); + aDateAccessed = Date(0); + aTimeAccessed = Time(0); + + if ( !rDirEntry.IsValid() ) + { + nError = FSYS_ERR_UNKNOWN; + nKindFlags = 0; + return FALSE; + } + + // Sonderbehandlung falls es sich um eine Root ohne Laufwerk handelt + + if ( !rDirEntry.aName.Len() && rDirEntry.eFlag == FSYS_FLAG_ABSROOT ) + { + nKindFlags = FSYS_KIND_DIR; + nError = FSYS_ERR_OK; + return TRUE; + } + + // keine Error-Boxen anzeigen + FSysFailOnErrorImpl(); + + // Redirect + String aPath( rDirEntry.GetFull() ); +#ifndef BOOTSTRAP + FSysRedirector::DoRedirect( aPath ); +#endif + DirEntry aDirEntry( aPath ); + + // ist ein Medium im Laufwerk? + HACK("wie?") + BOOL bAccess = TRUE; + const DirEntry *pTop = aDirEntry.ImpGetTopPtr(); + ByteString aName = ByteString(pTop->aName).ToLowerAscii(); + if ( !bForceAccess && + ( pTop->eFlag == FSYS_FLAG_ABSROOT || + pTop->eFlag == FSYS_FLAG_RELROOT || + pTop->eFlag == FSYS_FLAG_VOLUME ) ) + if ( aName == "a:" || aName == "b:" ) + bAccess = FALSE; + else + DBG_TRACE( "FSys: will access removable device!" ); + if ( bAccess && ( aName == "a:" || aName == "b:" ) ) { + DBG_WARNING( "floppy will clatter" ); + } + + // Sonderbehandlung, falls es sich um ein Volume handelt + if ( aDirEntry.eFlag == FSYS_FLAG_VOLUME || + aDirEntry.eFlag == FSYS_FLAG_ABSROOT ) + { + if ( aDirEntry.eFlag == FSYS_FLAG_VOLUME ) + nKindFlags = FSYS_KIND_DEV | ( aDirEntry.aName.Len() == 2 + ? FSYS_KIND_BLOCK + : FSYS_KIND_CHAR ); + else + nKindFlags = FSYS_KIND_DIR; + + if ( !bAccess ) + { + if ( aDirEntry.eFlag == FSYS_FLAG_VOLUME ) + nKindFlags |= FSYS_KIND_REMOVEABLE; + nError = FSYS_ERR_NOTEXISTS; + nKindFlags = 0; + return FALSE; + } + + ByteString aRootDir = aDirEntry.aName; + aRootDir += ByteString( "\\" ); + UINT nType = GetDriveType( (char *) aRootDir.GetBuffer() ); //TPF: 2i + if ( nType == 1 || nType == 0 ) + { + nError = FSYS_ERR_NOTEXISTS; + nKindFlags = 0; + return FALSE; + } + + if ( aDirEntry.eFlag == FSYS_FLAG_VOLUME ) + nKindFlags = nKindFlags | + ( ( nType == DRIVE_REMOVABLE ) ? FSYS_KIND_REMOVEABLE : 0 ) | + ( ( nType == DRIVE_FIXED ) ? FSYS_KIND_FIXED : 0 ) | + ( ( nType == DRIVE_REMOTE ) ? FSYS_KIND_REMOTE : 0 ) | + ( ( nType == DRIVE_RAMDISK ) ? FSYS_KIND_RAM : 0 ) | + ( ( nType == DRIVE_CDROM ) ? FSYS_KIND_CDROM : 0 ) | + ( ( nType == 0 ) ? FSYS_KIND_UNKNOWN : 0 ); + + nError = ERRCODE_NONE; + + return TRUE; + } + + // Statusinformation vom Betriebssystem holen + HANDLE h; //() + _WIN32_FIND_DATAA aEntry = {}; + DirEntry aAbsEntry( aDirEntry ); + if ( bAccess && aAbsEntry.ToAbs() ) + { + // im Namen k"onnen auch ';*?' als normale Zeichen vorkommen + ByteString aFilePath( aAbsEntry.GetFull(), osl_getThreadTextEncoding() ); + + // MI: dann gehen Umlaute auf Novell-Servern nicht / wozu ueberhaupt + // CharUpperBuff( (char*) aFilePath.GetStr(), aFilePath.Len() ); + DBG_TRACE1( "FileStat: %s", aFilePath.GetBuffer() ); + h = aFilePath.Len() < 230 + // die Win32-API ist hier sehr schwammig + ? FindFirstFile( (char *) aFilePath.GetBuffer(), &aEntry )//TPF: 2i + : INVALID_HANDLE_VALUE; + + if ( INVALID_HANDLE_VALUE != h ) + { + if ( !( aEntry.dwFileAttributes & 0x40 ) ) // com1: etc. e.g. not encrypted (means normal) + { + ByteString aUpperName = Upper_Impl(ByteString(aAbsEntry.GetName(), osl_getThreadTextEncoding())); + + // HRO: #74051# Compare also with short alternate filename + if ( aUpperName != Upper_Impl( aEntry.cFileName ) && aUpperName != Upper_Impl( aEntry.cAlternateFileName ) ) + h = INVALID_HANDLE_VALUE; + } + } + + if ( INVALID_HANDLE_VALUE == h ) + { + DWORD dwError = GetLastError(); + + if ( ERROR_BAD_NET_NAME == dwError ) + { + nKindFlags = FSYS_KIND_UNKNOWN; + nError = FSYS_ERR_NOTEXISTS; + return FALSE; + } + + // UNC-Volume? + DirEntry *pTop = aAbsEntry.ImpGetTopPtr(); + if ( pTop->GetFlag() == FSYS_FLAG_ABSROOT && + ( pTop->aName.Len() > 1 && (pTop->aName.GetBuffer()[1] != ':' )) ) + { + if ( bForceAccess ) + { + if ( Exists_Impl( aFilePath ) ) + { + nKindFlags = FSYS_KIND_DIR|FSYS_KIND_REMOTE; + nError = FSYS_ERR_OK; + return TRUE; + } + else + { + nKindFlags = FSYS_KIND_UNKNOWN; + nError = FSYS_ERR_NOTEXISTS; + return FALSE; + } + } + } + } + } + else + h = INVALID_HANDLE_VALUE; + + if ( h == INVALID_HANDLE_VALUE ) + { + // Sonderbehandlung falls es sich um eine Wildcard handelt + ByteString aTempName( aDirEntry.GetName(), osl_getThreadTextEncoding() ); + if ( strchr( aTempName.GetBuffer(), '?' ) || + strchr( aTempName.GetBuffer(), '*' ) || + strchr( aTempName.GetBuffer(), ';' ) ) + { + nKindFlags = FSYS_KIND_WILD; + nError = FSYS_ERR_OK; + return TRUE; + } + + if ( bAccess ) + { + nError = FSYS_ERR_NOTEXISTS; + nKindFlags = FSYS_KIND_UNKNOWN; + } + else + nKindFlags = FSYS_KIND_REMOVEABLE; + } + else + { + ImpInit( &aEntry ); + FindClose( h ); + } + + if ( 0 != nError ) + nKindFlags = 0; + + return 0 == nError; + +} + +BOOL IsRedirectable_Impl( const ByteString &rPath ) +{ + if ( rPath.Len() >= 3 && ':' == rPath.GetBuffer()[1] ) + { + ByteString aVolume = rPath.Copy( 0, 3 ); + UINT nType = GetDriveType( (char *) aVolume.GetBuffer() ); + SetLastError( ERROR_SUCCESS ); + return DRIVE_FIXED != nType; + } + return FALSE; +} + +/************************************************************************* +|* +|* TempDirImpl() +|* +|* Beschreibung liefert den Namens des Directories fuer temporaere +|* Dateien +|* Ersterstellung MI 16.03.94 +|* Letzte Aenderung MI 16.03.94 +|* +*************************************************************************/ + +const char* TempDirImpl( char *pBuf ) +{ + if ( !GetTempPath( MAX_PATH, pBuf ) && + !GetWindowsDirectory( pBuf, MAX_PATH ) && + !GetEnvironmentVariable( "HOMEPATH", pBuf, MAX_PATH ) ) + return 0; + + return pBuf; +} + +//======================================================================= + +ErrCode FileStat::QueryDiskSpace( const String &rPath, + BigInt &rFreeBytes, BigInt &rTotalBytes ) +{ + DWORD nSectorsPerCluster; /* address of sectors per cluster */ + DWORD nBytesPerSector; /* address of bytes per sector */ + DWORD nFreeClusters; /* address of number of free clusters */ + DWORD nClusters; /* address of total number of clusters */ + + ByteString aVol( DirEntry(rPath).ImpGetTopPtr()->GetName(), osl_getThreadTextEncoding()); + bool bOK = GetDiskFreeSpace( aVol.GetBuffer(), + &nSectorsPerCluster, &nBytesPerSector, + &nFreeClusters, &nClusters ); + if ( !bOK ) + return Sys2SolarError_Impl( GetLastError() ); + + BigInt aBytesPerCluster( BigInt(nSectorsPerCluster) * + BigInt(nBytesPerSector) ); + rFreeBytes = aBytesPerCluster * BigInt(nFreeClusters); + rTotalBytes = aBytesPerCluster * BigInt(nClusters); + return 0; +} + +//========================================================================= + +void FSysEnableSysErrorBox( BOOL bEnable ) +{ // Preserve other Bits!! + sal_uInt32 nErrorMode = SetErrorMode( bEnable ? 0 : SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX ); + if ( bEnable ) + nErrorMode &= ~(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + else + nErrorMode |= (SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + SetErrorMode( nErrorMode ); +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/wntmsc.hxx b/tools/source/fsys/wntmsc.hxx new file mode 100644 index 000000000000..b4226a70ec08 --- /dev/null +++ b/tools/source/fsys/wntmsc.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _dosmsc_hxx +#define _dosmsc_hxx + +#include <string.h> + +#ifndef ICC +#include <io.h> +#endif +#include <sys\types.h> +#include <sys\stat.h> +#include <direct.h> + +#include <tools/svwin.h> +#ifdef _MSC_VER +#pragma warning (push,1) +#endif +#include <winbase.h> +#ifdef _MSC_VER +#pragma warning (pop) +#endif +#include <tools/solar.h> + +#include <tools/string.hxx> + +//-------------------------------------------------------------------- + +#define FSYS_UNIX FALSE + +#define DOS_DIRECT _A_SUBDIR +#define DOS_VOLUMEID 0x08 +#ifndef S_IFBLK +#define S_IFBLK 0x6000 +#endif +#define setdrive(n,a) _chdrive(n) +#define GETDRIVE(n) (n = _getdrive()) + +#define dirent _WIN32_FIND_DATAA +#define d_name cFileName +#define d_type dwFileAttributes + +#if defined (TCPP) || defined (tcpp) +#define _mkdir mkdir +#define _rmdir rmdir +#define _chdir chdir +#define _unlink unlink +#define _getcwd getcwd +#define _access access +#endif + +typedef struct +{ + _WIN32_FIND_DATAA aDirEnt; + HANDLE h; + const char *p; +} DIR; + +#define PATHDELIMITER ";" +#define DEFSTYLE FSYS_STYLE_NTFS +#define MKDIR( p ) mkdir( p ) +#define CMP_LOWER(s) ( ByteString(s).ToLowerAscii() ) + +#define START_DRV 'a' + +inline BOOL DRIVE_EXISTS(char c) +{ + ByteString aDriveRoot( c ); + aDriveRoot += ":\\"; + return GetDriveType( aDriveRoot.GetBuffer() ) > 1; +} + +const char* TempDirImpl( char *pBuf ); + +#define FSysFailOnErrorImpl() + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |