diff options
author | Michael Meeks <michael.meeks@suse.com> | 2012-11-15 17:28:16 +0000 |
---|---|---|
committer | Michael Meeks <michael.meeks@suse.com> | 2012-11-19 17:44:55 +0000 |
commit | daeed90f4586eb9533041fb89bee163a5193596c (patch) | |
tree | 0e0a19c3f413fc32743e3b0b39aa20484ee40f95 /desktop/source/deployment/dp_persmap.cxx | |
parent | 19e8dd66cb8a66536e19fc7780fbc1101be13710 (diff) |
re-base on ALv2 code. Includes:
Patch contributed by: Jurgen Schmidt
remove onlineregistration with dependencies
http://svn.apache.org/viewvc?view=revision&revision=1240245
imported patch package_eventlistener.patch
http://svn.apache.org/viewvc?view=revision&revision=1172103
Patch contributed by Pedro Giffuni
Accept Google Chrome OS fonts as equivalent to MS fonts.
http://svn.apache.org/viewvc?view=revision&revision=1233155
http://svn.apache.org/viewvc?view=revision&revision=1233408
Patch contributed by Andre Fischer
Do not add targets for junit tests when junit is disabled.
http://svn.apache.org/viewvc?view=revision&revision=1241508
Patches contributed by Mathias Bauer (and others)
gnumake4 work variously
http://svn.apache.org/viewvc?view=revision&revision=1394707
http://svn.apache.org/viewvc?view=revision&revision=1394326
cws mba34issues01: #i114600#: remove forbidden characters
from list of unencoded characters
http://svn.apache.org/viewvc?view=revision&revision=1172370
Patches contributed by Oliver Rainer-Wittman
some clean up in JPEGReader due to memory constraints
http://svn.apache.org/viewvc?view=revision&revision=1299729
119114 - method <UpdateDialog::addSpecificError(..)> - create
entry with correct type
http://svn.apache.org/viewvc?view=revision&revision=1305265
Patches contributed by Ariel Constenla-Haile
i118707 - make toolbar control's popup window grab focus
http://svn.apache.org/viewvc?view=revision&revision=1225846
Patches contributed by Herbert Duerr
#i118662# remove usage of BerkeleyDB in desktop module
http://svn.apache.org/viewvc?view=revision&revision=1213171
minor cleanups in dp_persmap.*
http://svn.apache.org/viewvc?view=revision&revision=1215064
flush early to prevent problem with extension manager not
cleaning up its objects
http://svn.apache.org/viewvc?view=revision&revision=1228147
i118726 do not flush *pmap file while reading it
http://svn.apache.org/viewvc?view=revision&revision=1230614
#i119048# migrate BDB extension entries using a simple heuristic
http://svn.apache.org/viewvc?view=revision&revision=1300972
#i119048# handle edge cases when importing BDB hash files
http://svn.apache.org/viewvc?view=revision&revision=1301428
#i119113# fix of-by-one when importing BDB files
http://svn.apache.org/viewvc?view=revision&revision=1305420
restore our encryption settings, icon themes, and dictionaries.
removed wrapper hacks, kill obsolete bundled extension blob /
pre-registration handling, remove duplicated quickstart code.
remove OS/2 conditionals.
Diffstat (limited to 'desktop/source/deployment/dp_persmap.cxx')
-rw-r--r-- | desktop/source/deployment/dp_persmap.cxx | 546 |
1 files changed, 359 insertions, 187 deletions
diff --git a/desktop/source/deployment/dp_persmap.cxx b/desktop/source/deployment/dp_persmap.cxx index 047ad5331e6c..d1d859290350 100644 --- a/desktop/source/deployment/dp_persmap.cxx +++ b/desktop/source/deployment/dp_persmap.cxx @@ -1,250 +1,422 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* +/* + * This file is part of the LibreOffice project. * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2000, 2010 Oracle and/or its affiliates. + * This file incorporates work covered by the following license notice: * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ #include "dp_misc.h" -#include "dp_ucb.h" #include "dp_persmap.h" #include "rtl/strbuf.hxx" -#include "rtl/ustrbuf.hxx" -#include "osl/file.hxx" -#include "osl/thread.h" +#ifndef DISABLE_BDB2PMAP +# include <vector> +#endif -using namespace ::com::sun::star; -using namespace ::com::sun::star::uno; using namespace ::rtl; -using ::osl::File; + +// the persistent map is used to manage a handful of key-value string pairs +// this implementation replaces a rather heavy-weight berkeleydb integration + +// the file backing up a persistent map consists of line pairs with +// - a key string (encoded with chars 0x00..0x0F being escaped) +// - a value string (encoded with chars 0x00..0x0F being escaped) namespace dp_misc { -//______________________________________________________________________________ -void PersistentMap::throw_rtexc( int err, char const * pmsg ) const +static const char PmapMagic[4] = {'P','m','p','1'}; + +PersistentMap::PersistentMap( OUString const & url_, bool readOnly ) +: m_MapFile( expandUnoRcUrl(url_) ) +, m_bReadOnly( readOnly ) +, m_bIsOpen( false ) +, m_bToBeCreated( !readOnly ) +, m_bIsDirty( false ) { - OUStringBuffer buf; - buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[") ); - buf.append( m_sysPath ); - buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] Berkeley Db error (") ); - buf.append( static_cast<sal_Int32>(err) ); - buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("): ") ); - if (pmsg == 0) - pmsg = DbEnv::strerror(err); - const OString msg(pmsg); - buf.append( OUString( msg.getStr(), msg.getLength(), - osl_getThreadTextEncoding() ) ); - const OUString msg_(buf.makeStringAndClear()); - OSL_FAIL( rtl::OUStringToOString( - msg_, RTL_TEXTENCODING_UTF8 ).getStr() ); - throw RuntimeException( msg_, uno::Reference<XInterface>() ); +#ifndef DISABLE_BDB2PMAP + m_MapFileName = expandUnoRcUrl( url_ ); +#endif + open(); } -//______________________________________________________________________________ +PersistentMap::PersistentMap() +: m_MapFile( OUString() ) +, m_bReadOnly( false ) +, m_bIsOpen( false ) +, m_bToBeCreated( false ) +, m_bIsDirty( false ) +{} + PersistentMap::~PersistentMap() { - try { - m_db.close(0); - } - catch (DbException & exc) { - (void) exc; // avoid warnings - OSL_FAIL( DbEnv::strerror( exc.get_errno() ) ); - } + if( m_bIsDirty ) + flush(); + if( m_bIsOpen ) + m_MapFile.close(); } -//______________________________________________________________________________ -PersistentMap::PersistentMap( OUString const & url ) - : m_db( 0 ) + +// replace 0x00..0x0F with "%0".."%F" +// replace "%" with "%%" +static OString encodeString( const OString& rStr) { - try + const sal_Char* pChar = rStr.getStr(); + const sal_Int32 nLen = rStr.getLength(); + sal_Int32 i = nLen; + // short circuit for the simple non-encoded case + while( --i >= 0) { - rtl::OUString fileURL = expandUnoRcUrl(url); - if ( File::getSystemPathFromFileURL( fileURL, m_sysPath ) != File::E_None ) - OSL_ASSERT( false ); - - OString cstr_sysPath( - OUStringToOString( m_sysPath, RTL_TEXTENCODING_UTF8 ) ); - int err = m_db.open( - // xxx todo: DB_THREAD, DB_DBT_MALLOC currently not used - 0, cstr_sysPath.getStr(), 0, DB_HASH, - DB_CREATE/* | DB_THREAD*/, 0664 /* fs mode */ ); - if (err != 0) - throw_rtexc(err); + const sal_Char c = *(pChar++); + if( (0x00 <= c) && (c <= 0x0F)) + break; + if( c == '%') + break; } - catch (const DbException & exc) + if( i < 0) + return rStr; + + // escape chars 0x00..0x0F with "%0".."%F" + OStringBuffer aEncStr( nLen + 32); + aEncStr.append( pChar - (nLen-i), nLen - i); + while( --i >= 0) { - throw_rtexc( exc.get_errno(), exc.what() ); + sal_Char c = *(pChar++); + if( (0x00 <= c) && (c <= 0x0F)) + { + aEncStr.append( '%'); + c += (c <= 0x09) ? '0' : 'A'-10; + } else if( c == '%') + aEncStr.append( '%'); + aEncStr.append( c); } + + return aEncStr.makeStringAndClear(); } -//______________________________________________________________________________ -PersistentMap::PersistentMap() - : m_db( 0 ) +// replace "%0".."%F" with 0x00..0x0F +// replace "%%" with "%" +static OString decodeString( const sal_Char* pEncChars, int nLen) { - try { - // xxx todo: DB_THREAD, DB_DBT_MALLOC currently not used - int err = m_db.open( 0, 0, 0, DB_HASH, DB_CREATE/* | DB_THREAD*/, 0 ); - if (err != 0) - throw_rtexc(err); - } - catch (DbException & exc) { - throw_rtexc( exc.get_errno(), exc.what() ); + const char* pChar = pEncChars; + sal_Int32 i = nLen; + // short circuit for the simple non-encoded case + while( --i >= 0) + if( *(pChar++) == '%') + break; + if( i < 0) + return OString( pEncChars, nLen); + + // replace escaped chars with their decoded counterparts + OStringBuffer aDecStr( nLen); + pChar = pEncChars; + for( i = nLen; --i >= 0;) + { + sal_Char c = *(pChar++); + // handle escaped character + if( c == '%') + { + --i; + OSL_ASSERT( i >= 0); + c = *(pChar++); + if( ('0' <= c) && (c <= '9')) + c -= '0'; + else + { + OSL_ASSERT( ('A' <= c) && (c <= 'F')); + c -= ('A'-10); + } + } + aDecStr.append( c); } + + return aDecStr.makeStringAndClear(); } -//______________________________________________________________________________ -bool PersistentMap::has( OString const & key ) const +bool PersistentMap::open() { - return get( 0, key ); -} + // open the existing file + sal_uInt32 nOpenFlags = osl_File_OpenFlag_Read; + if( !m_bReadOnly) + nOpenFlags |= osl_File_OpenFlag_Write; -// for 3 functions here MSVC gives C4702 "unreachable code" if optimization -// is enabled and return is there and C4715 "not all control paths return -// a value" if optimization disabled and no return... -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable: 4702 ) + const osl::File::RC rcOpen = m_MapFile.open( nOpenFlags); + m_bIsOpen = (rcOpen == osl::File::E_None); + + // or create later if needed + m_bToBeCreated &= (rcOpen == osl::File::E_NOENT) && !m_bIsOpen; + +#ifndef DISABLE_BDB2PMAP + if( m_bToBeCreated ) + importFromBDB(); #endif + if( !m_bIsOpen) + return m_bToBeCreated; + + return readAll(); +} + //______________________________________________________________________________ -bool PersistentMap::get( OString * value, OString const & key ) const +bool PersistentMap::readAll() { - try { - Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); - Dbt dbData; - int err = m_db.get( 0, &dbKey, &dbData, 0 ); - if (err == DB_NOTFOUND) + // prepare for re-reading the map-file + const osl::FileBase::RC nRes = m_MapFile.setPos( osl_Pos_Absolut, 0); + (void)nRes; + m_entries.clear(); + + // read header and check magic + char aHeaderBytes[ sizeof(PmapMagic)]; + sal_uInt64 nBytesRead = 0; + m_MapFile.read( aHeaderBytes, sizeof(aHeaderBytes), nBytesRead); + OSL_ASSERT( nBytesRead == sizeof(aHeaderBytes)); + if( nBytesRead != sizeof(aHeaderBytes)) + return false; + // check header magic + for( int i = 0; i < (int)sizeof(PmapMagic); ++i) + if( aHeaderBytes[i] != PmapMagic[i]) return false; - if (err == 0) { - if (value != 0) { - *value = OString( - static_cast< sal_Char const * >(dbData.get_data()), - dbData.get_size() ); - } - return true; - } - throw_rtexc(err); - } - catch (DbException & exc) { - throw_rtexc( exc.get_errno(), exc.what() ); + + // read key value pairs and add them to the map + ByteSequence aKeyLine; + ByteSequence aValLine; + for(;;) + { + // read key-value line pair + // an empty key name indicates the end of the line pairs + if( m_MapFile.readLine( aKeyLine) != osl::File::E_None) + return false; + if( !aKeyLine.getLength()) + break; + if( m_MapFile.readLine( aValLine) != osl::File::E_None) + return false; + // decode key and value strings + const OString aKeyName = decodeString( (sal_Char*)aKeyLine.getConstArray(), aKeyLine.getLength()); + const OString aValName = decodeString( (sal_Char*)aValLine.getConstArray(), aValLine.getLength()); + // insert key-value pair into map + add( aKeyName, aValName ); + // check end-of-file status + sal_Bool bIsEOF = true; + if( m_MapFile.isEndOfFile( &bIsEOF) != osl::File::E_None ) + return false; + if( bIsEOF ) + break; } - return false; // avoiding warning + + m_bIsDirty = false; + return true; } -//______________________________________________________________________________ -void PersistentMap::put( OString const & key, OString const & value ) +void PersistentMap::flush() { - try { - Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); - Dbt dbData( const_cast< sal_Char * >( - value.getStr()), value.getLength() ); - int err = m_db.put( 0, &dbKey, &dbData, 0 ); - if (err == 0) { -#if OSL_DEBUG_LEVEL > 0 - OString v; - OSL_ASSERT( get( &v, key ) ); - OSL_ASSERT( v.equals( value ) ); -#endif - err = m_db.sync(0); - } - if (err != 0) - throw_rtexc(err); + if( !m_bIsDirty) + return; + OSL_ASSERT( !m_bReadOnly); + if( m_bToBeCreated && !m_entries.empty()) + { + const sal_uInt32 nOpenFlags = osl_File_OpenFlag_Read | osl_File_OpenFlag_Write | osl_File_OpenFlag_Create; + const osl::File::RC rcOpen = m_MapFile.open( nOpenFlags); + m_bIsOpen = (rcOpen == osl::File::E_None); + m_bToBeCreated = !m_bIsOpen; } - catch (DbException & exc) { - throw_rtexc( exc.get_errno(), exc.what() ); + if( !m_bIsOpen) + return; + + // write header magic + const osl::FileBase::RC nRes = m_MapFile.setPos( osl_Pos_Absolut, 0); + (void)nRes; + sal_uInt64 nBytesWritten = 0; + m_MapFile.write( PmapMagic, sizeof(PmapMagic), nBytesWritten); + + // write key value pairs + t_string2string_map::const_iterator it = m_entries.begin(); + for(; it != m_entries.end(); ++it) { + // write line for key + const OString aKeyString = encodeString( (*it).first); + const sal_Int32 nKeyLen = aKeyString.getLength(); + m_MapFile.write( aKeyString.getStr(), nKeyLen, nBytesWritten); + OSL_ASSERT( nKeyLen == (sal_Int32)nBytesWritten); + m_MapFile.write( "\n", 1, nBytesWritten); + // write line for value + const OString& rValString = encodeString( (*it).second); + const sal_Int32 nValLen = rValString.getLength(); + m_MapFile.write( rValString.getStr(), nValLen, nBytesWritten); + OSL_ASSERT( nValLen == (sal_Int32)nBytesWritten); + m_MapFile.write( "\n", 1, nBytesWritten); } + + // write a file delimiter (an empty key-string) + m_MapFile.write( "\n", 1, nBytesWritten); + // truncate file here + sal_uInt64 nNewFileSize; + if( m_MapFile.getPos( nNewFileSize) == osl::File::E_None) + m_MapFile.setSize( nNewFileSize); + // flush to disk + m_MapFile.sync(); + // the in-memory map now matches to the file on disk + m_bIsDirty = false; +} + +bool PersistentMap::has( OString const & key ) const +{ + return get( NULL, key ); +} + +bool PersistentMap::get( OString * value, OString const & key ) const +{ + t_string2string_map::const_iterator it = m_entries.find( key); + if( it == m_entries.end()) + return false; + if( value) + *value = it->second; + return true; +} + +void PersistentMap::add( OString const & key, OString const & value ) +{ + if( m_bReadOnly) + return; + typedef std::pair<t_string2string_map::iterator,bool> InsertRC; + InsertRC r = m_entries.insert( t_string2string_map::value_type(key,value)); + m_bIsDirty = r.second; } //______________________________________________________________________________ +void PersistentMap::put( OString const & key, OString const & value ) +{ + add( key, value); + // HACK: flush now as the extension manager does not seem + // to properly destruct this object in some situations + if(m_bIsDirty) + flush(); +} + bool PersistentMap::erase( OString const & key, bool flush_immediately ) { - try { - Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); - int err = m_db.del( &dbKey, 0 ); - if (err == 0) { - if (flush_immediately) { - err = m_db.sync(0); - if (err != 0) - throw_rtexc(err); - } - return true; - } - if (err == DB_NOTFOUND) - return false; - throw_rtexc(err); - } - catch (DbException & exc) { - throw_rtexc( exc.get_errno(), exc.what() ); - } - return false; // avoiding warning + if( m_bReadOnly) + return false; + size_t nCount = m_entries.erase( key); + if( !nCount) + return false; + m_bIsDirty = true; + if( flush_immediately) + flush(); + return true; } -//______________________________________________________________________________ t_string2string_map PersistentMap::getEntries() const { - try { - Dbc * pcurs = 0; - int err = m_db.cursor( 0, &pcurs, 0 ); - if (err != 0) - throw_rtexc(err); - - t_string2string_map ret; - for (;;) { - Dbt dbKey, dbData; - err = pcurs->get( &dbKey, &dbData, DB_NEXT ); - if (err == DB_NOTFOUND) + // TODO: return by const reference instead? + return m_entries; +} + +#ifndef DISABLE_BDB2PMAP +bool PersistentMap::importFromBDB() +{ + if( m_bReadOnly) + return false; + + // get the name of its BDB counterpart + rtl::OUString aDBName = m_MapFileName; + if( !aDBName.endsWithAsciiL( ".pmap", 5)) + return false; + aDBName = aDBName.replaceAt( aDBName.getLength()-5, 5, OUSTR(".db")); + + // open the corresponding BDB file for reading + osl::File aDBFile( aDBName); + osl::File::RC rc = aDBFile.open( osl_File_OpenFlag_Read); + if( rc != osl::File::E_None) + return false; + sal_uInt64 nFileSize = 0; + if( aDBFile.getSize( nFileSize) != osl::File::E_None) + return false; + + // read the BDB file + std::vector<sal_uInt8> aRawBDB( nFileSize); + for( sal_uInt64 nOfs = 0; nOfs < nFileSize;) { + sal_uInt64 nBytesRead = 0; + rc = aDBFile.read( (void*)&aRawBDB[nOfs], nFileSize - nOfs, nBytesRead); + if( (rc != osl::File::E_None) || !nBytesRead) + return false; + nOfs += nBytesRead; + } + + // check BDB file header for non_encrypted Hash format v4..9 + if( nFileSize < 0x0100) + return false; + if( aRawBDB[24] != 0) // only not-encrypted migration + return false; + if( aRawBDB[25] != 8) // we expect a P_HASHMETA page + return false; + const bool bLE = (aRawBDB[12]==0x61 && aRawBDB[13]==0x15 && aRawBDB[14]==0x06); + const bool bBE = (aRawBDB[15]==0x61 && aRawBDB[14]==0x15 && aRawBDB[13]==0x06); + if( bBE == bLE) + return false; + if( (aRawBDB[16] < 4) || (9 < aRawBDB[16])) // version + return false; + const sal_uInt64 nPgSize = bLE + ? (aRawBDB[20] + (aRawBDB[21]<<8) + (aRawBDB[22]<<16) + (aRawBDB[23]<<24)) + : (aRawBDB[23] + (aRawBDB[22]<<8) + (aRawBDB[21]<<16) + (aRawBDB[20]<<24)); + const int nPgCount = nFileSize / nPgSize; + if( nPgCount * nPgSize != nFileSize) + return false; + + // find PackageManager's new_style entries + // using a simple heuristic for BDB_Hash pages + int nEntryCount = 0; + for( int nPgNo = 1; nPgNo < nPgCount; ++nPgNo) { + // parse the next _db_page + const sal_uInt8* const pPage = &aRawBDB[ nPgNo * nPgSize]; + const sal_uInt8* const pEnd = pPage + nPgSize; + const int nHfOffset = bLE ? (pPage[22] + (pPage[23]<<8)) : (pPage[23] + (pPage[22]<<8)); + if( nHfOffset <= 0) + continue; + const sal_uInt8* pCur = pPage + nHfOffset; + // iterate through the entries + for(; pCur < pEnd; ++pCur) { + if( pCur[0] != 0x01) + continue; + // get the value-candidate + const sal_uInt8* pVal = pCur + 1; + while( ++pCur < pEnd) + if( (*pCur < ' ') || ((*pCur > 0x7F) && (*pCur != 0xFF))) + break; + if( pCur >= pEnd) break; - if (err != 0) - throw_rtexc(err); + if( (pCur[0] != 0x01) || (pCur[1] != 0xFF)) + continue; + const OString aVal( (sal_Char*)pVal, pCur - pVal); + // get the key-candidate + const sal_uInt8* pKey = pCur + 1; + while( ++pCur < pEnd) + if( (*pCur < ' ') || ((*pCur > 0x7F) && (*pCur != 0xFF))) + break; + if( (pCur < pEnd) && (*pCur > 0x01)) + continue; + const OString aKey( (sal_Char*)pKey, pCur - pKey); + --pCur; // prepare for next round by rewinding to end of key-string -#if OSL_DEBUG_LEVEL > 0 - ::std::pair<t_string2string_map::iterator, bool> insertion = -#endif - ret.insert( - t_string2string_map::value_type( - OString( static_cast<sal_Char const*>(dbKey.get_data()), dbKey.get_size() ), - OString( static_cast<sal_Char const*>(dbData.get_data()), dbData.get_size() ) - ) ); - OSL_ASSERT( insertion.second ); + // add the key/value pair + add( aKey, aVal); + ++nEntryCount; } - err = pcurs->close(); - if (err != 0) - throw_rtexc(err); - return ret; - } - catch (DbException & exc) { - throw_rtexc( exc.get_errno(), exc.what() ); } - return t_string2string_map(); // avoiding warning -} -#ifdef _MSC_VER -#pragma warning( pop ) -#endif + return (nEntryCount > 0); +} +#endif // DISABLE_BDB2PMAP } |