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