/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org.  If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/

#include "system.h"

#include "file_url.h"
#include "path_helper.hxx"

#include <osl/diagnose.h>
#include <osl/profile.h>
#include <osl/process.h>
#include <osl/file.h>
#include <osl/util.h>
#include <rtl/alloc.h>
#include <sal/macros.h>
#include <algorithm>
using std::min;
static inline void copy_ustr_n( void *dest, const void *source, size_t length ) { rtl_copyMemory(dest, source, length*sizeof(sal_Unicode)); }

#define LINES_INI       32
#define LINES_ADD       10
#define SECTIONS_INI    5
#define SECTIONS_ADD    3
#define ENTRIES_INI     5
#define ENTRIES_ADD     3


#define STR_INI_EXTENSION   L".ini"
#define STR_INI_METAHOME    "?~"
#define STR_INI_METASYS     "?$"
#define STR_INI_METACFG     "?^"
#define STR_INI_METAINS     "?#"

#define STR_INI_BOOLYES     "yes"
#define STR_INI_BOOLON      "on"
#define STR_INI_BOOLONE     "1"
#define STR_INI_BOOLNO      "no"
#define STR_INI_BOOLOFF     "off"
#define STR_INI_BOOLZERO    "0"

#define FLG_USER            0x00FF
#define FLG_AUTOOPEN        0x0100
#define FLG_MODIFIED        0x0200

#define SVERSION_LOCATION   STR_INI_METACFG
#define SVERSION_FALLBACK   STR_INI_METASYS
#define SVERSION_NAME       "sversion"
#define SVERSION_SECTION    "Versions"
#define SVERSION_SOFFICE    "StarOffice"
#define SVERSION_PROFILE    "soffice.ini"
#define SVERSION_OPTION     "userid:"
#define SVERSION_DIRS       { "bin", "program" }
#define SVERSION_USER       "user"

#define DEFAULT_PMODE   (_S_IREAD | _S_IWRITE)

#define _BUILD_STR_(n)  # n
#define BUILD_STR(n)    _BUILD_STR_(n)


/*#define DEBUG_OSL_PROFILE 1*/
/*#define TRACE_OSL_PROFILE 1*/


/*****************************************************************************/
/* Data Type Definition */
/*****************************************************************************/

typedef FILETIME osl_TStamp;

typedef enum _osl_TLockMode
{
    un_lock, read_lock, write_lock
} osl_TLockMode;

typedef struct _osl_TFile
{
    HANDLE  m_Handle;
    sal_Char*   m_pReadPtr;
    sal_Char    m_ReadBuf[512];
/*      sal_Char*   m_pWritePtr; */
/*      sal_Char    m_WriteBuf[512]; */
    sal_Char*   m_pWriteBuf;
    sal_uInt32  m_nWriteBufLen;
    sal_uInt32  m_nWriteBufFree;
} osl_TFile;

typedef struct _osl_TProfileEntry
{
    sal_uInt32      m_Line;
    sal_uInt32      m_Offset;
    sal_uInt32      m_Len;
} osl_TProfileEntry;

typedef struct _osl_TProfileSection
{
    sal_uInt32          m_Line;
    sal_uInt32          m_Offset;
    sal_uInt32          m_Len;
    sal_uInt32          m_NoEntries;
    sal_uInt32          m_MaxEntries;
    osl_TProfileEntry*  m_Entries;
} osl_TProfileSection;


/*
    Profile-data structure hidden behind oslProfile:
*/
typedef struct _osl_TProfileImpl
{
    sal_uInt32  m_Flags;
    osl_TFile*  m_pFile;
    osl_TStamp  m_Stamp;
    sal_uInt32  m_NoLines;
    sal_uInt32  m_MaxLines;
    sal_uInt32  m_NoSections;
    sal_uInt32  m_MaxSections;
    sal_Char**  m_Lines;
    rtl_uString *m_strFileName;
    osl_TProfileSection* m_Sections;
} osl_TProfileImpl;


/*****************************************************************************/
/* Static Module Function Declarations */
/*****************************************************************************/

static osl_TFile*           openFileImpl(rtl_uString * strFileName, oslProfileOption ProfileFlags  );
static osl_TStamp           closeFileImpl(osl_TFile* pFile);
static sal_Bool             lockFile(const osl_TFile* pFile, osl_TLockMode eMode);
static sal_Bool             rewindFile(osl_TFile* pFile, sal_Bool bTruncate);
static osl_TStamp           getFileStamp(osl_TFile* pFile);

static sal_Bool             getLine(osl_TFile* pFile, const sal_Char *pszLine, int MaxLen);
static sal_Bool             putLine(osl_TFile* pFile, const sal_Char *pszLine);
static const sal_Char*      stripBlanks(const sal_Char* String, sal_uInt32* pLen);
static const sal_Char*      addLine(osl_TProfileImpl* pProfile, const sal_Char* Line);
static const sal_Char*      insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo);
static void                 removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo);
static void                 setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection,
                                     sal_uInt32 NoEntry, sal_uInt32 Line,
                                     const sal_Char* Entry, sal_uInt32 Len);
static sal_Bool             addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection,
                                     int Line, const sal_Char* Entry, sal_uInt32 Len);
static void                 removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry);
static sal_Bool             addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len);
static void                 removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection);
static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section,
                                      const sal_Char* Entry, sal_uInt32 *pNoEntry);
static sal_Bool             loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile);
static sal_Bool             storeProfile(osl_TProfileImpl* pProfile, sal_Bool bCleanup);
static osl_TProfileImpl*    acquireProfile(oslProfile Profile, sal_Bool bWriteable);
static sal_Bool             releaseProfile(osl_TProfileImpl* pProfile);
static sal_Bool             lookupProfile(const sal_Unicode *strPath, const sal_Unicode *strFile, sal_Unicode *strProfile);

static sal_Bool writeProfileImpl (osl_TFile* pFile);
static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl*);
static sal_Bool osl_ProfileSwapProfileNames(osl_TProfileImpl*);
static rtl_uString* osl_ProfileGenerateExtension(rtl_uString* ustrFileName, rtl_uString* ustrExtension);

static sal_Bool SAL_CALL osl_getProfileName(rtl_uString* strPath, rtl_uString* strName, rtl_uString** strProfileName);

/*****************************************************************************/
/* Exported Module Functions */
/*****************************************************************************/

oslProfile SAL_CALL osl_openProfile(rtl_uString *strProfileName, sal_uInt32 Flags)
{
    osl_TFile*        pFile = NULL;
    osl_TProfileImpl* pProfile;
    rtl_uString       *FileName=NULL;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_openProfile\n");
#endif
    OSL_VERIFY(strProfileName);

    if (rtl_uString_getLength(strProfileName) == 0 )
    {
        OSL_VERIFY(osl_getProfileName(NULL, NULL, &FileName));
    }
    else
    {
        rtl_uString_assign(&FileName, strProfileName);
    }


    osl_getSystemPathFromFileURL(FileName, &FileName);


#ifdef DEBUG_OSL_PROFILE
    Flags=osl_Profile_FLUSHWRITE;

    // OSL_TRACE("opening '%s'\n",FileName);
    if ( Flags == osl_Profile_DEFAULT )
    {
        OSL_TRACE("with osl_Profile_DEFAULT \n");
    }
    if ( Flags & osl_Profile_SYSTEM )
    {
        OSL_TRACE("with osl_Profile_SYSTEM \n");
    }
    if ( Flags & osl_Profile_READLOCK )
    {
        OSL_TRACE("with osl_Profile_READLOCK \n");
    }
    if ( Flags & osl_Profile_WRITELOCK )
    {
        OSL_TRACE("with osl_Profile_WRITELOCK \n");
    }
/*      if ( Flags & osl_Profile_READWRITE ) */
/*      { */
/*          OSL_TRACE("with osl_Profile_READWRITE \n"); */
/*      } */
    if ( Flags & osl_Profile_FLUSHWRITE )
    {
        OSL_TRACE("with osl_Profile_FLUSHWRITE \n");
    }
#endif

    if ( (! (Flags & osl_Profile_SYSTEM)) && ( (pFile = openFileImpl(FileName, Flags) ) == NULL ) )
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_openProfile [not opened]\n");
#endif
        if( FileName)
            rtl_uString_release( FileName);

        return (NULL);
    }


    pProfile = (osl_TProfileImpl*)calloc(1, sizeof(osl_TProfileImpl));


    pProfile->m_Flags = Flags & FLG_USER;
    osl_getSystemPathFromFileURL(strProfileName, &pProfile->m_strFileName);
//  rtl_uString_assign(&pProfile->m_strFileName, strProfileName);

    if (Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ))
        pProfile->m_pFile = pFile;

    pProfile->m_Stamp = getFileStamp(pFile);

    loadProfile(pFile, pProfile);

    if (pProfile->m_pFile == NULL)
        closeFileImpl(pFile);

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_openProfile [ok]\n");
#endif
    if( FileName)
        rtl_uString_release( FileName);

    return (pProfile);
}

sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile)
{
    osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_closeProfile\n");
#endif

    if ( Profile == 0 )
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_closeProfile [profile==0]\n");
#endif
        return sal_False;
    }

    if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
    {
        pProfile = acquireProfile(Profile,sal_True);

        if ( pProfile != 0 )
        {
            if ( !( pProfile->m_Flags & osl_Profile_READLOCK )  && ( pProfile->m_Flags & FLG_MODIFIED ) )
            {
/*                  if (pProfile->m_pFile == NULL) */
/*                      pProfile->m_pFile = openFileImpl(pProfile->m_Filename, sal_True); */

                storeProfile(pProfile, sal_False);
            }
        }
        else
        {
            pProfile = acquireProfile(Profile,sal_False);
        }

        if ( pProfile == 0 )
        {
#ifdef TRACE_OSL_PROFILE
            OSL_TRACE("Out osl_closeProfile [pProfile==0]\n");
#endif
            return sal_False;
        }

        if (pProfile->m_pFile != NULL)
            closeFileImpl(pProfile->m_pFile);
    }

    pProfile->m_pFile = NULL;
    rtl_uString_release(pProfile->m_strFileName);
    pProfile->m_strFileName = NULL;

    /* release whole profile data types memory */
    if ( pProfile->m_NoLines > 0)
    {
        unsigned int index=0;
        if ( pProfile->m_Lines != 0 )
        {
            for ( index = 0 ; index < pProfile->m_NoLines ; ++index)
            {
                if ( pProfile->m_Lines[index] != 0 )
                {
                    free(pProfile->m_Lines[index]);
                }
            }
            free(pProfile->m_Lines);
        }
        if ( pProfile->m_Sections != 0 )
        {
            /*osl_TProfileSection* pSections=pProfile->m_Sections;*/
            for ( index = 0 ; index < pProfile->m_NoSections ; ++index )
            {
                if ( pProfile->m_Sections[index].m_Entries != 0 )
                {
                    free(pProfile->m_Sections[index].m_Entries);
                }
            }
            free(pProfile->m_Sections);
        }

    }
    free(pProfile);

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_closeProfile [ok]\n");
#endif
    return (sal_True);
}


sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile)
{
    osl_TProfileImpl* pProfile = (osl_TProfileImpl*) Profile;
    osl_TFile* pFile;
    sal_Bool bRet = sal_False;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_flushProfile()\n");
#endif

    if ( pProfile == 0 )
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_flushProfile() [pProfile == 0]\n");
#endif
        return sal_False;
    }

    pFile = pProfile->m_pFile;
    if ( !( pFile != 0 && pFile->m_Handle >= 0 ) )
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_flushProfile() [invalid file]\n");
#endif
        return sal_False;
    }

    if ( pProfile->m_Flags & FLG_MODIFIED )
    {
#ifdef DEBUG_OSL_PROFILE
        OSL_TRACE("swapping to storeprofile\n");
#endif
        bRet = storeProfile(pProfile,sal_False);
    }

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_flushProfile() [ok]\n");
#endif
    return bRet;
}

static sal_Bool writeProfileImpl(osl_TFile* pFile)
{
    DWORD BytesWritten=0;
    BOOL bRet;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_writeProfileImpl()\n");
#endif

    if ( !( pFile != 0 && pFile->m_Handle != INVALID_HANDLE_VALUE ) || ( pFile->m_pWriteBuf == 0 ) )
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_writeProfileImpl() [invalid args]\n");
#endif
        return sal_False;
    }

#ifdef DEBUG_OSL_PROFILE
/*    OSL_TRACE("File Buffer in writeProfileImpl '%s' size == '%i' '%i'(%i)\n",
      pFile->m_pWriteBuf,pFile->m_nWriteBufLen,strlen(pFile->m_pWriteBuf),pFile->m_nWriteBufLen - pFile->m_nWriteBufFree);*/
#endif

    bRet=WriteFile(pFile->m_Handle, pFile->m_pWriteBuf, pFile->m_nWriteBufLen - pFile->m_nWriteBufFree,&BytesWritten,NULL);

    if ( bRet == 0 || BytesWritten <= 0 )
    {
        OSL_ENSURE(bRet,"WriteFile failed!!!");

        OSL_TRACE("write failed '%s'\n",strerror(errno));

/*        OSL_TRACE("Out osl_writeProfileImpl() [write '%s']\n",strerror(errno));*/
        return (sal_False);
    }

    free(pFile->m_pWriteBuf);
    pFile->m_pWriteBuf=0;
    pFile->m_nWriteBufLen=0;
    pFile->m_nWriteBufFree=0;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_writeProfileImpl() [ok]\n");
#endif
    return sal_True;
}


sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile,
                              const sal_Char* pszSection, const sal_Char* pszEntry,
                              sal_Char* pszString, sal_uInt32 MaxLen,
                              const sal_Char* pszDefault)
{
    sal_uInt32    NoEntry;
    const sal_Char* pStr = 0;
    osl_TProfileSection* pSec;
    osl_TProfileImpl*    pProfile = 0;


#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_readProfileString\n");
#endif

    pProfile = acquireProfile(Profile, sal_False);

    if (pProfile == NULL)
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_readProfileString [pProfile==0]\n");
#endif


        return (sal_False);
    }


    if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
    {
        if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) &&
            (NoEntry < pSec->m_NoEntries) &&
            ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line],
                            '=')) != NULL))
            pStr++;
        else
            pStr = pszDefault;

        if ( pStr != 0 )
        {
            pStr = stripBlanks(pStr, NULL);
            MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr);
            pStr = stripBlanks(pStr, &MaxLen);
            strncpy(pszString, pStr, MaxLen);
            pszString[MaxLen] = '\0';
        }
    }
    else
    {
        ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH );

        WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL);
        GetPrivateProfileString(pszSection, pszEntry, pszDefault, pszString, MaxLen, aFileName);
    }

    releaseProfile(pProfile);

    if ( pStr == 0 )
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_readProfileString [pStr==0]\n");
#endif


        return (sal_False);
    }

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_readProfileString [ok]\n");
#endif




    return (sal_True);
}


sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile,
                            const sal_Char* pszSection, const sal_Char* pszEntry,
                            sal_Bool Default)
{
    sal_Char Line[32];

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_readProfileBool\n");
#endif

    if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), ""))
    {
        if ((stricmp(Line, STR_INI_BOOLYES) == 0) ||
            (stricmp(Line, STR_INI_BOOLON)  == 0) ||
            (stricmp(Line, STR_INI_BOOLONE) == 0))
            Default = sal_True;
        else
            if ((stricmp(Line, STR_INI_BOOLNO)   == 0) ||
                (stricmp(Line, STR_INI_BOOLOFF)  == 0) ||
                (stricmp(Line, STR_INI_BOOLZERO) == 0))
                Default = sal_False;
    }

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_readProfileBool [ok]\n");
#endif

    return (Default);
}


sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile,
                              const sal_Char* pszSection, const sal_Char* pszEntry,
                              sal_uInt32 FirstId, const sal_Char* Strings[],
                              sal_uInt32 Default)
{
    sal_uInt32    i;
    sal_Char        Line[256];

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_readProfileIdent\n");
#endif

    if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), ""))
    {
        i = 0;
        while (Strings[i] != NULL)
        {
            if (stricmp(Line, Strings[i]) == 0)
            {
                Default = i + FirstId;
                break;
            }
            i++;
        }
    }

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_readProfileIdent [ok]\n");
#endif
    return (Default);
}

sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile,
                               const sal_Char* pszSection, const sal_Char* pszEntry,
                               const sal_Char* pszString)
{
    sal_uInt32    i;
    sal_Bool bRet = sal_False;
    sal_uInt32    NoEntry;
    const sal_Char* pStr;
    sal_Char        Line[4096];
    osl_TProfileSection* pSec;
    osl_TProfileImpl*    pProfile = 0;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_writeProfileString\n");
#endif

    pProfile = acquireProfile(Profile, sal_True);

    if (pProfile == NULL)
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_writeProfileString [pProfile==0]\n");
#endif
        return (sal_False);
    }


    if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
    {
        if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == NULL)
        {
            Line[0] = '\0';
            addLine(pProfile, Line);

            Line[0] = '[';
            strcpy(&Line[1], pszSection);
            Line[1 + strlen(pszSection)] = ']';
            Line[2 + strlen(pszSection)] = '\0';

            if (((pStr = addLine(pProfile, Line)) == NULL) ||
                (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection))))
            {
                releaseProfile(pProfile);
#ifdef TRACE_OSL_PROFILE
                OSL_TRACE("Out osl_writeProfileString [not added]\n");
#endif
                return (sal_False);
            }

            pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1];
            NoEntry = pSec->m_NoEntries;
        }

        Line[0] = '\0';
        strcpy(&Line[0], pszEntry);
        Line[0 + strlen(pszEntry)] = '=';
        strcpy(&Line[1 + strlen(pszEntry)], pszString);

        if (NoEntry >= pSec->m_NoEntries)
        {
            if (pSec->m_NoEntries > 0)
                i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1;
            else
                i = pSec->m_Line + 1;

            if (((pStr = insertLine(pProfile, Line, i)) == NULL) ||
                (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry))))
            {
                releaseProfile(pProfile);
#ifdef TRACE_OSL_PROFILE
                OSL_TRACE("Out osl_writeProfileString [not inserted]\n");
#endif
                return (sal_False);
            }

            pProfile->m_Flags |= FLG_MODIFIED;
        }
        else
        {
            i = pSec->m_Entries[NoEntry].m_Line;
            free(pProfile->m_Lines[i]);
            pProfile->m_Lines[i] = strdup(Line);
            setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry));

            pProfile->m_Flags |= FLG_MODIFIED;
        }
    }
    else
    {
        ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH );

        WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL);
        WritePrivateProfileString(pszSection, pszEntry, pszString, aFileName);
    }

    bRet = releaseProfile(pProfile);
