1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: binaryreader.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
34 #include "binaryreader.hxx"
35 #include "binarytype.hxx"
36 #include "valuenode.hxx"
37 #include "filehelper.hxx"
38 #include "oslstream.hxx"
41 #include <com/sun/star/uno/Type.hxx>
42 #include <com/sun/star/uno/Any.hxx>
43 #include <com/sun/star/io/IOException.hpp>
44 #include <com/sun/star/io/XOutputStream.hpp>
45 #include <com/sun/star/io/XActiveDataSource.hpp>
46 #include <com/sun/star/io/XDataInputStream.hpp>
47 #include <com/sun/star/io/XDataOutputStream.hpp>
48 #include <com/sun/star/io/BufferSizeExceededException.hpp>
49 #include <com/sun/star/io/UnexpectedEOFException.hpp>
51 #include <cppuhelper/implbase1.hxx>
52 #include <osl/file.hxx>
54 #ifndef INCLUDED_ALGORITHM
56 #define INCLUDED_ALGORITHM
60 #define ASCII(x) rtl::OUString::createFromAscii(x)
64 // -----------------------------------------------------------------------------
67 namespace uno
= com::sun::star::uno
;
68 namespace io
= com::sun::star::io
;
71 // --------------------------------------------------------------------------
73 inline rtl::OUString
ErrorToMessage_Impl (osl::FileBase::RC eError
)
75 return FileHelper::createOSLErrorString (eError
);
78 // --------------------------------------------------------------------------
80 class BinaryReader_Impl
:
81 public cppu::WeakImplHelper1
< com::sun::star::io::XDataInputStream
>
86 explicit BinaryReader_Impl (rtl::OUString
const & rFileUrl
)
87 SAL_THROW( (io::IOException
, uno::RuntimeException
) );
91 virtual sal_Int32 SAL_CALL
readBytes (
92 uno::Sequence
<sal_Int8
> & rData
, sal_Int32 nBytesToRead
)
94 io::NotConnectedException
,
95 io::BufferSizeExceededException
,
96 io::IOException
, uno::RuntimeException
);
98 virtual sal_Int32 SAL_CALL
readSomeBytes (
99 uno::Sequence
<sal_Int8
> & rData
, sal_Int32 nBytesToRead
)
101 io::NotConnectedException
,
102 io::BufferSizeExceededException
,
103 io::IOException
, uno::RuntimeException
);
105 virtual void SAL_CALL
skipBytes (sal_Int32 nBytesToSkip
)
107 io::NotConnectedException
,
108 io::BufferSizeExceededException
,
109 io::IOException
, uno::RuntimeException
);
111 virtual sal_Int32 SAL_CALL
available()
113 io::NotConnectedException
,
114 io::IOException
, uno::RuntimeException
);
116 virtual void SAL_CALL
closeInput()
118 io::NotConnectedException
,
119 io::IOException
, uno::RuntimeException
);
122 /** XDataInputStream.
124 virtual sal_Int8 SAL_CALL
readBoolean()
126 io::IOException
, uno::RuntimeException
);
128 virtual sal_Int8 SAL_CALL
readByte()
130 io::IOException
, uno::RuntimeException
);
132 virtual sal_Unicode SAL_CALL
readChar()
134 io::IOException
, uno::RuntimeException
);
136 virtual sal_Int16 SAL_CALL
readShort()
138 io::IOException
, uno::RuntimeException
);
140 virtual sal_Int32 SAL_CALL
readLong()
142 io::IOException
, uno::RuntimeException
);
144 virtual sal_Int64 SAL_CALL
readHyper()
146 io::IOException
, uno::RuntimeException
);
148 virtual float SAL_CALL
readFloat()
150 io::IOException
, uno::RuntimeException
);
152 virtual double SAL_CALL
readDouble()
154 io::IOException
, uno::RuntimeException
);
156 virtual rtl::OUString SAL_CALL
readUTF()
158 io::IOException
, uno::RuntimeException
);
163 virtual ~BinaryReader_Impl();
166 sal_uInt32
checkAvail(); // may throw NotConnectedException
167 sal_uInt32
getMaxAvail(sal_Int32 nRequest
); // may throw NotConnectedException, BufferSizeExceededException
168 sal_uInt8
const * readBuffer(sal_uInt32 nRequired
); // may throw NotConnectedException, UnexpectedEOFException
172 sal_uInt8
* m_pBuffer
;
173 sal_uInt32 m_nLength
;
174 sal_uInt32 m_nOffset
;
178 BinaryReader_Impl (const BinaryReader_Impl
&);
179 BinaryReader_Impl
& operator= (const BinaryReader_Impl
&);
182 // --------------------------------------------------------------------------
183 static inline void checkIOError(osl::File::RC errcode
)
185 if (errcode
!= osl::FileBase::E_None
)
187 throw io::IOException (ErrorToMessage_Impl (errcode
), NULL
);
190 static void raiseBufferError()
192 rtl::OUString sMsg
= rtl::OUString::createFromAscii("Cannot allocate Buffer: Too large");
193 throw io:: BufferSizeExceededException(sMsg
, NULL
);
195 // -------------------------------------------------------------------------
196 BinaryReader_Impl::BinaryReader_Impl (rtl::OUString
const & rFileUrl
)
197 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
202 osl::File
aFile (rFileUrl
);
204 checkIOError( aFile
.open (OpenFlag_Read
) );
205 sal_uInt64 nLength
= 0;
206 checkIOError( aFile
.getSize (nLength
) );
207 if (nLength
> 0xffffffff)
209 m_nLength
= sal_uInt32(nLength
);
211 sal_uInt8
*pBuffer
= static_cast<sal_uInt8
*>(rtl_allocateMemory (m_nLength
));
215 sal_uInt64 nRead
= 0;
216 osl::File::RC result
= aFile
.read (pBuffer
, nLength
, nRead
);
217 if (result
!= osl::FileBase::E_None
)
219 rtl_freeMemory (pBuffer
);
220 checkIOError( result
);
222 if (nRead
!= nLength
)
224 rtl_freeMemory (pBuffer
);
225 rtl::OUString sMsg
= rtl::OUString::createFromAscii("BinaryCache - Could not read entire size of file: ");
226 throw io::UnexpectedEOFException(sMsg
.concat(rFileUrl
),NULL
);
231 // --------------------------------------------------------------------------
233 BinaryReader_Impl::~BinaryReader_Impl()
235 if (m_pBuffer
) rtl_freeMemory (m_pBuffer
);
238 // --------------------------------------------------------------------------
239 // XInputStream implementation.
240 // --------------------------------------------------------------------------
241 sal_uInt32
BinaryReader_Impl::checkAvail ()
245 rtl::OUString sMsg
= rtl::OUString::createFromAscii("BinaryCache - Stream is not open. No data available for reading.");
246 throw io::NotConnectedException(sMsg
,*this);
248 OSL_ASSERT(m_nLength
>= m_nOffset
);
249 return m_nLength
- m_nOffset
;
251 // --------------------------------------------------------------------------
253 sal_uInt32
BinaryReader_Impl::getMaxAvail (sal_Int32 nRequest
)
257 rtl::OUString sMsg
= rtl::OUString::createFromAscii("BinaryCache - Invalid read request - negative byte count requested.");
258 throw io::BufferSizeExceededException(sMsg
,*this);
260 sal_uInt32
const uRequest
= sal_uInt32(nRequest
);
261 sal_uInt32
const uAvail
= checkAvail ();
262 return std::min(uRequest
,uAvail
);
264 // --------------------------------------------------------------------------
266 sal_uInt8
const * BinaryReader_Impl::readBuffer (sal_uInt32 nRequest
)
268 sal_uInt32
const nAvail
= checkAvail ();
269 if (nRequest
> nAvail
)
271 rtl::OUString sMsg
= rtl::OUString::createFromAscii("BinaryCache - Invalid file format - read past end-of-file.");
272 throw io::UnexpectedEOFException(sMsg
,*this);
274 sal_uInt8
const * pData
= m_pBuffer
+ m_nOffset
;
275 m_nOffset
+= nRequest
;
278 // --------------------------------------------------------------------------
280 sal_Int32 SAL_CALL
BinaryReader_Impl::readBytes (
281 uno::Sequence
<sal_Int8
> & rData
, sal_Int32 nBytesToRead
)
283 io::NotConnectedException
,
284 io::BufferSizeExceededException
,
285 io::IOException
, uno::RuntimeException
)
287 sal_uInt32 nRead
= getMaxAvail(nBytesToRead
);
290 rData
.realloc (nRead
);
291 memcpy (rData
.getArray(), readBuffer(nRead
), nRead
);
293 return sal_Int32(nRead
);
296 // --------------------------------------------------------------------------
298 sal_Int32 SAL_CALL
BinaryReader_Impl::readSomeBytes (
299 uno::Sequence
<sal_Int8
> & rData
, sal_Int32 nBytesToRead
)
301 io::NotConnectedException
,
302 io::BufferSizeExceededException
,
303 io::IOException
, uno::RuntimeException
)
305 return readBytes(rData
,nBytesToRead
);
308 // --------------------------------------------------------------------------
310 void SAL_CALL
BinaryReader_Impl::skipBytes (sal_Int32 nBytesToSkip
)
312 io::NotConnectedException
,
313 io::BufferSizeExceededException
,
314 io::IOException
, uno::RuntimeException
)
316 (void) readBuffer(sal_uInt32(nBytesToSkip
));
319 // --------------------------------------------------------------------------
321 sal_Int32 SAL_CALL
BinaryReader_Impl::available()
323 io::NotConnectedException
,
324 io::IOException
, uno::RuntimeException
)
326 const sal_uInt32 nMaxAvail
= 0x7FFFFFFF;
327 const sal_uInt32 nAvail
= checkAvail();
328 return sal_Int32(std::min(nAvail
,nMaxAvail
));
331 // --------------------------------------------------------------------------
333 void SAL_CALL
BinaryReader_Impl::closeInput()
335 io::NotConnectedException
,
336 io::IOException
, uno::RuntimeException
)
338 OSL_ENSURE(m_pBuffer
,"BinaryCache - Closing stream that is already closed");
341 rtl_freeMemory (m_pBuffer
);
346 // --------------------------------------------------------------------------
347 // XDataInputStream implementation.
348 // --------------------------------------------------------------------------
350 sal_Int8 SAL_CALL
BinaryReader_Impl::readBoolean()
351 throw (io::IOException
, uno::RuntimeException
)
353 return this->readByte();
356 // --------------------------------------------------------------------------
358 sal_Int8 SAL_CALL
BinaryReader_Impl::readByte()
359 throw (io::IOException
, uno::RuntimeException
)
361 sal_Int8 result
= sal_Int8(*readBuffer(1));
366 // --------------------------------------------------------------------------
368 sal_Unicode SAL_CALL
BinaryReader_Impl::readChar()
369 throw (io::IOException
, uno::RuntimeException
)
373 sal_uInt8
const * pData
= readBuffer(sizeof result
);
375 result
= sal_Unicode(
376 (sal_uInt16(pData
[0]) << 8) |
377 (sal_uInt16(pData
[1]) << 0) );
382 // --------------------------------------------------------------------------
384 sal_Int16 SAL_CALL
BinaryReader_Impl::readShort()
385 throw (io::IOException
, uno::RuntimeException
)
389 sal_uInt8
const * pData
= readBuffer(sizeof result
);
392 (sal_uInt16(pData
[0]) << 8) |
393 (sal_uInt16(pData
[1]) << 0) );
398 // --------------------------------------------------------------------------
400 sal_Int32 SAL_CALL
BinaryReader_Impl::readLong()
401 throw (io::IOException
, uno::RuntimeException
)
405 sal_uInt8
const * pData
= readBuffer(sizeof result
);
408 (sal_uInt32(pData
[0]) << 24) |
409 (sal_uInt32(pData
[1]) << 16) |
410 (sal_uInt32(pData
[2]) << 8) |
411 (sal_uInt32(pData
[3]) << 0) );
416 // --------------------------------------------------------------------------
418 sal_Int64 SAL_CALL
BinaryReader_Impl::readHyper()
419 throw (io::IOException
, uno::RuntimeException
)
423 sal_uInt8
const * pData
= readBuffer(sizeof result
);
426 (sal_uInt64(pData
[0]) << 56) |
427 (sal_uInt64(pData
[1]) << 48) |
428 (sal_uInt64(pData
[2]) << 40) |
429 (sal_uInt64(pData
[3]) << 32) |
430 (sal_uInt64(pData
[4]) << 24) |
431 (sal_uInt64(pData
[5]) << 16) |
432 (sal_uInt64(pData
[6]) << 8) |
433 (sal_uInt64(pData
[7]) << 0) );
438 // --------------------------------------------------------------------------
440 float SAL_CALL
BinaryReader_Impl::readFloat()
441 throw (io::IOException
, uno::RuntimeException
)
443 union { float f
; sal_uInt32 n
; } result
;
445 sal_uInt8
const * pData
= readBuffer(sizeof result
.n
);
447 result
.n
= sal_uInt32(
448 (sal_uInt32(pData
[0]) << 24) |
449 (sal_uInt32(pData
[1]) << 16) |
450 (sal_uInt32(pData
[2]) << 8) |
451 (sal_uInt32(pData
[3]) << 0) );
456 // --------------------------------------------------------------------------
458 double SAL_CALL
BinaryReader_Impl::readDouble()
459 throw (io::IOException
, uno::RuntimeException
)
461 union { double d
; sal_uInt64 n
; } result
;
463 sal_uInt8
const * pData
= readBuffer(sizeof result
.n
);
465 result
.n
= sal_uInt64(
466 (sal_uInt64(pData
[0]) << 56) |
467 (sal_uInt64(pData
[1]) << 48) |
468 (sal_uInt64(pData
[2]) << 40) |
469 (sal_uInt64(pData
[3]) << 32) |
470 (sal_uInt64(pData
[4]) << 24) |
471 (sal_uInt64(pData
[5]) << 16) |
472 (sal_uInt64(pData
[6]) << 8) |
473 (sal_uInt64(pData
[7]) << 0) );
478 // --------------------------------------------------------------------------
480 rtl::OUString SAL_CALL
BinaryReader_Impl::readUTF()
481 throw (io::IOException
, uno::RuntimeException
)
485 sal_uInt8
const * const pData
= readBuffer(sizeof nLength
);
487 nLength
= sal_uInt32(
488 (sal_uInt32(pData
[0]) << 24) |
489 (sal_uInt32(pData
[1]) << 16) |
490 (sal_uInt32(pData
[2]) << 8) |
491 (sal_uInt32(pData
[3]) << 0) );
493 bool bIsAscii
= (nLength
& binary::STR_ASCII_MASK
) == binary::STR_ASCII_MASK
;
494 nLength
&=~binary::STR_ASCII_MASK
;
496 rtl::OUString result
;
499 sal_Char
const * const pUTF
= reinterpret_cast<sal_Char
const * >(readBuffer(nLength
));
501 sal_Int32
const nStrLength
= sal_Int32(nLength
);
502 OSL_ASSERT(nStrLength
>= 0);
504 rtl_TextEncoding
const enc
= bIsAscii
? RTL_TEXTENCODING_ASCII_US
: RTL_TEXTENCODING_UTF8
;
506 rtl_uString_internConvert(&result
.pData
, pUTF
, nStrLength
, enc
,
507 OSTRING_TO_OUSTRING_CVTFLAGS
, NULL
);
513 // --------------------------------------------------------------------------
514 // BinaryReader implementation.
515 // --------------------------------------------------------------------------
517 BinaryReader::BinaryReader(rtl::OUString
const & _sFileURL
):
518 m_sFileURL(_sFileURL
) {}
520 BinaryReader::~BinaryReader() {}
522 bool BinaryReader::open()
523 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
525 OSL_PRECOND(!m_xDataInputStream
.is(),"Binary Reader: already open");
526 if (m_xDataInputStream
.is())
529 if (m_sFileURL
.getLength() == 0)
532 if (!FileHelper::fileExists(m_sFileURL
))
535 m_xDataInputStream
.set(new BinaryReader_Impl (m_sFileURL
));
539 // --------------------------------------------------------------------------
541 inline BinaryReader_Impl
* BinaryReader::getDataInputStream()
543 OSL_ENSURE(m_xDataInputStream
.is(),"Binary Cache: Reader was not opened - no input stream");
544 return m_xDataInputStream
.get();
547 // --------------------------------------------------------------------------
549 void BinaryReader::read(sal_Bool
&_bValue
)
550 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
552 _bValue
= getDataInputStream()->readBoolean();
555 // --------------------------------------------------------------------------
557 void BinaryReader::read(sal_Int8
&_nValue
)
558 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
560 _nValue
= getDataInputStream()->readByte();
563 // --------------------------------------------------------------------------
565 void BinaryReader::read(sal_Int16
&_nValue
)
566 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
568 _nValue
= getDataInputStream()->readShort();
571 // --------------------------------------------------------------------------
573 void BinaryReader::read(sal_Int32
&_nValue
)
574 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
576 _nValue
= getDataInputStream()->readLong();
579 // --------------------------------------------------------------------------
581 void BinaryReader::read(sal_Int64
&_nValue
)
582 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
584 _nValue
= getDataInputStream()->readHyper();
587 // --------------------------------------------------------------------------
589 void BinaryReader::read(double &_nValue
)
590 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
592 _nValue
= getDataInputStream()->readDouble();
595 // --------------------------------------------------------------------------
597 void BinaryReader::read(rtl::OUString
& _aStr
)
598 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
600 _aStr
= getDataInputStream()->readUTF();
603 // -----------------------------------------------------------------------------
604 template <class Element
>
605 void readSequence(BinaryReader
& _rReader
, uno::Sequence
< Element
> & aSequence
)
606 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
608 // PRE: the Sequence must exist
610 _rReader
.read(nLength
);
612 aSequence
.realloc(nLength
);
614 Element
* const pElement
= aSequence
.getArray(); // fill the hole array
615 for(sal_Int32 i
=0; i
<nLength
; ++i
)
617 _rReader
.read(pElement
[i
]); // read one element
621 // --------------------------------------------------------------------------
623 void BinaryReader::read (uno::Sequence
< sal_Int8
> &_aValue
)
624 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
626 readSequence(*this, _aValue
);
629 // --------------------------------------------------------------------------
631 void BinaryReader::read (uno::Sequence
< rtl::OUString
> &_aValue
)
632 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
634 readSequence(*this, _aValue
);
637 // --------------------------------------------------------------------------
639 uno::Sequence
< sal_Int8
> const * const for_binary
= 0;
641 #define CASE_READ_SEQUENCE(TYPE_CLASS, DATA_TYPE) \
644 OSL_ENSURE( ::getCppuType(static_cast<DATA_TYPE const*>(0)).getTypeClass() == (TYPE_CLASS), "Typeclass does not match element type" ); \
645 uno::Sequence< DATA_TYPE > aData; \
646 readSequence(_rReader, aData); \
650 bool readSequenceValue (
651 BinaryReader
& _rReader
,
653 uno::Type
const & _aElementType
)
654 SAL_THROW( (io::IOException
, uno::RuntimeException
) )
656 switch(_aElementType
.getTypeClass())
658 CASE_READ_SEQUENCE( uno::TypeClass_BOOLEAN
, sal_Bool
);
660 CASE_READ_SEQUENCE( uno::TypeClass_SHORT
, sal_Int16
);
662 CASE_READ_SEQUENCE( uno::TypeClass_LONG
, sal_Int32
);
664 CASE_READ_SEQUENCE( uno::TypeClass_HYPER
, sal_Int64
);
666 CASE_READ_SEQUENCE( uno::TypeClass_DOUBLE
, double );
668 CASE_READ_SEQUENCE( uno::TypeClass_STRING
, rtl::OUString
);
670 case uno::TypeClass_SEQUENCE
:
671 if (_aElementType
== ::getCppuType(for_binary
))
673 uno::Sequence
< sal_Int8
> aData
;
674 readSequence(_rReader
, aData
);
681 OSL_ENSURE(false, "Unexpected type for sequence elements");
687 #undef CASE_READ_SEQUENCE
689 // --------------------------------------------------------------------------