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; 30*3a63f8e7SHerbert Dürr 31*3a63f8e7SHerbert Dürr // the persistent map is used to manage a handful of key-value string pairs 32*3a63f8e7SHerbert Dürr // this implementation replaces a rather heavy-weight berkeleydb integration 33*3a63f8e7SHerbert Dürr 34*3a63f8e7SHerbert Dürr // the file backing up a persistent map consists of line pairs with 35*3a63f8e7SHerbert Dürr // - an encoded key name (with chars 0x00..0x0F being escaped) 36*3a63f8e7SHerbert Dürr // - an encoded value name (with chars 0x00..0x0F being escaped) 37cdf0e10cSrcweir 38cdf0e10cSrcweir namespace dp_misc 39cdf0e10cSrcweir { 40cdf0e10cSrcweir 41*3a63f8e7SHerbert Dürr static const char PmapMagic[4] = {'P','m','p','1'}; 42*3a63f8e7SHerbert Dürr 43cdf0e10cSrcweir //______________________________________________________________________________ 44*3a63f8e7SHerbert Dürr PersistentMap::PersistentMap( OUString const & url_, bool readOnly ) 45*3a63f8e7SHerbert Dürr : m_MapFile( expandUnoRcUrl(url_) ) 46*3a63f8e7SHerbert Dürr , m_bReadOnly( readOnly) 47*3a63f8e7SHerbert Dürr , m_bIsOpen( false) 48*3a63f8e7SHerbert Dürr , m_bToBeCreated( !readOnly) 49*3a63f8e7SHerbert Dürr , m_bIsDirty( false) 50cdf0e10cSrcweir { 51*3a63f8e7SHerbert Dürr open(); 52cdf0e10cSrcweir } 53cdf0e10cSrcweir 54*3a63f8e7SHerbert Dürr //______________________________________________________________________________ 55*3a63f8e7SHerbert Dürr PersistentMap::PersistentMap() 56*3a63f8e7SHerbert Dürr : m_MapFile( OUString()) 57*3a63f8e7SHerbert Dürr , m_bReadOnly( false) 58*3a63f8e7SHerbert Dürr , m_bIsOpen( false) 59*3a63f8e7SHerbert Dürr , m_bToBeCreated( false) 60*3a63f8e7SHerbert Dürr , m_bIsDirty( false) 61*3a63f8e7SHerbert Dürr {} 62*3a63f8e7SHerbert Dürr 63cdf0e10cSrcweir //______________________________________________________________________________ 64cdf0e10cSrcweir PersistentMap::~PersistentMap() 65cdf0e10cSrcweir { 66*3a63f8e7SHerbert Dürr if( m_bIsDirty) 67*3a63f8e7SHerbert Dürr flush(); 68*3a63f8e7SHerbert Dürr if( m_bIsOpen) 69*3a63f8e7SHerbert Dürr m_MapFile.close(); 70cdf0e10cSrcweir } 71cdf0e10cSrcweir 72cdf0e10cSrcweir //______________________________________________________________________________ 73*3a63f8e7SHerbert Dürr 74*3a63f8e7SHerbert Dürr // replace 0x00..0x0F with "%0".."%F" 75*3a63f8e7SHerbert Dürr // replace "%" with "%%" 76*3a63f8e7SHerbert Dürr static OString encodeString( const OString& rStr) 77cdf0e10cSrcweir { 78*3a63f8e7SHerbert Dürr const sal_Char* pChar = rStr.getStr(); 79*3a63f8e7SHerbert Dürr const sal_Int32 nLen = rStr.getLength(); 80*3a63f8e7SHerbert Dürr sal_Int32 i = nLen; 81*3a63f8e7SHerbert Dürr // short circuit for the simple non-encoded case 82*3a63f8e7SHerbert Dürr while( --i >= 0) 83*3a63f8e7SHerbert Dürr { 84*3a63f8e7SHerbert Dürr const sal_Char c = *(pChar++); 85*3a63f8e7SHerbert Dürr if( (0x00 <= c) && (c <= 0x0F)) 86*3a63f8e7SHerbert Dürr break; 87*3a63f8e7SHerbert Dürr if( c == '%') 88*3a63f8e7SHerbert Dürr break; 89*3a63f8e7SHerbert Dürr } 90*3a63f8e7SHerbert Dürr if( i < 0) 91*3a63f8e7SHerbert Dürr return rStr; 92*3a63f8e7SHerbert Dürr 93*3a63f8e7SHerbert Dürr // escape chars 0x00..0x0F with "%0".."%F" 94*3a63f8e7SHerbert Dürr OStringBuffer aEncStr( nLen + 32); 95*3a63f8e7SHerbert Dürr aEncStr.append( pChar - (nLen-i), nLen - i); 96*3a63f8e7SHerbert Dürr while( --i >= 0) 97*3a63f8e7SHerbert Dürr { 98*3a63f8e7SHerbert Dürr sal_Char c = *(pChar++); 99*3a63f8e7SHerbert Dürr if( (0x00 <= c) && (c <= 0x0F)) 100*3a63f8e7SHerbert Dürr { 101*3a63f8e7SHerbert Dürr aEncStr.append( '%'); 102*3a63f8e7SHerbert Dürr c += (c <= 0x09) ? '0' : 'A'-10; 103*3a63f8e7SHerbert Dürr } else if( c == '%') 104*3a63f8e7SHerbert Dürr aEncStr.append( '%'); 105*3a63f8e7SHerbert Dürr aEncStr.append( c); 106*3a63f8e7SHerbert Dürr } 107*3a63f8e7SHerbert Dürr 108*3a63f8e7SHerbert Dürr return aEncStr.makeStringAndClear(); 109cdf0e10cSrcweir } 110cdf0e10cSrcweir 111cdf0e10cSrcweir //______________________________________________________________________________ 112*3a63f8e7SHerbert Dürr 113*3a63f8e7SHerbert Dürr // replace "%0".."%F" with 0x00..0x0F 114*3a63f8e7SHerbert Dürr // replace "%%" with "%" 115*3a63f8e7SHerbert Dürr static OString decodeString( const sal_Char* pEncChars, int nLen) 116cdf0e10cSrcweir { 117*3a63f8e7SHerbert Dürr const char* pChar = pEncChars; 118*3a63f8e7SHerbert Dürr sal_Int32 i = nLen; 119*3a63f8e7SHerbert Dürr // short circuit for the simple non-encoded case 120*3a63f8e7SHerbert Dürr while( --i >= 0) 121*3a63f8e7SHerbert Dürr if( *(pChar++) == '%') 122*3a63f8e7SHerbert Dürr break; 123*3a63f8e7SHerbert Dürr if( i < 0) 124*3a63f8e7SHerbert Dürr return OString( pEncChars, nLen); 125*3a63f8e7SHerbert Dürr 126*3a63f8e7SHerbert Dürr // replace escaped chars with their decoded counterparts 127*3a63f8e7SHerbert Dürr OStringBuffer aDecStr( nLen); 128*3a63f8e7SHerbert Dürr pChar = pEncChars; 129*3a63f8e7SHerbert Dürr for( i = nLen; --i >= 0;) 130*3a63f8e7SHerbert Dürr { 131*3a63f8e7SHerbert Dürr sal_Char c = *(pChar++); 132*3a63f8e7SHerbert Dürr // handle escaped character 133*3a63f8e7SHerbert Dürr if( c == '%') 134*3a63f8e7SHerbert Dürr { 135*3a63f8e7SHerbert Dürr --i; 136*3a63f8e7SHerbert Dürr OSL_ASSERT( i >= 0); 137*3a63f8e7SHerbert Dürr c = *(pChar++); 138*3a63f8e7SHerbert Dürr if( ('0' <= c) && (c <= '9')) 139*3a63f8e7SHerbert Dürr c -= '0'; 140*3a63f8e7SHerbert Dürr else 141*3a63f8e7SHerbert Dürr { 142*3a63f8e7SHerbert Dürr OSL_ASSERT( ('A' <= c) && (c <= 'F')); 143*3a63f8e7SHerbert Dürr c -= ('A'-10); 144*3a63f8e7SHerbert Dürr } 145*3a63f8e7SHerbert Dürr } 146*3a63f8e7SHerbert Dürr aDecStr.append( c); 147*3a63f8e7SHerbert Dürr } 148*3a63f8e7SHerbert Dürr 149*3a63f8e7SHerbert Dürr return aDecStr.makeStringAndClear(); 150*3a63f8e7SHerbert Dürr } 151*3a63f8e7SHerbert Dürr 152*3a63f8e7SHerbert Dürr //______________________________________________________________________________ 153*3a63f8e7SHerbert Dürr bool PersistentMap::open() 154*3a63f8e7SHerbert Dürr { 155*3a63f8e7SHerbert Dürr // open the existing file 156*3a63f8e7SHerbert Dürr sal_uInt32 nOpenFlags = osl_File_OpenFlag_Read; 157*3a63f8e7SHerbert Dürr if( !m_bReadOnly) 158*3a63f8e7SHerbert Dürr nOpenFlags |= osl_File_OpenFlag_Write; 159*3a63f8e7SHerbert Dürr 160*3a63f8e7SHerbert Dürr ::osl::File::RC rcOpen = m_MapFile.open( nOpenFlags); 161*3a63f8e7SHerbert Dürr m_bIsOpen = (rcOpen == osl::File::E_None); 162*3a63f8e7SHerbert Dürr 163*3a63f8e7SHerbert Dürr // or create later if needed 164*3a63f8e7SHerbert Dürr m_bToBeCreated = (rcOpen == osl::File::E_NOENT) && !m_bIsOpen; 165*3a63f8e7SHerbert Dürr if( !m_bIsOpen) 166*3a63f8e7SHerbert Dürr return m_bToBeCreated; 167*3a63f8e7SHerbert Dürr 168*3a63f8e7SHerbert Dürr // read header and check magic 169*3a63f8e7SHerbert Dürr char aHeaderBytes[ sizeof(PmapMagic)]; 170*3a63f8e7SHerbert Dürr sal_uInt64 nBytesRead = 0; 171*3a63f8e7SHerbert Dürr m_MapFile.read( aHeaderBytes, sizeof(aHeaderBytes), nBytesRead); 172*3a63f8e7SHerbert Dürr OSL_ASSERT( nBytesRead == sizeof(aHeaderBytes)); 173*3a63f8e7SHerbert Dürr if( nBytesRead != sizeof(aHeaderBytes)) 174*3a63f8e7SHerbert Dürr return false; 175*3a63f8e7SHerbert Dürr // check header magic 176*3a63f8e7SHerbert Dürr for( int i = 0; i < (int)sizeof(PmapMagic); ++i) 177*3a63f8e7SHerbert Dürr if( aHeaderBytes[i] != PmapMagic[i]) 178*3a63f8e7SHerbert Dürr return false; 179*3a63f8e7SHerbert Dürr 180*3a63f8e7SHerbert Dürr // read key value pairs and add them to the map 181*3a63f8e7SHerbert Dürr ByteSequence aKeyLine; 182*3a63f8e7SHerbert Dürr ByteSequence aValLine; 183*3a63f8e7SHerbert Dürr for(;;) 184*3a63f8e7SHerbert Dürr { 185*3a63f8e7SHerbert Dürr // read key-value line pair 186*3a63f8e7SHerbert Dürr // an empty key name indicates the end of the line pairs 187*3a63f8e7SHerbert Dürr if( m_MapFile.readLine( aKeyLine) != osl::File::E_None) 188*3a63f8e7SHerbert Dürr return false; 189*3a63f8e7SHerbert Dürr if( !aKeyLine.getLength()) 190*3a63f8e7SHerbert Dürr break; 191*3a63f8e7SHerbert Dürr if( m_MapFile.readLine( aValLine) != osl::File::E_None) 192*3a63f8e7SHerbert Dürr return false; 193*3a63f8e7SHerbert Dürr // decode key and value strings 194*3a63f8e7SHerbert Dürr const OString aKeyName = decodeString( (sal_Char*)aKeyLine.getConstArray(), aKeyLine.getLength()); 195*3a63f8e7SHerbert Dürr const OString aValName = decodeString( (sal_Char*)aValLine.getConstArray(), aValLine.getLength()); 196*3a63f8e7SHerbert Dürr // insert key-value pair into map 197*3a63f8e7SHerbert Dürr put( aKeyName, aValName); 198*3a63f8e7SHerbert Dürr // check end-of-file status 199*3a63f8e7SHerbert Dürr sal_Bool bIsEOF = true; 200*3a63f8e7SHerbert Dürr if( m_MapFile.isEndOfFile( &bIsEOF) != osl::File::E_None) 201*3a63f8e7SHerbert Dürr return false; 202*3a63f8e7SHerbert Dürr if( bIsEOF) 203*3a63f8e7SHerbert Dürr break; 204*3a63f8e7SHerbert Dürr } 205*3a63f8e7SHerbert Dürr 206*3a63f8e7SHerbert Dürr return true; 207*3a63f8e7SHerbert Dürr } 208*3a63f8e7SHerbert Dürr 209*3a63f8e7SHerbert Dürr //______________________________________________________________________________ 210*3a63f8e7SHerbert Dürr void PersistentMap::flush( void) 211*3a63f8e7SHerbert Dürr { 212*3a63f8e7SHerbert Dürr if( !m_bIsDirty) 213*3a63f8e7SHerbert Dürr return; 214*3a63f8e7SHerbert Dürr OSL_ASSERT( !m_bReadOnly); 215*3a63f8e7SHerbert Dürr if( m_bToBeCreated && !m_entries.empty()) 216*3a63f8e7SHerbert Dürr { 217*3a63f8e7SHerbert Dürr const sal_uInt32 nOpenFlags = osl_File_OpenFlag_Read | osl_File_OpenFlag_Write | osl_File_OpenFlag_Create; 218*3a63f8e7SHerbert Dürr ::osl::File::RC rcOpen = m_MapFile.open( nOpenFlags); 219*3a63f8e7SHerbert Dürr m_bIsOpen = (rcOpen == osl::File::E_None); 220*3a63f8e7SHerbert Dürr m_bToBeCreated = !m_bIsOpen; 221*3a63f8e7SHerbert Dürr } 222*3a63f8e7SHerbert Dürr if( !m_bIsOpen) 223*3a63f8e7SHerbert Dürr return; 224*3a63f8e7SHerbert Dürr 225*3a63f8e7SHerbert Dürr // write header magic 226*3a63f8e7SHerbert Dürr m_MapFile.setPos( osl_Pos_Absolut, 0); 227*3a63f8e7SHerbert Dürr sal_uInt64 nBytesWritten = 0; 228*3a63f8e7SHerbert Dürr m_MapFile.write( PmapMagic, sizeof(PmapMagic), nBytesWritten); 229*3a63f8e7SHerbert Dürr 230*3a63f8e7SHerbert Dürr // write key value pairs 231*3a63f8e7SHerbert Dürr t_string2string_map::const_iterator it = m_entries.begin(); 232*3a63f8e7SHerbert Dürr for(; it != m_entries.end(); ++it) { 233*3a63f8e7SHerbert Dürr // write line for key 234*3a63f8e7SHerbert Dürr const OString aKeyString = encodeString( (*it).first); 235*3a63f8e7SHerbert Dürr const sal_Int32 nKeyLen = aKeyString.getLength(); 236*3a63f8e7SHerbert Dürr m_MapFile.write( aKeyString.getStr(), nKeyLen, nBytesWritten); 237*3a63f8e7SHerbert Dürr OSL_ASSERT( nKeyLen == (sal_Int32)nBytesWritten); 238*3a63f8e7SHerbert Dürr m_MapFile.write( "\n", 1, nBytesWritten); 239*3a63f8e7SHerbert Dürr // write line for value 240*3a63f8e7SHerbert Dürr const OString& rValString = encodeString( (*it).second); 241*3a63f8e7SHerbert Dürr const sal_Int32 nValLen = rValString.getLength(); 242*3a63f8e7SHerbert Dürr m_MapFile.write( rValString.getStr(), nValLen, nBytesWritten); 243*3a63f8e7SHerbert Dürr OSL_ASSERT( nValLen == (sal_Int32)nBytesWritten); 244*3a63f8e7SHerbert Dürr m_MapFile.write( "\n", 1, nBytesWritten); 245*3a63f8e7SHerbert Dürr } 246*3a63f8e7SHerbert Dürr 247*3a63f8e7SHerbert Dürr // write a file delimiter (an empty key-string) 248*3a63f8e7SHerbert Dürr m_MapFile.write( "\n", 1, nBytesWritten); 249*3a63f8e7SHerbert Dürr // truncate file here 250*3a63f8e7SHerbert Dürr sal_uInt64 nNewFileSize; 251*3a63f8e7SHerbert Dürr if( m_MapFile.getPos( nNewFileSize) == osl::File::E_None) 252*3a63f8e7SHerbert Dürr m_MapFile.setSize( nNewFileSize); 253*3a63f8e7SHerbert Dürr // flush to disk 254*3a63f8e7SHerbert Dürr m_MapFile.sync(); 255*3a63f8e7SHerbert Dürr // the in-memory map now matches to the file on disk 256*3a63f8e7SHerbert Dürr m_bIsDirty = false; 257cdf0e10cSrcweir } 258cdf0e10cSrcweir 259cdf0e10cSrcweir //______________________________________________________________________________ 260cdf0e10cSrcweir bool PersistentMap::has( OString const & key ) const 261cdf0e10cSrcweir { 262*3a63f8e7SHerbert Dürr return get( NULL, key ); 263cdf0e10cSrcweir } 264cdf0e10cSrcweir 265cdf0e10cSrcweir //______________________________________________________________________________ 266cdf0e10cSrcweir bool PersistentMap::get( OString * value, OString const & key ) const 267cdf0e10cSrcweir { 268*3a63f8e7SHerbert Dürr t_string2string_map::const_iterator it = m_entries.find( key); 269*3a63f8e7SHerbert Dürr if( it == m_entries.end()) 270*3a63f8e7SHerbert Dürr return false; 271*3a63f8e7SHerbert Dürr if( value) 272*3a63f8e7SHerbert Dürr *value = it->second; 273*3a63f8e7SHerbert Dürr return true; 274cdf0e10cSrcweir } 275cdf0e10cSrcweir 276cdf0e10cSrcweir //______________________________________________________________________________ 277cdf0e10cSrcweir void PersistentMap::put( OString const & key, OString const & value ) 278cdf0e10cSrcweir { 279*3a63f8e7SHerbert Dürr if( m_bReadOnly) 280*3a63f8e7SHerbert Dürr return; 281*3a63f8e7SHerbert Dürr typedef std::pair<t_string2string_map::iterator,bool> InsertRC; 282*3a63f8e7SHerbert Dürr InsertRC r = m_entries.insert( t_string2string_map::value_type(key,value)); 283*3a63f8e7SHerbert Dürr m_bIsDirty = r.second; 284*3a63f8e7SHerbert Dürr (void)r; 285cdf0e10cSrcweir } 286cdf0e10cSrcweir 287cdf0e10cSrcweir //______________________________________________________________________________ 288cdf0e10cSrcweir bool PersistentMap::erase( OString const & key, bool flush_immediately ) 289cdf0e10cSrcweir { 290*3a63f8e7SHerbert Dürr if( m_bReadOnly) 291*3a63f8e7SHerbert Dürr return false; 292*3a63f8e7SHerbert Dürr size_t nCount = m_entries.erase( key); 293*3a63f8e7SHerbert Dürr if( !nCount) 294*3a63f8e7SHerbert Dürr return false; 295*3a63f8e7SHerbert Dürr m_bIsDirty = true; 296*3a63f8e7SHerbert Dürr if( flush_immediately) 297*3a63f8e7SHerbert Dürr flush(); 298*3a63f8e7SHerbert Dürr return true; 299cdf0e10cSrcweir } 300cdf0e10cSrcweir 301cdf0e10cSrcweir //______________________________________________________________________________ 302cdf0e10cSrcweir t_string2string_map PersistentMap::getEntries() const 303cdf0e10cSrcweir { 304*3a63f8e7SHerbert Dürr // TODO: return by const reference instead? 305*3a63f8e7SHerbert Dürr return m_entries; 306cdf0e10cSrcweir } 307cdf0e10cSrcweir 308cdf0e10cSrcweir } 309