#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_writeProfileString [ok]\n");
#endif
    return bRet;
}


sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile,
                             const sal_Char* pszSection, const sal_Char* pszEntry,
                             sal_Bool Value)
{
    sal_Bool bRet = sal_False;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_writeProfileBool\n");
#endif

    if (Value)
        bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE);
    else
        bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO);

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_writeProfileBool [ok]\n");
#endif

    return bRet;
}


sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile,
                              const sal_Char* pszSection, const sal_Char* pszEntry,
                              sal_uInt32 FirstId, const sal_Char* Strings[],
                              sal_uInt32 Value)
{
    int i, n;
    sal_Bool bRet = sal_False;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_writeProfileIdent\n");
#endif

    for (n = 0; Strings[n] != NULL; n++);

    if ((i = Value - FirstId) >= n)
        bRet=sal_False;
    else
        bRet=osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]);

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_writeProfileIdent\n");
#endif
    return bRet;
}


sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile,
                               const sal_Char *pszSection, const sal_Char *pszEntry)
{
    sal_uInt32    NoEntry;
    osl_TProfileSection* pSec;
    osl_TProfileImpl*    pProfile = 0;
    sal_Bool bRet = sal_False;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_removeProfileEntry\n");
#endif

    pProfile = acquireProfile(Profile, sal_True);

    if (pProfile == NULL)
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_removeProfileEntry [pProfile==0]\n");
#endif


        return (sal_False);
    }


    if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
    {
        if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) &&
            (NoEntry < pSec->m_NoEntries))
        {
            removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line);
            removeEntry(pSec, NoEntry);
            if (pSec->m_NoEntries == 0)
            {
                removeLine(pProfile, pSec->m_Line);

                /* remove any empty separation line */
                if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0'))
                    removeLine(pProfile, pSec->m_Line - 1);

                removeSection(pProfile, pSec);
            }

            pProfile->m_Flags |= FLG_MODIFIED;
        }
    }
    else
    {
        ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH );

        WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL);
        WritePrivateProfileString(pszSection, pszEntry, NULL, aFileName);
    }

    bRet = releaseProfile(pProfile);
#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_removeProfileEntry [ok]\n");
#endif
    return bRet;
}


sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile, const sal_Char *pszSection,
                                       sal_Char* pszBuffer, sal_uInt32 MaxLen)
{
    sal_uInt32    i, n = 0;
    sal_uInt32    NoEntry;
    osl_TProfileSection* pSec;
    osl_TProfileImpl*    pProfile = 0;

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  osl_getProfileSectionEntries\n");
#endif

    pProfile = acquireProfile(Profile, sal_False);

    if (pProfile == NULL)
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out osl_getProfileSectionEntries [pProfile=0]\n");
#endif


        return (0);
    }


    if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
    {
        if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != NULL)
        {
            if (MaxLen != 0)
            {
                for (i = 0; i < pSec->m_NoEntries; i++)
                {
                    if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen)
                    {
                        strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line]
                                [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len);
                        n += pSec->m_Entries[i].m_Len;
                        pszBuffer[n++] = '\0';
                    }
                    else
                        break;

                }

                pszBuffer[n++] = '\0';
            }
            else
            {
                for (i = 0; i < pSec->m_NoEntries; i++)
                    n += pSec->m_Entries[i].m_Len + 1;

                n += 1;
            }
        }
        else
            n = 0;
    }
    else
    {
        ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH );

        WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL);
        n = GetPrivateProfileString(pszSection, NULL, NULL, pszBuffer, MaxLen, aFileName);
    }

    releaseProfile(pProfile);

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out osl_getProfileSectionEntries [ok]\n");
#endif

    return (n);
}


sal_Bool SAL_CALL osl_getProfileName(rtl_uString* strPath, rtl_uString* strName, rtl_uString** strProfileName)
{
    sal_Bool bFailed;
    ::osl::LongPathBuffer< sal_Unicode > aFile( MAX_LONG_PATH );
    ::osl::LongPathBuffer< sal_Unicode > aPath( MAX_LONG_PATH );
    sal_uInt32  nFileLen = 0;
    sal_uInt32  nPathLen = 0;

    rtl_uString * strTmp = NULL;
    oslFileError nError;

    /* build file name */
    if (strName && strName->length)
    {
        if( ::sal::static_int_cast< sal_uInt32 >( strName->length ) >= aFile.getBufSizeInSymbols() )
            return sal_False;

        copy_ustr_n( aFile, strName->buffer, strName->length+1);
        nFileLen = strName->length;

        if (rtl_ustr_indexOfChar( aFile, L'.' ) == -1)
        {
            if (nFileLen + wcslen(STR_INI_EXTENSION) >= aFile.getBufSizeInSymbols())
                return sal_False;

            /* add default extension */
            copy_ustr_n( aFile + nFileLen, STR_INI_EXTENSION, wcslen(STR_INI_EXTENSION)+1 );
            nFileLen += wcslen(STR_INI_EXTENSION);
        }
    }
    else
    {
        rtl_uString *strProgName = NULL;
        sal_Unicode *pProgName;
        sal_Int32 nOffset = 0;
        sal_Int32 nLen;
        sal_Int32 nPos;

        if (osl_getExecutableFile(&strProgName) != osl_Process_E_None)
            return sal_False;

        /* remove path and extension from filename */
        pProgName = strProgName->buffer;
        nLen = strProgName->length ;

        if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L'/' )) != -1)
            nOffset = nPos + 1;
        else if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L':' )) != -1)
            nOffset = nPos + 1;

        if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L'.' )) != -1 )
            nLen -= 4;

        if ((nFileLen = nLen - nOffset) >= aFile.getBufSizeInSymbols())
            return sal_False;

        copy_ustr_n(aFile, pProgName + nOffset, nFileLen);

        if (nFileLen + wcslen(STR_INI_EXTENSION) >= aFile.getBufSizeInSymbols())
            return sal_False;

        /* add default extension */
        copy_ustr_n(aFile + nFileLen, STR_INI_EXTENSION, wcslen(STR_INI_EXTENSION)+1);
        nFileLen += wcslen(STR_INI_EXTENSION);

        rtl_uString_release( strProgName );
    }

    if (aFile[0] == 0)
        return sal_False;

    /* build directory path */
    if (strPath && strPath->length)
    {
        sal_Unicode *pPath = rtl_uString_getStr(strPath);
        sal_Int32 nLen = rtl_uString_getLength(strPath);

        if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METAHOME) , STR_INI_METAHOME) == 0) &&
            ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)] == '/')))
        {
            rtl_uString * strHome = NULL;
            oslSecurity security = osl_getCurrentSecurity();

            bFailed = ! osl_getHomeDir(security, &strHome);
            osl_freeSecurityHandle(security);

            if (bFailed) return (sal_False);

            if ( ::sal::static_int_cast< sal_uInt32 >( strHome->length ) >= aPath.getBufSizeInSymbols())
                return sal_False;

            copy_ustr_n( aPath, strHome->buffer, strHome->length+1);
            nPathLen = strHome->length;

            if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METAHOME))
            {
                pPath += RTL_CONSTASCII_LENGTH(STR_INI_METAHOME);
                nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METAHOME);

                if (nLen + nPathLen >= aPath.getBufSizeInSymbols())
                    return sal_False;

                copy_ustr_n(aPath + nPathLen, pPath, nLen+1);
                nPathLen += nLen;
            }

            rtl_uString_release(strHome);
        }

        else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METACFG), STR_INI_METACFG) == 0) &&
            ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METACFG)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METACFG)] == '/')))
        {
            rtl_uString * strConfig = NULL;
            oslSecurity security = osl_getCurrentSecurity();

            bFailed = ! osl_getConfigDir(security, &strConfig);
            osl_freeSecurityHandle(security);

            if (bFailed) return (sal_False);

            if ( ::sal::static_int_cast< sal_uInt32 >( strConfig->length ) >= aPath.getBufSizeInSymbols())
                return sal_False;

            copy_ustr_n( aPath, strConfig->buffer, strConfig->length+1 );
            nPathLen = strConfig->length;

            if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METACFG))
            {
                pPath += RTL_CONSTASCII_LENGTH(STR_INI_METACFG);
                nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METACFG);

                if (nLen + nPathLen >= aPath.getBufSizeInSymbols())
                    return sal_False;

                copy_ustr_n(aPath + nPathLen, pPath, nLen+1);
                nPathLen += nLen;
            }

            rtl_uString_release(strConfig);
        }

        else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METASYS), STR_INI_METASYS) == 0) &&
            ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METASYS)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METASYS)] == '/')))
        {
            if (((nPathLen = GetWindowsDirectoryW(::osl::mingw_reinterpret_cast<LPWSTR>(aPath), aPath.getBufSizeInSymbols())) == 0) || (nPathLen >= aPath.getBufSizeInSymbols()))
                return (sal_False);

            if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METASYS))
            {
                pPath += RTL_CONSTASCII_LENGTH(STR_INI_METASYS);
                nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METASYS);

                if (nLen + nPathLen >= aPath.getBufSizeInSymbols())
                    return sal_False;

                copy_ustr_n(aPath + nPathLen, pPath, nLen+1);
                nPathLen += nLen;
            }
        }

        else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METAINS), STR_INI_METAINS) == 0) &&
            ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METAINS)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAINS)] == '/') ||
                (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAINS)] == '"') ) )
        {
            if (! lookupProfile(pPath + RTL_CONSTASCII_LENGTH(STR_INI_METAINS), aFile, aPath))
                return (sal_False);

            nPathLen = rtl_ustr_getLength(aPath);
        }

        else if( ::sal::static_int_cast< sal_uInt32 >( nLen ) < aPath.getBufSizeInSymbols())
        {
            copy_ustr_n(aPath, pPath, nLen+1);
            nPathLen = rtl_ustr_getLength(aPath);
        }
        else
            return sal_False;
    }
    else
    {
        rtl_uString * strConfigDir = NULL;
        oslSecurity security = osl_getCurrentSecurity();

        bFailed = ! osl_getConfigDir(security, &strConfigDir);
        osl_freeSecurityHandle(security);

        if (bFailed) return (sal_False);
        if ( ::sal::static_int_cast< sal_uInt32 >( strConfigDir->length ) >= aPath.getBufSizeInSymbols() )
            return sal_False;

        copy_ustr_n(aPath, strConfigDir->buffer, strConfigDir->length+1);
        nPathLen = strConfigDir->length;
    }

    if (nPathLen && (aPath[nPathLen - 1] != L'/') && (aPath[nPathLen - 1] != L'\\'))
    {
        aPath[nPathLen++] = L'\\';
        aPath[nPathLen] = 0;
    }

    if (nPathLen + nFileLen >= aPath.getBufSizeInSymbols())
        return sal_False;

    /* append file name */
    copy_ustr_n(aPath + nPathLen, aFile, nFileLen+1);
    nPathLen += nFileLen;

    /* copy filename */
    rtl_uString_newFromStr_WithLength(&strTmp, aPath, nPathLen);
    nError = osl_getFileURLFromSystemPath(strTmp, strProfileName);
    rtl_uString_release(strTmp);

    return (sal_Bool) (nError == osl_File_E_None);
}


sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile, sal_Char* pszBuffer, sal_uInt32 MaxLen)
{
    sal_uInt32    i, n = 0;
    osl_TProfileSection* pSec;
    osl_TProfileImpl*    pProfile = acquireProfile(Profile, sal_False);

    if (pProfile == NULL)
        return (0);

    if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
    {
        if (MaxLen != 0)
        {
             for (i = 0; i < pProfile->m_NoSections; i++)
            {
                pSec = &pProfile->m_Sections[i];

                if ((n + pSec->m_Len + 1) < MaxLen)
                {
                    strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset],
                            pSec->m_Len);
                    n += pSec->m_Len;
                    pszBuffer[n++] = '\0';
                }
                else
                    break;
            }

            pszBuffer[n++] = '\0';
        }
        else
        {
             for (i = 0; i < pProfile->m_NoSections; i++)
                n += pProfile->m_Sections[i].m_Len + 1;

            n += 1;
        }
    }
    else
    {
        ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH );

        WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL);
        n = GetPrivateProfileSectionNames(pszBuffer, MaxLen, aFileName);
    }

    releaseProfile(pProfile);

    return (n);
}




/*****************************************************************************/
/* Static Module Functions */
/*****************************************************************************/

static osl_TStamp getFileStamp(osl_TFile* pFile)
{
    FILETIME FileTime;

    if ((pFile->m_Handle == INVALID_HANDLE_VALUE) ||
        (! GetFileTime(pFile->m_Handle, NULL, NULL, &FileTime)))
        memset(&FileTime, 0, sizeof(FileTime));

    return (FileTime);
}



static sal_Bool lockFile(const osl_TFile* pFile, osl_TLockMode eMode)
{
    sal_Bool     status = sal_False;
    OVERLAPPED  Overlapped;

    if (pFile->m_Handle == INVALID_HANDLE_VALUE)
        return (sal_False);

    memset(&Overlapped, 0, sizeof(Overlapped));

    switch (eMode)
    {
        case un_lock:
            status = (sal_Bool) UnlockFileEx(
                pFile->m_Handle, 0, 0xFFFFFFFF, 0, &Overlapped);
            break;

        case read_lock:
            status = (sal_Bool) LockFileEx(
                pFile->m_Handle, 0, 0, 0xFFFFFFFF, 0, &Overlapped);
            break;

        case write_lock:
            status = (sal_Bool) LockFileEx(
                pFile->m_Handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 0xFFFFFFFF, 0,
                &Overlapped);
            break;
    }

    return (status);
}






















































static osl_TFile* openFileImpl(rtl_uString * strFileName, oslProfileOption ProfileFlags )
{
    osl_TFile* pFile = reinterpret_cast< osl_TFile*>( calloc( 1, sizeof(osl_TFile) ) );
    sal_Bool bWriteable = sal_False;

/*    if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE | osl_Profile_READWRITE ) )*/
    if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) )
    {
#ifdef DEBUG_OSL_PROFILE
        OSL_TRACE("setting bWriteable to TRUE\n");
#endif
        bWriteable=sal_True;
    }

    if (! bWriteable)
    {
        pFile->m_Handle = CreateFileW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strFileName )), GENERIC_READ,
                                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        /* mfe: argghh!!! do not check if the file could be openend */
        /*      default mode expects it that way!!!                 */
    }
    else
    {
#ifdef DEBUG_OSL_PROFILE
        OSL_TRACE("opening '%s' read/write\n",pszFilename);
#endif

        if ((pFile->m_Handle = CreateFileW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strFileName )), GENERIC_READ | GENERIC_WRITE,
                                               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                               OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL))
            == INVALID_HANDLE_VALUE)
        {
            free(pFile);
            return (NULL);
        }
    }

    pFile->m_pWriteBuf=0;
    pFile->m_nWriteBufFree=0;
    pFile->m_nWriteBufLen=0;

    if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) )
    {
#ifdef DEBUG_OSL_PROFILE
        OSL_TRACE("locking '%s' file\n",pszFilename);
#endif

        lockFile(pFile, bWriteable ? write_lock : read_lock);
    }

    /* mfe: new WriteBuf obsolete */
/*  pFile->m_pWritePtr = pFile->m_Buf;*/
/*  pFile->m_pReadPtr  = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);*/

    return (pFile);
}









static osl_TStamp closeFileImpl(osl_TFile* pFile)
{
    osl_TStamp stamp = {0, 0};

    if ( pFile == 0 )
    {
        return stamp;
    }

    if (pFile->m_Handle != INVALID_HANDLE_VALUE)
    {
       /* mfe: new WriteBuf obsolete */
        /* we just closing the file here, DO NOT write, it has to be handled in higher levels */
/*      if (pFile->m_pWritePtr > pFile->m_Buf)*/
/*      {*/
/*          DWORD Bytes;*/

/*          WriteFile(pFile->m_Handle, pFile->m_WriteBuf,*/
/*                    pFile->m_pWritePtr - pFile->m_WriteBuf,*/
/*                    &Bytes, NULL);*/
/*      }*/

        stamp = getFileStamp(pFile);

        lockFile(pFile, un_lock);

        CloseHandle(pFile->m_Handle);
        pFile->m_Handle = INVALID_HANDLE_VALUE;
    }

    if ( pFile->m_pWriteBuf != 0 )
    {
        free(pFile->m_pWriteBuf);
    }

    free(pFile);

    return(stamp);
}








static sal_Bool rewindFile(osl_TFile* pFile, sal_Bool bTruncate)
{
    if (pFile->m_Handle != INVALID_HANDLE_VALUE)
    {
        /* mfe: new WriteBuf obsolete */
        /* we just closing the file here, DO NOT write, it has to be handled in higher levels */
/*      if (pFile->m_pWritePtr > pFile->m_WriteBuf)*/
/*      {*/
/*          DWORD Bytes;*/

/*          WriteFile(pFile->m_Handle, pFile->m_WriteBuf,*/
/*                    pFile->m_pWritePtr - pFile->m_WriteBuf,*/
/*                    &Bytes, NULL);*/

/*          pFile->m_pWritePtr = pFile->m_WriteBuf;*/
/*      }*/

        pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);

        SetFilePointer(pFile->m_Handle, 0, NULL, FILE_BEGIN);

        if (bTruncate)
            SetEndOfFile(pFile->m_Handle);
    }

    return (sal_True);
}










