/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * 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/. * * This file incorporates work covered by the following license notice: * * 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 "db.hxx" #include #include #include #include using namespace com::sun::star::uno; using namespace com::sun::star::io; namespace { //TODO: Replace with C++17 std::from_chars once available: std::pair readInt32(char const * begin, char const * end) { sal_Int32 n = 0; for (; begin != end; ++begin) { auto const w = INetMIME::getHexWeight(static_cast(*begin)); if (w == -1) { break; } n = 16 * n + w; } return {n, begin}; } } namespace helpdatafileproxy { void HDFData::copyToBuffer( const char* pSrcData, int nSize ) { m_nSize = nSize; m_pBuffer.reset( new char[m_nSize+1] ); memcpy( m_pBuffer.get(), pSrcData, m_nSize ); m_pBuffer[m_nSize] = 0; } // Hdf bool Hdf::implReadLenAndData( const char* pData, char const * end, int& riPos, HDFData& rValue ) { bool bSuccess = false; // Read key len const char* pStartPtr = pData + riPos; auto [nKeyLen, pEndPtr] = readInt32(pStartPtr, end); if( pEndPtr == pStartPtr ) return bSuccess; riPos += (pEndPtr - pStartPtr) + 1; const char* pKeySrc = pData + riPos; rValue.copyToBuffer( pKeySrc, nKeyLen ); riPos += nKeyLen + 1; bSuccess = true; return bSuccess; } void Hdf::createHashMap( bool bOptimizeForPerformance ) { releaseHashMap(); if( bOptimizeForPerformance ) { if( m_pStringToDataMap != nullptr ) return; m_pStringToDataMap.reset(new StringToDataMap); } else { if( m_pStringToValPosMap != nullptr ) return; m_pStringToValPosMap.reset(new StringToValPosMap); } Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileURL ); if( !xIn.is() ) return; Sequence< sal_Int8 > aData; sal_Int32 nSize = m_xSFA->getSize( m_aFileURL ); sal_Int32 nRead = xIn->readBytes( aData, nSize ); const char* pData = reinterpret_cast(aData.getConstArray()); auto const end = pData + nRead; int iPos = 0; while( iPos < nRead ) { HDFData aDBKey; if( !implReadLenAndData( pData, end, iPos, aDBKey ) ) break; OString aOKeyStr = aDBKey.getData(); // Read val len const char* pStartPtr = pData + iPos; auto [nValLen, pEndPtr] = readInt32(pStartPtr, end); if( pEndPtr == pStartPtr ) break; iPos += (pEndPtr - pStartPtr) + 1; if( bOptimizeForPerformance ) { const char* pValSrc = pData + iPos; OString aValStr( pValSrc, nValLen ); (*m_pStringToDataMap)[aOKeyStr] = aValStr; } else { // store value start position (*m_pStringToValPosMap)[aOKeyStr] = std::pair( iPos, nValLen ); } iPos += nValLen + 1; } xIn->closeInput(); } void Hdf::releaseHashMap() { m_pStringToDataMap.reset(); m_pStringToValPosMap.reset(); } Hdf::~Hdf() { } bool Hdf::getValueForKey( const OString& rKey, HDFData& rValue ) { bool bSuccess = false; if( !m_xSFA.is() ) return bSuccess; try { if( m_pStringToDataMap == nullptr && m_pStringToValPosMap == nullptr ) { createHashMap( false/*bOptimizeForPerformance*/ ); } if( m_pStringToValPosMap != nullptr ) { StringToValPosMap::const_iterator it = m_pStringToValPosMap->find( rKey ); if( it != m_pStringToValPosMap->end() ) { const std::pair& rValPair = it->second; int iValuePos = rValPair.first; int nValueLen = rValPair.second; Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileURL ); if( xIn.is() ) { Reference< XSeekable > xXSeekable( xIn, UNO_QUERY ); if( xXSeekable.is() ) { xXSeekable->seek( iValuePos ); Sequence< sal_Int8 > aData; sal_Int32 nRead = xIn->readBytes( aData, nValueLen ); if( nRead == nValueLen ) { const char* pData = reinterpret_cast(aData.getConstArray()); rValue.copyToBuffer( pData, nValueLen ); bSuccess = true; } } xIn->closeInput(); } } } else if( m_pStringToDataMap != nullptr ) { StringToDataMap::const_iterator it = m_pStringToDataMap->find( rKey ); if( it != m_pStringToDataMap->end() ) { const OString& rValueStr = it->second; int nValueLen = rValueStr.getLength(); const char* pData = rValueStr.getStr(); rValue.copyToBuffer( pData, nValueLen ); bSuccess = true; } } } catch( Exception & ) { bSuccess = false; } return bSuccess; } bool Hdf::startIteration() { bool bSuccess = false; sal_Int32 nSize = m_xSFA->getSize( m_aFileURL ); Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileURL ); if( xIn.is() ) { m_nItRead = xIn->readBytes( m_aItData, nSize ); if( m_nItRead == nSize ) { bSuccess = true; m_iItPos = 0; } else { stopIteration(); } } return bSuccess; } bool Hdf::getNextKeyAndValue( HDFData& rKey, HDFData& rValue ) { bool bSuccess = false; if( m_iItPos < m_nItRead ) { auto const p = reinterpret_cast(m_aItData.getConstArray()); if( implReadLenAndData( p, p + m_aItData.size(), m_iItPos, rKey ) ) { if( implReadLenAndData( p, p + m_aItData.size(), m_iItPos, rValue ) ) bSuccess = true; } } return bSuccess; } void Hdf::stopIteration() { m_aItData = Sequence(); m_nItRead = -1; m_iItPos = -1; } } // end of namespace helpdatafileproxy /* vim:set shiftwidth=4 softtabstop=4 expandtab: */