12722ceddSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 32722ceddSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 42722ceddSAndrew Rist * or more contributor license agreements. See the NOTICE file 52722ceddSAndrew Rist * distributed with this work for additional information 62722ceddSAndrew Rist * regarding copyright ownership. The ASF licenses this file 72722ceddSAndrew Rist * to you under the Apache License, Version 2.0 (the 82722ceddSAndrew Rist * "License"); you may not use this file except in compliance 92722ceddSAndrew Rist * with the License. You may obtain a copy of the License at 102722ceddSAndrew Rist * 112722ceddSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 122722ceddSAndrew Rist * 132722ceddSAndrew Rist * Unless required by applicable law or agreed to in writing, 142722ceddSAndrew Rist * software distributed under the License is distributed on an 152722ceddSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 162722ceddSAndrew Rist * KIND, either express or implied. See the License for the 172722ceddSAndrew Rist * specific language governing permissions and limitations 182722ceddSAndrew Rist * under the License. 192722ceddSAndrew Rist * 202722ceddSAndrew Rist *************************************************************/ 212722ceddSAndrew Rist 22cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 23cdf0e10cSrcweir #include "precompiled_desktop.hxx" 24cdf0e10cSrcweir 25cdf0e10cSrcweir #include "dp_misc.h" 26cdf0e10cSrcweir #include "dp_persmap.h" 27cdf0e10cSrcweir #include "rtl/strbuf.hxx" 28cdf0e10cSrcweir 29cdf0e10cSrcweir using namespace ::rtl; 303a63f8e7SHerbert Dürr 313a63f8e7SHerbert Dürr // the persistent map is used to manage a handful of key-value string pairs 323a63f8e7SHerbert Dürr // this implementation replaces a rather heavy-weight berkeleydb integration 333a63f8e7SHerbert Dürr 343a63f8e7SHerbert Dürr // the file backing up a persistent map consists of line pairs with 35eaecd99eSHerbert Dürr // - a key string (encoded with chars 0x00..0x0F being escaped) 36eaecd99eSHerbert Dürr // - a value string (encoded with chars 0x00..0x0F being escaped) 37cdf0e10cSrcweir 38cdf0e10cSrcweir namespace dp_misc 39cdf0e10cSrcweir { 40cdf0e10cSrcweir 413a63f8e7SHerbert Dürr static const char PmapMagic[4] = {'P','m','p','1'}; 423a63f8e7SHerbert Dürr 43cdf0e10cSrcweir //______________________________________________________________________________ 443a63f8e7SHerbert Dürr PersistentMap::PersistentMap( OUString const & url_, bool readOnly ) 453a63f8e7SHerbert Dürr : m_MapFile( expandUnoRcUrl(url_) ) 463a63f8e7SHerbert Dürr , m_bReadOnly( readOnly) 473a63f8e7SHerbert Dürr , m_bIsOpen( false) 483a63f8e7SHerbert Dürr , m_bToBeCreated( !readOnly) 493a63f8e7SHerbert Dürr , m_bIsDirty( false) 50cdf0e10cSrcweir { 513a63f8e7SHerbert Dürr open(); 52cdf0e10cSrcweir } 53cdf0e10cSrcweir 543a63f8e7SHerbert Dürr //______________________________________________________________________________ 553a63f8e7SHerbert Dürr PersistentMap::PersistentMap() 563a63f8e7SHerbert Dürr : m_MapFile( OUString()) 573a63f8e7SHerbert Dürr , m_bReadOnly( false) 583a63f8e7SHerbert Dürr , m_bIsOpen( false) 593a63f8e7SHerbert Dürr , m_bToBeCreated( false) 603a63f8e7SHerbert Dürr , m_bIsDirty( false) 613a63f8e7SHerbert Dürr {} 623a63f8e7SHerbert Dürr 63cdf0e10cSrcweir //______________________________________________________________________________ 64cdf0e10cSrcweir PersistentMap::~PersistentMap() 65cdf0e10cSrcweir { 663a63f8e7SHerbert Dürr if( m_bIsDirty) 673a63f8e7SHerbert Dürr flush(); 683a63f8e7SHerbert Dürr if( m_bIsOpen) 693a63f8e7SHerbert Dürr m_MapFile.close(); 70cdf0e10cSrcweir } 71cdf0e10cSrcweir 72cdf0e10cSrcweir //______________________________________________________________________________ 733a63f8e7SHerbert Dürr 743a63f8e7SHerbert Dürr // replace 0x00..0x0F with "%0".."%F" 753a63f8e7SHerbert Dürr // replace "%" with "%%" 763a63f8e7SHerbert Dürr static OString encodeString( const OString& rStr) 77cdf0e10cSrcweir { 783a63f8e7SHerbert Dürr const sal_Char* pChar = rStr.getStr(); 793a63f8e7SHerbert Dürr const sal_Int32 nLen = rStr.getLength(); 803a63f8e7SHerbert Dürr sal_Int32 i = nLen; 813a63f8e7SHerbert Dürr // short circuit for the simple non-encoded case 823a63f8e7SHerbert Dürr while( --i >= 0) 833a63f8e7SHerbert Dürr { 843a63f8e7SHerbert Dürr const sal_Char c = *(pChar++); 853a63f8e7SHerbert Dürr if( (0x00 <= c) && (c <= 0x0F)) 863a63f8e7SHerbert Dürr break; 873a63f8e7SHerbert Dürr if( c == '%') 883a63f8e7SHerbert Dürr break; 893a63f8e7SHerbert Dürr } 903a63f8e7SHerbert Dürr if( i < 0) 913a63f8e7SHerbert Dürr return rStr; 923a63f8e7SHerbert Dürr 933a63f8e7SHerbert Dürr // escape chars 0x00..0x0F with "%0".."%F" 943a63f8e7SHerbert Dürr OStringBuffer aEncStr( nLen + 32); 953a63f8e7SHerbert Dürr aEncStr.append( pChar - (nLen-i), nLen - i); 963a63f8e7SHerbert Dürr while( --i >= 0) 973a63f8e7SHerbert Dürr { 983a63f8e7SHerbert Dürr sal_Char c = *(pChar++); 993a63f8e7SHerbert Dürr if( (0x00 <= c) && (c <= 0x0F)) 1003a63f8e7SHerbert Dürr { 1013a63f8e7SHerbert Dürr aEncStr.append( '%'); 1023a63f8e7SHerbert Dürr c += (c <= 0x09) ? '0' : 'A'-10; 1033a63f8e7SHerbert Dürr } else if( c == '%') 1043a63f8e7SHerbert Dürr aEncStr.append( '%'); 1053a63f8e7SHerbert Dürr aEncStr.append( c); 1063a63f8e7SHerbert Dürr } 1073a63f8e7SHerbert Dürr 1083a63f8e7SHerbert Dürr return aEncStr.makeStringAndClear(); 109cdf0e10cSrcweir } 110cdf0e10cSrcweir 111cdf0e10cSrcweir //______________________________________________________________________________ 1123a63f8e7SHerbert Dürr 1133a63f8e7SHerbert Dürr // replace "%0".."%F" with 0x00..0x0F 1143a63f8e7SHerbert Dürr // replace "%%" with "%" 1153a63f8e7SHerbert Dürr static OString decodeString( const sal_Char* pEncChars, int nLen) 116cdf0e10cSrcweir { 1173a63f8e7SHerbert Dürr const char* pChar = pEncChars; 1183a63f8e7SHerbert Dürr sal_Int32 i = nLen; 1193a63f8e7SHerbert Dürr // short circuit for the simple non-encoded case 1203a63f8e7SHerbert Dürr while( --i >= 0) 1213a63f8e7SHerbert Dürr if( *(pChar++) == '%') 1223a63f8e7SHerbert Dürr break; 1233a63f8e7SHerbert Dürr if( i < 0) 1243a63f8e7SHerbert Dürr return OString( pEncChars, nLen); 1253a63f8e7SHerbert Dürr 1263a63f8e7SHerbert Dürr // replace escaped chars with their decoded counterparts 1273a63f8e7SHerbert Dürr OStringBuffer aDecStr( nLen); 1283a63f8e7SHerbert Dürr pChar = pEncChars; 1293a63f8e7SHerbert Dürr for( i = nLen; --i >= 0;) 1303a63f8e7SHerbert Dürr { 1313a63f8e7SHerbert Dürr sal_Char c = *(pChar++); 1323a63f8e7SHerbert Dürr // handle escaped character 1333a63f8e7SHerbert Dürr if( c == '%') 1343a63f8e7SHerbert Dürr { 1353a63f8e7SHerbert Dürr --i; 1363a63f8e7SHerbert Dürr OSL_ASSERT( i >= 0); 1373a63f8e7SHerbert Dürr c = *(pChar++); 1383a63f8e7SHerbert Dürr if( ('0' <= c) && (c <= '9')) 1393a63f8e7SHerbert Dürr c -= '0'; 1403a63f8e7SHerbert Dürr else 1413a63f8e7SHerbert Dürr { 1423a63f8e7SHerbert Dürr OSL_ASSERT( ('A' <= c) && (c <= 'F')); 1433a63f8e7SHerbert Dürr c -= ('A'-10); 1443a63f8e7SHerbert Dürr } 1453a63f8e7SHerbert Dürr } 1463a63f8e7SHerbert Dürr aDecStr.append( c); 1473a63f8e7SHerbert Dürr } 1483a63f8e7SHerbert Dürr 1493a63f8e7SHerbert Dürr return aDecStr.makeStringAndClear(); 1503a63f8e7SHerbert Dürr } 1513a63f8e7SHerbert Dürr 1523a63f8e7SHerbert Dürr //______________________________________________________________________________ 1533a63f8e7SHerbert Dürr bool PersistentMap::open() 1543a63f8e7SHerbert Dürr { 1553a63f8e7SHerbert Dürr // open the existing file 1563a63f8e7SHerbert Dürr sal_uInt32 nOpenFlags = osl_File_OpenFlag_Read; 1573a63f8e7SHerbert Dürr if( !m_bReadOnly) 1583a63f8e7SHerbert Dürr nOpenFlags |= osl_File_OpenFlag_Write; 1593a63f8e7SHerbert Dürr 160eaecd99eSHerbert Dürr const ::osl::File::RC rcOpen = m_MapFile.open( nOpenFlags); 1613a63f8e7SHerbert Dürr m_bIsOpen = (rcOpen == osl::File::E_None); 1623a63f8e7SHerbert Dürr 1633a63f8e7SHerbert Dürr // or create later if needed 164eaecd99eSHerbert Dürr m_bToBeCreated &= (rcOpen == osl::File::E_NOENT) && !m_bIsOpen; 1653a63f8e7SHerbert Dürr if( !m_bIsOpen) 1663a63f8e7SHerbert Dürr return m_bToBeCreated; 1673a63f8e7SHerbert Dürr 168eaecd99eSHerbert Dürr const bool readOK = readAll(); 169eaecd99eSHerbert Dürr return readOK; 170eaecd99eSHerbert Dürr } 171eaecd99eSHerbert Dürr 172eaecd99eSHerbert Dürr //______________________________________________________________________________ 173eaecd99eSHerbert Dürr bool PersistentMap::readAll() 174eaecd99eSHerbert Dürr { 175eaecd99eSHerbert Dürr // prepare for re-reading the map-file 176eaecd99eSHerbert Dürr m_MapFile.setPos( osl_Pos_Absolut, 0); 177eaecd99eSHerbert Dürr m_entries.clear(); 178eaecd99eSHerbert Dürr 1793a63f8e7SHerbert Dürr // read header and check magic 1803a63f8e7SHerbert Dürr char aHeaderBytes[ sizeof(PmapMagic)]; 1813a63f8e7SHerbert Dürr sal_uInt64 nBytesRead = 0; 1823a63f8e7SHerbert Dürr m_MapFile.read( aHeaderBytes, sizeof(aHeaderBytes), nBytesRead); 1833a63f8e7SHerbert Dürr OSL_ASSERT( nBytesRead == sizeof(aHeaderBytes)); 1843a63f8e7SHerbert Dürr if( nBytesRead != sizeof(aHeaderBytes)) 1853a63f8e7SHerbert Dürr return false; 1863a63f8e7SHerbert Dürr // check header magic 1873a63f8e7SHerbert Dürr for( int i = 0; i < (int)sizeof(PmapMagic); ++i) 1883a63f8e7SHerbert Dürr if( aHeaderBytes[i] != PmapMagic[i]) 1893a63f8e7SHerbert Dürr return false; 1903a63f8e7SHerbert Dürr 1913a63f8e7SHerbert Dürr // read key value pairs and add them to the map 1923a63f8e7SHerbert Dürr ByteSequence aKeyLine; 1933a63f8e7SHerbert Dürr ByteSequence aValLine; 1943a63f8e7SHerbert Dürr for(;;) 1953a63f8e7SHerbert Dürr { 1963a63f8e7SHerbert Dürr // read key-value line pair 1973a63f8e7SHerbert Dürr // an empty key name indicates the end of the line pairs 1983a63f8e7SHerbert Dürr if( m_MapFile.readLine( aKeyLine) != osl::File::E_None) 1993a63f8e7SHerbert Dürr return false; 2003a63f8e7SHerbert Dürr if( !aKeyLine.getLength()) 2013a63f8e7SHerbert Dürr break; 2023a63f8e7SHerbert Dürr if( m_MapFile.readLine( aValLine) != osl::File::E_None) 2033a63f8e7SHerbert Dürr return false; 2043a63f8e7SHerbert Dürr // decode key and value strings 2053a63f8e7SHerbert Dürr const OString aKeyName = decodeString( (sal_Char*)aKeyLine.getConstArray(), aKeyLine.getLength()); 2063a63f8e7SHerbert Dürr const OString aValName = decodeString( (sal_Char*)aValLine.getConstArray(), aValLine.getLength()); 2073a63f8e7SHerbert Dürr // insert key-value pair into map 2083a63f8e7SHerbert Dürr put( aKeyName, aValName); 2093a63f8e7SHerbert Dürr // check end-of-file status 2103a63f8e7SHerbert Dürr sal_Bool bIsEOF = true; 2113a63f8e7SHerbert Dürr if( m_MapFile.isEndOfFile( &bIsEOF) != osl::File::E_None) 2123a63f8e7SHerbert Dürr return false; 2133a63f8e7SHerbert Dürr if( bIsEOF) 2143a63f8e7SHerbert Dürr break; 2153a63f8e7SHerbert Dürr } 2163a63f8e7SHerbert Dürr 217eaecd99eSHerbert Dürr m_bIsDirty = false; 2183a63f8e7SHerbert Dürr return true; 2193a63f8e7SHerbert Dürr } 2203a63f8e7SHerbert Dürr 2213a63f8e7SHerbert Dürr //______________________________________________________________________________ 2223a63f8e7SHerbert Dürr void PersistentMap::flush( void) 2233a63f8e7SHerbert Dürr { 2243a63f8e7SHerbert Dürr if( !m_bIsDirty) 2253a63f8e7SHerbert Dürr return; 2263a63f8e7SHerbert Dürr OSL_ASSERT( !m_bReadOnly); 2273a63f8e7SHerbert Dürr if( m_bToBeCreated && !m_entries.empty()) 2283a63f8e7SHerbert Dürr { 2293a63f8e7SHerbert Dürr const sal_uInt32 nOpenFlags = osl_File_OpenFlag_Read | osl_File_OpenFlag_Write | osl_File_OpenFlag_Create; 230eaecd99eSHerbert Dürr const ::osl::File::RC rcOpen = m_MapFile.open( nOpenFlags); 2313a63f8e7SHerbert Dürr m_bIsOpen = (rcOpen == osl::File::E_None); 2323a63f8e7SHerbert Dürr m_bToBeCreated = !m_bIsOpen; 2333a63f8e7SHerbert Dürr } 2343a63f8e7SHerbert Dürr if( !m_bIsOpen) 2353a63f8e7SHerbert Dürr return; 2363a63f8e7SHerbert Dürr 2373a63f8e7SHerbert Dürr // write header magic 2383a63f8e7SHerbert Dürr m_MapFile.setPos( osl_Pos_Absolut, 0); 2393a63f8e7SHerbert Dürr sal_uInt64 nBytesWritten = 0; 2403a63f8e7SHerbert Dürr m_MapFile.write( PmapMagic, sizeof(PmapMagic), nBytesWritten); 2413a63f8e7SHerbert Dürr 2423a63f8e7SHerbert Dürr // write key value pairs 2433a63f8e7SHerbert Dürr t_string2string_map::const_iterator it = m_entries.begin(); 2443a63f8e7SHerbert Dürr for(; it != m_entries.end(); ++it) { 2453a63f8e7SHerbert Dürr // write line for key 2463a63f8e7SHerbert Dürr const OString aKeyString = encodeString( (*it).first); 2473a63f8e7SHerbert Dürr const sal_Int32 nKeyLen = aKeyString.getLength(); 2483a63f8e7SHerbert Dürr m_MapFile.write( aKeyString.getStr(), nKeyLen, nBytesWritten); 2493a63f8e7SHerbert Dürr OSL_ASSERT( nKeyLen == (sal_Int32)nBytesWritten); 2503a63f8e7SHerbert Dürr m_MapFile.write( "\n", 1, nBytesWritten); 2513a63f8e7SHerbert Dürr // write line for value 2523a63f8e7SHerbert Dürr const OString& rValString = encodeString( (*it).second); 2533a63f8e7SHerbert Dürr const sal_Int32 nValLen = rValString.getLength(); 2543a63f8e7SHerbert Dürr m_MapFile.write( rValString.getStr(), nValLen, nBytesWritten); 2553a63f8e7SHerbert Dürr OSL_ASSERT( nValLen == (sal_Int32)nBytesWritten); 2563a63f8e7SHerbert Dürr m_MapFile.write( "\n", 1, nBytesWritten); 2573a63f8e7SHerbert Dürr } 2583a63f8e7SHerbert Dürr 2593a63f8e7SHerbert Dürr // write a file delimiter (an empty key-string) 2603a63f8e7SHerbert Dürr m_MapFile.write( "\n", 1, nBytesWritten); 2613a63f8e7SHerbert Dürr // truncate file here 2623a63f8e7SHerbert Dürr sal_uInt64 nNewFileSize; 2633a63f8e7SHerbert Dürr if( m_MapFile.getPos( nNewFileSize) == osl::File::E_None) 2643a63f8e7SHerbert Dürr m_MapFile.setSize( nNewFileSize); 2653a63f8e7SHerbert Dürr // flush to disk 2663a63f8e7SHerbert Dürr m_MapFile.sync(); 2673a63f8e7SHerbert Dürr // the in-memory map now matches to the file on disk 2683a63f8e7SHerbert Dürr m_bIsDirty = false; 269cdf0e10cSrcweir } 270cdf0e10cSrcweir 271cdf0e10cSrcweir //______________________________________________________________________________ 272cdf0e10cSrcweir bool PersistentMap::has( OString const & key ) const 273cdf0e10cSrcweir { 2743a63f8e7SHerbert Dürr return get( NULL, key ); 275cdf0e10cSrcweir } 276cdf0e10cSrcweir 277cdf0e10cSrcweir //______________________________________________________________________________ 278cdf0e10cSrcweir bool PersistentMap::get( OString * value, OString const & key ) const 279cdf0e10cSrcweir { 2803a63f8e7SHerbert Dürr t_string2string_map::const_iterator it = m_entries.find( key); 2813a63f8e7SHerbert Dürr if( it == m_entries.end()) 2823a63f8e7SHerbert Dürr return false; 2833a63f8e7SHerbert Dürr if( value) 2843a63f8e7SHerbert Dürr *value = it->second; 2853a63f8e7SHerbert Dürr return true; 286cdf0e10cSrcweir } 287cdf0e10cSrcweir 288cdf0e10cSrcweir //______________________________________________________________________________ 289cdf0e10cSrcweir void PersistentMap::put( OString const & key, OString const & value ) 290cdf0e10cSrcweir { 2913a63f8e7SHerbert Dürr if( m_bReadOnly) 2923a63f8e7SHerbert Dürr return; 2933a63f8e7SHerbert Dürr typedef std::pair<t_string2string_map::iterator,bool> InsertRC; 2943a63f8e7SHerbert Dürr InsertRC r = m_entries.insert( t_string2string_map::value_type(key,value)); 2953a63f8e7SHerbert Dürr m_bIsDirty = r.second; 296*de4a8351SHerbert Dürr // HACK: flush now as the extension manager does not seem 297*de4a8351SHerbert Dürr // to properly destruct this object in some situations 298*de4a8351SHerbert Dürr if( m_bIsDirty) 299*de4a8351SHerbert Dürr flush(); 300cdf0e10cSrcweir } 301cdf0e10cSrcweir 302cdf0e10cSrcweir //______________________________________________________________________________ 303cdf0e10cSrcweir bool PersistentMap::erase( OString const & key, bool flush_immediately ) 304cdf0e10cSrcweir { 3053a63f8e7SHerbert Dürr if( m_bReadOnly) 3063a63f8e7SHerbert Dürr return false; 3073a63f8e7SHerbert Dürr size_t nCount = m_entries.erase( key); 3083a63f8e7SHerbert Dürr if( !nCount) 3093a63f8e7SHerbert Dürr return false; 3103a63f8e7SHerbert Dürr m_bIsDirty = true; 3113a63f8e7SHerbert Dürr if( flush_immediately) 3123a63f8e7SHerbert Dürr flush(); 3133a63f8e7SHerbert Dürr return true; 314cdf0e10cSrcweir } 315cdf0e10cSrcweir 316cdf0e10cSrcweir //______________________________________________________________________________ 317cdf0e10cSrcweir t_string2string_map PersistentMap::getEntries() const 318cdf0e10cSrcweir { 3193a63f8e7SHerbert Dürr // TODO: return by const reference instead? 3203a63f8e7SHerbert Dürr return m_entries; 321cdf0e10cSrcweir } 322cdf0e10cSrcweir 323cdf0e10cSrcweir } 324