static sal_Bool getLine(osl_TFile* pFile, const sal_Char *pszLine, int MaxLen)
{
    DWORD Max;
    size_t Free, Bytes;
    sal_Char* pChr;
    sal_Char* pLine = (sal_Char *)pszLine;

    if (pFile->m_Handle == INVALID_HANDLE_VALUE)
        return (sal_False);

    MaxLen -= 1;

    do
    {
        Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf);

        if (Bytes <= 1)
        {
            /* refill buffer */
            memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes);
            pFile->m_pReadPtr = pFile->m_ReadBuf;

            Free = sizeof(pFile->m_ReadBuf) - Bytes;

            if (! ReadFile(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free, &Max, NULL))
            {
                *pLine = '\0';
                return (sal_False);
            }

            if (Max < Free)
            {
                if ((Max == 0) && (pLine == pszLine))
                {
                    *pLine = '\0';
                    return (sal_False);
                }

                pFile->m_ReadBuf[Bytes + Max] = '\0';
            }
        }

        for (pChr = pFile->m_pReadPtr;
             (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') &&
             (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1));
             pChr++);

        Max = min(pChr - pFile->m_pReadPtr, MaxLen);
        memcpy(pLine, pFile->m_pReadPtr, Max);
        MaxLen -= Max;
        pLine  += Max;

        if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1))
        {
            if (*pChr != '\0')
            {
                if ((pChr[0] == '\r') && (pChr[1] == '\n'))
                    pChr += 2;
                else
                    pChr += 1;
            }

            if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) &&
                (*pChr == '\0'))
                pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);

            *pLine = '\0';

            /* setting MaxLen to -1 indicates terminating read loop */
            MaxLen = -1;
        }

        pFile->m_pReadPtr = pChr;
    }
    while (MaxLen > 0);

    return (sal_True);
}










static sal_Bool putLine(osl_TFile* pFile, const sal_Char *pszLine)
{
    unsigned int Len = strlen(pszLine);

#ifdef DEBUG_OSL_PROFILE
    int strLen=0;
#endif

    if ( pFile == 0 || pFile->m_Handle < 0 )
    {
        return (sal_False);
    }

    if ( pFile->m_pWriteBuf == 0 )
    {
        pFile->m_pWriteBuf = (sal_Char*) malloc(Len+3);
        pFile->m_nWriteBufLen = Len+3;
        pFile->m_nWriteBufFree = Len+3;
    }
    else
    {
        if ( pFile->m_nWriteBufFree <= Len + 3 )
        {
            sal_Char* pTmp;

            pTmp=(sal_Char*) realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) );
            if ( pTmp == 0 )
            {
                return sal_False;
            }
            pFile->m_pWriteBuf = pTmp;
            pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len );
            pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2;
            memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree);
        }
    }



    memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1);
#ifdef DEBUG_OSL_PROFILE
    strLen = strlen(pFile->m_pWriteBuf);
#endif
    pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\r';
    pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\n';
    pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 2]='\0';

    pFile->m_nWriteBufFree-=Len+2;

#ifdef DEBUG_OSL_PROFILE
/*    OSL_TRACE("File Buffer in _putLine '%s' '%i'(%i)\n",pFile->m_pWriteBuf,strlen(pFile->m_pWriteBuf),pFile->m_nWriteBufLen - pFile->m_nWriteBufFree);*/
#endif

    return (sal_True);
}

/* platform specific end */


static const sal_Char* stripBlanks(const sal_Char* String, sal_uInt32* pLen)
{
    if ( (pLen != NULL) && ( *pLen != 0 ) )
    {
        while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t'))
            (*pLen)--;

        while ((*String == ' ') || (*String == '\t'))
        {
            String++;
            (*pLen)--;
        }
    }
    else
        while ((*String == ' ') || (*String == '\t'))
            String++;

    return (String);
}

static const sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line)
{
    if (pProfile->m_NoLines >= pProfile->m_MaxLines)
    {
        if (pProfile->m_Lines == NULL)
        {
            pProfile->m_MaxLines = LINES_INI;
            pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *));
            memset(pProfile->m_Lines,0,pProfile->m_MaxLines * sizeof(sal_Char *));
        }
        else
        {
            unsigned int index=0;
            unsigned int oldmax=pProfile->m_MaxLines;

            pProfile->m_MaxLines += LINES_ADD;
            pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, pProfile->m_MaxLines * sizeof(sal_Char *));

            for ( index = oldmax ; index < pProfile->m_MaxLines ; ++index )
            {
                pProfile->m_Lines[index]=0;
            }
        }

        if (pProfile->m_Lines == NULL)
        {
            pProfile->m_NoLines  = 0;
            pProfile->m_MaxLines = 0;
            return (NULL);
        }

    }

    if ( pProfile->m_Lines != 0 && pProfile->m_Lines[pProfile->m_NoLines] != 0 )
    {
            free(pProfile->m_Lines[pProfile->m_NoLines]);
    }
    pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line);

    return (pProfile->m_Lines[pProfile->m_NoLines - 1]);
}

static const sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo)
{
    if (pProfile->m_NoLines >= pProfile->m_MaxLines)
    {
        if (pProfile->m_Lines == NULL)
        {
            pProfile->m_MaxLines = LINES_INI;
            pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *));
            memset(pProfile->m_Lines,0,pProfile->m_MaxLines * sizeof(sal_Char *));
        }
        else
        {
            pProfile->m_MaxLines += LINES_ADD;
            pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines,
                                                 pProfile->m_MaxLines * sizeof(sal_Char *));

            memset(&pProfile->m_Lines[pProfile->m_NoLines],
                0,
                (pProfile->m_MaxLines - pProfile->m_NoLines - 1) * sizeof(sal_Char*));
        }

        if (pProfile->m_Lines == NULL)
        {
            pProfile->m_NoLines  = 0;
            pProfile->m_MaxLines = 0;
            return (NULL);
        }
    }

    LineNo = LineNo > pProfile->m_NoLines ? pProfile->m_NoLines : LineNo;

    if (LineNo < pProfile->m_NoLines)
    {
        sal_uInt32 i, n;
        osl_TProfileSection* pSec;

        memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo],
                (pProfile->m_NoLines - LineNo) * sizeof(sal_Char *));


        /* adjust line references */
        for (i = 0; i < pProfile->m_NoSections; i++)
        {
            pSec = &pProfile->m_Sections[i];

            if (pSec->m_Line >= LineNo)
                pSec->m_Line++;

            for (n = 0; n < pSec->m_NoEntries; n++)
                if (pSec->m_Entries[n].m_Line >= LineNo)
                    pSec->m_Entries[n].m_Line++;
        }
    }

    pProfile->m_NoLines++;

    pProfile->m_Lines[LineNo] = strdup(Line);

    return (pProfile->m_Lines[LineNo]);
}

static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo)
{
    if (LineNo < pProfile->m_NoLines)
    {
        free(pProfile->m_Lines[LineNo]);
        pProfile->m_Lines[LineNo]=0;
        if (pProfile->m_NoLines - LineNo > 1)
        {
            sal_uInt32 i, n;
            osl_TProfileSection* pSec;

            memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1],
                    (pProfile->m_NoLines - LineNo - 1) * sizeof(sal_Char *));

            memset(&pProfile->m_Lines[pProfile->m_NoLines - 1],
                0,
                (pProfile->m_MaxLines - pProfile->m_NoLines) * sizeof(sal_Char*));

            /* adjust line references */
            for (i = 0; i < pProfile->m_NoSections; i++)
            {
                pSec = &pProfile->m_Sections[i];

                if (pSec->m_Line > LineNo)
                    pSec->m_Line--;

                for (n = 0; n < pSec->m_NoEntries; n++)
                    if (pSec->m_Entries[n].m_Line > LineNo)
                        pSec->m_Entries[n].m_Line--;
            }
        }
        else
        {
            pProfile->m_Lines[LineNo] = 0;
        }

        pProfile->m_NoLines--;
    }

    return;
}

static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection,
                     sal_uInt32 NoEntry, sal_uInt32 Line,
                     const sal_Char* Entry, sal_uInt32 Len)
{
    Entry = stripBlanks(Entry, &Len);
    pSection->m_Entries[NoEntry].m_Line   = Line;
    pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line];
    pSection->m_Entries[NoEntry].m_Len    = Len;

    return;
}

static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection,
                        int Line, const sal_Char* Entry, sal_uInt32 Len)
{
    if (pSection != NULL)
    {
        if (pSection->m_NoEntries >= pSection->m_MaxEntries)
        {
            if (pSection->m_Entries == NULL)
            {
                pSection->m_MaxEntries = ENTRIES_INI;
                pSection->m_Entries = (osl_TProfileEntry *)malloc(
                                pSection->m_MaxEntries * sizeof(osl_TProfileEntry));
            }
            else
            {
                pSection->m_MaxEntries += ENTRIES_ADD;
                pSection->m_Entries = (osl_TProfileEntry *)realloc(pSection->m_Entries,
                                pSection->m_MaxEntries * sizeof(osl_TProfileEntry));
            }

            if (pSection->m_Entries == NULL)
            {
                pSection->m_NoEntries  = 0;
                pSection->m_MaxEntries = 0;
                return (sal_False);
            }
        }

        pSection->m_NoEntries++;

        Entry = stripBlanks(Entry, &Len);
        setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line,
                 Entry, Len);

        return (sal_True);
    }

    return (sal_False);
}

static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry)
{
    if (NoEntry < pSection->m_NoEntries)
    {
        if (pSection->m_NoEntries - NoEntry > 1)
        {
            memmove(&pSection->m_Entries[NoEntry],
                    &pSection->m_Entries[NoEntry + 1],
                    (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry));
            pSection->m_Entries[pSection->m_NoEntries - 1].m_Line=0;
            pSection->m_Entries[pSection->m_NoEntries - 1].m_Offset=0;
            pSection->m_Entries[pSection->m_NoEntries - 1].m_Len=0;
        }

        pSection->m_NoEntries--;
    }

    return;
}

static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len)
{
    if (pProfile->m_NoSections >= pProfile->m_MaxSections)
    {
        if (pProfile->m_Sections == NULL)
        {
            pProfile->m_MaxSections = SECTIONS_INI;
            pProfile->m_Sections = (osl_TProfileSection *)malloc(pProfile->m_MaxSections * sizeof(osl_TProfileSection));
            memset(pProfile->m_Sections,0,pProfile->m_MaxSections * sizeof(osl_TProfileSection));
        }
        else
        {
            unsigned int index=0;
            unsigned int oldmax=pProfile->m_MaxSections;

            pProfile->m_MaxSections += SECTIONS_ADD;
            pProfile->m_Sections = (osl_TProfileSection *)realloc(pProfile->m_Sections,
                                          pProfile->m_MaxSections * sizeof(osl_TProfileSection));
            for ( index = oldmax ; index < pProfile->m_MaxSections ; ++index )
            {
                pProfile->m_Sections[index].m_Entries=0;
            }
        }

        if (pProfile->m_Sections == NULL)
        {
            pProfile->m_NoSections = 0;
            pProfile->m_MaxSections = 0;
            return (sal_False);
        }
    }

    pProfile->m_NoSections++;

    if ( pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries != 0 )
    {
        free(pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries);
    }
    pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries    = NULL;
    pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries  = 0;
    pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0;

    Section = (sal_Char *)stripBlanks(Section, &Len);
    pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line;
    pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line];
    pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len;

    return (sal_True);
}

static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection)
{
    sal_uInt32 Section;

    if ((Section = pSection - pProfile->m_Sections) < pProfile->m_NoSections)
    {
        free (pSection->m_Entries);
        pSection->m_Entries=0;
        if (pProfile->m_NoSections - Section > 1)
        {
            memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1],
                    (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection));

            memset(&pProfile->m_Sections[pProfile->m_NoSections - 1],
                0,
                (pProfile->m_MaxSections - pProfile->m_NoSections) * sizeof(osl_TProfileSection));
            pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = 0;
        }
        else
        {
            pSection->m_Entries = 0;
        }

        pProfile->m_NoSections--;
    }

    return;
}

static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section,
                                      const sal_Char* Entry, sal_uInt32 *pNoEntry)
{
static  sal_uInt32    Sect = 0;
        sal_uInt32    i, n;
        sal_uInt32    Len;
        const sal_Char* pStr;
        osl_TProfileSection* pSec = NULL;

    Len = strlen(Section);
    Section = (sal_Char *)stripBlanks(Section, &Len);

    n = Sect;

    for (i = 0; i < pProfile->m_NoSections; i++)
    {
        n %= pProfile->m_NoSections;
        pSec = &pProfile->m_Sections[n];
        if ((Len == pSec->m_Len) &&
            (strnicmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len)
             == 0))
            break;
        n++;
    }

    Sect = n;

    if (i < pProfile->m_NoSections)
    {
        Len = strlen(Entry);
        Entry = stripBlanks(Entry, &Len);

        *pNoEntry = pSec->m_NoEntries;

        for (i = 0; i < pSec->m_NoEntries; i++)
        {
            pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line]
                                     [pSec->m_Entries[i].m_Offset];
            if ((Len == pSec->m_Entries[i].m_Len) &&
                (strnicmp(Entry, pStr, pSec->m_Entries[i].m_Len)
                 == 0))
            {
                *pNoEntry = i;
                break;
            }
        }
    }
    else
        pSec = NULL;

    return (pSec);
}

static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile)
{
    sal_uInt32    i;
    sal_Char*       pStr;
    sal_Char*       pChar;
    sal_Char        Line[4096];

    pProfile->m_NoLines    = 0;
    pProfile->m_NoSections = 0;

    OSL_VERIFY(rewindFile(pFile, sal_False));

    while (getLine(pFile, Line, sizeof(Line)))
    {
        if (! addLine(pProfile, Line))
            return (sal_False);
    }

    for (i = 0; i < pProfile->m_NoLines; i++)
    {
        pStr = (sal_Char *)stripBlanks(pProfile->m_Lines[i], NULL);

        if ((*pStr == '\0') || (*pStr == ';'))
            continue;

        if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == NULL) ||
            ((pChar - pStr) <= 2))
        {
            /* insert entry */

            if (pProfile->m_NoSections < 1)
                continue;

            if ((pChar = strchr(pStr, '=')) == NULL)
                pChar = pStr + strlen(pStr);

            if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1],
                           i, pStr, pChar - pStr))
                return (sal_False);
        }
        else
        {
            /* new section */

            if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1))
                return (sal_False);
        }
    }

    return (sal_True);
}





static sal_Bool storeProfile(osl_TProfileImpl* pProfile, sal_Bool bCleanup)
{
#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  storeProfile\n");
#endif

    if (pProfile->m_Lines != NULL)
    {
        if (pProfile->m_Flags & FLG_MODIFIED)
        {
            sal_uInt32 i;

            osl_TFile* pTmpFile = osl_openTmpProfileImpl(pProfile);

            if ( pTmpFile == 0 )
            {
                return sal_False;
            }

            OSL_VERIFY(rewindFile(pTmpFile, sal_True));

            for (i = 0; i < pProfile->m_NoLines; i++)
            {
                OSL_VERIFY(putLine(pTmpFile, pProfile->m_Lines[i]));
            }

            if ( ! writeProfileImpl(pTmpFile) )
            {
                if ( pTmpFile->m_pWriteBuf != 0 )
                {
                    free(pTmpFile->m_pWriteBuf);
                }

                pTmpFile->m_pWriteBuf=0;
                pTmpFile->m_nWriteBufLen=0;
                pTmpFile->m_nWriteBufFree=0;

#ifdef TRACE_OSL_PROFILE
                OSL_TRACE("Out storeProfile [not flushed]\n");
#endif
                closeFileImpl(pTmpFile);

                return sal_False;
            }

            pProfile->m_Flags &= ~FLG_MODIFIED;

            closeFileImpl(pProfile->m_pFile);
            closeFileImpl(pTmpFile);

            osl_ProfileSwapProfileNames(pProfile);

/*          free(pProfile->m_pFile);*/
/*          free(pTmpFile);*/

            pProfile->m_pFile = openFileImpl(pProfile->m_strFileName,pProfile->m_Flags);

        }

        if (bCleanup)
        {
            while (pProfile->m_NoLines > 0)
                removeLine(pProfile, pProfile->m_NoLines - 1);

            free(pProfile->m_Lines);
            pProfile->m_Lines = NULL;
            pProfile->m_MaxLines = 0;

            while (pProfile->m_NoSections > 0)
                removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]);

            free(pProfile->m_Sections);
            pProfile->m_Sections = NULL;
            pProfile->m_MaxSections = 0;
        }
    }

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out storeProfile [ok]\n");
#endif
    return (sal_True);
}


static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl* pProfile)
{
    osl_TFile* pFile=0;
    rtl_uString* ustrExtension=0;
    rtl_uString* ustrTmpName=0;
    oslProfileOption PFlags=0;

    rtl_uString_newFromAscii(&ustrExtension,"tmp");


    /* generate tmp profilename */
    ustrTmpName=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension);
    rtl_uString_release(ustrExtension);

    if ( ustrTmpName == 0 )
    {
        return 0;
    }


    if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) )
    {
        PFlags |= osl_Profile_WRITELOCK;
    }

    /* open this file */
    pFile = openFileImpl(ustrTmpName,pProfile->m_Flags | PFlags);


    /* return new pFile */
    return pFile;
}


static sal_Bool osl_ProfileSwapProfileNames(osl_TProfileImpl* pProfile)
{
    sal_Bool bRet = sal_False;

    rtl_uString* ustrBakFile=0;
    rtl_uString* ustrTmpFile=0;
    rtl_uString* ustrIniFile=0;
    rtl_uString* ustrExtension=0;


    rtl_uString_newFromAscii(&ustrExtension,"bak");

    ustrBakFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension);
    rtl_uString_release(ustrExtension);
    ustrExtension=0;


    rtl_uString_newFromAscii(&ustrExtension,"ini");

    ustrIniFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension);
    rtl_uString_release(ustrExtension);
    ustrExtension=0;


    rtl_uString_newFromAscii(&ustrExtension,"tmp");

    ustrTmpFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension);
    rtl_uString_release(ustrExtension);
    ustrExtension=0;


    /* unlink bak */
    DeleteFileW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrBakFile )) );

    /* rename ini bak */
    MoveFileExW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrIniFile )), reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrBakFile )), MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH );

    /* rename tmp ini */
    MoveFileExW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrTmpFile )), reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrIniFile )), MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH );

    return bRet;
}


