lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / sal / osl / w32 / profile.cxx
blobccf96ff35e03a8e9771657c6b949ebf4628df955
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "system.h"
22 #include "file_url.hxx"
23 #include "path_helper.hxx"
25 #include <string.h>
26 #include <osl/diagnose.h>
27 #include <osl/profile.h>
28 #include <osl/process.h>
29 #include <osl/thread.h>
30 #include <osl/file.h>
31 #include <rtl/alloc.h>
32 #include <sal/macros.h>
33 #include <sal/log.hxx>
34 #include <o3tl/char16_t2wchar_t.hxx>
35 #include <algorithm>
36 #include <vector>
37 using std::min;
38 static inline void copy_ustr_n( void *dest, const void *source, size_t length ) { memcpy(dest, source, length*sizeof(sal_Unicode)); }
40 #define LINES_INI 32
41 #define LINES_ADD 10
42 #define SECTIONS_INI 5
43 #define SECTIONS_ADD 3
44 #define ENTRIES_INI 5
45 #define ENTRIES_ADD 3
47 #define STR_INI_EXTENSION L".ini"
48 #define STR_INI_METAHOME "?~"
49 #define STR_INI_METASYS "?$"
50 #define STR_INI_METACFG "?^"
51 #define STR_INI_METAINS "?#"
53 #define STR_INI_BOOLYES "yes"
54 #define STR_INI_BOOLON "on"
55 #define STR_INI_BOOLONE "1"
56 #define STR_INI_BOOLNO "no"
57 #define STR_INI_BOOLOFF "off"
58 #define STR_INI_BOOLZERO "0"
60 #define FLG_USER 0x00FF
61 #define FLG_AUTOOPEN 0x0100
62 #define FLG_MODIFIED 0x0200
64 #define SVERSION_LOCATION STR_INI_METACFG
65 #define SVERSION_FALLBACK STR_INI_METASYS
66 #define SVERSION_NAME "sversion"
67 #define SVERSION_SECTION "Versions"
68 #define SVERSION_SOFFICE "StarOffice"
69 #define SVERSION_PROFILE "soffice.ini"
70 #define SVERSION_DIRS { "bin", "program" }
71 #define SVERSION_USER "user"
73 /*#define DEBUG_OSL_PROFILE 1*/
75 typedef FILETIME osl_TStamp;
77 enum osl_TLockMode
79 un_lock, read_lock, write_lock
82 struct osl_TFile
84 HANDLE m_Handle;
85 sal_Char* m_pReadPtr;
86 sal_Char m_ReadBuf[512];
87 sal_Char* m_pWriteBuf;
88 sal_uInt32 m_nWriteBufLen;
89 sal_uInt32 m_nWriteBufFree;
92 struct osl_TProfileEntry
94 sal_uInt32 m_Line;
95 sal_uInt32 m_Offset;
96 sal_uInt32 m_Len;
99 struct osl_TProfileSection
101 sal_uInt32 m_Line;
102 sal_uInt32 m_Offset;
103 sal_uInt32 m_Len;
104 sal_uInt32 m_NoEntries;
105 sal_uInt32 m_MaxEntries;
106 osl_TProfileEntry* m_Entries;
110 Profile-data structure hidden behind oslProfile:
112 struct osl_TProfileImpl
114 sal_uInt32 m_Flags;
115 osl_TFile* m_pFile;
116 osl_TStamp m_Stamp;
117 sal_uInt32 m_NoLines;
118 sal_uInt32 m_MaxLines;
119 sal_uInt32 m_NoSections;
120 sal_uInt32 m_MaxSections;
121 sal_Char** m_Lines;
122 rtl_uString *m_strFileName;
123 osl_TProfileSection* m_Sections;
126 static osl_TFile* openFileImpl(rtl_uString * strFileName, oslProfileOption ProfileFlags );
127 static osl_TStamp closeFileImpl(osl_TFile* pFile);
128 static bool lockFile(const osl_TFile* pFile, osl_TLockMode eMode);
129 static bool rewindFile(osl_TFile* pFile, bool bTruncate);
130 static osl_TStamp getFileStamp(osl_TFile* pFile);
132 static bool getLine(osl_TFile* pFile, sal_Char *pszLine, int MaxLen);
133 static bool putLine(osl_TFile* pFile, const sal_Char *pszLine);
134 static const sal_Char* stripBlanks(const sal_Char* String, sal_uInt32* pLen);
135 static const sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line);
136 static const sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo);
137 static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo);
138 static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection,
139 sal_uInt32 NoEntry, sal_uInt32 Line,
140 const sal_Char* Entry, sal_uInt32 Len);
141 static bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection,
142 int Line, const sal_Char* Entry, sal_uInt32 Len);
143 static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry);
144 static bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len);
145 static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection);
146 static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section,
147 const sal_Char* Entry, sal_uInt32 *pNoEntry);
148 static bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile);
149 static bool storeProfile(osl_TProfileImpl* pProfile, bool bCleanup);
150 static osl_TProfileImpl* acquireProfile(oslProfile Profile, bool bWriteable);
151 static bool releaseProfile(osl_TProfileImpl* pProfile);
152 static bool lookupProfile(const sal_Unicode *strPath, const sal_Unicode *strFile, sal_Unicode *strProfile);
154 static bool writeProfileImpl (osl_TFile* pFile);
155 static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl*);
156 static bool osl_ProfileSwapProfileNames(osl_TProfileImpl*);
157 static rtl_uString* osl_ProfileGenerateExtension(rtl_uString* ustrFileName, rtl_uString* ustrExtension);
159 static bool osl_getProfileName(rtl_uString* strPath, rtl_uString* strName, rtl_uString** strProfileName);
161 oslProfile SAL_CALL osl_openProfile(rtl_uString *strProfileName, sal_uInt32 Flags)
163 osl_TFile* pFile = nullptr;
164 osl_TProfileImpl* pProfile;
165 rtl_uString *FileName=nullptr;
167 OSL_VERIFY(strProfileName);
169 if (rtl_uString_getLength(strProfileName) == 0 )
171 OSL_VERIFY(osl_getProfileName(nullptr, nullptr, &FileName));
173 else
175 rtl_uString_assign(&FileName, strProfileName);
178 osl_getSystemPathFromFileURL(FileName, &FileName);
180 #ifdef DEBUG_OSL_PROFILE
181 Flags=osl_Profile_FLUSHWRITE;
183 if ( Flags == osl_Profile_DEFAULT )
185 SAL_INFO("sal.osl", "with osl_Profile_DEFAULT");
187 if ( Flags & osl_Profile_SYSTEM )
189 SAL_INFO("sal.osl", "with osl_Profile_SYSTEM");
191 if ( Flags & osl_Profile_READLOCK )
193 SAL_INFO("sal.osl", "with osl_Profile_READLOCK");
195 if ( Flags & osl_Profile_WRITELOCK )
197 SAL_INFO("sal.osl", "with osl_Profile_WRITELOCK");
199 if ( Flags & osl_Profile_FLUSHWRITE )
201 SAL_INFO("sal.osl", "with osl_Profile_FLUSHWRITE");
203 #endif
205 if ( (! (Flags & osl_Profile_SYSTEM)) && ( (pFile = openFileImpl(FileName, Flags) ) == nullptr ) )
207 if( FileName)
208 rtl_uString_release( FileName);
210 return nullptr;
213 pProfile = static_cast<osl_TProfileImpl*>(calloc(1, sizeof(osl_TProfileImpl)));
214 if (!pProfile)
215 return nullptr;
217 pProfile->m_Flags = Flags & FLG_USER;
218 osl_getSystemPathFromFileURL(strProfileName, &pProfile->m_strFileName);
220 if (Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ))
221 pProfile->m_pFile = pFile;
223 pProfile->m_Stamp = getFileStamp(pFile);
225 loadProfile(pFile, pProfile);
227 if (pProfile->m_pFile == nullptr)
228 closeFileImpl(pFile);
230 if( FileName)
231 rtl_uString_release( FileName);
233 return pProfile;
236 sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile)
238 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
241 if ( Profile == nullptr )
243 return false;
246 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
248 pProfile = acquireProfile(Profile,true);
250 if ( pProfile != nullptr )
252 if ( !( pProfile->m_Flags & osl_Profile_READLOCK ) && ( pProfile->m_Flags & FLG_MODIFIED ) )
254 storeProfile(pProfile, false);
257 else
259 pProfile = acquireProfile(Profile,false);
262 if ( pProfile == nullptr )
264 return false;
267 if (pProfile->m_pFile != nullptr)
268 closeFileImpl(pProfile->m_pFile);
271 pProfile->m_pFile = nullptr;
272 rtl_uString_release(pProfile->m_strFileName);
273 pProfile->m_strFileName = nullptr;
275 /* release whole profile data types memory */
276 if ( pProfile->m_NoLines > 0)
278 unsigned int index=0;
279 if ( pProfile->m_Lines != nullptr )
281 for ( index = 0 ; index < pProfile->m_NoLines ; ++index)
283 if ( pProfile->m_Lines[index] != nullptr )
285 free(pProfile->m_Lines[index]);
288 free(pProfile->m_Lines);
290 if ( pProfile->m_Sections != nullptr )
292 for ( index = 0 ; index < pProfile->m_NoSections ; ++index )
294 if ( pProfile->m_Sections[index].m_Entries != nullptr )
295 free(pProfile->m_Sections[index].m_Entries);
297 free(pProfile->m_Sections);
301 free(pProfile);
303 return true;
306 sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile)
308 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
309 osl_TFile* pFile;
310 bool bRet = false;
313 if ( pProfile == nullptr )
315 return false;
318 pFile = pProfile->m_pFile;
319 if ( pFile == nullptr || pFile->m_Handle == INVALID_HANDLE_VALUE )
321 return false;
324 if ( pProfile->m_Flags & FLG_MODIFIED )
326 #ifdef DEBUG_OSL_PROFILE
327 SAL_INFO("sal.osl", "swapping to storeprofile");
328 #endif
329 bRet = storeProfile(pProfile,false);
332 return bRet;
335 static bool writeProfileImpl(osl_TFile* pFile)
337 DWORD BytesWritten=0;
338 BOOL bRet;
340 if ( !( pFile != nullptr && pFile->m_Handle != INVALID_HANDLE_VALUE ) || ( pFile->m_pWriteBuf == nullptr ) )
342 return false;
345 bRet=WriteFile(pFile->m_Handle, pFile->m_pWriteBuf, pFile->m_nWriteBufLen - pFile->m_nWriteBufFree,&BytesWritten,nullptr);
347 if ( bRet == 0 || BytesWritten == 0 )
349 OSL_ENSURE(bRet,"WriteFile failed!!!");
350 SAL_WARN("sal.osl", "write failed " << strerror(errno));
352 return false;
355 free(pFile->m_pWriteBuf);
356 pFile->m_pWriteBuf=nullptr;
357 pFile->m_nWriteBufLen=0;
358 pFile->m_nWriteBufFree=0;
360 return true;
363 namespace {
364 // Use Unicode version of GetPrivateProfileString, to work with Multi-language paths
365 DWORD GetPrivateProfileStringWrapper(const osl_TProfileImpl* pProfile,
366 const sal_Char* pszSection, const sal_Char* pszEntry,
367 sal_Char* pszString, sal_uInt32 MaxLen,
368 const sal_Char* pszDefault)
370 OSL_ASSERT(pProfile && (!MaxLen || pszString));
372 rtl_uString *pSection = nullptr, *pEntry = nullptr, *pDefault = nullptr;
373 if (pszSection)
375 rtl_string2UString(&pSection, pszSection, strlen(pszSection), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);
376 OSL_ASSERT(pSection);
378 if (pszEntry)
380 rtl_string2UString(&pEntry, pszEntry, strlen(pszEntry), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);
381 OSL_ASSERT(pEntry);
383 if (pszDefault)
385 rtl_string2UString(&pDefault, pszDefault, strlen(pszDefault), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);
386 OSL_ASSERT(pDefault);
389 LPCWSTR pWSection = (pSection ? o3tl::toW(rtl_uString_getStr(pSection)) : nullptr),
390 pWEntry = (pEntry ? o3tl::toW(rtl_uString_getStr(pEntry)) : nullptr),
391 pWDefault = (pDefault ? o3tl::toW(rtl_uString_getStr(pDefault)) : nullptr);
393 std::vector<wchar_t> aBuf(MaxLen + 1);
394 GetPrivateProfileStringW(pWSection, pWEntry, pWDefault, &aBuf[0], MaxLen, o3tl::toW(rtl_uString_getStr(pProfile->m_strFileName)));
396 if (pDefault)
397 rtl_uString_release(pDefault);
398 if (pEntry)
399 rtl_uString_release(pEntry);
400 if (pSection)
401 rtl_uString_release(pSection);
403 return WideCharToMultiByte(CP_ACP, 0, &aBuf[0], -1, pszString, MaxLen, nullptr, nullptr);
406 // Use Unicode version of WritePrivateProfileString, to work with Multi-language paths
407 BOOL WritePrivateProfileStringWrapper(const osl_TProfileImpl* pProfile,
408 const sal_Char* pszSection, const sal_Char* pszEntry,
409 const sal_Char* pszString)
411 OSL_ASSERT(pProfile && pszSection);
412 rtl_uString *pSection, *pEntry = nullptr, *pString = nullptr;
413 rtl_string2UString(&pSection, pszSection, strlen(pszSection), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);
414 OSL_ASSERT(pSection);
415 if (pszEntry)
417 rtl_string2UString(&pEntry, pszEntry, strlen(pszEntry), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);
418 OSL_ASSERT(pEntry);
420 if (pszString)
422 rtl_string2UString(&pString, pszString, strlen(pszString), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);
423 OSL_ASSERT(pString);
426 LPCWSTR pWSection = o3tl::toW(pSection->buffer),
427 pWEntry = (pEntry ? o3tl::toW(rtl_uString_getStr(pEntry)) : nullptr),
428 pWString = (pString ? o3tl::toW(rtl_uString_getStr(pString)) : nullptr);
430 BOOL bResult = WritePrivateProfileStringW(pWSection, pWEntry, pWString, o3tl::toW(rtl_uString_getStr(pProfile->m_strFileName)));
432 if (pString)
433 rtl_uString_release(pString);
434 if (pEntry)
435 rtl_uString_release(pEntry);
436 rtl_uString_release(pSection);
438 return bResult;
442 sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile,
443 const sal_Char* pszSection, const sal_Char* pszEntry,
444 sal_Char* pszString, sal_uInt32 MaxLen,
445 const sal_Char* pszDefault)
447 sal_uInt32 NoEntry;
448 const sal_Char* pStr = nullptr;
449 osl_TProfileImpl* pProfile = nullptr;
451 pProfile = acquireProfile(Profile, false);
453 if (pProfile == nullptr)
455 return false;
458 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
460 osl_TProfileSection* pSec;
461 if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != nullptr) &&
462 (NoEntry < pSec->m_NoEntries) &&
463 ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line],
464 '=')) != nullptr))
465 pStr++;
466 else
467 pStr = pszDefault;
469 if ( pStr != nullptr )
471 pStr = stripBlanks(pStr, nullptr);
472 MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr);
473 pStr = stripBlanks(pStr, &MaxLen);
474 strncpy(pszString, pStr, MaxLen);
475 pszString[MaxLen] = '\0';
478 else
480 if (GetPrivateProfileStringWrapper(pProfile, pszSection, pszEntry, pszString, MaxLen, pszDefault) > 0)
481 pStr = pszString; // required to return true below
484 releaseProfile(pProfile);
486 if ( pStr == nullptr )
488 return false;
491 return true;
494 sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile,
495 const sal_Char* pszSection, const sal_Char* pszEntry,
496 sal_Bool Default)
498 sal_Char Line[32];
500 if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), ""))
502 if ((stricmp(Line, STR_INI_BOOLYES) == 0) ||
503 (stricmp(Line, STR_INI_BOOLON) == 0) ||
504 (stricmp(Line, STR_INI_BOOLONE) == 0))
505 Default = true;
506 else
507 if ((stricmp(Line, STR_INI_BOOLNO) == 0) ||
508 (stricmp(Line, STR_INI_BOOLOFF) == 0) ||
509 (stricmp(Line, STR_INI_BOOLZERO) == 0))
510 Default = false;
513 return Default;
516 sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile,
517 const sal_Char* pszSection, const sal_Char* pszEntry,
518 sal_uInt32 FirstId, const sal_Char* Strings[],
519 sal_uInt32 Default)
521 sal_uInt32 i;
522 sal_Char Line[256];
524 if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), ""))
526 i = 0;
527 while (Strings[i] != nullptr)
529 if (stricmp(Line, Strings[i]) == 0)
531 Default = i + FirstId;
532 break;
534 i++;
538 return Default;
541 sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile,
542 const sal_Char* pszSection, const sal_Char* pszEntry,
543 const sal_Char* pszString)
545 sal_uInt32 i;
546 bool bRet = false;
547 sal_uInt32 NoEntry;
548 const sal_Char* pStr;
549 sal_Char Line[4096];
550 osl_TProfileSection* pSec;
551 osl_TProfileImpl* pProfile = nullptr;
553 pProfile = acquireProfile(Profile, true);
555 if (pProfile == nullptr)
557 return false;
560 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
562 if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == nullptr)
564 Line[0] = '\0';
565 addLine(pProfile, Line);
567 Line[0] = '[';
568 strcpy(&Line[1], pszSection);
569 Line[1 + strlen(pszSection)] = ']';
570 Line[2 + strlen(pszSection)] = '\0';
572 if (((pStr = addLine(pProfile, Line)) == nullptr) ||
573 (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection))))
575 releaseProfile(pProfile);
576 return false;
579 pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1];
580 NoEntry = pSec->m_NoEntries;
583 Line[0] = '\0';
584 strcpy(&Line[0], pszEntry);
585 Line[0 + strlen(pszEntry)] = '=';
586 strcpy(&Line[1 + strlen(pszEntry)], pszString);
588 if (NoEntry >= pSec->m_NoEntries)
590 if (pSec->m_NoEntries > 0)
591 i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1;
592 else
593 i = pSec->m_Line + 1;
595 if (((pStr = insertLine(pProfile, Line, i)) == nullptr) ||
596 (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry))))
598 releaseProfile(pProfile);
599 return false;
602 pProfile->m_Flags |= FLG_MODIFIED;
604 else
606 i = pSec->m_Entries[NoEntry].m_Line;
607 free(pProfile->m_Lines[i]);
608 pProfile->m_Lines[i] = strdup(Line);
609 setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry));
611 pProfile->m_Flags |= FLG_MODIFIED;
614 else
616 WritePrivateProfileStringWrapper(pProfile, pszSection, pszEntry, pszString);
619 bRet = releaseProfile(pProfile);
620 return bRet;
623 sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile,
624 const sal_Char* pszSection, const sal_Char* pszEntry,
625 sal_Bool Value)
627 bool bRet = false;
629 if (Value)
630 bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE);
631 else
632 bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO);
634 return bRet;
637 sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile,
638 const sal_Char* pszSection, const sal_Char* pszEntry,
639 sal_uInt32 FirstId, const sal_Char* Strings[],
640 sal_uInt32 Value)
642 int i, n;
643 bool bRet = false;
645 for (n = 0; Strings[n] != nullptr; n++);
647 if ((i = Value - FirstId) >= n)
648 bRet=false;
649 else
650 bRet=osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]);
652 return bRet;
655 sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile,
656 const sal_Char *pszSection, const sal_Char *pszEntry)
658 sal_uInt32 NoEntry;
659 osl_TProfileImpl* pProfile = nullptr;
660 bool bRet = false;
662 pProfile = acquireProfile(Profile, true);
664 if (pProfile == nullptr)
665 return false;
667 if (!(pProfile->m_Flags & osl_Profile_SYSTEM))
669 osl_TProfileSection* pSec;
670 if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != nullptr) &&
671 (NoEntry < pSec->m_NoEntries))
673 removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line);
674 removeEntry(pSec, NoEntry);
675 if (pSec->m_NoEntries == 0)
677 removeLine(pProfile, pSec->m_Line);
679 /* remove any empty separation line */
680 if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0'))
681 removeLine(pProfile, pSec->m_Line - 1);
683 removeSection(pProfile, pSec);
686 pProfile->m_Flags |= FLG_MODIFIED;
689 else
691 WritePrivateProfileStringWrapper(pProfile, pszSection, pszEntry, nullptr);
694 bRet = releaseProfile(pProfile);
695 return bRet;
698 sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile, const sal_Char *pszSection,
699 sal_Char* pszBuffer, sal_uInt32 MaxLen)
701 sal_uInt32 i, n = 0;
702 sal_uInt32 NoEntry;
703 osl_TProfileImpl* pProfile = nullptr;
705 pProfile = acquireProfile(Profile, false);
707 if (pProfile == nullptr)
708 return 0;
710 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
712 osl_TProfileSection* pSec;
713 if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != nullptr)
715 if (MaxLen != 0)
717 for (i = 0; i < pSec->m_NoEntries; i++)
719 if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen)
721 strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line]
722 [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len);
723 n += pSec->m_Entries[i].m_Len;
724 pszBuffer[n++] = '\0';
726 else
728 break;
733 pszBuffer[n++] = '\0';
735 else
737 for (i = 0; i < pSec->m_NoEntries; i++)
739 n += pSec->m_Entries[i].m_Len + 1;
742 n += 1;
745 else
747 n = 0;
750 else
752 n = GetPrivateProfileStringWrapper(pProfile, pszSection, nullptr, pszBuffer, MaxLen, nullptr);
755 releaseProfile(pProfile);
757 return n;
760 bool osl_getProfileName(rtl_uString* strPath, rtl_uString* strName, rtl_uString** strProfileName)
762 bool bFailed;
763 ::osl::LongPathBuffer< sal_Unicode > aFile( MAX_LONG_PATH );
764 ::osl::LongPathBuffer< sal_Unicode > aPath( MAX_LONG_PATH );
765 sal_uInt32 nFileLen = 0;
766 sal_uInt32 nPathLen = 0;
768 rtl_uString * strTmp = nullptr;
769 oslFileError nError;
771 /* build file name */
772 if (strName && strName->length)
774 if( ::sal::static_int_cast< sal_uInt32 >( strName->length ) >= aFile.getBufSizeInSymbols() )
775 return false;
777 copy_ustr_n( aFile, strName->buffer, strName->length+1);
778 nFileLen = strName->length;
780 if (rtl_ustr_indexOfChar( aFile, L'.' ) == -1)
782 if (nFileLen + wcslen(STR_INI_EXTENSION) >= aFile.getBufSizeInSymbols())
783 return false;
785 /* add default extension */
786 copy_ustr_n( aFile + nFileLen, STR_INI_EXTENSION, wcslen(STR_INI_EXTENSION)+1 );
787 nFileLen += wcslen(STR_INI_EXTENSION);
790 else
792 rtl_uString *strProgName = nullptr;
793 sal_Unicode *pProgName;
794 sal_Int32 nOffset = 0;
795 sal_Int32 nLen;
796 sal_Int32 nPos;
798 if (osl_getExecutableFile(&strProgName) != osl_Process_E_None)
799 return false;
801 /* remove path and extension from filename */
802 pProgName = strProgName->buffer;
803 nLen = strProgName->length ;
805 if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L'/' )) != -1)
806 nOffset = nPos + 1;
807 else if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L':' )) != -1)
808 nOffset = nPos + 1;
810 if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L'.' )) != -1 )
811 nLen -= 4;
813 if ((nFileLen = nLen - nOffset) >= aFile.getBufSizeInSymbols())
814 return false;
816 copy_ustr_n(aFile, pProgName + nOffset, nFileLen);
818 if (nFileLen + wcslen(STR_INI_EXTENSION) >= aFile.getBufSizeInSymbols())
819 return false;
821 /* add default extension */
822 copy_ustr_n(aFile + nFileLen, STR_INI_EXTENSION, wcslen(STR_INI_EXTENSION)+1);
823 nFileLen += wcslen(STR_INI_EXTENSION);
825 rtl_uString_release( strProgName );
828 if (aFile[0] == 0)
829 return false;
831 /* build directory path */
832 if (strPath && strPath->length)
834 sal_Unicode *pPath = rtl_uString_getStr(strPath);
835 sal_Int32 nLen = rtl_uString_getLength(strPath);
837 if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METAHOME) , STR_INI_METAHOME) == 0) &&
838 ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)] == '/')))
840 rtl_uString * strHome = nullptr;
841 oslSecurity security = osl_getCurrentSecurity();
843 bFailed = ! osl_getHomeDir(security, &strHome);
844 osl_freeSecurityHandle(security);
846 if (bFailed) return false;
848 if ( ::sal::static_int_cast< sal_uInt32 >( strHome->length ) >= aPath.getBufSizeInSymbols())
849 return false;
851 copy_ustr_n( aPath, strHome->buffer, strHome->length+1);
852 nPathLen = strHome->length;
854 if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METAHOME))
856 pPath += RTL_CONSTASCII_LENGTH(STR_INI_METAHOME);
857 nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METAHOME);
859 if (nLen + nPathLen >= aPath.getBufSizeInSymbols())
860 return false;
862 copy_ustr_n(aPath + nPathLen, pPath, nLen+1);
863 nPathLen += nLen;
866 rtl_uString_release(strHome);
869 else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METACFG), STR_INI_METACFG) == 0) &&
870 ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METACFG)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METACFG)] == '/')))
872 rtl_uString * strConfig = nullptr;
873 oslSecurity security = osl_getCurrentSecurity();
875 bFailed = ! osl_getConfigDir(security, &strConfig);
876 osl_freeSecurityHandle(security);
878 if (bFailed) return false;
880 if ( ::sal::static_int_cast< sal_uInt32 >( strConfig->length ) >= aPath.getBufSizeInSymbols())
881 return false;
883 copy_ustr_n( aPath, strConfig->buffer, strConfig->length+1 );
884 nPathLen = strConfig->length;
886 if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METACFG))
888 pPath += RTL_CONSTASCII_LENGTH(STR_INI_METACFG);
889 nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METACFG);
891 if (nLen + nPathLen >= aPath.getBufSizeInSymbols())
892 return false;
894 copy_ustr_n(aPath + nPathLen, pPath, nLen+1);
895 nPathLen += nLen;
898 rtl_uString_release(strConfig);
901 else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METASYS), STR_INI_METASYS) == 0) &&
902 ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METASYS)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METASYS)] == '/')))
904 if (((nPathLen = GetWindowsDirectoryW(o3tl::toW(aPath), aPath.getBufSizeInSymbols())) == 0) || (nPathLen >= aPath.getBufSizeInSymbols()))
905 return false;
907 if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METASYS))
909 pPath += RTL_CONSTASCII_LENGTH(STR_INI_METASYS);
910 nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METASYS);
912 if (nLen + nPathLen >= aPath.getBufSizeInSymbols())
913 return false;
915 copy_ustr_n(aPath + nPathLen, pPath, nLen+1);
916 nPathLen += nLen;
920 else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METAINS), STR_INI_METAINS) == 0) &&
921 ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METAINS)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAINS)] == '/') ||
922 (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAINS)] == '"') ) )
924 if (! lookupProfile(pPath + RTL_CONSTASCII_LENGTH(STR_INI_METAINS), aFile, aPath))
925 return false;
927 nPathLen = rtl_ustr_getLength(aPath);
930 else if( ::sal::static_int_cast< sal_uInt32 >( nLen ) < aPath.getBufSizeInSymbols())
932 copy_ustr_n(aPath, pPath, nLen+1);
933 nPathLen = rtl_ustr_getLength(aPath);
935 else
936 return false;
938 else
940 rtl_uString * strConfigDir = nullptr;
941 oslSecurity security = osl_getCurrentSecurity();
943 bFailed = ! osl_getConfigDir(security, &strConfigDir);
944 osl_freeSecurityHandle(security);
946 if (bFailed) return false;
947 if ( ::sal::static_int_cast< sal_uInt32 >( strConfigDir->length ) >= aPath.getBufSizeInSymbols() )
948 return false;
950 copy_ustr_n(aPath, strConfigDir->buffer, strConfigDir->length+1);
951 nPathLen = strConfigDir->length;
954 if (nPathLen && (aPath[nPathLen - 1] != L'/') && (aPath[nPathLen - 1] != L'\\'))
956 aPath[nPathLen++] = L'\\';
957 aPath[nPathLen] = 0;
960 if (nPathLen + nFileLen >= aPath.getBufSizeInSymbols())
961 return false;
963 /* append file name */
964 copy_ustr_n(aPath + nPathLen, aFile, nFileLen+1);
965 nPathLen += nFileLen;
967 /* copy filename */
968 rtl_uString_newFromStr_WithLength(&strTmp, aPath, nPathLen);
969 nError = osl_getFileURLFromSystemPath(strTmp, strProfileName);
970 rtl_uString_release(strTmp);
972 return nError == osl_File_E_None;
975 sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile, sal_Char* pszBuffer, sal_uInt32 MaxLen)
977 sal_uInt32 i, n = 0;
978 osl_TProfileImpl* pProfile = acquireProfile(Profile, false);
980 if (pProfile == nullptr)
981 return 0;
983 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
985 if (MaxLen != 0)
987 for (i = 0; i < pProfile->m_NoSections; i++)
989 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
991 if ((n + pSec->m_Len + 1) < MaxLen)
993 strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset],
994 pSec->m_Len);
995 n += pSec->m_Len;
996 pszBuffer[n++] = '\0';
998 else
999 break;
1002 pszBuffer[n++] = '\0';
1004 else
1006 for (i = 0; i < pProfile->m_NoSections; i++)
1007 n += pProfile->m_Sections[i].m_Len + 1;
1009 n += 1;
1012 else
1014 std::vector<wchar_t> aBuf(MaxLen + 1);
1015 GetPrivateProfileSectionNamesW(&aBuf[0], MaxLen, o3tl::toW(rtl_uString_getStr(pProfile->m_strFileName)));
1017 n = WideCharToMultiByte(CP_ACP, 0, &aBuf[0], -1, pszBuffer, MaxLen, nullptr, nullptr);
1020 releaseProfile(pProfile);
1022 return n;
1025 static osl_TStamp getFileStamp(osl_TFile* pFile)
1027 FILETIME FileTime;
1029 if ((pFile->m_Handle == INVALID_HANDLE_VALUE) ||
1030 (! GetFileTime(pFile->m_Handle, nullptr, nullptr, &FileTime)))
1031 memset(&FileTime, 0, sizeof(FileTime));
1033 return FileTime;
1036 static bool lockFile(const osl_TFile* pFile, osl_TLockMode eMode)
1038 bool status = false;
1039 OVERLAPPED Overlapped;
1041 if (pFile->m_Handle == INVALID_HANDLE_VALUE)
1042 return false;
1044 memset(&Overlapped, 0, sizeof(Overlapped));
1046 switch (eMode)
1048 case un_lock:
1049 status = UnlockFileEx(
1050 pFile->m_Handle, 0, 0xFFFFFFFF, 0, &Overlapped);
1051 break;
1053 case read_lock:
1054 status = LockFileEx(
1055 pFile->m_Handle, 0, 0, 0xFFFFFFFF, 0, &Overlapped);
1056 break;
1058 case write_lock:
1059 status = LockFileEx(
1060 pFile->m_Handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 0xFFFFFFFF, 0,
1061 &Overlapped);
1062 break;
1065 return status;
1068 static osl_TFile* openFileImpl(rtl_uString * strFileName, oslProfileOption ProfileFlags )
1070 osl_TFile* pFile = static_cast< osl_TFile*>( calloc( 1, sizeof(osl_TFile) ) );
1071 if (!pFile)
1072 return nullptr;
1073 bool bWriteable = false;
1075 if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) )
1077 #ifdef DEBUG_OSL_PROFILE
1078 SAL_INFO("sal.osl", "setting bWriteable to TRUE");
1079 #endif
1080 bWriteable=true;
1083 if (! bWriteable)
1085 pFile->m_Handle = CreateFileW( o3tl::toW(rtl_uString_getStr( strFileName )), GENERIC_READ,
1086 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
1087 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
1089 /* mfe: argghh!!! do not check if the file could be opened */
1090 /* default mode expects it that way!!! */
1092 else
1094 #ifdef DEBUG_OSL_PROFILE
1095 SAL_INFO("sal.osl", "opening read/write " << pszFilename);
1096 #endif
1098 if ((pFile->m_Handle = CreateFileW( o3tl::toW(rtl_uString_getStr( strFileName )), GENERIC_READ | GENERIC_WRITE,
1099 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
1100 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr))
1101 == INVALID_HANDLE_VALUE)
1103 free(pFile);
1104 return nullptr;
1108 pFile->m_pWriteBuf=nullptr;
1109 pFile->m_nWriteBufFree=0;
1110 pFile->m_nWriteBufLen=0;
1112 if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) )
1114 #ifdef DEBUG_OSL_PROFILE
1115 SAL_INFO("sal.osl", "locking file " << pszFilename);
1116 #endif
1118 lockFile(pFile, bWriteable ? write_lock : read_lock);
1121 return pFile;
1124 static osl_TStamp closeFileImpl(osl_TFile* pFile)
1126 osl_TStamp stamp = {0, 0};
1128 if ( pFile == nullptr )
1130 return stamp;
1133 if (pFile->m_Handle != INVALID_HANDLE_VALUE)
1135 stamp = getFileStamp(pFile);
1137 lockFile(pFile, un_lock);
1139 CloseHandle(pFile->m_Handle);
1140 pFile->m_Handle = INVALID_HANDLE_VALUE;
1143 if ( pFile->m_pWriteBuf != nullptr )
1145 free(pFile->m_pWriteBuf);
1148 free(pFile);
1150 return stamp;
1153 static bool rewindFile(osl_TFile* pFile, bool bTruncate)
1155 if (pFile->m_Handle != INVALID_HANDLE_VALUE)
1157 pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);
1159 SetFilePointer(pFile->m_Handle, 0, nullptr, FILE_BEGIN);
1161 if (bTruncate)
1162 SetEndOfFile(pFile->m_Handle);
1165 return true;
1168 static bool getLine(osl_TFile* pFile, sal_Char *pszLine, int MaxLen)
1170 DWORD Max;
1171 size_t Free;
1172 sal_Char* pChr;
1173 sal_Char* pLine = pszLine;
1175 if (pFile->m_Handle == INVALID_HANDLE_VALUE)
1176 return false;
1178 MaxLen -= 1;
1182 size_t Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf);
1184 if (Bytes <= 1)
1186 /* refill buffer */
1187 memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes);
1188 pFile->m_pReadPtr = pFile->m_ReadBuf;
1190 Free = sizeof(pFile->m_ReadBuf) - Bytes;
1192 if (! ReadFile(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free, &Max, nullptr))
1194 *pLine = '\0';
1195 return false;
1198 if (Max < Free)
1200 if ((Max == 0) && (pLine == pszLine))
1202 *pLine = '\0';
1203 return false;
1206 pFile->m_ReadBuf[Bytes + Max] = '\0';
1210 for (pChr = pFile->m_pReadPtr;
1211 (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') &&
1212 (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1));
1213 pChr++);
1215 Max = min(static_cast<int>(pChr - pFile->m_pReadPtr), MaxLen);
1216 memcpy(pLine, pFile->m_pReadPtr, Max);
1217 MaxLen -= Max;
1218 pLine += Max;
1220 if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1))
1222 if (*pChr != '\0')
1224 if ((pChr[0] == '\r') && (pChr[1] == '\n'))
1225 pChr += 2;
1226 else
1227 pChr += 1;
1230 if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) &&
1231 (*pChr == '\0'))
1232 pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);
1234 *pLine = '\0';
1236 /* setting MaxLen to -1 indicates terminating read loop */
1237 MaxLen = -1;
1240 pFile->m_pReadPtr = pChr;
1242 while (MaxLen > 0);
1244 return true;
1247 static bool putLine(osl_TFile* pFile, const sal_Char *pszLine)
1249 unsigned int Len = strlen(pszLine);
1251 if ( pFile == nullptr || pFile->m_Handle == INVALID_HANDLE_VALUE )
1253 return false;
1256 if ( pFile->m_pWriteBuf == nullptr )
1258 pFile->m_pWriteBuf = static_cast<sal_Char*>(malloc(Len+3));
1259 pFile->m_nWriteBufLen = Len+3;
1260 pFile->m_nWriteBufFree = Len+3;
1262 else
1264 if ( pFile->m_nWriteBufFree <= Len + 3 )
1266 sal_Char* pTmp;
1268 pTmp=static_cast<sal_Char*>(realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) ));
1269 if ( pTmp == nullptr )
1271 return false;
1273 pFile->m_pWriteBuf = pTmp;
1274 pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len );
1275 pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2;
1276 memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree);
1280 memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1);
1282 pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\r';
1283 pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\n';
1284 pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 2]='\0';
1286 pFile->m_nWriteBufFree-=Len+2;
1288 return true;
1291 /* platform specific end */
1293 static const sal_Char* stripBlanks(const sal_Char* String, sal_uInt32* pLen)
1295 if ( (pLen != nullptr) && ( *pLen != 0 ) )
1297 while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t'))
1298 (*pLen)--;
1300 while ((*String == ' ') || (*String == '\t'))
1302 String++;
1303 (*pLen)--;
1306 else
1307 while ((*String == ' ') || (*String == '\t'))
1308 String++;
1310 return String;
1313 static const sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line)
1315 if (pProfile->m_NoLines >= pProfile->m_MaxLines)
1317 if (pProfile->m_Lines == nullptr)
1319 pProfile->m_MaxLines = LINES_INI;
1320 pProfile->m_Lines = static_cast<sal_Char **>(calloc(pProfile->m_MaxLines, sizeof(sal_Char *)));
1322 else
1324 unsigned int index=0;
1325 unsigned int oldmax=pProfile->m_MaxLines;
1327 pProfile->m_MaxLines += LINES_ADD;
1328 if (auto p = static_cast<sal_Char **>(realloc(pProfile->m_Lines, pProfile->m_MaxLines * sizeof(sal_Char *))))
1330 pProfile->m_Lines = p;
1332 for ( index = oldmax ; index < pProfile->m_MaxLines ; ++index )
1334 pProfile->m_Lines[index]=nullptr;
1337 else
1339 free(pProfile->m_Lines);
1340 pProfile->m_Lines = nullptr;
1344 if (pProfile->m_Lines == nullptr)
1346 pProfile->m_NoLines = 0;
1347 pProfile->m_MaxLines = 0;
1348 return nullptr;
1353 if ( pProfile->m_Lines != nullptr && pProfile->m_Lines[pProfile->m_NoLines] != nullptr )
1355 free(pProfile->m_Lines[pProfile->m_NoLines]);
1357 pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line);
1359 return pProfile->m_Lines[pProfile->m_NoLines - 1];
1362 static const sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo)
1364 if (pProfile->m_NoLines >= pProfile->m_MaxLines)
1366 if (pProfile->m_Lines == nullptr)
1368 pProfile->m_MaxLines = LINES_INI;
1369 pProfile->m_Lines = static_cast<sal_Char **>(calloc(pProfile->m_MaxLines, sizeof(sal_Char *)));
1371 else
1373 pProfile->m_MaxLines += LINES_ADD;
1374 if (auto p = static_cast<sal_Char**>(
1375 realloc(pProfile->m_Lines, pProfile->m_MaxLines * sizeof(sal_Char*))))
1377 pProfile->m_Lines = p;
1379 memset(&pProfile->m_Lines[pProfile->m_NoLines], 0,
1380 (pProfile->m_MaxLines - pProfile->m_NoLines - 1) * sizeof(sal_Char*));
1382 else
1384 free(pProfile->m_Lines);
1385 pProfile->m_Lines = nullptr;
1389 if (pProfile->m_Lines == nullptr)
1391 pProfile->m_NoLines = 0;
1392 pProfile->m_MaxLines = 0;
1393 return nullptr;
1397 LineNo = std::min(LineNo, pProfile->m_NoLines);
1399 if (LineNo < pProfile->m_NoLines)
1401 sal_uInt32 i, n;
1403 memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo],
1404 (pProfile->m_NoLines - LineNo) * sizeof(sal_Char *));
1406 /* adjust line references */
1407 for (i = 0; i < pProfile->m_NoSections; i++)
1409 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
1411 if (pSec->m_Line >= LineNo)
1412 pSec->m_Line++;
1414 for (n = 0; n < pSec->m_NoEntries; n++)
1415 if (pSec->m_Entries[n].m_Line >= LineNo)
1416 pSec->m_Entries[n].m_Line++;
1420 pProfile->m_NoLines++;
1422 pProfile->m_Lines[LineNo] = strdup(Line);
1424 return pProfile->m_Lines[LineNo];
1427 static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo)
1429 if (LineNo < pProfile->m_NoLines)
1431 free(pProfile->m_Lines[LineNo]);
1432 pProfile->m_Lines[LineNo]=nullptr;
1433 if (pProfile->m_NoLines - LineNo > 1)
1435 sal_uInt32 i, n;
1437 memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1],
1438 (pProfile->m_NoLines - LineNo - 1) * sizeof(sal_Char *));
1440 memset(&pProfile->m_Lines[pProfile->m_NoLines - 1],
1442 (pProfile->m_MaxLines - pProfile->m_NoLines) * sizeof(sal_Char*));
1444 /* adjust line references */
1445 for (i = 0; i < pProfile->m_NoSections; i++)
1447 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
1449 if (pSec->m_Line > LineNo)
1450 pSec->m_Line--;
1452 for (n = 0; n < pSec->m_NoEntries; n++)
1453 if (pSec->m_Entries[n].m_Line > LineNo)
1454 pSec->m_Entries[n].m_Line--;
1457 else
1459 pProfile->m_Lines[LineNo] = nullptr;
1462 pProfile->m_NoLines--;
1465 return;
1468 static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection,
1469 sal_uInt32 NoEntry, sal_uInt32 Line,
1470 const sal_Char* Entry, sal_uInt32 Len)
1472 Entry = stripBlanks(Entry, &Len);
1473 pSection->m_Entries[NoEntry].m_Line = Line;
1474 pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line];
1475 pSection->m_Entries[NoEntry].m_Len = Len;
1477 return;
1480 static bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection,
1481 int Line, const sal_Char* Entry, sal_uInt32 Len)
1483 if (pSection != nullptr)
1485 if (pSection->m_NoEntries >= pSection->m_MaxEntries)
1487 if (pSection->m_Entries == nullptr)
1489 pSection->m_MaxEntries = ENTRIES_INI;
1490 pSection->m_Entries = static_cast<osl_TProfileEntry *>(malloc(
1491 pSection->m_MaxEntries * sizeof(osl_TProfileEntry)));
1493 else
1495 pSection->m_MaxEntries += ENTRIES_ADD;
1496 if (auto p = static_cast<osl_TProfileEntry*>(realloc(
1497 pSection->m_Entries, pSection->m_MaxEntries * sizeof(osl_TProfileEntry))))
1498 pSection->m_Entries = p;
1499 else
1501 free(pSection->m_Entries);
1502 pSection->m_Entries = nullptr;
1506 if (pSection->m_Entries == nullptr)
1508 pSection->m_NoEntries = 0;
1509 pSection->m_MaxEntries = 0;
1510 return false;
1514 pSection->m_NoEntries++;
1516 Entry = stripBlanks(Entry, &Len);
1517 setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line,
1518 Entry, Len);
1520 return true;
1523 return false;
1526 static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry)
1528 if (NoEntry < pSection->m_NoEntries)
1530 if (pSection->m_NoEntries - NoEntry > 1)
1532 memmove(&pSection->m_Entries[NoEntry],
1533 &pSection->m_Entries[NoEntry + 1],
1534 (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry));
1535 pSection->m_Entries[pSection->m_NoEntries - 1].m_Line=0;
1536 pSection->m_Entries[pSection->m_NoEntries - 1].m_Offset=0;
1537 pSection->m_Entries[pSection->m_NoEntries - 1].m_Len=0;
1540 pSection->m_NoEntries--;
1543 return;
1546 static bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len)
1548 if (pProfile->m_NoSections >= pProfile->m_MaxSections)
1550 if (pProfile->m_Sections == nullptr)
1552 pProfile->m_MaxSections = SECTIONS_INI;
1553 pProfile->m_Sections = static_cast<osl_TProfileSection*>(calloc(pProfile->m_MaxSections, sizeof(osl_TProfileSection)));
1555 else
1557 unsigned int index=0;
1558 unsigned int oldmax=pProfile->m_MaxSections;
1560 pProfile->m_MaxSections += SECTIONS_ADD;
1561 if (auto p = static_cast<osl_TProfileSection*>(realloc(
1562 pProfile->m_Sections, pProfile->m_MaxSections * sizeof(osl_TProfileSection))))
1564 pProfile->m_Sections = p;
1565 for ( index = oldmax ; index < pProfile->m_MaxSections ; ++index )
1567 pProfile->m_Sections[index].m_Entries=nullptr;
1570 else
1572 free(pProfile->m_Sections);
1573 pProfile->m_Sections = nullptr;
1577 if (pProfile->m_Sections == nullptr)
1579 pProfile->m_NoSections = 0;
1580 pProfile->m_MaxSections = 0;
1581 return false;
1585 pProfile->m_NoSections++;
1587 if ( pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries != nullptr )
1589 free(pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries);
1591 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = nullptr;
1592 pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries = 0;
1593 pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0;
1595 Section = stripBlanks(Section, &Len);
1596 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line;
1597 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line];
1598 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len;
1600 return true;
1603 static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection)
1605 sal_uInt32 Section;
1607 if ((Section = pSection - pProfile->m_Sections) < pProfile->m_NoSections)
1609 free (pSection->m_Entries);
1610 pSection->m_Entries=nullptr;
1611 if (pProfile->m_NoSections - Section > 1)
1613 memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1],
1614 (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection));
1616 memset(&pProfile->m_Sections[pProfile->m_NoSections - 1],
1618 (pProfile->m_MaxSections - pProfile->m_NoSections) * sizeof(osl_TProfileSection));
1619 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = nullptr;
1621 else
1623 pSection->m_Entries = nullptr;
1626 pProfile->m_NoSections--;
1629 return;
1632 static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section,
1633 const sal_Char* Entry, sal_uInt32 *pNoEntry)
1635 static sal_uInt32 Sect = 0;
1636 sal_uInt32 i, n;
1637 sal_uInt32 Len;
1638 osl_TProfileSection* pSec = nullptr;
1640 Len = strlen(Section);
1641 Section = stripBlanks(Section, &Len);
1643 n = Sect;
1645 for (i = 0; i < pProfile->m_NoSections; i++)
1647 n %= pProfile->m_NoSections;
1648 pSec = &pProfile->m_Sections[n];
1649 if ((Len == pSec->m_Len) &&
1650 (strnicmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len)
1651 == 0))
1652 break;
1653 n++;
1656 Sect = n;
1658 if (i < pProfile->m_NoSections)
1660 Len = strlen(Entry);
1661 Entry = stripBlanks(Entry, &Len);
1663 *pNoEntry = pSec->m_NoEntries;
1665 for (i = 0; i < pSec->m_NoEntries; i++)
1667 const sal_Char* pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line]
1668 [pSec->m_Entries[i].m_Offset];
1669 if ((Len == pSec->m_Entries[i].m_Len) &&
1670 (strnicmp(Entry, pStr, pSec->m_Entries[i].m_Len)
1671 == 0))
1673 *pNoEntry = i;
1674 break;
1678 else
1679 pSec = nullptr;
1681 return pSec;
1684 static bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile)
1686 sal_uInt32 i;
1687 sal_Char const * pStr;
1688 sal_Char const * pChar;
1689 sal_Char Line[4096];
1691 pProfile->m_NoLines = 0;
1692 pProfile->m_NoSections = 0;
1694 OSL_VERIFY(rewindFile(pFile, false));
1696 while (getLine(pFile, Line, sizeof(Line)))
1698 if (! addLine(pProfile, Line))
1699 return false;
1702 for (i = 0; i < pProfile->m_NoLines; i++)
1704 pStr = stripBlanks(pProfile->m_Lines[i], nullptr);
1706 if ((*pStr == '\0') || (*pStr == ';'))
1707 continue;
1709 if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == nullptr) ||
1710 ((pChar - pStr) <= 2))
1712 /* insert entry */
1714 if (pProfile->m_NoSections < 1)
1715 continue;
1717 if ((pChar = strchr(pStr, '=')) == nullptr)
1718 pChar = pStr + strlen(pStr);
1720 if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1],
1721 i, pStr, pChar - pStr))
1722 return false;
1724 else
1726 /* new section */
1727 if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1))
1728 return false;
1732 return true;
1735 static bool storeProfile(osl_TProfileImpl* pProfile, bool bCleanup)
1737 if (pProfile->m_Lines != nullptr)
1739 if (pProfile->m_Flags & FLG_MODIFIED)
1741 sal_uInt32 i;
1743 osl_TFile* pTmpFile = osl_openTmpProfileImpl(pProfile);
1745 if ( pTmpFile == nullptr )
1747 return false;
1750 OSL_VERIFY(rewindFile(pTmpFile, true));
1752 for (i = 0; i < pProfile->m_NoLines; i++)
1754 OSL_VERIFY(putLine(pTmpFile, pProfile->m_Lines[i]));
1757 if ( ! writeProfileImpl(pTmpFile) )
1759 if ( pTmpFile->m_pWriteBuf != nullptr )
1761 free(pTmpFile->m_pWriteBuf);
1764 pTmpFile->m_pWriteBuf=nullptr;
1765 pTmpFile->m_nWriteBufLen=0;
1766 pTmpFile->m_nWriteBufFree=0;
1768 closeFileImpl(pTmpFile);
1770 return false;
1773 pProfile->m_Flags &= ~FLG_MODIFIED;
1775 closeFileImpl(pProfile->m_pFile);
1776 closeFileImpl(pTmpFile);
1778 osl_ProfileSwapProfileNames(pProfile);
1780 pProfile->m_pFile = openFileImpl(pProfile->m_strFileName,pProfile->m_Flags);
1784 if (bCleanup)
1786 while (pProfile->m_NoLines > 0)
1787 removeLine(pProfile, pProfile->m_NoLines - 1);
1789 free(pProfile->m_Lines);
1790 pProfile->m_Lines = nullptr;
1791 pProfile->m_MaxLines = 0;
1793 while (pProfile->m_NoSections > 0)
1794 removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]);
1796 free(pProfile->m_Sections);
1797 pProfile->m_Sections = nullptr;
1798 pProfile->m_MaxSections = 0;
1802 return true;
1805 static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl* pProfile)
1807 osl_TFile* pFile=nullptr;
1808 rtl_uString* ustrExtension=nullptr;
1809 rtl_uString* ustrTmpName=nullptr;
1810 oslProfileOption PFlags=0;
1812 rtl_uString_newFromAscii(&ustrExtension,"tmp");
1814 /* generate tmp profilename */
1815 ustrTmpName=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension);
1816 rtl_uString_release(ustrExtension);
1818 if (ustrTmpName == nullptr)
1819 return nullptr;
1821 if (!(pProfile->m_Flags & osl_Profile_READLOCK))
1822 PFlags |= osl_Profile_WRITELOCK;
1824 /* open this file */
1825 pFile = openFileImpl(ustrTmpName,pProfile->m_Flags | PFlags);
1827 /* return new pFile */
1828 return pFile;
1831 static bool osl_ProfileSwapProfileNames(osl_TProfileImpl* pProfile)
1833 rtl_uString* ustrBakFile=nullptr;
1834 rtl_uString* ustrTmpFile=nullptr;
1835 rtl_uString* ustrIniFile=nullptr;
1836 rtl_uString* ustrExtension=nullptr;
1838 rtl_uString_newFromAscii(&ustrExtension,"bak");
1840 ustrBakFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension);
1841 rtl_uString_release(ustrExtension);
1842 ustrExtension=nullptr;
1844 rtl_uString_newFromAscii(&ustrExtension,"ini");
1846 ustrIniFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension);
1847 rtl_uString_release(ustrExtension);
1848 ustrExtension=nullptr;
1850 rtl_uString_newFromAscii(&ustrExtension,"tmp");
1852 ustrTmpFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension);
1853 rtl_uString_release(ustrExtension);
1854 ustrExtension=nullptr;
1856 /* unlink bak */
1857 DeleteFileW( o3tl::toW(rtl_uString_getStr( ustrBakFile )) );
1859 /* rename ini bak */
1860 MoveFileExW( o3tl::toW(rtl_uString_getStr( ustrIniFile )), o3tl::toW(rtl_uString_getStr( ustrBakFile )), MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH );
1862 /* rename tmp ini */
1863 MoveFileExW( o3tl::toW(rtl_uString_getStr( ustrTmpFile )), o3tl::toW(rtl_uString_getStr( ustrIniFile )), MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH );
1865 return false;
1868 static rtl_uString* osl_ProfileGenerateExtension(rtl_uString* ustrFileName, rtl_uString* ustrExtension)
1870 rtl_uString* ustrNewFileName = nullptr;
1871 rtl_uString* ustrOldExtension = nullptr;
1873 sal_Unicode* pFileNameBuf = rtl_uString_getStr(ustrFileName);
1875 rtl_uString_newFromAscii(&ustrOldExtension, ".");
1877 sal_Unicode* pExtensionBuf = rtl_uString_getStr(ustrOldExtension);
1879 sal_Int32 nIndex = rtl_ustr_lastIndexOfChar(pFileNameBuf, *pExtensionBuf);
1881 rtl_uString_newReplaceStrAt(&ustrNewFileName,
1882 ustrFileName,
1883 nIndex+1,
1885 ustrExtension);
1887 return ustrNewFileName;
1890 static osl_TProfileImpl* acquireProfile(oslProfile Profile, bool bWriteable)
1892 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
1893 oslProfileOption PFlags=0;
1895 if ( bWriteable )
1897 PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK;
1899 else
1901 PFlags = osl_Profile_DEFAULT;
1904 if (pProfile == nullptr)
1906 #ifdef DEBUG_OSL_PROFILE
1907 SAL_INFO("sal.osl", "AUTOOPEN MODE");
1908 #endif
1910 if ( ( pProfile = static_cast<osl_TProfileImpl*>(osl_openProfile( nullptr, PFlags )) ) != nullptr )
1912 pProfile->m_Flags |= FLG_AUTOOPEN;
1915 else
1917 #ifdef DEBUG_OSL_PROFILE
1918 SAL_INFO("sal.osl", "try to acquire");
1919 #endif
1921 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
1923 if (! (pProfile->m_Flags & (osl_Profile_READLOCK |
1924 osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE)))
1926 osl_TStamp Stamp;
1927 #ifdef DEBUG_OSL_PROFILE
1928 SAL_INFO("sal.osl", "DEFAULT MODE");
1929 #endif
1930 pProfile->m_pFile = openFileImpl(
1931 pProfile->m_strFileName, pProfile->m_Flags | PFlags);
1932 if (!pProfile->m_pFile)
1933 return nullptr;
1935 Stamp = getFileStamp(pProfile->m_pFile);
1937 if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp)))
1939 pProfile->m_Stamp = Stamp;
1941 loadProfile(pProfile->m_pFile, pProfile);
1944 else
1946 #ifdef DEBUG_OSL_PROFILE
1947 SAL_INFO("sal.osl", "READ/WRITELOCK MODE");
1948 #endif
1950 /* A readlock file could not be written */
1951 if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable)
1953 return nullptr;
1959 return pProfile;
1962 static bool releaseProfile(osl_TProfileImpl* pProfile)
1964 if ( pProfile == nullptr )
1966 return false;
1969 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
1971 if (pProfile->m_Flags & FLG_AUTOOPEN)
1973 return osl_closeProfile(static_cast<oslProfile>(pProfile));
1975 else
1977 #ifdef DEBUG_OSL_PROFILE
1978 SAL_INFO("sal.osl", "DEFAULT MODE");
1979 #endif
1980 if (! (pProfile->m_Flags & (osl_Profile_READLOCK |
1981 osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE)))
1983 if (pProfile->m_Flags & FLG_MODIFIED)
1984 storeProfile(pProfile, false);
1986 closeFileImpl(pProfile->m_pFile);
1987 pProfile->m_pFile = nullptr;
1992 return true;
1995 static bool lookupProfile(const sal_Unicode *strPath, const sal_Unicode *strFile, sal_Unicode *strProfile)
1997 sal_Char *pChr;
1998 sal_Char Buffer[4096] = "";
1999 sal_Char Product[132] = "";
2001 ::osl::LongPathBuffer< sal_Unicode > aPath( MAX_LONG_PATH );
2002 aPath[0] = 0;
2004 if (*strPath == L'"')
2006 int i = 0;
2008 strPath++;
2010 while ((strPath[i] != L'"') && (strPath[i] != L'\0'))
2011 i++;
2013 WideCharToMultiByte(CP_ACP,0, o3tl::toW(strPath), i, Product, sizeof(Product), nullptr, nullptr);
2014 Product[i] = '\0';
2015 strPath += i;
2017 if (*strPath == L'"')
2018 strPath++;
2020 if ( (*strPath == L'/') || (*strPath == L'\\') )
2022 strPath++;
2026 else
2028 /* if we have not product identification, do a special handling for soffice.ini */
2029 if (rtl_ustr_ascii_compare(strFile, SVERSION_PROFILE) == 0)
2031 rtl_uString * strSVProfile = nullptr;
2032 rtl_uString * strSVFallback = nullptr;
2033 rtl_uString * strSVLocation = nullptr;
2034 rtl_uString * strSVName = nullptr;
2035 ::osl::LongPathBuffer< sal_Char > aDir( MAX_LONG_PATH );
2036 oslProfile hProfile;
2038 rtl_uString_newFromAscii(&strSVFallback, SVERSION_FALLBACK);
2039 rtl_uString_newFromAscii(&strSVLocation, SVERSION_LOCATION);
2040 rtl_uString_newFromAscii(&strSVName, SVERSION_NAME);
2042 /* open sversion.ini in the system directory, and try to locate the entry
2043 with the highest version for StarOffice */
2044 if (osl_getProfileName( strSVFallback, strSVName, &strSVProfile))
2046 hProfile = osl_openProfile(strSVProfile, osl_Profile_READLOCK);
2047 if (hProfile)
2049 osl_getProfileSectionEntries(
2050 hProfile, SVERSION_SECTION, Buffer, sizeof(Buffer));
2052 for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1)
2054 if ((strnicmp(
2055 pChr, SVERSION_SOFFICE,
2056 sizeof(SVERSION_SOFFICE) - 1)
2057 == 0)
2058 && (stricmp(Product, pChr) < 0))
2060 osl_readProfileString(
2061 hProfile, SVERSION_SECTION, pChr, aDir,
2062 aDir.getBufSizeInSymbols(), "");
2064 /* check for existence of path */
2065 if (access(aDir, 0) >= 0)
2066 strcpy(Product, pChr);
2070 osl_closeProfile(hProfile);
2072 rtl_uString_release(strSVProfile);
2073 strSVProfile = nullptr;
2076 /* open sversion.ini in the users directory, and try to locate the entry
2077 with the highest version for StarOffice */
2078 if ( osl_getProfileName(strSVLocation, strSVName, &strSVProfile) )
2080 hProfile = osl_openProfile(strSVProfile, osl_Profile_READLOCK);
2081 if (hProfile)
2083 osl_getProfileSectionEntries(
2084 hProfile, SVERSION_SECTION, Buffer, sizeof(Buffer));
2086 for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1)
2088 if ((strnicmp(
2089 pChr, SVERSION_SOFFICE,
2090 sizeof(SVERSION_SOFFICE) - 1)
2091 == 0)
2092 && (stricmp(Product, pChr) < 0))
2094 osl_readProfileString(
2095 hProfile, SVERSION_SECTION, pChr, aDir,
2096 aDir.getBufSizeInSymbols(), "");
2098 /* check for existence of path */
2099 if (access(aDir, 0) >= 0)
2100 strcpy(Product, pChr);
2104 osl_closeProfile(hProfile);
2106 rtl_uString_release(strSVProfile);
2109 rtl_uString_release(strSVFallback);
2110 rtl_uString_release(strSVLocation);
2111 rtl_uString_release(strSVName);
2113 /* remove any trailing build number */
2114 if ((pChr = strrchr(Product, '/')) != nullptr)
2115 *pChr = '\0';
2119 rtl_uString * strExecutable = nullptr;
2120 rtl_uString * strTmp = nullptr;
2121 sal_Int32 nPos;
2123 /* try to find the file in the directory of the executable */
2124 if (osl_getExecutableFile(&strTmp) != osl_Process_E_None)
2125 return false;
2127 /* convert to native path */
2128 if (osl_getSystemPathFromFileURL(strTmp, &strExecutable) != osl_File_E_None)
2130 rtl_uString_release(strTmp);
2131 return false;
2134 rtl_uString_release(strTmp);
2136 DWORD dwPathLen = 0;
2138 /* separate path from filename */
2139 if ((nPos = rtl_ustr_lastIndexOfChar(strExecutable->buffer, L'\\')) == -1)
2141 if ((nPos = rtl_ustr_lastIndexOfChar(strExecutable->buffer, L':')) == -1)
2143 rtl_uString_release(strExecutable);
2144 return false;
2146 else
2148 copy_ustr_n(aPath, strExecutable->buffer, nPos);
2149 aPath[nPos] = 0;
2150 dwPathLen = nPos;
2153 else
2155 copy_ustr_n(aPath, strExecutable->buffer, nPos);
2156 dwPathLen = nPos;
2157 aPath[dwPathLen] = 0;
2160 /* if we have no product identification use the executable file name */
2161 if (*Product == 0)
2163 WideCharToMultiByte(CP_ACP,0, o3tl::toW(strExecutable->buffer + nPos + 1), -1, Product, sizeof(Product), nullptr, nullptr);
2165 /* remove extension */
2166 if ((pChr = strrchr(Product, '.')) != nullptr)
2167 *pChr = '\0';
2170 rtl_uString_release(strExecutable);
2172 /* remember last subdir */
2173 nPos = rtl_ustr_lastIndexOfChar(aPath, L'\\');
2175 copy_ustr_n(aPath + dwPathLen++, L"\\", 2);
2177 if (*strPath)
2179 copy_ustr_n(aPath + dwPathLen, strPath, rtl_ustr_getLength(strPath)+1);
2180 dwPathLen += rtl_ustr_getLength(strPath);
2184 ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH );
2186 WideCharToMultiByte(CP_ACP,0, o3tl::toW(aPath), -1, aTmpPath, aTmpPath.getBufSizeInSymbols(), nullptr, nullptr);
2188 /* if file not exists, remove any specified subdirectories
2189 like "bin" or "program" */
2191 if (((access(aTmpPath, 0) < 0) && (nPos != -1)) || (*strPath == 0))
2193 static const sal_Char *SubDirs[] = SVERSION_DIRS;
2195 unsigned i = 0;
2196 sal_Char *pStr = aTmpPath + nPos;
2198 for (i = 0; i < SAL_N_ELEMENTS(SubDirs); i++)
2199 if (strnicmp(pStr + 1, SubDirs[i], strlen(SubDirs[i])) == 0)
2201 if ( *strPath == 0)
2203 strcpy(pStr + 1,SVERSION_USER);
2204 if ( access(aTmpPath, 0) < 0 )
2206 *(pStr+1)='\0';
2208 else
2210 dwPathLen = nPos + MultiByteToWideChar( CP_ACP, 0, SVERSION_USER, -1, o3tl::toW(aPath + nPos + 1), aPath.getBufSizeInSymbols() - (nPos + 1) );
2213 else
2215 copy_ustr_n(aPath + nPos + 1, strPath, rtl_ustr_getLength(strPath)+1);
2216 dwPathLen = nPos + 1 + rtl_ustr_getLength(strPath);
2219 break;
2224 if ((aPath[dwPathLen - 1] != L'/') && (aPath[dwPathLen - 1] != L'\\'))
2226 aPath[dwPathLen++] = L'\\';
2227 aPath[dwPathLen] = 0;
2230 copy_ustr_n(aPath + dwPathLen, strFile, rtl_ustr_getLength(strFile)+1);
2233 ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH );
2235 WideCharToMultiByte(CP_ACP,0, o3tl::toW(aPath), -1, aTmpPath, aTmpPath.getBufSizeInSymbols(), nullptr, nullptr);
2237 if ((access(aTmpPath, 0) < 0) && (Product[0] != '\0'))
2239 rtl_uString * strSVFallback = nullptr;
2240 rtl_uString * strSVProfile = nullptr;
2241 rtl_uString * strSVLocation = nullptr;
2242 rtl_uString * strSVName = nullptr;
2243 oslProfile hProfile;
2245 rtl_uString_newFromAscii(&strSVFallback, SVERSION_FALLBACK);
2246 rtl_uString_newFromAscii(&strSVLocation, SVERSION_LOCATION);
2247 rtl_uString_newFromAscii(&strSVName, SVERSION_NAME);
2249 /* open sversion.ini in the system directory, and try to locate the entry
2250 with the highest version for StarOffice */
2251 if (osl_getProfileName(strSVLocation, strSVName, &strSVProfile))
2253 hProfile = osl_openProfile(
2254 strSVProfile, osl_Profile_READLOCK);
2255 if (hProfile)
2257 osl_readProfileString(
2258 hProfile, SVERSION_SECTION, Product, Buffer,
2259 sizeof(Buffer), "");
2260 osl_closeProfile(hProfile);
2262 /* if not found, try the fallback */
2263 if (Buffer[0] == '\0')
2265 if (osl_getProfileName(
2266 strSVFallback, strSVName, &strSVProfile))
2268 hProfile = osl_openProfile(
2269 strSVProfile, osl_Profile_READLOCK);
2270 if (hProfile)
2272 osl_readProfileString(
2273 hProfile, SVERSION_SECTION, Product,
2274 Buffer, sizeof(Buffer), "");
2278 osl_closeProfile(hProfile);
2281 if (Buffer[0] != '\0')
2283 dwPathLen = MultiByteToWideChar(
2284 CP_ACP, 0, Buffer, -1, o3tl::toW(aPath), aPath.getBufSizeInSymbols() );
2285 dwPathLen -=1;
2287 /* build full path */
2288 if ((aPath[dwPathLen - 1] != L'/')
2289 && (aPath[dwPathLen - 1] != L'\\'))
2291 copy_ustr_n(aPath + dwPathLen++, L"\\", 2);
2294 if (*strPath)
2296 copy_ustr_n(aPath + dwPathLen, strPath, rtl_ustr_getLength(strPath)+1);
2297 dwPathLen += rtl_ustr_getLength(strPath);
2299 else
2301 ::osl::LongPathBuffer< sal_Char > aTmpPath2( MAX_LONG_PATH );
2302 int n;
2304 if ((n = WideCharToMultiByte(
2305 CP_ACP,0, o3tl::toW(aPath), -1, aTmpPath2,
2306 aTmpPath2.getBufSizeInSymbols(), nullptr, nullptr))
2307 > 0)
2309 strcpy(aTmpPath2 + n, SVERSION_USER);
2310 if (access(aTmpPath2, 0) >= 0)
2312 dwPathLen += MultiByteToWideChar(
2313 CP_ACP, 0, SVERSION_USER, -1,
2314 o3tl::toW(aPath + dwPathLen),
2315 aPath.getBufSizeInSymbols() - dwPathLen );
2322 rtl_uString_release(strSVProfile);
2325 rtl_uString_release(strSVFallback);
2326 rtl_uString_release(strSVLocation);
2327 rtl_uString_release(strSVName);
2331 aPath[dwPathLen] = 0;
2333 /* copy filename */
2334 copy_ustr_n(strProfile, aPath, dwPathLen+1);
2336 return true;
2339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */