1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_tools.hxx" 30 31 #define _CONFIG_CXX 32 33 #include <cstddef> 34 #include <cstdlib> 35 #include <limits> 36 #include <new> 37 #include <string.h> 38 39 #ifdef WNT 40 #include "stdlib.h" 41 #endif 42 #include <osl/file.hxx> 43 #include <tools/stream.hxx> 44 #include <tools/debug.hxx> 45 #include <tools/config.hxx> 46 #include <osl/security.h> 47 48 #define MAXBUFLEN 1024 // Fuer Buffer bei VOS-Funktionen 49 50 // ----------------- 51 // - ImplConfigData - 52 // ----------------- 53 54 struct ImplKeyData 55 { 56 ImplKeyData* mpNext; 57 ByteString maKey; 58 ByteString maValue; 59 sal_Bool mbIsComment; 60 }; 61 62 struct ImplGroupData 63 { 64 ImplGroupData* mpNext; 65 ImplKeyData* mpFirstKey; 66 ByteString maGroupName; 67 sal_uInt16 mnEmptyLines; 68 }; 69 70 struct ImplConfigData 71 { 72 ImplGroupData* mpFirstGroup; 73 XubString maFileName; 74 sal_uIntPtr mnDataUpdateId; 75 sal_uIntPtr mnTimeStamp; 76 LineEnd meLineEnd; 77 sal_uInt16 mnRefCount; 78 sal_Bool mbModified; 79 sal_Bool mbRead; 80 sal_Bool mbIsUTF8BOM; 81 }; 82 83 // ======================================================================= 84 85 static ByteString& getEmptyByteString() 86 { 87 static ByteString aEmpty; 88 return aEmpty; 89 } 90 91 // ======================================================================= 92 93 static String toUncPath( const String& rPath ) 94 { 95 ::rtl::OUString aFileURL; 96 97 // check if rFileName is already a URL; if not make it so 98 if( rPath.CompareToAscii( "file://", 7 ) == COMPARE_EQUAL ) 99 aFileURL = rPath; 100 else if( ::osl::FileBase::getFileURLFromSystemPath( rPath, aFileURL ) != ::osl::FileBase::E_None ) 101 aFileURL = rPath; 102 103 return aFileURL; 104 } 105 106 static sal_uIntPtr ImplSysGetConfigTimeStamp( const XubString& rFileName ) 107 { 108 sal_uIntPtr nTimeStamp = 0; 109 ::osl::DirectoryItem aItem; 110 ::osl::FileStatus aStatus( osl_FileStatus_Mask_ModifyTime ); 111 112 int nError = 0; 113 if( ( nError = ::osl::DirectoryItem::get( rFileName, aItem ) ) == ::osl::FileBase::E_None && 114 aItem.getFileStatus( aStatus ) == ::osl::FileBase::E_None ) 115 { 116 nTimeStamp = aStatus.getModifyTime().Seconds; 117 } 118 119 return nTimeStamp; 120 } 121 122 // ----------------------------------------------------------------------- 123 124 static sal_uInt8* ImplSysReadConfig( const XubString& rFileName, 125 sal_uInt64& rRead, sal_Bool& rbRead, sal_Bool& rbIsUTF8BOM, sal_uIntPtr& rTimeStamp ) 126 { 127 sal_uInt8* pBuf = NULL; 128 ::osl::File aFile( rFileName ); 129 130 if( aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None ) 131 { 132 sal_uInt64 nPos = 0, nRead = 0; 133 if( aFile.getSize( nPos ) == ::osl::FileBase::E_None ) 134 { 135 if (nPos > std::numeric_limits< std::size_t >::max()) { 136 aFile.close(); 137 return 0; 138 } 139 pBuf = new sal_uInt8[static_cast< std::size_t >(nPos)]; 140 if( aFile.read( pBuf, nPos, nRead ) == ::osl::FileBase::E_None && nRead == nPos ) 141 { 142 //skip the byte-order-mark 0xEF 0xBB 0xBF, if it was UTF8 files 143 unsigned char BOM[3] = {0xEF, 0xBB, 0xBF}; 144 if (nRead > 2 && memcmp(pBuf, BOM, 3) == 0) 145 { 146 nRead -= 3; 147 rtl_moveMemory(pBuf, pBuf + 3, sal::static_int_cast<sal_Size>(nRead * sizeof(sal_uInt8)) ); 148 rbIsUTF8BOM = sal_True; 149 } 150 151 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName ); 152 rbRead = sal_True; 153 rRead = nRead; 154 } 155 else 156 { 157 delete[] pBuf; 158 pBuf = NULL; 159 } 160 } 161 aFile.close(); 162 } 163 164 return pBuf; 165 } 166 167 // ----------------------------------------------------------------------- 168 169 static sal_Bool ImplSysWriteConfig( const XubString& rFileName, 170 const sal_uInt8* pBuf, sal_uIntPtr nBufLen, sal_Bool rbIsUTF8BOM, sal_uIntPtr& rTimeStamp ) 171 { 172 sal_Bool bSuccess = sal_False; 173 sal_Bool bUTF8BOMSuccess = sal_False; 174 175 ::osl::File aFile( rFileName ); 176 ::osl::FileBase::RC eError = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); 177 if( eError != ::osl::FileBase::E_None ) 178 eError = aFile.open( osl_File_OpenFlag_Write ); 179 if( eError == ::osl::FileBase::E_None ) 180 { 181 // truncate 182 aFile.setSize( 0 ); 183 sal_uInt64 nWritten; 184 185 //write the the byte-order-mark 0xEF 0xBB 0xBF first , if it was UTF8 files 186 if ( rbIsUTF8BOM ) 187 { 188 unsigned char BOM[3] = {0xEF, 0xBB, 0xBF}; 189 sal_uInt64 nUTF8BOMWritten; 190 if( aFile.write( BOM, 3, nUTF8BOMWritten ) == ::osl::FileBase::E_None && 3 == nUTF8BOMWritten ) 191 { 192 bUTF8BOMSuccess = sal_True; 193 } 194 } 195 196 if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen ) 197 { 198 bSuccess = sal_True; 199 } 200 if ( rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess ) 201 { 202 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName ); 203 } 204 } 205 206 return rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess; 207 } 208 209 // ----------------------------------------------------------------------- 210 211 static String ImplMakeConfigName( const XubString* pFileName, 212 const XubString* pPathName ) 213 { 214 ::rtl::OUString aFileName; 215 ::rtl::OUString aPathName; 216 if ( pFileName ) 217 { 218 #ifdef UNX 219 aFileName = ::rtl::OUString::createFromAscii( "." ); 220 aFileName += *pFileName; 221 aFileName += ::rtl::OUString::createFromAscii( "rc" ); 222 #else 223 aFileName = *pFileName; 224 aFileName += ::rtl::OUString::createFromAscii( ".ini" ); 225 #endif 226 } 227 else 228 { 229 #ifdef UNX 230 aFileName = ::rtl::OUString::createFromAscii( ".sversionrc" ); 231 #else 232 aFileName = ::rtl::OUString::createFromAscii( "sversion.ini" ); 233 #endif 234 } 235 236 // #88208# in case pPathName is set but empty and pFileName is set 237 // and not empty just return the filename; on the default case 238 // prepend default path as usual 239 if ( pPathName && pPathName->Len() ) 240 aPathName = toUncPath( *pPathName ); 241 else if( pPathName && pFileName && pFileName->Len() ) 242 return aFileName; 243 else 244 { 245 oslSecurity aSec = osl_getCurrentSecurity(); 246 osl_getConfigDir( aSec, &aPathName.pData ); 247 osl_freeSecurityHandle( aSec ); 248 } 249 250 ::rtl::OUString aName( aPathName ); 251 aName += ::rtl::OUString::createFromAscii( "/" ); 252 aName += aFileName; 253 254 return aName; 255 } 256 257 // ----------------------------------------------------------------------- 258 259 namespace { 260 261 ByteString makeByteString(sal_uInt8 const * p, sal_uInt64 n) { 262 if (n > STRING_MAXLEN) { 263 #ifdef WNT 264 abort(); 265 #else 266 ::std::abort(); //TODO: handle this gracefully 267 #endif 268 } 269 return ByteString( 270 reinterpret_cast< char const * >(p), 271 sal::static_int_cast< xub_StrLen >(n)); 272 } 273 274 } 275 276 static void ImplMakeConfigList( ImplConfigData* pData, 277 const sal_uInt8* pBuf, sal_uInt64 nLen ) 278 { 279 // kein Buffer, keine Daten 280 if ( !nLen ) 281 return; 282 283 // Buffer parsen und Liste zusammenbauen 284 sal_uInt64 nStart; 285 sal_uInt64 nLineLen; 286 xub_StrLen nNameLen; 287 xub_StrLen nKeyLen; 288 sal_uInt64 i; 289 const sal_uInt8* pLine; 290 ImplKeyData* pPrevKey = NULL; 291 ImplKeyData* pKey; 292 ImplGroupData* pPrevGroup = NULL; 293 ImplGroupData* pGroup = NULL; 294 i = 0; 295 while ( i < nLen ) 296 { 297 // Ctrl+Z 298 if ( pBuf[i] == 0x1A ) 299 break; 300 301 // Spaces und Tabs entfernen 302 while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') ) 303 i++; 304 305 // Zeilenanfang merken 306 nStart = i; 307 pLine = pBuf+i; 308 309 // Zeilenende suchen 310 while ( (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') && 311 (pBuf[i] != 0x1A) ) 312 i++; 313 314 nLineLen = i-nStart; 315 316 // Wenn Zeilenende (CR/LF), dann noch einen weiterschalten 317 if ( (i+1 < nLen) && 318 (pBuf[i] != pBuf[i+1]) && 319 ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) ) 320 i++; 321 i++; 322 323 // Zeile auswerten 324 if ( *pLine == '[' ) 325 { 326 pGroup = new ImplGroupData; 327 pGroup->mpNext = NULL; 328 pGroup->mpFirstKey = NULL; 329 pGroup->mnEmptyLines = 0; 330 if ( pPrevGroup ) 331 pPrevGroup->mpNext = pGroup; 332 else 333 pData->mpFirstGroup = pGroup; 334 pPrevGroup = pGroup; 335 pPrevKey = NULL; 336 pKey = NULL; 337 338 // Gruppennamen rausfiltern 339 pLine++; 340 nLineLen--; 341 // Spaces und Tabs entfernen 342 while ( (*pLine == ' ') || (*pLine == '\t') ) 343 { 344 nLineLen--; 345 pLine++; 346 } 347 nNameLen = 0; 348 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') ) 349 nNameLen++; 350 if ( nNameLen ) 351 { 352 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') ) 353 nNameLen--; 354 } 355 pGroup->maGroupName = ByteString( (const sal_Char*)pLine, nNameLen ); 356 } 357 else 358 { 359 if ( nLineLen ) 360 { 361 // Wenn noch keine Gruppe existiert, dann alle Keys in die 362 // Default-Gruppe 363 if ( !pGroup ) 364 { 365 pGroup = new ImplGroupData; 366 pGroup->mpNext = NULL; 367 pGroup->mpFirstKey = NULL; 368 pGroup->mnEmptyLines = 0; 369 if ( pPrevGroup ) 370 pPrevGroup->mpNext = pGroup; 371 else 372 pData->mpFirstGroup = pGroup; 373 pPrevGroup = pGroup; 374 pPrevKey = NULL; 375 } 376 377 // Falls Leerzeile vorhanden, dann anhaengen 378 if ( pPrevKey ) 379 { 380 while ( pGroup->mnEmptyLines ) 381 { 382 pKey = new ImplKeyData; 383 pKey->mbIsComment = sal_True; 384 pPrevKey->mpNext = pKey; 385 pPrevKey = pKey; 386 pGroup->mnEmptyLines--; 387 } 388 } 389 390 // Neuen Key erzeugen 391 pKey = new ImplKeyData; 392 pKey->mpNext = NULL; 393 if ( pPrevKey ) 394 pPrevKey->mpNext = pKey; 395 else 396 pGroup->mpFirstKey = pKey; 397 pPrevKey = pKey; 398 if ( pLine[0] == ';' ) 399 { 400 pKey->maValue = makeByteString(pLine, nLineLen); 401 pKey->mbIsComment = sal_True; 402 } 403 else 404 { 405 pKey->mbIsComment = sal_False; 406 nNameLen = 0; 407 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != '=') ) 408 nNameLen++; 409 nKeyLen = nNameLen; 410 // Spaces und Tabs entfernen 411 if ( nNameLen ) 412 { 413 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') ) 414 nNameLen--; 415 } 416 pKey->maKey = ByteString( (const sal_Char*)pLine, nNameLen ); 417 nKeyLen++; 418 if ( nKeyLen < nLineLen ) 419 { 420 pLine += nKeyLen; 421 nLineLen -= nKeyLen; 422 // Spaces und Tabs entfernen 423 while ( (*pLine == ' ') || (*pLine == '\t') ) 424 { 425 nLineLen--; 426 pLine++; 427 } 428 if ( nLineLen ) 429 { 430 while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') ) 431 nLineLen--; 432 pKey->maValue = makeByteString(pLine, nLineLen); 433 } 434 } 435 } 436 } 437 else 438 { 439 // Leerzeilen werden nur gezaehlt und beim Erzeugen des 440 // naechsten Keys angehaengt, da wir Leerzeilen am Ende 441 // einer Gruppe auch nach hinzufuegen von neuen Keys nur 442 // am Ende der Gruppe wieder speichern wollen 443 if ( pGroup ) 444 pGroup->mnEmptyLines++; 445 } 446 } 447 } 448 } 449 450 // ----------------------------------------------------------------------- 451 452 static sal_uInt8* ImplGetConfigBuffer( const ImplConfigData* pData, sal_uIntPtr& rLen ) 453 { 454 sal_uInt8* pWriteBuf; 455 sal_uInt8* pBuf; 456 sal_uInt8 aLineEndBuf[2] = {0, 0}; 457 ImplKeyData* pKey; 458 ImplGroupData* pGroup; 459 unsigned int nBufLen; 460 sal_uInt16 nValueLen; 461 sal_uInt16 nKeyLen; 462 sal_uInt16 nLineEndLen; 463 464 if ( pData->meLineEnd == LINEEND_CR ) 465 { 466 aLineEndBuf[0] = _CR; 467 nLineEndLen = 1; 468 } 469 else if ( pData->meLineEnd == LINEEND_LF ) 470 { 471 aLineEndBuf[0] = _LF; 472 nLineEndLen = 1; 473 } 474 else 475 { 476 aLineEndBuf[0] = _CR; 477 aLineEndBuf[1] = _LF; 478 nLineEndLen = 2; 479 } 480 481 // Buffergroesse ermitteln 482 nBufLen = 0; 483 pGroup = pData->mpFirstGroup; 484 while ( pGroup ) 485 { 486 // Leere Gruppen werden nicht geschrieben 487 if ( pGroup->mpFirstKey ) 488 { 489 nBufLen += pGroup->maGroupName.Len() + nLineEndLen + 2; 490 pKey = pGroup->mpFirstKey; 491 while ( pKey ) 492 { 493 nValueLen = pKey->maValue.Len(); 494 if ( pKey->mbIsComment ) 495 nBufLen += nValueLen + nLineEndLen; 496 else 497 nBufLen += pKey->maKey.Len() + nValueLen + nLineEndLen + 1; 498 499 pKey = pKey->mpNext; 500 } 501 502 // Leerzeile nach jeder Gruppe auch wieder speichern 503 if ( !pGroup->mnEmptyLines ) 504 pGroup->mnEmptyLines = 1; 505 nBufLen += nLineEndLen * pGroup->mnEmptyLines; 506 } 507 508 pGroup = pGroup->mpNext; 509 } 510 511 // Laenge dem Aufrufer mitteilen 512 rLen = nBufLen; 513 if ( !nBufLen ) 514 { 515 pWriteBuf = new sal_uInt8[nLineEndLen]; 516 if ( pWriteBuf ) 517 { 518 pWriteBuf[0] = aLineEndBuf[0]; 519 if ( nLineEndLen == 2 ) 520 pWriteBuf[1] = aLineEndBuf[1]; 521 return pWriteBuf; 522 } 523 else 524 return 0; 525 } 526 527 // Schreibbuffer anlegen (wird vom Aufrufer zerstoert) 528 pWriteBuf = new sal_uInt8[nBufLen]; 529 if ( !pWriteBuf ) 530 return 0; 531 532 // Buffer fuellen 533 pBuf = pWriteBuf; 534 pGroup = pData->mpFirstGroup; 535 while ( pGroup ) 536 { 537 // Leere Gruppen werden nicht geschrieben 538 if ( pGroup->mpFirstKey ) 539 { 540 *pBuf = '['; pBuf++; 541 memcpy( pBuf, pGroup->maGroupName.GetBuffer(), pGroup->maGroupName.Len() ); 542 pBuf += pGroup->maGroupName.Len(); 543 *pBuf = ']'; pBuf++; 544 *pBuf = aLineEndBuf[0]; pBuf++; 545 if ( nLineEndLen == 2 ) 546 { 547 *pBuf = aLineEndBuf[1]; pBuf++; 548 } 549 pKey = pGroup->mpFirstKey; 550 while ( pKey ) 551 { 552 nValueLen = pKey->maValue.Len(); 553 if ( pKey->mbIsComment ) 554 { 555 if ( nValueLen ) 556 { 557 memcpy( pBuf, pKey->maValue.GetBuffer(), nValueLen ); 558 pBuf += nValueLen; 559 } 560 *pBuf = aLineEndBuf[0]; pBuf++; 561 if ( nLineEndLen == 2 ) 562 { 563 *pBuf = aLineEndBuf[1]; pBuf++; 564 } 565 } 566 else 567 { 568 nKeyLen = pKey->maKey.Len(); 569 memcpy( pBuf, pKey->maKey.GetBuffer(), nKeyLen ); 570 pBuf += nKeyLen; 571 *pBuf = '='; pBuf++; 572 memcpy( pBuf, pKey->maValue.GetBuffer(), nValueLen ); 573 pBuf += nValueLen; 574 *pBuf = aLineEndBuf[0]; pBuf++; 575 if ( nLineEndLen == 2 ) 576 { 577 *pBuf = aLineEndBuf[1]; pBuf++; 578 } 579 } 580 581 pKey = pKey->mpNext; 582 } 583 584 // Leerzeile nach jeder Gruppe auch wieder speichern 585 sal_uInt16 nEmptyLines = pGroup->mnEmptyLines; 586 while ( nEmptyLines ) 587 { 588 *pBuf = aLineEndBuf[0]; pBuf++; 589 if ( nLineEndLen == 2 ) 590 { 591 *pBuf = aLineEndBuf[1]; pBuf++; 592 } 593 nEmptyLines--; 594 } 595 } 596 597 pGroup = pGroup->mpNext; 598 } 599 600 return pWriteBuf; 601 } 602 603 // ----------------------------------------------------------------------- 604 605 static void ImplReadConfig( ImplConfigData* pData ) 606 { 607 sal_uIntPtr nTimeStamp = 0; 608 sal_uInt64 nRead = 0; 609 sal_Bool bRead = sal_False; 610 sal_Bool bIsUTF8BOM =sal_False; 611 sal_uInt8* pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp ); 612 613 // Aus dem Buffer die Config-Verwaltungsliste aufbauen 614 if ( pBuf ) 615 { 616 ImplMakeConfigList( pData, pBuf, nRead ); 617 delete[] pBuf; 618 } 619 pData->mnTimeStamp = nTimeStamp; 620 pData->mbModified = sal_False; 621 if ( bRead ) 622 pData->mbRead = sal_True; 623 if ( bIsUTF8BOM ) 624 pData->mbIsUTF8BOM = sal_True; 625 } 626 627 // ----------------------------------------------------------------------- 628 629 static void ImplWriteConfig( ImplConfigData* pData ) 630 { 631 #ifdef DBG_UTIL 632 if ( DbgIsAssert() ) 633 { 634 if ( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ) ) 635 { 636 DBG_ERROR1( "Config overwrites modified configfile:\n %s", ByteString( pData->maFileName, RTL_TEXTENCODING_UTF8 ).GetBuffer() ); 637 } 638 } 639 #endif 640 641 // Aus der Config-Liste einen Buffer zusammenbauen 642 sal_uIntPtr nBufLen; 643 sal_uInt8* pBuf = ImplGetConfigBuffer( pData, nBufLen ); 644 if ( pBuf ) 645 { 646 if ( ImplSysWriteConfig( pData->maFileName, pBuf, nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) ) 647 pData->mbModified = sal_False; 648 delete[] pBuf; 649 } 650 else 651 pData->mbModified = sal_False; 652 } 653 654 // ----------------------------------------------------------------------- 655 656 static void ImplDeleteConfigData( ImplConfigData* pData ) 657 { 658 ImplKeyData* pTempKey; 659 ImplKeyData* pKey; 660 ImplGroupData* pTempGroup; 661 ImplGroupData* pGroup = pData->mpFirstGroup; 662 while ( pGroup ) 663 { 664 pTempGroup = pGroup->mpNext; 665 666 // Alle Keys loeschen 667 pKey = pGroup->mpFirstKey; 668 while ( pKey ) 669 { 670 pTempKey = pKey->mpNext; 671 delete pKey; 672 pKey = pTempKey; 673 } 674 675 // Gruppe loeschen und weiterschalten 676 delete pGroup; 677 pGroup = pTempGroup; 678 } 679 680 pData->mpFirstGroup = NULL; 681 } 682 683 // ======================================================================= 684 685 static ImplConfigData* ImplGetConfigData( const XubString& rFileName ) 686 { 687 ImplConfigData* pData; 688 689 pData = new ImplConfigData; 690 pData->maFileName = rFileName; 691 pData->mpFirstGroup = NULL; 692 pData->mnDataUpdateId = 0; 693 pData->meLineEnd = LINEEND_CRLF; 694 pData->mnRefCount = 0; 695 pData->mbRead = sal_False; 696 pData->mbIsUTF8BOM = sal_False; 697 ImplReadConfig( pData ); 698 699 return pData; 700 } 701 702 // ----------------------------------------------------------------------- 703 704 static void ImplFreeConfigData( ImplConfigData* pDelData ) 705 { 706 ImplDeleteConfigData( pDelData ); 707 delete pDelData; 708 } 709 710 // ======================================================================= 711 712 sal_Bool Config::ImplUpdateConfig() const 713 { 714 // Wenn sich TimeStamp unterscheidet, dann Datei neu einlesen 715 if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) ) 716 { 717 ImplDeleteConfigData( mpData ); 718 ImplReadConfig( mpData ); 719 mpData->mnDataUpdateId++; 720 return sal_True; 721 } 722 else 723 return sal_False; 724 } 725 726 // ----------------------------------------------------------------------- 727 728 ImplGroupData* Config::ImplGetGroup() const 729 { 730 if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) ) 731 { 732 ImplGroupData* pPrevGroup = NULL; 733 ImplGroupData* pGroup = mpData->mpFirstGroup; 734 while ( pGroup ) 735 { 736 if ( pGroup->maGroupName.EqualsIgnoreCaseAscii( maGroupName ) ) 737 break; 738 739 pPrevGroup = pGroup; 740 pGroup = pGroup->mpNext; 741 } 742 743 // Falls Gruppe noch nicht existiert, dann dazufuegen 744 if ( !pGroup ) 745 { 746 pGroup = new ImplGroupData; 747 pGroup->mpNext = NULL; 748 pGroup->mpFirstKey = NULL; 749 pGroup->mnEmptyLines = 1; 750 if ( pPrevGroup ) 751 pPrevGroup->mpNext = pGroup; 752 else 753 mpData->mpFirstGroup = pGroup; 754 } 755 756 // Gruppenname immer uebernehmen, da er auch in dieser Form 757 // geschrieben werden soll. Ausserdem die Cache-Members der 758 // Config-Klasse updaten 759 pGroup->maGroupName = maGroupName; 760 ((Config*)this)->mnDataUpdateId = mpData->mnDataUpdateId; 761 ((Config*)this)->mpActGroup = pGroup; 762 } 763 764 return mpActGroup; 765 } 766 767 // ======================================================================= 768 769 Config::Config() 770 { 771 // Daten initialisieren und einlesen 772 maFileName = ImplMakeConfigName( NULL, NULL ); 773 mpData = ImplGetConfigData( maFileName ); 774 mpActGroup = NULL; 775 mnDataUpdateId = 0; 776 mnLockCount = 1; 777 mbPersistence = sal_True; 778 779 #ifdef DBG_UTIL 780 DBG_TRACE( "Config::Config()" ); 781 #endif 782 } 783 784 // ----------------------------------------------------------------------- 785 786 Config::Config( const XubString& rFileName ) 787 { 788 // Daten initialisieren und einlesen 789 maFileName = toUncPath( rFileName ); 790 mpData = ImplGetConfigData( maFileName ); 791 mpActGroup = NULL; 792 mnDataUpdateId = 0; 793 mnLockCount = 1; 794 mbPersistence = sal_True; 795 796 #ifdef DBG_UTIL 797 ByteString aTraceStr( "Config::Config( " ); 798 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 ); 799 aTraceStr += " )"; 800 DBG_TRACE( aTraceStr.GetBuffer() ); 801 #endif 802 } 803 804 // ----------------------------------------------------------------------- 805 806 Config::~Config() 807 { 808 #ifdef DBG_UTIL 809 DBG_TRACE( "Config::~Config()" ); 810 #endif 811 812 Flush(); 813 ImplFreeConfigData( mpData ); 814 } 815 816 // ----------------------------------------------------------------------- 817 818 String Config::GetDefDirectory() 819 { 820 ::rtl::OUString aDefConfig; 821 oslSecurity aSec = osl_getCurrentSecurity(); 822 osl_getConfigDir( aSec, &aDefConfig.pData ); 823 osl_freeSecurityHandle( aSec ); 824 825 return aDefConfig; 826 } 827 828 // ----------------------------------------------------------------------- 829 830 XubString Config::GetConfigName( const XubString& rPath, 831 const XubString& rBaseName ) 832 { 833 return ImplMakeConfigName( &rBaseName, &rPath ); 834 } 835 836 // ----------------------------------------------------------------------- 837 838 void Config::SetGroup( const ByteString& rGroup ) 839 { 840 // Wenn neue Gruppe gesetzt wird, muss beim naechsten mal die 841 // Gruppe neu ermittelt werden 842 if ( maGroupName != rGroup ) 843 { 844 maGroupName = rGroup; 845 mnDataUpdateId = mpData->mnDataUpdateId-1; 846 } 847 } 848 849 // ----------------------------------------------------------------------- 850 851 void Config::DeleteGroup( const ByteString& rGroup ) 852 { 853 // Config-Daten evt. updaten 854 if ( !mnLockCount || !mpData->mbRead ) 855 { 856 ImplUpdateConfig(); 857 mpData->mbRead = sal_True; 858 } 859 860 ImplGroupData* pPrevGroup = NULL; 861 ImplGroupData* pGroup = mpData->mpFirstGroup; 862 while ( pGroup ) 863 { 864 if ( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) ) 865 break; 866 867 pPrevGroup = pGroup; 868 pGroup = pGroup->mpNext; 869 } 870 871 if ( pGroup ) 872 { 873 // Alle Keys loeschen 874 ImplKeyData* pTempKey; 875 ImplKeyData* pKey = pGroup->mpFirstKey; 876 while ( pKey ) 877 { 878 pTempKey = pKey->mpNext; 879 delete pKey; 880 pKey = pTempKey; 881 } 882 883 // Gruppe weiterschalten und loeschen 884 if ( pPrevGroup ) 885 pPrevGroup->mpNext = pGroup->mpNext; 886 else 887 mpData->mpFirstGroup = pGroup->mpNext; 888 delete pGroup; 889 890 // Config-Datei neu schreiben 891 if ( !mnLockCount && mbPersistence ) 892 ImplWriteConfig( mpData ); 893 else 894 { 895 mpData->mbModified = sal_True; 896 } 897 898 // Gruppen auf ungluetig setzen 899 mnDataUpdateId = mpData->mnDataUpdateId; 900 mpData->mnDataUpdateId++; 901 } 902 } 903 904 // ----------------------------------------------------------------------- 905 906 ByteString Config::GetGroupName( sal_uInt16 nGroup ) const 907 { 908 // Config-Daten evt. updaten 909 if ( !mnLockCount ) 910 ImplUpdateConfig(); 911 912 ImplGroupData* pGroup = mpData->mpFirstGroup; 913 sal_uInt16 nGroupCount = 0; 914 ByteString aGroupName; 915 while ( pGroup ) 916 { 917 if ( nGroup == nGroupCount ) 918 { 919 aGroupName = pGroup->maGroupName; 920 break; 921 } 922 923 nGroupCount++; 924 pGroup = pGroup->mpNext; 925 } 926 927 return aGroupName; 928 } 929 930 // ----------------------------------------------------------------------- 931 932 sal_uInt16 Config::GetGroupCount() const 933 { 934 // Config-Daten evt. updaten 935 if ( !mnLockCount ) 936 ImplUpdateConfig(); 937 938 ImplGroupData* pGroup = mpData->mpFirstGroup; 939 sal_uInt16 nGroupCount = 0; 940 while ( pGroup ) 941 { 942 nGroupCount++; 943 pGroup = pGroup->mpNext; 944 } 945 946 return nGroupCount; 947 } 948 949 // ----------------------------------------------------------------------- 950 951 sal_Bool Config::HasGroup( const ByteString& rGroup ) const 952 { 953 // Config-Daten evt. updaten 954 if ( !mnLockCount ) 955 ImplUpdateConfig(); 956 957 ImplGroupData* pGroup = mpData->mpFirstGroup; 958 sal_Bool bRet = sal_False; 959 960 while( pGroup ) 961 { 962 if( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) ) 963 { 964 bRet = sal_True; 965 break; 966 } 967 968 pGroup = pGroup->mpNext; 969 } 970 971 return bRet; 972 } 973 974 // ----------------------------------------------------------------------- 975 976 ByteString Config::ReadKey( const ByteString& rKey ) const 977 { 978 return ReadKey( rKey, getEmptyByteString() ); 979 } 980 981 // ----------------------------------------------------------------------- 982 983 UniString Config::ReadKey( const ByteString& rKey, rtl_TextEncoding eEncoding ) const 984 { 985 if ( mpData->mbIsUTF8BOM ) 986 eEncoding = RTL_TEXTENCODING_UTF8; 987 return UniString( ReadKey( rKey ), eEncoding ); 988 } 989 990 // ----------------------------------------------------------------------- 991 992 ByteString Config::ReadKey( const ByteString& rKey, const ByteString& rDefault ) const 993 { 994 #ifdef DBG_UTIL 995 ByteString aTraceStr( "Config::ReadKey( " ); 996 aTraceStr += rKey; 997 aTraceStr += " ) from "; 998 aTraceStr += GetGroup(); 999 aTraceStr += " in "; 1000 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 ); 1001 DBG_TRACE( aTraceStr.GetBuffer() ); 1002 #endif 1003 1004 // Config-Daten evt. updaten 1005 if ( !mnLockCount ) 1006 ImplUpdateConfig(); 1007 1008 // Key suchen und Value zurueckgeben 1009 ImplGroupData* pGroup = ImplGetGroup(); 1010 if ( pGroup ) 1011 { 1012 ImplKeyData* pKey = pGroup->mpFirstKey; 1013 while ( pKey ) 1014 { 1015 if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) ) 1016 return pKey->maValue; 1017 1018 pKey = pKey->mpNext; 1019 } 1020 } 1021 1022 return rDefault; 1023 } 1024 1025 // ----------------------------------------------------------------------- 1026 1027 void Config::WriteKey( const ByteString& rKey, const ByteString& rStr ) 1028 { 1029 #ifdef DBG_UTIL 1030 ByteString aTraceStr( "Config::WriteKey( " ); 1031 aTraceStr += rKey; 1032 aTraceStr += ", "; 1033 aTraceStr += rStr; 1034 aTraceStr += " ) to "; 1035 aTraceStr += GetGroup(); 1036 aTraceStr += " in "; 1037 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 ); 1038 DBG_TRACE( aTraceStr.GetBuffer() ); 1039 DBG_ASSERTWARNING( rStr != ReadKey( rKey ), "Config::WriteKey() with the same Value" ); 1040 #endif 1041 1042 // Config-Daten evt. updaten 1043 if ( !mnLockCount || !mpData->mbRead ) 1044 { 1045 ImplUpdateConfig(); 1046 mpData->mbRead = sal_True; 1047 } 1048 1049 // Key suchen und Value setzen 1050 ImplGroupData* pGroup = ImplGetGroup(); 1051 if ( pGroup ) 1052 { 1053 ImplKeyData* pPrevKey = NULL; 1054 ImplKeyData* pKey = pGroup->mpFirstKey; 1055 while ( pKey ) 1056 { 1057 if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) ) 1058 break; 1059 1060 pPrevKey = pKey; 1061 pKey = pKey->mpNext; 1062 } 1063 1064 sal_Bool bNewValue; 1065 if ( !pKey ) 1066 { 1067 pKey = new ImplKeyData; 1068 pKey->mpNext = NULL; 1069 pKey->maKey = rKey; 1070 pKey->mbIsComment = sal_False; 1071 if ( pPrevKey ) 1072 pPrevKey->mpNext = pKey; 1073 else 1074 pGroup->mpFirstKey = pKey; 1075 bNewValue = sal_True; 1076 } 1077 else 1078 bNewValue = pKey->maValue != rStr; 1079 1080 if ( bNewValue ) 1081 { 1082 pKey->maValue = rStr; 1083 1084 if ( !mnLockCount && mbPersistence ) 1085 ImplWriteConfig( mpData ); 1086 else 1087 { 1088 mpData->mbModified = sal_True; 1089 } 1090 } 1091 } 1092 } 1093 1094 // ----------------------------------------------------------------------- 1095 1096 void Config::WriteKey( const ByteString& rKey, const UniString& rValue, rtl_TextEncoding eEncoding ) 1097 { 1098 if ( mpData->mbIsUTF8BOM ) 1099 eEncoding = RTL_TEXTENCODING_UTF8; 1100 WriteKey( rKey, ByteString( rValue, eEncoding ) ); 1101 } 1102 1103 // ----------------------------------------------------------------------- 1104 1105 void Config::DeleteKey( const ByteString& rKey ) 1106 { 1107 // Config-Daten evt. updaten 1108 if ( !mnLockCount || !mpData->mbRead ) 1109 { 1110 ImplUpdateConfig(); 1111 mpData->mbRead = sal_True; 1112 } 1113 1114 // Key suchen und Value setzen 1115 ImplGroupData* pGroup = ImplGetGroup(); 1116 if ( pGroup ) 1117 { 1118 ImplKeyData* pPrevKey = NULL; 1119 ImplKeyData* pKey = pGroup->mpFirstKey; 1120 while ( pKey ) 1121 { 1122 if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) ) 1123 break; 1124 1125 pPrevKey = pKey; 1126 pKey = pKey->mpNext; 1127 } 1128 1129 if ( pKey ) 1130 { 1131 // Gruppe weiterschalten und loeschen 1132 if ( pPrevKey ) 1133 pPrevKey->mpNext = pKey->mpNext; 1134 else 1135 pGroup->mpFirstKey = pKey->mpNext; 1136 delete pKey; 1137 1138 // Config-Datei neu schreiben 1139 if ( !mnLockCount && mbPersistence ) 1140 ImplWriteConfig( mpData ); 1141 else 1142 { 1143 mpData->mbModified = sal_True; 1144 } 1145 } 1146 } 1147 } 1148 1149 // ----------------------------------------------------------------------- 1150 1151 sal_uInt16 Config::GetKeyCount() const 1152 { 1153 #ifdef DBG_UTIL 1154 ByteString aTraceStr( "Config::GetKeyCount()" ); 1155 aTraceStr += " from "; 1156 aTraceStr += GetGroup(); 1157 aTraceStr += " in "; 1158 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 ); 1159 DBG_TRACE( aTraceStr.GetBuffer() ); 1160 #endif 1161 1162 // Config-Daten evt. updaten 1163 if ( !mnLockCount ) 1164 ImplUpdateConfig(); 1165 1166 // Key suchen und Value zurueckgeben 1167 sal_uInt16 nCount = 0; 1168 ImplGroupData* pGroup = ImplGetGroup(); 1169 if ( pGroup ) 1170 { 1171 ImplKeyData* pKey = pGroup->mpFirstKey; 1172 while ( pKey ) 1173 { 1174 if ( !pKey->mbIsComment ) 1175 nCount++; 1176 1177 pKey = pKey->mpNext; 1178 } 1179 } 1180 1181 return nCount; 1182 } 1183 1184 // ----------------------------------------------------------------------- 1185 1186 ByteString Config::GetKeyName( sal_uInt16 nKey ) const 1187 { 1188 #ifdef DBG_UTIL 1189 ByteString aTraceStr( "Config::GetKeyName( " ); 1190 aTraceStr += ByteString::CreateFromInt32(nKey); 1191 aTraceStr += " ) from "; 1192 aTraceStr += GetGroup(); 1193 aTraceStr += " in "; 1194 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 ); 1195 DBG_TRACE( aTraceStr.GetBuffer() ); 1196 #endif 1197 1198 // Key suchen und Name zurueckgeben 1199 ImplGroupData* pGroup = ImplGetGroup(); 1200 if ( pGroup ) 1201 { 1202 ImplKeyData* pKey = pGroup->mpFirstKey; 1203 while ( pKey ) 1204 { 1205 if ( !pKey->mbIsComment ) 1206 { 1207 if ( !nKey ) 1208 return pKey->maKey; 1209 nKey--; 1210 } 1211 1212 pKey = pKey->mpNext; 1213 } 1214 } 1215 1216 return getEmptyByteString(); 1217 } 1218 1219 // ----------------------------------------------------------------------- 1220 1221 ByteString Config::ReadKey( sal_uInt16 nKey ) const 1222 { 1223 #ifdef DBG_UTIL 1224 ByteString aTraceStr( "Config::ReadKey( " ); 1225 aTraceStr += ByteString::CreateFromInt32( nKey ); 1226 aTraceStr += " ) from "; 1227 aTraceStr += GetGroup(); 1228 aTraceStr += " in "; 1229 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 ); 1230 DBG_TRACE( aTraceStr.GetBuffer() ); 1231 #endif 1232 1233 // Key suchen und Value zurueckgeben 1234 ImplGroupData* pGroup = ImplGetGroup(); 1235 if ( pGroup ) 1236 { 1237 ImplKeyData* pKey = pGroup->mpFirstKey; 1238 while ( pKey ) 1239 { 1240 if ( !pKey->mbIsComment ) 1241 { 1242 if ( !nKey ) 1243 return pKey->maValue; 1244 nKey--; 1245 } 1246 1247 pKey = pKey->mpNext; 1248 } 1249 } 1250 1251 return getEmptyByteString(); 1252 } 1253 1254 // ----------------------------------------------------------------------- 1255 1256 void Config::EnterLock() 1257 { 1258 // Config-Daten evt. updaten 1259 if ( !mnLockCount ) 1260 ImplUpdateConfig(); 1261 1262 mnLockCount++; 1263 } 1264 1265 // ----------------------------------------------------------------------- 1266 1267 void Config::LeaveLock() 1268 { 1269 DBG_ASSERT( mnLockCount, "Config::LeaveLook() without Config::EnterLook()" ); 1270 mnLockCount--; 1271 1272 if ( (mnLockCount == 0) && mpData->mbModified && mbPersistence ) 1273 ImplWriteConfig( mpData ); 1274 } 1275 1276 // ----------------------------------------------------------------------- 1277 1278 sal_Bool Config::Update() 1279 { 1280 return ImplUpdateConfig(); 1281 } 1282 1283 // ----------------------------------------------------------------------- 1284 1285 void Config::Flush() 1286 { 1287 if ( mpData->mbModified && mbPersistence ) 1288 ImplWriteConfig( mpData ); 1289 } 1290 1291 // ----------------------------------------------------------------------- 1292 1293 void Config::SetLineEnd( LineEnd eLineEnd ) 1294 { 1295 mpData->meLineEnd = eLineEnd; 1296 } 1297 1298 // ----------------------------------------------------------------------- 1299 1300 LineEnd Config::GetLineEnd() const 1301 { 1302 return mpData->meLineEnd; 1303 } 1304 1305