static rtl_uString* osl_ProfileGenerateExtension(rtl_uString* ustrFileName, rtl_uString* ustrExtension)
{
    rtl_uString* ustrNewFileName=0;
    rtl_uString* ustrOldExtension = 0;
    sal_Unicode* pExtensionBuf = 0;
    sal_Unicode* pFileNameBuf  = 0;
    sal_Int32 nIndex = -1;

    pFileNameBuf = rtl_uString_getStr(ustrFileName);

    rtl_uString_newFromAscii(&ustrOldExtension,".");

    pExtensionBuf = rtl_uString_getStr(ustrOldExtension);

    nIndex = rtl_ustr_lastIndexOfChar(pFileNameBuf,*pExtensionBuf);

    rtl_uString_newReplaceStrAt(&ustrNewFileName,
                                ustrFileName,
                                nIndex+1,
                                3,
                                ustrExtension);

    return ustrNewFileName;
}


static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable)
{
    osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile;
    oslProfileOption PFlags=0;


    if ( bWriteable )
    {
/*          PFlags = osl_Profile_DEFAULT | osl_Profile_READWRITE; */
        PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK;
    }
    else
    {
        PFlags = osl_Profile_DEFAULT;
    }


    if (pProfile == NULL)
    {
#ifdef DEBUG_OSL_PROFILE
        OSL_TRACE("AUTOOPEN MODE\n");
#endif



        if ( ( pProfile = (osl_TProfileImpl*)osl_openProfile( NULL, PFlags ) ) != NULL )
        {
            pProfile->m_Flags |= FLG_AUTOOPEN;
        }
    }
    else
    {
#ifdef DEBUG_OSL_PROFILE
        OSL_TRACE("try to acquire\n");
#endif



        if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
        {
            if (! (pProfile->m_Flags & (osl_Profile_READLOCK |
                                        osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE)))
            {
                osl_TStamp Stamp;
#ifdef DEBUG_OSL_PROFILE
                OSL_TRACE("DEFAULT MODE\n");
#endif
                pProfile->m_pFile = openFileImpl(
                    pProfile->m_strFileName, pProfile->m_Flags | PFlags);
                if (!pProfile->m_pFile)
                    return NULL;

                Stamp = getFileStamp(pProfile->m_pFile);

                if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp)))
                {
                    pProfile->m_Stamp = Stamp;

                    loadProfile(pProfile->m_pFile, pProfile);
                }
            }
            else
            {
#ifdef DEBUG_OSL_PROFILE
                OSL_TRACE("READ/WRITELOCK MODE\n");
#endif


                /* A readlock file could not be written */
                if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable)
                {
                    return (NULL);
                }
            }
        }
    }

    return (pProfile);
}

static sal_Bool releaseProfile(osl_TProfileImpl* pProfile)
{
#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("In  releaseProfile\n");
#endif

    if ( pProfile == 0 )
    {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out releaseProfile [profile==0]\n");
#endif
        return sal_False;
    }

    if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
    {
        if (pProfile->m_Flags & FLG_AUTOOPEN)
        {
#ifdef TRACE_OSL_PROFILE
        OSL_TRACE("Out releaseProfile [AUTOOPEN]\n");
#endif
            return (osl_closeProfile((oslProfile)pProfile));
        }
        else
        {
#ifdef DEBUG_OSL_PROFILE
        OSL_TRACE("DEFAULT MODE\n");
#endif
        if (! (pProfile->m_Flags & (osl_Profile_READLOCK |
                                    osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE)))
            {
                if (pProfile->m_Flags & FLG_MODIFIED)
                    storeProfile(pProfile, sal_False);

                closeFileImpl(pProfile->m_pFile);
                pProfile->m_pFile = NULL;
            }
        }
    }

#ifdef TRACE_OSL_PROFILE
    OSL_TRACE("Out releaseProfile [ok]\n");
#endif
    return (sal_True);
}

