/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: binaryreader.cxx,v $ * $Revision: 1.9 $ * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_configmgr.hxx" #include "binaryreader.hxx" #include "binarytype.hxx" #include "valuenode.hxx" #include "filehelper.hxx" #include "oslstream.hxx" #include #include #include #include #include #include #include #include #include #include #ifndef INCLUDED_ALGORITHM #include #define INCLUDED_ALGORITHM #endif #include "tracer.hxx" #define ASCII(x) rtl::OUString::createFromAscii(x) namespace configmgr { // ----------------------------------------------------------------------------- namespace backend { using ::rtl::OUString; using namespace ::osl; namespace uno = com::sun::star::uno; namespace io = com::sun::star::io; // -------------------------------------------------------------------------- inline rtl::OUString ErrorToMessage_Impl (osl::FileBase::RC eError) { return FileHelper::createOSLErrorString (eError); } // -------------------------------------------------------------------------- class BinaryReader_Impl : public cppu::WeakImplHelper1< com::sun::star::io::XDataInputStream > { public: /** Construction. */ explicit BinaryReader_Impl (rtl::OUString const & rFileUrl) SAL_THROW( (io::IOException, uno::RuntimeException) ); /** XInputStream. */ virtual sal_Int32 SAL_CALL readBytes ( uno::Sequence & rData, sal_Int32 nBytesToRead) throw ( io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException); virtual sal_Int32 SAL_CALL readSomeBytes ( uno::Sequence & rData, sal_Int32 nBytesToRead) throw ( io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException); virtual void SAL_CALL skipBytes (sal_Int32 nBytesToSkip) throw ( io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException); virtual sal_Int32 SAL_CALL available() throw ( io::NotConnectedException, io::IOException, uno::RuntimeException); virtual void SAL_CALL closeInput() throw ( io::NotConnectedException, io::IOException, uno::RuntimeException); /** XDataInputStream. */ virtual sal_Int8 SAL_CALL readBoolean() throw ( io::IOException, uno::RuntimeException); virtual sal_Int8 SAL_CALL readByte() throw ( io::IOException, uno::RuntimeException); virtual sal_Unicode SAL_CALL readChar() throw ( io::IOException, uno::RuntimeException); virtual sal_Int16 SAL_CALL readShort() throw ( io::IOException, uno::RuntimeException); virtual sal_Int32 SAL_CALL readLong() throw ( io::IOException, uno::RuntimeException); virtual sal_Int64 SAL_CALL readHyper() throw ( io::IOException, uno::RuntimeException); virtual float SAL_CALL readFloat() throw ( io::IOException, uno::RuntimeException); virtual double SAL_CALL readDouble() throw ( io::IOException, uno::RuntimeException); virtual rtl::OUString SAL_CALL readUTF() throw ( io::IOException, uno::RuntimeException); protected: /** Destruction. */ virtual ~BinaryReader_Impl(); private: sal_uInt32 checkAvail(); // may throw NotConnectedException sal_uInt32 getMaxAvail(sal_Int32 nRequest); // may throw NotConnectedException, BufferSizeExceededException sal_uInt8 const * readBuffer(sal_uInt32 nRequired); // may throw NotConnectedException, UnexpectedEOFException private: /** Representation. */ sal_uInt8 * m_pBuffer; sal_uInt32 m_nLength; sal_uInt32 m_nOffset; /** Not implemented. */ BinaryReader_Impl (const BinaryReader_Impl&); BinaryReader_Impl& operator= (const BinaryReader_Impl&); }; // -------------------------------------------------------------------------- static inline void checkIOError(osl::File::RC errcode) { if (errcode != osl::FileBase::E_None) { throw io::IOException (ErrorToMessage_Impl (errcode), NULL); } } static void raiseBufferError() { OUString sMsg = OUString::createFromAscii("Cannot allocate Buffer: Too large"); throw io:: BufferSizeExceededException(sMsg, NULL); } // ------------------------------------------------------------------------- BinaryReader_Impl::BinaryReader_Impl (rtl::OUString const & rFileUrl) SAL_THROW( (io::IOException, uno::RuntimeException) ) : m_pBuffer (0) , m_nLength (0) , m_nOffset (0) { osl::File aFile (rFileUrl); checkIOError( aFile.open (OpenFlag_Read) ); sal_uInt64 nLength = 0; checkIOError( aFile.getSize (nLength) ); if (nLength > 0xffffffff) raiseBufferError(); m_nLength = sal_uInt32(nLength); sal_uInt8 *pBuffer = static_cast(rtl_allocateMemory (m_nLength)); if (!pBuffer) raiseBufferError(); sal_uInt64 nRead = 0; osl::File::RC result = aFile.read (pBuffer, nLength, nRead); if (result != osl::FileBase::E_None) { rtl_freeMemory (pBuffer); checkIOError( result ); } if (nRead != nLength) { rtl_freeMemory (pBuffer); OUString sMsg = OUString::createFromAscii("BinaryCache - Could not read entire size of file: "); throw io::UnexpectedEOFException(sMsg.concat(rFileUrl),NULL); } m_pBuffer = pBuffer; } // -------------------------------------------------------------------------- BinaryReader_Impl::~BinaryReader_Impl() { if (m_pBuffer) rtl_freeMemory (m_pBuffer); } // -------------------------------------------------------------------------- // XInputStream implementation. // -------------------------------------------------------------------------- sal_uInt32 BinaryReader_Impl::checkAvail () { if (!m_pBuffer) { OUString sMsg = OUString::createFromAscii("BinaryCache - Stream is not open. No data available for reading."); throw io::NotConnectedException(sMsg,*this); } OSL_ASSERT(m_nLength >= m_nOffset); return m_nLength - m_nOffset; } // -------------------------------------------------------------------------- sal_uInt32 BinaryReader_Impl::getMaxAvail (sal_Int32 nRequest) { if (nRequest < 0) { OUString sMsg = OUString::createFromAscii("BinaryCache - Invalid read request - negative byte count requested."); throw io::BufferSizeExceededException(sMsg,*this); } sal_uInt32 const uRequest = sal_uInt32(nRequest); sal_uInt32 const uAvail = checkAvail (); return std::min(uRequest,uAvail); } // -------------------------------------------------------------------------- sal_uInt8 const * BinaryReader_Impl::readBuffer (sal_uInt32 nRequest) { sal_uInt32 const nAvail = checkAvail (); if (nRequest > nAvail) { OUString sMsg = OUString::createFromAscii("BinaryCache - Invalid file format - read past end-of-file."); throw io::UnexpectedEOFException(sMsg,*this); } sal_uInt8 const * pData = m_pBuffer + m_nOffset; m_nOffset += nRequest; return pData; } // -------------------------------------------------------------------------- sal_Int32 SAL_CALL BinaryReader_Impl::readBytes ( uno::Sequence & rData, sal_Int32 nBytesToRead) throw ( io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) { sal_uInt32 nRead = getMaxAvail(nBytesToRead); if (nRead > 0) { rData.realloc (nRead); memcpy (rData.getArray(), readBuffer(nRead), nRead); } return sal_Int32(nRead); } // -------------------------------------------------------------------------- sal_Int32 SAL_CALL BinaryReader_Impl::readSomeBytes ( uno::Sequence & rData, sal_Int32 nBytesToRead) throw ( io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) { return readBytes(rData,nBytesToRead); } // -------------------------------------------------------------------------- void SAL_CALL BinaryReader_Impl::skipBytes (sal_Int32 nBytesToSkip) throw ( io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) { (void) readBuffer(sal_uInt32(nBytesToSkip)); } // -------------------------------------------------------------------------- sal_Int32 SAL_CALL BinaryReader_Impl::available() throw ( io::NotConnectedException, io::IOException, uno::RuntimeException) { const sal_uInt32 nMaxAvail = 0x7FFFFFFF; const sal_uInt32 nAvail = checkAvail(); return sal_Int32(std::min(nAvail,nMaxAvail)); } // -------------------------------------------------------------------------- void SAL_CALL BinaryReader_Impl::closeInput() throw ( io::NotConnectedException, io::IOException, uno::RuntimeException) { OSL_ENSURE(m_pBuffer,"BinaryCache - Closing stream that is already closed"); if (m_pBuffer) { rtl_freeMemory (m_pBuffer); m_pBuffer = 0; } } // -------------------------------------------------------------------------- // XDataInputStream implementation. // -------------------------------------------------------------------------- sal_Int8 SAL_CALL BinaryReader_Impl::readBoolean() throw (io::IOException, uno::RuntimeException) { return this->readByte(); } // -------------------------------------------------------------------------- sal_Int8 SAL_CALL BinaryReader_Impl::readByte() throw (io::IOException, uno::RuntimeException) { sal_Int8 result = sal_Int8(*readBuffer(1)); return result; } // -------------------------------------------------------------------------- sal_Unicode SAL_CALL BinaryReader_Impl::readChar() throw (io::IOException, uno::RuntimeException) { sal_Unicode result; sal_uInt8 const * pData = readBuffer(sizeof result); result = sal_Unicode( (sal_uInt16(pData[0]) << 8) | (sal_uInt16(pData[1]) << 0) ); return result; } // -------------------------------------------------------------------------- sal_Int16 SAL_CALL BinaryReader_Impl::readShort() throw (io::IOException, uno::RuntimeException) { sal_Int16 result; sal_uInt8 const * pData = readBuffer(sizeof result); result = sal_Int16( (sal_uInt16(pData[0]) << 8) | (sal_uInt16(pData[1]) << 0) ); return result; } // -------------------------------------------------------------------------- sal_Int32 SAL_CALL BinaryReader_Impl::readLong() throw (io::IOException, uno::RuntimeException) { sal_Int32 result; sal_uInt8 const * pData = readBuffer(sizeof result); result = sal_Int32( (sal_uInt32(pData[0]) << 24) | (sal_uInt32(pData[1]) << 16) | (sal_uInt32(pData[2]) << 8) | (sal_uInt32(pData[3]) << 0) ); return result; } // -------------------------------------------------------------------------- sal_Int64 SAL_CALL BinaryReader_Impl::readHyper() throw (io::IOException, uno::RuntimeException) { sal_Int64 result; sal_uInt8 const * pData = readBuffer(sizeof result); result = sal_Int64( (sal_uInt64(pData[0]) << 56) | (sal_uInt64(pData[1]) << 48) | (sal_uInt64(pData[2]) << 40) | (sal_uInt64(pData[3]) << 32) | (sal_uInt64(pData[4]) << 24) | (sal_uInt64(pData[5]) << 16) | (sal_uInt64(pData[6]) << 8) | (sal_uInt64(pData[7]) << 0) ); return result; } // -------------------------------------------------------------------------- float SAL_CALL BinaryReader_Impl::readFloat() throw (io::IOException, uno::RuntimeException) { union { float f; sal_uInt32 n; } result; sal_uInt8 const * pData = readBuffer(sizeof result.n); result.n = sal_uInt32( (sal_uInt32(pData[0]) << 24) | (sal_uInt32(pData[1]) << 16) | (sal_uInt32(pData[2]) << 8) | (sal_uInt32(pData[3]) << 0) ); return result.f; } // -------------------------------------------------------------------------- double SAL_CALL BinaryReader_Impl::readDouble() throw (io::IOException, uno::RuntimeException) { union { double d; sal_uInt64 n; } result; sal_uInt8 const * pData = readBuffer(sizeof result.n); result.n = sal_uInt64( (sal_uInt64(pData[0]) << 56) | (sal_uInt64(pData[1]) << 48) | (sal_uInt64(pData[2]) << 40) | (sal_uInt64(pData[3]) << 32) | (sal_uInt64(pData[4]) << 24) | (sal_uInt64(pData[5]) << 16) | (sal_uInt64(pData[6]) << 8) | (sal_uInt64(pData[7]) << 0) ); return result.d; } // -------------------------------------------------------------------------- rtl::OUString SAL_CALL BinaryReader_Impl::readUTF() throw (io::IOException, uno::RuntimeException) { sal_uInt32 nLength; sal_uInt8 const * const pData = readBuffer(sizeof nLength); nLength = sal_uInt32( (sal_uInt32(pData[0]) << 24) | (sal_uInt32(pData[1]) << 16) | (sal_uInt32(pData[2]) << 8) | (sal_uInt32(pData[3]) << 0) ); using binary::STR_ASCII_MASK; bool bIsAscii = (nLength & STR_ASCII_MASK) == STR_ASCII_MASK; nLength &=~STR_ASCII_MASK; rtl::OUString result; if (nLength != 0) { sal_Char const * const pUTF = reinterpret_cast(readBuffer(nLength)); sal_Int32 const nStrLength = sal_Int32(nLength); OSL_ASSERT(nStrLength >= 0); rtl_TextEncoding const enc = bIsAscii ? RTL_TEXTENCODING_ASCII_US : RTL_TEXTENCODING_UTF8; rtl_uString_internConvert(&result.pData, pUTF, nStrLength, enc, OSTRING_TO_OUSTRING_CVTFLAGS, NULL); } return result; } // -------------------------------------------------------------------------- // BinaryReader implementation. // -------------------------------------------------------------------------- bool BinaryReader::open() SAL_THROW( (io::IOException, uno::RuntimeException) ) { OSL_PRECOND(!m_xDataInputStream.is(),"Binary Reader: already open"); if (m_xDataInputStream.is()) return false; if (m_sFileURL.getLength() == 0) return false; if (!FileHelper::fileExists(m_sFileURL)) return false; m_xDataInputStream.set(new BinaryReader_Impl (m_sFileURL)); return true; } // -------------------------------------------------------------------------- void BinaryReader::reopen() SAL_THROW( (io::IOException, uno::RuntimeException) ) { OSL_PRECOND(m_xDataInputStream.is(),"Binary Reader - cannot reopen: not open"); if (m_xDataInputStream.is()) { m_xDataInputStream->closeInput(); m_xDataInputStream.set(new BinaryReader_Impl (m_sFileURL)); } } // -------------------------------------------------------------------------- void BinaryReader::close() SAL_THROW( (io::IOException, uno::RuntimeException) ) { if (m_xDataInputStream.is()) m_xDataInputStream->closeInput(); } // -------------------------------------------------------------------------- inline uno::Reference BinaryReader::getDataInputStream() { OSL_ENSURE(m_xDataInputStream.is(),"Binary Cache: Reader was not opened - no input stream"); #if 0 if (!m_xDataInputStream.is()) throw io::NotConnectedException(); #endif return m_xDataInputStream; } // -------------------------------------------------------------------------- void BinaryReader::read(sal_Bool &_bValue) SAL_THROW( (io::IOException, uno::RuntimeException) ) { _bValue = getDataInputStream()->readBoolean(); } // -------------------------------------------------------------------------- void BinaryReader::read(sal_Int8 &_nValue) SAL_THROW( (io::IOException, uno::RuntimeException) ) { _nValue = getDataInputStream()->readByte(); } // -------------------------------------------------------------------------- void BinaryReader::read(sal_Int16 &_nValue) SAL_THROW( (io::IOException, uno::RuntimeException) ) { _nValue = getDataInputStream()->readShort(); } // -------------------------------------------------------------------------- void BinaryReader::read(sal_Int32 &_nValue) SAL_THROW( (io::IOException, uno::RuntimeException) ) { _nValue = getDataInputStream()->readLong(); } // -------------------------------------------------------------------------- void BinaryReader::read(sal_Int64 &_nValue) SAL_THROW( (io::IOException, uno::RuntimeException) ) { _nValue = getDataInputStream()->readHyper(); } // -------------------------------------------------------------------------- void BinaryReader::read(double &_nValue) SAL_THROW( (io::IOException, uno::RuntimeException) ) { _nValue = getDataInputStream()->readDouble(); } // -------------------------------------------------------------------------- void BinaryReader::read(rtl::OUString& _aStr) SAL_THROW( (io::IOException, uno::RuntimeException) ) { _aStr = getDataInputStream()->readUTF(); } // ----------------------------------------------------------------------------- template void readSequence(BinaryReader& _rReader, uno::Sequence< Element > & aSequence) SAL_THROW( (io::IOException, uno::RuntimeException) ) { // PRE: the Sequence must exist sal_Int32 nLength; _rReader.read(nLength); aSequence.realloc(nLength); Element* const pElement = aSequence.getArray(); // fill the hole array for(sal_Int32 i=0; i(0)).getTypeClass() == (TYPE_CLASS), "Typeclass does not match element type" ); \ uno::Sequence< DATA_TYPE > aData; \ readSequence(_rReader, aData); \ _aValue <<= aData; \ } break bool readSequenceValue ( BinaryReader & _rReader, uno::Any & _aValue, uno::Type const & _aElementType) SAL_THROW( (io::IOException, uno::RuntimeException) ) { switch(_aElementType.getTypeClass()) { CASE_READ_SEQUENCE( uno::TypeClass_BOOLEAN, sal_Bool ); CASE_READ_SEQUENCE( uno::TypeClass_SHORT, sal_Int16 ); CASE_READ_SEQUENCE( uno::TypeClass_LONG, sal_Int32 ); CASE_READ_SEQUENCE( uno::TypeClass_HYPER, sal_Int64 ); CASE_READ_SEQUENCE( uno::TypeClass_DOUBLE, double ); CASE_READ_SEQUENCE( uno::TypeClass_STRING, rtl::OUString ); case uno::TypeClass_SEQUENCE: if (_aElementType == ::getCppuType(for_binary)) { Binary aData; readSequence(_rReader, aData); _aValue <<= aData; break; } // else fall through default: OSL_ENSURE(false, "Unexpected type for sequence elements"); return false; } return true; } #undef CASE_READ_SEQUENCE // -------------------------------------------------------------------------- } }