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_desktop.hxx" 26 27 #include "dp_misc.h" 28 #include "dp_ucb.h" 29 #include "dp_persmap.h" 30 #include "rtl/strbuf.hxx" 31 #include "rtl/ustrbuf.hxx" 32 #include "osl/file.hxx" 33 #include "osl/thread.h" 34 35 36 using namespace ::com::sun::star; 37 using namespace ::com::sun::star::uno; 38 using namespace ::rtl; 39 using ::osl::File; 40 41 namespace dp_misc 42 { 43 44 //______________________________________________________________________________ 45 void PersistentMap::throw_rtexc( int err, char const * pmsg ) const 46 { 47 OUStringBuffer buf; 48 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[") ); 49 buf.append( m_sysPath ); 50 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] Berkeley Db error (") ); 51 buf.append( static_cast<sal_Int32>(err) ); 52 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("): ") ); 53 if (pmsg == 0) 54 pmsg = DbEnv::strerror(err); 55 const OString msg(pmsg); 56 buf.append( OUString( msg.getStr(), msg.getLength(), 57 osl_getThreadTextEncoding() ) ); 58 const OUString msg_(buf.makeStringAndClear()); 59 OSL_ENSURE( 0, rtl::OUStringToOString( 60 msg_, RTL_TEXTENCODING_UTF8 ).getStr() ); 61 throw RuntimeException( msg_, Reference<XInterface>() ); 62 } 63 64 //______________________________________________________________________________ 65 PersistentMap::~PersistentMap() 66 { 67 try { 68 m_db.close(0); 69 } 70 catch (DbException & exc) { 71 (void) exc; // avoid warnings 72 OSL_ENSURE( 0, DbEnv::strerror( exc.get_errno() ) ); 73 } 74 } 75 76 //______________________________________________________________________________ 77 PersistentMap::PersistentMap( OUString const & url_, bool readOnly ) 78 : m_db( 0, 0 ) 79 { 80 try { 81 OUString url( expandUnoRcUrl(url_) ); 82 if ( File::getSystemPathFromFileURL( url, m_sysPath ) != File::E_None ) 83 { 84 OSL_ASSERT( false ); 85 } 86 OString cstr_sysPath( 87 OUStringToOString( m_sysPath, RTL_TEXTENCODING_UTF8 ) ); 88 char const * pcstr_sysPath = cstr_sysPath.getStr(); 89 90 u_int32_t flags = DB_CREATE; 91 if (readOnly) { 92 flags = DB_RDONLY; 93 if (! create_ucb_content( 94 0, url, 95 Reference<com::sun::star::ucb::XCommandEnvironment>(), 96 false /* no throw */ )) { 97 // ignore non-existent file in read-only mode: simulate empty db 98 pcstr_sysPath = 0; 99 flags = DB_CREATE; 100 } 101 } 102 103 int err = m_db.open( 104 // xxx todo: DB_THREAD, DB_DBT_MALLOC currently not used 105 0, pcstr_sysPath, 0, DB_HASH, flags/* | DB_THREAD*/, 0664 /* fs mode */ ); 106 if (err != 0) 107 throw_rtexc(err); 108 } 109 catch (DbException & exc) { 110 throw_rtexc( exc.get_errno(), exc.what() ); 111 } 112 } 113 114 //______________________________________________________________________________ 115 PersistentMap::PersistentMap() 116 : m_db( 0, 0 ) 117 { 118 try { 119 // xxx todo: DB_THREAD, DB_DBT_MALLOC currently not used 120 int err = m_db.open( 0, 0, 0, DB_HASH, DB_CREATE/* | DB_THREAD*/, 0 ); 121 if (err != 0) 122 throw_rtexc(err); 123 } 124 catch (DbException & exc) { 125 throw_rtexc( exc.get_errno(), exc.what() ); 126 } 127 } 128 129 //______________________________________________________________________________ 130 bool PersistentMap::has( OString const & key ) const 131 { 132 return get( 0, key ); 133 } 134 135 //______________________________________________________________________________ 136 bool PersistentMap::get( OString * value, OString const & key ) const 137 { 138 try { 139 Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); 140 Dbt dbData; 141 int err = m_db.get( 0, &dbKey, &dbData, 0 ); 142 if (err == DB_NOTFOUND) 143 return false; 144 if (err == 0) { 145 if (value != 0) { 146 *value = OString( 147 static_cast< sal_Char const * >(dbData.get_data()), 148 dbData.get_size() ); 149 } 150 return true; 151 } 152 throw_rtexc(err); 153 } 154 catch (DbException & exc) { 155 throw_rtexc( exc.get_errno(), exc.what() ); 156 } 157 return false; // avoiding warning 158 } 159 160 //______________________________________________________________________________ 161 void PersistentMap::put( OString const & key, OString const & value ) 162 { 163 try { 164 Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); 165 Dbt dbData( const_cast< sal_Char * >( 166 value.getStr()), value.getLength() ); 167 int err = m_db.put( 0, &dbKey, &dbData, 0 ); 168 if (err == 0) { 169 #if OSL_DEBUG_LEVEL > 0 170 OString v; 171 OSL_ASSERT( get( &v, key ) ); 172 OSL_ASSERT( v.equals( value ) ); 173 #endif 174 err = m_db.sync(0); 175 } 176 if (err != 0) 177 throw_rtexc(err); 178 } 179 catch (DbException & exc) { 180 throw_rtexc( exc.get_errno(), exc.what() ); 181 } 182 } 183 184 //______________________________________________________________________________ 185 bool PersistentMap::erase( OString const & key, bool flush_immediately ) 186 { 187 try { 188 Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); 189 int err = m_db.del( &dbKey, 0 ); 190 if (err == 0) { 191 if (flush_immediately) { 192 err = m_db.sync(0); 193 if (err != 0) 194 throw_rtexc(err); 195 } 196 return true; 197 } 198 if (err == DB_NOTFOUND) 199 return false; 200 throw_rtexc(err); 201 } 202 catch (DbException & exc) { 203 throw_rtexc( exc.get_errno(), exc.what() ); 204 } 205 return false; // avoiding warning 206 } 207 208 //______________________________________________________________________________ 209 t_string2string_map PersistentMap::getEntries() const 210 { 211 try { 212 Dbc * pcurs = 0; 213 int err = m_db.cursor( 0, &pcurs, 0 ); 214 if (err != 0) 215 throw_rtexc(err); 216 217 t_string2string_map ret; 218 for (;;) { 219 Dbt dbKey, dbData; 220 err = pcurs->get( &dbKey, &dbData, DB_NEXT ); 221 if (err == DB_NOTFOUND) 222 break; 223 if (err != 0) 224 throw_rtexc(err); 225 226 ::std::pair<t_string2string_map::iterator, bool > insertion( 227 ret.insert( t_string2string_map::value_type( 228 t_string2string_map::value_type( 229 OString( static_cast< sal_Char const * >( 230 dbKey.get_data()), 231 dbKey.get_size() ), 232 OString( static_cast< sal_Char const * >( 233 dbData.get_data()), 234 dbData.get_size() ) ) ) ) ); 235 OSL_ASSERT( insertion.second ); 236 } 237 err = pcurs->close(); 238 if (err != 0) 239 throw_rtexc(err); 240 return ret; 241 } 242 catch (DbException & exc) { 243 throw_rtexc( exc.get_errno(), exc.what() ); 244 } 245 return t_string2string_map(); // avoiding warning 246 } 247 248 } 249 250