static sal_Bool lookupProfile(const sal_Unicode *strPath, const sal_Unicode *strFile, sal_Unicode *strProfile)
{
    sal_Char *pChr, *pStr;
    sal_Char Buffer[4096] = "";
    sal_Char Product[132] = "";

    ::osl::LongPathBuffer< sal_Unicode > aPath( MAX_LONG_PATH );
    aPath[0] = 0;
    DWORD dwPathLen = 0;

    if (*strPath == L'"')
    {
        int i = 0;

        strPath++;

        while ((strPath[i] != L'"') && (strPath[i] != L'\0'))
            i++;

        WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(strPath), i, Product, sizeof(Product), NULL, NULL);
        Product[i] = '\0';
        strPath += i;

        if (*strPath == L'"')
            strPath++;

        if ( (*strPath == L'/') || (*strPath == L'\\') )
        {
            strPath++;
        }
    }

    else
    {
        /* if we have not product identfication, do a special handling for soffice.ini */
        if (rtl_ustr_ascii_compare(strFile, SVERSION_PROFILE) == 0)
        {
            rtl_uString * strSVProfile  = NULL;
            rtl_uString * strSVFallback = NULL;
            rtl_uString * strSVLocation = NULL;
            rtl_uString * strSVName     = NULL;
            ::osl::LongPathBuffer< sal_Char > aDir( MAX_LONG_PATH );
            oslProfile hProfile;

            rtl_uString_newFromAscii(&strSVFallback, SVERSION_FALLBACK);
            rtl_uString_newFromAscii(&strSVLocation, SVERSION_LOCATION);
            rtl_uString_newFromAscii(&strSVName, SVERSION_NAME);

            /* open sversion.ini in the system directory, and try to locate the entry
               with the highest version for StarOffice */
            if (osl_getProfileName( strSVFallback, strSVName, &strSVProfile))
            {
                hProfile = osl_openProfile(strSVProfile, osl_Profile_READLOCK);
                if (hProfile)
                {
                    osl_getProfileSectionEntries(
                        hProfile, SVERSION_SECTION, Buffer, sizeof(Buffer));

                    for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1)
                    {
                        if ((strnicmp(
                                 pChr, SVERSION_SOFFICE,
                                 sizeof(SVERSION_SOFFICE) - 1)
                             == 0)
                            && (stricmp(Product, pChr) < 0))
                        {
                            osl_readProfileString(
                                hProfile, SVERSION_SECTION, pChr, aDir,
                                aDir.getBufSizeInSymbols(), "");

                            /* check for existence of path */
                            if (access(aDir, 0) >= 0)
                                strcpy(Product, pChr);
                        }
                    }

                    osl_closeProfile(hProfile);
                }
                rtl_uString_release(strSVProfile);
                strSVProfile = NULL;
            }

            /* open sversion.ini in the users directory, and try to locate the entry
               with the highest version for StarOffice */
            if ((strcmp(SVERSION_LOCATION, SVERSION_FALLBACK) != 0) &&
                (osl_getProfileName(strSVLocation, strSVName, &strSVProfile)))
            {
                hProfile = osl_openProfile(strSVProfile, osl_Profile_READLOCK);
                if (hProfile)
                {
                    osl_getProfileSectionEntries(
                        hProfile, SVERSION_SECTION, Buffer, sizeof(Buffer));

                    for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1)
                    {
                        if ((strnicmp(
                                 pChr, SVERSION_SOFFICE,
                                 sizeof(SVERSION_SOFFICE) - 1)
                             == 0)
                            && (stricmp(Product, pChr) < 0))
                        {
                            osl_readProfileString(
                                hProfile, SVERSION_SECTION, pChr, aDir,
                                aDir.getBufSizeInSymbols(), "");

                            /* check for existence of path */
                            if (access(aDir, 0) >= 0)
                                strcpy(Product, pChr);
                        }
                    }

                    osl_closeProfile(hProfile);
                }
                rtl_uString_release(strSVProfile);
            }

            rtl_uString_release(strSVFallback);
            rtl_uString_release(strSVLocation);
            rtl_uString_release(strSVName);

            /* remove any trailing build number */
            if ((pChr = strrchr(Product, '/')) != NULL)
                *pChr = '\0';
        }
    }

    /* if we have an userid option eg. "-userid:rh[/usr/home/rh/staroffice]",
       this will supercede all other locations */
    {
        sal_uInt32 n, nArgs = osl_getCommandArgCount();

        for (n = 0; n < nArgs; n++)
        {
            rtl_uString * strCommandArg = NULL;

            if ((osl_getCommandArg( n, &strCommandArg ) == osl_Process_E_None) &&
                ((strCommandArg->buffer[0] == L'-') || (strCommandArg->buffer[0] == L'+')) &&
                (rtl_ustr_ascii_compare_WithLength(strCommandArg->buffer, RTL_CONSTASCII_LENGTH(SVERSION_OPTION), SVERSION_OPTION)))
            {
                sal_Unicode *pCommandArg = strCommandArg->buffer + RTL_CONSTASCII_LENGTH(SVERSION_OPTION);
                sal_Int32 nStart, nEnd;

                if (((nStart = rtl_ustr_indexOfChar(pCommandArg, L'[')) != -1) &&
                    ((nEnd = rtl_ustr_indexOfChar(pCommandArg + nStart + 1, L']')) != -1))
                {
                    dwPathLen = nEnd;
                    copy_ustr_n(aPath, pCommandArg + nStart + 1, dwPathLen);
                    aPath[dwPathLen] = 0;

                    /* build full path */
                    if ((aPath[dwPathLen - 1] != L'/') && (aPath[dwPathLen - 1] != L'\\'))
                    {
                        copy_ustr_n(aPath + dwPathLen++, L"/", 2);
                    }

                    if (*strPath)
                    {
                        copy_ustr_n(aPath + dwPathLen, strPath, rtl_ustr_getLength(strPath)+1);
                        dwPathLen += rtl_ustr_getLength(strPath);
                    }
                    else
                    {
                        ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH );
                        int n;

                        if ((n = WideCharToMultiByte(CP_ACP,0, ::osl::mingw_reinterpret_cast<LPCWSTR>(aPath), -1, aTmpPath, aTmpPath.getBufSizeInSymbols(), NULL, NULL)) > 0)
                        {
                            strcpy(aTmpPath + n, SVERSION_USER);
                            if (access(aTmpPath, 0) >= 0)
                            {
                                dwPathLen += MultiByteToWideChar( CP_ACP, 0, SVERSION_USER, -1, reinterpret_cast<LPWSTR>(aPath + dwPathLen), aPath.getBufSizeInSymbols() - dwPathLen );
                            }
                        }
                    }

                    break;
                }
            }
        }
    }


    if (dwPathLen == 0)
    {
        rtl_uString * strExecutable = NULL;
        rtl_uString * strTmp = NULL;
        sal_Int32 nPos;

        /* try to find the file in the directory of the executbale */
        if (osl_getExecutableFile(&strTmp) != osl_Process_E_None)
            return (sal_False);

        /* convert to native path */
        if (osl_getSystemPathFromFileURL(strTmp, &strExecutable) != osl_File_E_None)
        {
            rtl_uString_release(strTmp);
            return sal_False;
        }

        rtl_uString_release(strTmp);

        /* seperate path from filename */
        if ((nPos = rtl_ustr_lastIndexOfChar(strExecutable->buffer, L'\\')) == -1)
        {
            if ((nPos = rtl_ustr_lastIndexOfChar(strExecutable->buffer, L':')) == -1)
            {
                return sal_False;
            }
            else
            {
                copy_ustr_n(aPath, strExecutable->buffer, nPos);
                aPath[nPos] = 0;
                dwPathLen = nPos;
            }
        }
        else
        {
            copy_ustr_n(aPath, strExecutable->buffer, nPos);
            dwPathLen = nPos;
            aPath[dwPathLen] = 0;
        }

        /* if we have no product identification use the executable file name */
        if (*Product == 0)
        {
            WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(strExecutable->buffer + nPos + 1), -1, Product, sizeof(Product), NULL, NULL);

            /* remove extension */
            if ((pChr = strrchr(Product, '.')) != NULL)
                *pChr = '\0';
        }

        rtl_uString_release(strExecutable);

        /* remember last subdir */
        nPos = rtl_ustr_lastIndexOfChar(aPath, L'\\');

        copy_ustr_n(aPath + dwPathLen++, L"\\", 2);

        if (*strPath)
        {
            copy_ustr_n(aPath + dwPathLen, strPath, rtl_ustr_getLength(strPath)+1);
            dwPathLen += rtl_ustr_getLength(strPath);
        }

        {
            ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH );

            WideCharToMultiByte(CP_ACP,0, ::osl::mingw_reinterpret_cast<LPCWSTR>(aPath), -1, aTmpPath, aTmpPath.getBufSizeInSymbols(), NULL, NULL);

            /* if file not exists, remove any specified subdirectories
               like "bin" or "program" */

            if (((access(aTmpPath, 0) < 0) && (nPos != -1)) || (*strPath == 0))
            {
                static sal_Char *SubDirs[] = SVERSION_DIRS;

                int i = 0;
                pStr = aTmpPath + nPos;

                for (i = 0; i < SAL_N_ELEMENTS(SubDirs); i++)
                    if (strnicmp(pStr + 1, SubDirs[i], strlen(SubDirs[i])) == 0)
                    {
                        if ( *strPath == 0)
                        {
                            strcpy(pStr + 1,SVERSION_USER);
                            if ( access(aTmpPath, 0) < 0 )
                            {
                                *(pStr+1)='\0';
                            }
                            else
                            {
                                dwPathLen = nPos + MultiByteToWideChar( CP_ACP, 0, SVERSION_USER, -1, reinterpret_cast<LPWSTR>(aPath + nPos + 1), aPath.getBufSizeInSymbols() - (nPos + 1) );
                            }
                        }
                        else
                        {
                            copy_ustr_n(aPath + nPos + 1, strPath, rtl_ustr_getLength(strPath)+1);
                            dwPathLen = nPos + 1 + rtl_ustr_getLength(strPath);
                        }

                        break;
                    }
            }
        }

        if ((aPath[dwPathLen - 1] != L'/') && (aPath[dwPathLen - 1] != L'\\'))
        {
            aPath[dwPathLen++] = L'\\';
            aPath[dwPathLen] = 0;
        }

        copy_ustr_n(aPath + dwPathLen, strFile, rtl_ustr_getLength(strFile)+1);

        {
            ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH );

            WideCharToMultiByte(CP_ACP,0, ::osl::mingw_reinterpret_cast<LPCWSTR>(aPath), -1, aTmpPath, aTmpPath.getBufSizeInSymbols(), NULL, NULL);

            if ((access(aTmpPath, 0) < 0) && (strlen(Product) > 0))
            {
                rtl_uString * strSVFallback = NULL;
                rtl_uString * strSVProfile  = NULL;
                rtl_uString * strSVLocation = NULL;
                rtl_uString * strSVName     = NULL;
                oslProfile hProfile;

                rtl_uString_newFromAscii(&strSVFallback, SVERSION_FALLBACK);
                rtl_uString_newFromAscii(&strSVLocation, SVERSION_LOCATION);
                rtl_uString_newFromAscii(&strSVName, SVERSION_NAME);

                /* open sversion.ini in the system directory, and try to locate the entry
                   with the highest version for StarOffice */
                if (osl_getProfileName(strSVLocation, strSVName, &strSVProfile))
                {
                    hProfile = osl_openProfile(
                        strSVProfile, osl_Profile_READLOCK);
                    if (hProfile)
                    {
                        osl_readProfileString(
                            hProfile, SVERSION_SECTION, Product, Buffer,
                            sizeof(Buffer), "");
                        osl_closeProfile(hProfile);

                        /* if not found, try the fallback */
                        if ((strlen(Buffer) <= 0)
                            && (strcmp(SVERSION_LOCATION, SVERSION_FALLBACK)
                                != 0))
                        {
                            if (osl_getProfileName(
                                    strSVFallback, strSVName, &strSVProfile))
                            {
                                hProfile = osl_openProfile(
                                    strSVProfile, osl_Profile_READLOCK);
                                if (hProfile)
                                {
                                    osl_readProfileString(
                                        hProfile, SVERSION_SECTION, Product,
                                        Buffer, sizeof(Buffer), "");
                                }
                            }

                            osl_closeProfile(hProfile);
                        }

                        if (strlen(Buffer) > 0)
                        {
                            dwPathLen = MultiByteToWideChar(
                                CP_ACP, 0, Buffer, -1, ::osl::mingw_reinterpret_cast<LPWSTR>(aPath), aPath.getBufSizeInSymbols() );
                            dwPathLen -=1;

                            /* build full path */
                            if ((aPath[dwPathLen - 1] != L'/')
                                && (aPath[dwPathLen - 1] != L'\\'))
                            {
                                copy_ustr_n(aPath + dwPathLen++, L"\\", 2);
                            }

                            if (*strPath)
                            {
                                copy_ustr_n(aPath + dwPathLen, strPath, rtl_ustr_getLength(strPath)+1);
                                dwPathLen += rtl_ustr_getLength(strPath);
                            }
                            else
                            {
                                ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH );
                                int n;

                                if ((n = WideCharToMultiByte(
                                         CP_ACP,0, ::osl::mingw_reinterpret_cast<LPCWSTR>(aPath), -1, aTmpPath,
                                         aTmpPath.getBufSizeInSymbols(), NULL, NULL))
                                    > 0)
                                {
                                    strcpy(aTmpPath + n, SVERSION_USER);
                                    if (access(aTmpPath, 0) >= 0)
                                    {
                                        dwPathLen += MultiByteToWideChar(
                                            CP_ACP, 0, SVERSION_USER, -1,
                                            reinterpret_cast<LPWSTR>(aPath + dwPathLen),
                                            aPath.getBufSizeInSymbols() - dwPathLen );
                                    }
                                }
                            }
                        }
                    }

                    rtl_uString_release(strSVProfile);
                }

                rtl_uString_release(strSVFallback);
                rtl_uString_release(strSVLocation);
                rtl_uString_release(strSVName);
            }
        }

        aPath[dwPathLen] = 0;
    }

    /* copy filename */
    copy_ustr_n(strProfile, aPath, dwPathLen+1);

    return sal_True;
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
