Commits

Anonymous committed 76ef3d8

dr81: make RecordParser reentrant, introduce RecordHandler as counterpart to FastTokenHandler

Comments (0)

Files changed (52)

oox/inc/oox/core/contexthandler.hxx

 #include <boost/shared_ptr.hpp>
 #include <cppuhelper/implbase1.hxx>
 #include <rtl/ref.hxx>
+#include "oox/core/relations.hxx"
 #include "oox/token/namespaces.hxx"
 #include "oox/token/tokens.hxx"
 
 namespace core {
 
 class XmlFilterBase;
-class FragmentHandler;
-struct Relation;
-class Relations;
+
+// ============================================================================
+
+/** Base data of a fragment.
+
+    This data is stored in a separate struct to make it accessible in every
+    child context handler of a fragment.
+ */
+struct FragmentBaseData
+{
+    XmlFilterBase&      mrFilter;
+    const ::rtl::OUString maFragmentPath;
+    ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XLocator >
+                        mxLocator;
+    RelationsRef        mxRelations;
+
+    explicit            FragmentBaseData(
+                            XmlFilterBase& rFilter,
+                            const ::rtl::OUString& rFragmentPath,
+                            const RelationsRef& rxRelations );
+};
+
+typedef ::boost::shared_ptr< FragmentBaseData > FragmentBaseDataRef;
 
 // ============================================================================
 
 class ContextHandler;
 typedef ::rtl::Reference< ContextHandler > ContextHandlerRef;
 
-struct FragmentBaseData;
-typedef ::boost::shared_ptr< FragmentBaseData > FragmentBaseDataRef;
-
 typedef ::cppu::WeakImplHelper1< ::com::sun::star::xml::sax::XFastContextHandler > ContextHandler_BASE;
 
 class ContextHandler : public ContextHandler_BASE
 {
 public:
-    explicit            ContextHandler( ContextHandler& rParent );
     virtual             ~ContextHandler();
 
     /** Returns the filter instance. */
 
     // com.sun.star.xml.sax.XFastContextHandler interface ---------------------
 
-    virtual void SAL_CALL startFastElement( ::sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+    virtual void SAL_CALL startFastElement( sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual void SAL_CALL startUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual void SAL_CALL endFastElement( ::sal_Int32 Element ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+    virtual void SAL_CALL endFastElement( sal_Int32 Element ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual void SAL_CALL endUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
 
     // record context interface -----------------------------------------------
 

oox/inc/oox/core/fastparser.hxx

 public:
     explicit            FastParser(
                             const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext )
-                            throw( ::com::sun::star::uno::RuntimeException );
+                            throw (::com::sun::star::uno::RuntimeException);
 
     virtual             ~FastParser();
 
     /** Registers an OOXML namespace at the parser. */
     void                registerNamespace( sal_Int32 nNamespaceId )
-    		                throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException );
+    		                throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
 
     /** Sets the passed document handler that will receive the SAX parser events. */
     void                setDocumentHandler(
                             const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastDocumentHandler >& rxDocHandler )
-    		                throw( ::com::sun::star::uno::RuntimeException );
+    		                throw (::com::sun::star::uno::RuntimeException);
 
-    /** Parses the passed SAX input source.
-        @param bCloseStream  True = closes the stream in the input source after parsing. */
-    void                parseStream( const ::com::sun::star::xml::sax::InputSource& rInputSource, bool bCloseStream = false )
-                            throw( ::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException );
+    /** Parses the stream described in the passed input source. Before parsing,
+        a document handler must be set.
+     */
+    void                parseStream( const ::com::sun::star::xml::sax::InputSource& rInputSource )
+                            throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
 
-    /** Parses the passed input stream.
-        @param bCloseStream  True = closes the passed stream after parsing. */
+    /** Parses the passed stream. Before parsing, a document handler must be
+        set.
+     */
     void                parseStream(
                             const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& rxInStream,
-                            const ::rtl::OUString& rStreamName, bool bCloseStream = false )
-                            throw( ::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException );
+                            const ::rtl::OUString& rStreamName )
+                            throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
 
-    /** Parses a stream from the passed storage with the specified name.
-        @param bCloseStream  True = closes the stream after parsing. */
-    void                parseStream( StorageBase& rStorage, const ::rtl::OUString& rStreamName, bool bCloseStream = false )
-                            throw( ::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException );
+    /** Parses a stream from the passed storage with the specified name. Before
+        parsing, a document handler must be set.
+     */
+    void                parseStream( StorageBase& rStorage, const ::rtl::OUString& rStreamName, bool bCloseStream )
+                            throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
 
 private:
     ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastParser >

oox/inc/oox/core/filterbase.hxx

 #include <com/sun/star/io/XStream.hpp>
 #include <com/sun/star/lang/XInitialization.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
-#include <cppuhelper/basemutex.hxx>
 #include <cppuhelper/implbase5.hxx>
 #include "oox/helper/binarystreambase.hxx"
 #include "oox/helper/storagebase.hxx"
         ::com::sun::star::document::XFilter >
     FilterBase_BASE;
 
-class OOX_DLLPUBLIC FilterBase : public FilterBase_BASE, public ::cppu::BaseMutex
+class OOX_DLLPUBLIC FilterBase : public FilterBase_BASE
 {
 public:
     explicit            FilterBase(

oox/inc/oox/core/filterdetect.hxx

 
 // ============================================================================
 
+typedef ::cppu::WeakImplHelper1< ::com::sun::star::xml::sax::XFastDocumentHandler > FilterDetectFragment_BASE;
+    
 /** Document handler specifically designed for detecting OOXML file formats.
 
     It takes a reference to the filter string object via its constructor, and
     puts the name of the detected filter to it, if it successfully finds one.
  */
-class FilterDetectDocHandler : public ::cppu::WeakImplHelper1< ::com::sun::star::xml::sax::XFastDocumentHandler >
+class FilterDetectFragment : public FilterDetectFragment_BASE
 {
 public:
-    explicit            FilterDetectDocHandler( ::rtl::OUString& rFilter );
-    virtual             ~FilterDetectDocHandler();
+    explicit            FilterDetectFragment( ::rtl::OUString& rFilter );
+    virtual             ~FilterDetectFragment();
 
     // XFastDocumentHandler
     virtual void SAL_CALL startDocument() throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual ::com::sun::star::uno::Reference< XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual ::com::sun::star::uno::Reference< XFastContextHandler > SAL_CALL createUnknownChildContext( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
 
 private:
 
 // ============================================================================
 
-class OOX_DLLPUBLIC FilterDetect : public ::cppu::WeakImplHelper2< ::com::sun::star::document::XExtendedFilterDetection, ::com::sun::star::lang::XServiceInfo >
+typedef ::cppu::WeakImplHelper2< ::com::sun::star::document::XExtendedFilterDetection, ::com::sun::star::lang::XServiceInfo > FilterDetect_BASE;
+
+class OOX_DLLPUBLIC FilterDetect : public FilterDetect_BASE
 {
 public:
     explicit            FilterDetect( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext )

oox/inc/oox/core/fragmenthandler.hxx

 #include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
 #include <cppuhelper/implbase1.hxx>
 #include "oox/core/contexthandler.hxx"
-#include "oox/core/relations.hxx"
 
 namespace com { namespace sun { namespace star {
     namespace io { class XInputStream; }
 
 // ============================================================================
 
-/** Base data of a fragment.
-
-    This data is stored in a separate struct to make it accessible in every
-    child context handler of the fragment.
- */
-struct FragmentBaseData
-{
-    XmlFilterBase&      mrFilter;
-    const ::rtl::OUString maFragmentPath;
-    ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XLocator >
-                        mxLocator;
-    RelationsRef        mxRelations;
-
-    explicit            FragmentBaseData(
-                            XmlFilterBase& rFilter,
-                            const ::rtl::OUString& rFragmentPath,
-                            RelationsRef xRelations );
-};
-
-// ============================================================================
-
-/** Describes record identifiers used to create contexts in a binary stream.
-
-    If a record is used to start a new context, usually the record identifier
-    increased by 1 is used to mark the end of this context, e.g. the Excel
-    record SHEETDATA == 0x0091 starts the <sheetData> context, and the record
-    SHEETDATA_END == 0x0092 ends this context. But some records are used to
-    start a new context, though there is no identifier to end this context,
-    e.g. the ROW or EXTROW records. These record identifiers can be marked by
-    setting the mnEndRecId member of this struct to -1.
- */
-struct RecordInfo
-{
-    sal_Int32           mnStartRecId;       /// Record identifier for context start.
-    sal_Int32           mnEndRecId;         /// Record identifier for context end, -1 = no record.
-};
-
-// ============================================================================
-
 typedef ::cppu::ImplInheritanceHelper1< ContextHandler, ::com::sun::star::xml::sax::XFastDocumentHandler > FragmentHandler_BASE;
 
 class FragmentHandler : public FragmentHandler_BASE
 {
 public:
     explicit            FragmentHandler( XmlFilterBase& rFilter, const ::rtl::OUString& rFragmentPath );
-    virtual             ~FragmentHandler();
-
-    /** Returns the com.sun.star.xml.sax.XFastContextHandler interface of this context. */
-    inline ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler >
-                        getFastContextHandler() { return static_cast< ContextHandler* >( this ); }
 
     // com.sun.star.xml.sax.XFastDocumentHandler interface --------------------
 
     virtual void SAL_CALL setDocumentLocator( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XLocator >& rxLocator ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
 
     // com.sun.star.xml.sax.XFastContextHandler interface ---------------------
+    // has to be implemented again due to double inheritance
 
-    virtual void SAL_CALL startFastElement( ::sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+    virtual void SAL_CALL startFastElement( sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual void SAL_CALL startUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual void SAL_CALL endFastElement( ::sal_Int32 Element ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+    virtual void SAL_CALL endFastElement( sal_Int32 Element ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual void SAL_CALL endUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 Element, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& Attribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
     virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
-    virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
 
     // XML stream handling ----------------------------------------------------
 
     /** Opens the fragment stream referred by the own fragment path. Derived
-        classes may provide specilized stream implementations. */
+        classes may provide specialized stream implementations. */
     virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >
                         openFragmentStream() const;
 
-    // binary records ---------------------------------------------------------
-
-    virtual const RecordInfo* getRecordInfos() const;
-
 protected:
-    explicit            FragmentHandler( XmlFilterBase& rFilter, const ::rtl::OUString& rFragmentPath, RelationsRef xRelations );
+    explicit            FragmentHandler( XmlFilterBase& rFilter, const ::rtl::OUString& rFragmentPath, const RelationsRef& rxRelations );
 };
 
 typedef ::rtl::Reference< FragmentHandler > FragmentHandlerRef;

oox/inc/oox/core/recordhandler.hxx

+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef OOX_CORE_RECORDHANDLER_HXX
+#define OOX_CORE_RECORDHANDLER_HXX
+
+#include <map>
+#include <cppuhelper/weak.hxx>
+#include <rtl/ref.hxx>
+
+namespace oox {
+    class BinaryInputStream;
+    class BinaryOutputStream;
+}
+
+namespace oox {
+namespace core {
+
+// ============================================================================
+
+/** Used to mark record contexts without closing record. */
+/** Contains identifiers of records used to form a record context in a binary
+    record stream, similar to open/close elements in XML streams.
+
+    In binary record streams, different records are used to form a record
+    context. For example, the Excel BIFF12 record SHEETDATA (0x0091) is related
+    to the XML start element <sheetData>, and the record SHEETDATA_END (0x0092)
+    is related to the XML end element </sheetData>.
+ */
+struct RecordContextInfo
+{
+    sal_Int32           mnOpenContextId;    /// Identifier of the record opening the record context.
+    sal_Int32           mnCloseContextId;   /// Identifier of the record closing the record context.
+};
+
+// ============================================================================
+
+/** Describes a header of a record in binary record streams.
+ */
+struct RecordHeader
+{
+    sal_Int32           mnIdentifier;       /// The identifier of the record.
+    sal_Int32           mnBodySize;         /// The size of the record body in bytes.
+    
+    inline explicit     RecordHeader() : mnIdentifier( 0 ), mnBodySize( 0 ) {}
+};
+
+// ============================================================================
+
+class RecordHandler : public ::cppu::OWeakObject
+{
+public:
+    explicit            RecordHandler( const RecordContextInfo* pContextInfos, size_t nContextInfoCount );
+
+    /** Returns a record context info structure, if the record with the passed
+        identifier is a record opening a record context.
+        
+        @return  Pointer to a context info structure containing the passed
+            record identifier in the member mnStartRecId, otherwise null.
+     */
+    const RecordContextInfo* getOpenContextInfo( sal_Int32 nIdentifier );
+
+    /** Returns a record context info structure, if the record with the passed
+        identifier is a record closing a record context.
+
+        @return  Pointer to a context info structure containing the passed
+            record identifier in the member mnStartRecId, otherwise null.
+     */
+    const RecordContextInfo* getCloseContextInfo( sal_Int32 nIdentifier );
+
+    /** Derived classes implement reading a record header from the current
+        position of the passed input stream.
+        
+        @param rHeader  (output parameter) The record header info structure to
+            be filled from the passed input stream.
+
+        @return  True = reading the record header was successful. The stream is
+            expected to point to the beginning of the record body. False =
+            reading the record header was not successful. Stream may be in EOF
+            state, or another internal error may have been occurred.
+     */
+    virtual bool    readRecordHeader( BinaryInputStream& rStrm, RecordHeader& rHeader ) = 0;
+
+    /** Derived classes implement writing a record header to the current
+        position of the passed output stream.
+
+        @param rHeader  The record header info structure to be written to the
+            passed output stream.
+
+        @return  True = writing the record header was successful. The stream is
+            expected to point after the new record header. False = writing the
+            record header was not successful. Stream may be in EOF state, or
+            another internal error may have been occurred.
+     */
+    virtual bool    writeRecordHeader( BinaryOutputStream& rStrm, const RecordHeader& rHeader ) = 0;
+
+private:
+    typedef ::std::map< sal_Int32, RecordContextInfo > RecordContextInfoMap;
+
+    RecordContextInfoMap maOpenContextMap;  /// Maps record identifiers of opening context records.
+    RecordContextInfoMap maCloseContextMap; /// Maps record identifiers of closing context records.
+};
+
+typedef ::rtl::Reference< RecordHandler > RecordHandlerRef;
+
+// ============================================================================
+
+} // namespace core
+} // namespace oox
+
+#endif

oox/inc/oox/core/recordparser.hxx

 #ifndef OOX_CORE_RECORDPARSER_HXX
 #define OOX_CORE_RECORDPARSER_HXX
 
-#include <map>
+#include <memory>
 #include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
 #include <com/sun/star/xml/sax/SAXException.hpp>
 #include <rtl/ref.hxx>
 #include "oox/helper/binaryinputstream.hxx"
 
+namespace oox { class StorageBase; }
+
 namespace oox {
 namespace core {
 
 class FragmentHandler;
-struct RecordInfo;
-
-namespace prv { class Locator; }
-namespace prv { class ContextStack; }
+class RecordHandler;
+struct RecordParserImpl;
 
 // ============================================================================
 
-struct RecordInputSource
-{
-    BinaryInputStreamRef mxInStream;
-    ::rtl::OUString     maPublicId;
-    ::rtl::OUString     maSystemId;
-};
+/** A parser for binary streams containing record structures.
 
-// ============================================================================
-
+    A record is a sequence of bytes in the stream consisting of a record header
+    followed by the record body. The record header contains an identifier and
+    the record size. The record body contains the data of the record. Its
+    meaning depends on the record identifier.
+    
+    This class is designed similar to an XML parser as defined by the UNO
+    interface com.sun.star.xml.sax.XFastParser. It uses document handlers of
+    type ::oox::core::FragmentHandler which implement record handler functions
+    as well as XML context handler functions.
+ */
 class RecordParser
 {
 public:
     explicit            RecordParser();
-    virtual             ~RecordParser();
+                        ~RecordParser();
 
-    void                setFragmentHandler( const ::rtl::Reference< FragmentHandler >& rxHandler );
+    /** Registers a handler that reads the record headers in the binary input
+        stream and provides record context information.
 
-    void                parseStream( const RecordInputSource& rInputSource )
-                            throw(  ::com::sun::star::xml::sax::SAXException,
-                                    ::com::sun::star::io::IOException,
-                                    ::com::sun::star::uno::RuntimeException );
+        MUST NOT be called after starting to parse the first record stream.
+     */
+    void                setRecordHandler( const ::rtl::Reference< RecordHandler >& rxRecordHandler )
+                            throw (::com::sun::star::uno::RuntimeException);
 
-    inline const RecordInputSource& getInputSource() const { return maSource; }
+    /** Sets a handler that takes document and record context events from this
+        parser.
+     */
+    void                setDocumentHandler( const ::rtl::Reference< FragmentHandler >& rxDocumentHandler )
+                            throw (::com::sun::star::uno::RuntimeException);
+
+    /** Parses the stream described in the passed input source. Before parsing,
+        a record handler and document handler must be set.
+     */
+    void                parseStream( const ::com::sun::star::xml::sax::InputSource& rInputSource )
+                            throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
+
+    /** Parses the passed stream. Before parsing, a record handler and document
+        handler must be set.
+     */
+    void                parseStream(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& rxInStream,
+                            const ::rtl::OUString& rStreamName )
+                            throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
+
+    /** Parses a stream from the passed storage with the specified name. Before
+        parsing, a record handler and document handler must be set.
+     */
+    void                parseStream( StorageBase& rStorage, const ::rtl::OUString& rStreamName, bool bCloseStream )
+                            throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
 
 private:
-    /** Returns a RecordInfo struct that contains the passed record identifier
-        as context start identifier. */
-    const RecordInfo*   getStartRecordInfo( sal_Int32 nRecId ) const;
-    /** Returns a RecordInfo struct that contains the passed record identifier
-        as context end identifier. */
-    const RecordInfo*   getEndRecordInfo( sal_Int32 nRecId ) const;
-
-private:
-    typedef ::std::map< sal_Int32, RecordInfo > RecordInfoMap;
-
-    RecordInputSource   maSource;
-    ::rtl::Reference< FragmentHandler > mxHandler;
-    ::rtl::Reference< prv::Locator > mxLocator;
-    ::std::auto_ptr< prv::ContextStack > mxStack;
-    RecordInfoMap       maStartMap;
-    RecordInfoMap       maEndMap;
+    ::std::auto_ptr< RecordParserImpl > mxImpl;
 };
 
 // ============================================================================

oox/inc/oox/core/xmlfilterbase.hxx

 namespace core {
 
 class FragmentHandler;
+class RecordHandler;
 
 // ============================================================================
 
         used for fragments referred by the root relations. */
     ::rtl::OUString     getFragmentPathFromFirstType( const ::rtl::OUString& rType );
 
+
+    /** Sets a record handler at the record parser used to process binary
+        record streams.
+     */
+    void                setRecordHandler( const ::rtl::Reference< RecordHandler >& rxRecordHandler );
+
     /** Imports a fragment using the passed fragment handler, which contains
         the full path to the fragment stream.
 

oox/inc/oox/helper/helper.hxx

 #include <algorithm>
 #include <limits>
 #include <boost/static_assert.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
 #include <osl/endian.h>
 #include <rtl/math.hxx>
 #include <rtl/string.hxx>
 template< typename ReturnType, typename Type >
 inline ReturnType getIntervalValue( Type nValue, Type nBegin, Type nEnd )
 {
-//    this BOOST_STATIC_ASSERT fails with suncc
-//    BOOST_STATIC_ASSERT( ::std::numeric_limits< Type >::is_integer );
+    BOOST_STATIC_ASSERT( ::std::numeric_limits< Type >::is_integer );
     Type nInterval = nEnd - nBegin;
     Type nCount = (nValue < nBegin) ? -((nBegin - nValue - 1) / nInterval + 1) : ((nValue - nBegin) / nInterval);
     return static_cast< ReturnType >( nValue - nCount * nInterval );
 
 // ============================================================================
 
+/** Closes the passed input stream on destruction. Used for exception safety. */
+class XInputStreamCloseGuard
+{
+public:
+    inline explicit     XInputStreamCloseGuard( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& rxInStream, bool bClose = true ) :
+                            mxInStream( rxInStream ), mbClose( bClose ) {}
+    inline              ~XInputStreamCloseGuard()
+                            { if( mbClose && mxInStream.is() ) try { mxInStream->closeInput(); } catch( ::com::sun::star::uno::Exception& ) {} }
+
+private:
+    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > mxInStream;
+    bool                mbClose;
+};
+
+// ============================================================================
+
 } // namespace oox
 
 #endif

oox/inc/oox/xls/chartsheetfragment.hxx

 
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
     virtual void        initializeImport();
     virtual void        finalizeImport();
 

oox/inc/oox/xls/commentsfragment.hxx

     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
     virtual void        onEndRecord();
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
-
 private:
     /** Imports comment data from the comment element. */
     void                importComment( const AttributeList& rAttribs );

oox/inc/oox/xls/connectionsfragment.hxx

     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
     virtual void        finalizeImport();
 };
 

oox/inc/oox/xls/externallinkfragment.hxx

     void                setCellValue( const ::com::sun::star::uno::Any& rValue );
 
 private:
+    AddressVerifier&    mrAddrVerifier;         /// The address verifier for fast access.
     ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalSheetCache >
                         mxSheetCache;           /// The sheet cache used to store external cell values.
     Address2d           maCurrPos;              /// Position of current cell.
 
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
-
 private:
     ::oox::core::ContextHandlerRef createSheetDataContext( sal_Int32 nSheetId );
 

oox/inc/oox/xls/pivotcachefragment.hxx

 protected:
     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
     virtual void        finalizeImport();
 
 private:
 protected:
     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
 
 private:
     void                startCacheRecord();

oox/inc/oox/xls/pivottablefragment.hxx

 protected:
     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
 
 private:
     PivotTable&         mrPivotTable;

oox/inc/oox/xls/querytablefragment.hxx

     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
-    
 private:
     QueryTable&         mrQueryTable;
 };

oox/inc/oox/xls/sharedstringsfragment.hxx

     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
     virtual void        finalizeImport();
 };
 

oox/inc/oox/xls/stylesfragment.hxx

     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
     virtual void        finalizeImport();
 };
 

oox/inc/oox/xls/tablefragment.hxx

     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
-
 private:
     Table&              mrTable;
 };

oox/inc/oox/xls/workbookfragment.hxx

 
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
     virtual void        finalizeImport();
 
 private:

oox/inc/oox/xls/worksheetfragment.hxx

 
     virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
 
-    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
     virtual void        initializeImport();
     virtual void        finalizeImport();
 

oox/source/core/contexthandler.cxx

 
 #include "oox/core/contexthandler.hxx"
 
-#include "oox/core/fragmenthandler.hxx"
-
 namespace oox {
 namespace core {
 
 
 // ============================================================================
 
-ContextHandler::ContextHandler( ContextHandler& rParent ) :
-    ContextHandler_BASE(),
-    mxBaseData( rParent.mxBaseData )
+FragmentBaseData::FragmentBaseData( XmlFilterBase& rFilter, const OUString& rFragmentPath, const RelationsRef& rxRelations ) :
+    mrFilter( rFilter ),
+    maFragmentPath( rFragmentPath ),
+    mxRelations( rxRelations )
 {
 }
 
+// ============================================================================
+
 ContextHandler::ContextHandler( const FragmentBaseDataRef& rxBaseData ) :
     mxBaseData( rxBaseData )
 {
     return mxBaseData->mxRelations->getFragmentPathFromFirstType( rType );
 }
 
-void ContextHandler::implSetLocator( const Reference< XLocator >& rxLocator )
-{
-    mxBaseData->mxLocator = rxLocator;
-}
-
 // com.sun.star.xml.sax.XFastContextHandler interface -------------------------
 
-void ContextHandler::startFastElement( sal_Int32, const Reference< XFastAttributeList >& ) throw( SAXException, RuntimeException )
+void ContextHandler::startFastElement( sal_Int32, const Reference< XFastAttributeList >& ) throw (SAXException, RuntimeException)
 {
 }
 
-void ContextHandler::startUnknownElement( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) throw( SAXException, RuntimeException )
+void ContextHandler::startUnknownElement( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) throw (SAXException, RuntimeException)
 {
 }
 
-void ContextHandler::endFastElement( sal_Int32 ) throw( SAXException, RuntimeException )
+void ContextHandler::endFastElement( sal_Int32 ) throw (SAXException, RuntimeException)
 {
 }
 
-void ContextHandler::endUnknownElement( const OUString&, const OUString& ) throw( SAXException, RuntimeException )
+void ContextHandler::endUnknownElement( const OUString&, const OUString& ) throw (SAXException, RuntimeException)
 {
 }
 
-Reference< XFastContextHandler > ContextHandler::createFastChildContext( sal_Int32, const Reference< XFastAttributeList >& ) throw( SAXException, RuntimeException )
+Reference< XFastContextHandler > ContextHandler::createFastChildContext( sal_Int32, const Reference< XFastAttributeList >& ) throw (SAXException, RuntimeException)
 {
     return 0;
 }
 
-Reference< XFastContextHandler > ContextHandler::createUnknownChildContext( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) throw( SAXException, RuntimeException )
+Reference< XFastContextHandler > ContextHandler::createUnknownChildContext( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) throw (SAXException, RuntimeException)
 {
     return 0;
 }
 
-void ContextHandler::characters( const OUString& ) throw( SAXException, RuntimeException )
-{
-}
-
-void ContextHandler::ignorableWhitespace( const OUString& ) throw( SAXException, RuntimeException )
-{
-}
-
-void ContextHandler::processingInstruction( const OUString&, const OUString& ) throw( SAXException, RuntimeException )
+void ContextHandler::characters( const OUString& ) throw (SAXException, RuntimeException)
 {
 }
 
 {
 }
 
+// protected ------------------------------------------------------------------
+
+void ContextHandler::implSetLocator( const Reference< XLocator >& rxLocator )
+{
+    mxBaseData->mxLocator = rxLocator;
+}
+
 // ============================================================================
 
 } // namespace core

oox/source/core/fastparser.cxx

 
 // ============================================================================
 
-namespace {
-
-class InputStreamCloseGuard
-{
-public:
-    explicit            InputStreamCloseGuard( const Reference< XInputStream >& rxInStream, bool bCloseStream );
-                        ~InputStreamCloseGuard();
-private:
-    Reference< XInputStream > mxInStream;
-    bool                mbCloseStream;
-};
-
-InputStreamCloseGuard::InputStreamCloseGuard( const Reference< XInputStream >& rxInStream, bool bCloseStream ) :
-    mxInStream( rxInStream ),
-    mbCloseStream( bCloseStream )
-{
-}
-
-InputStreamCloseGuard::~InputStreamCloseGuard()
-{
-    if( mxInStream.is() && mbCloseStream ) try { mxInStream->closeInput(); } catch( Exception& ) {}
-}
-
-} // namespace
-
-// ============================================================================
-
-FastParser::FastParser( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
+FastParser::FastParser( const Reference< XComponentContext >& rxContext ) throw (RuntimeException) :
     mrNamespaceMap( StaticNamespaceMap::get() )
 {
     // create a fast parser instance
 {
 }
 
-void FastParser::registerNamespace( sal_Int32 nNamespaceId ) throw( IllegalArgumentException, RuntimeException )
+void FastParser::registerNamespace( sal_Int32 nNamespaceId ) throw (IllegalArgumentException, RuntimeException)
 {
     if( !mxParser.is() )
         throw RuntimeException();
     mxParser->registerNamespace( *pNamespaceUrl, nNamespaceId );
 }
 
-void FastParser::setDocumentHandler( const Reference< XFastDocumentHandler >& rxDocHandler ) throw( RuntimeException )
+void FastParser::setDocumentHandler( const Reference< XFastDocumentHandler >& rxDocHandler ) throw (RuntimeException)
 {
     if( !mxParser.is() )
         throw RuntimeException();
     mxParser->setFastDocumentHandler( rxDocHandler );
 }
 
-void FastParser::parseStream( const InputSource& rInputSource, bool bCloseStream ) throw( SAXException, IOException, RuntimeException )
+void FastParser::parseStream( const InputSource& rInputSource ) throw (SAXException, IOException, RuntimeException)
 {
-    // guard closing the input stream also when exceptions are thrown
-    InputStreamCloseGuard aGuard( rInputSource.aInputStream, bCloseStream );
     if( !mxParser.is() )
         throw RuntimeException();
     mxParser->parseStream( rInputSource );
 }
 
-void FastParser::parseStream( const Reference< XInputStream >& rxInStream, const OUString& rStreamName, bool bCloseStream ) throw( SAXException, IOException, RuntimeException )
+void FastParser::parseStream( const Reference< XInputStream >& rxInStream, const OUString& rStreamName ) throw (SAXException, IOException, RuntimeException)
 {
     InputSource aInputSource;
+    aInputSource.aInputStream = rxInStream;
     aInputSource.sSystemId = rStreamName;
-    aInputSource.aInputStream = rxInStream;
-    parseStream( aInputSource, bCloseStream );
+    parseStream( aInputSource );
 }
 
-void FastParser::parseStream( StorageBase& rStorage, const OUString& rStreamName, bool bCloseStream ) throw( SAXException, IOException, RuntimeException )
+void FastParser::parseStream( StorageBase& rStorage, const OUString& rStreamName, bool bCloseStream ) throw (SAXException, IOException, RuntimeException)
 {
-    parseStream( rStorage.openInputStream( rStreamName ), rStreamName, bCloseStream );
+    Reference< XInputStream > xInStrm = rStorage.openInputStream( rStreamName );
+    XInputStreamCloseGuard aGuard( xInStrm, bCloseStream );
+    parseStream( xInStrm, rStreamName );
 }
 
 // ============================================================================

oox/source/core/filterdetect.cxx

 
 // ============================================================================
 
-FilterDetectDocHandler::FilterDetectDocHandler( OUString& rFilterName ) :
+FilterDetectFragment::FilterDetectFragment( OUString& rFilterName ) :
     mrFilterName( rFilterName )
 {
     maContextStack.reserve( 2 );
 }
 
-FilterDetectDocHandler::~FilterDetectDocHandler()
+FilterDetectFragment::~FilterDetectFragment()
 {
 }
 
-void SAL_CALL FilterDetectDocHandler::startDocument()
+void SAL_CALL FilterDetectFragment::startDocument()
     throw (SAXException, RuntimeException)
 {
 }
 
-void SAL_CALL FilterDetectDocHandler::endDocument()
+void SAL_CALL FilterDetectFragment::endDocument()
     throw (SAXException, RuntimeException)
 {
 }
 
-void SAL_CALL FilterDetectDocHandler::setDocumentLocator( const Reference<XLocator>& /*xLocator*/ )
+void SAL_CALL FilterDetectFragment::setDocumentLocator( const Reference<XLocator>& /*xLocator*/ )
     throw (SAXException, RuntimeException)
 {
 }
 
-void SAL_CALL FilterDetectDocHandler::startFastElement(
+void SAL_CALL FilterDetectFragment::startFastElement(
         sal_Int32 nElement, const Reference< XFastAttributeList >& rAttribs )
     throw (SAXException,RuntimeException)
 {
     maContextStack.push_back( nElement );
 }
 
-void SAL_CALL FilterDetectDocHandler::startUnknownElement(
+void SAL_CALL FilterDetectFragment::startUnknownElement(
     const OUString& /*Namespace*/, const OUString& /*Name*/, const Reference<XFastAttributeList>& /*Attribs*/ )
     throw (SAXException, RuntimeException)
 {
 }
 
-void SAL_CALL FilterDetectDocHandler::endFastElement( sal_Int32 /*nElement*/ )
+void SAL_CALL FilterDetectFragment::endFastElement( sal_Int32 /*nElement*/ )
     throw (SAXException, RuntimeException)
 {
     maContextStack.pop_back();
 }
 
-void SAL_CALL FilterDetectDocHandler::endUnknownElement(
+void SAL_CALL FilterDetectFragment::endUnknownElement(
     const OUString& /*Namespace*/, const OUString& /*Name*/ ) throw (SAXException, RuntimeException)
 {
 }
 
-Reference<XFastContextHandler> SAL_CALL FilterDetectDocHandler::createFastChildContext(
+Reference<XFastContextHandler> SAL_CALL FilterDetectFragment::createFastChildContext(
     sal_Int32 /*Element*/, const Reference<XFastAttributeList>& /*Attribs*/ )
     throw (SAXException, RuntimeException)
 {
     return this;
 }
 
-Reference<XFastContextHandler> SAL_CALL FilterDetectDocHandler::createUnknownChildContext(
+Reference<XFastContextHandler> SAL_CALL FilterDetectFragment::createUnknownChildContext(
     const OUString& /*Namespace*/, const OUString& /*Name*/, const Reference<XFastAttributeList>& /*Attribs*/)
     throw (SAXException, RuntimeException)
 {
     return this;
 }
 
-void SAL_CALL FilterDetectDocHandler::characters( const OUString& /*aChars*/ )
+void SAL_CALL FilterDetectFragment::characters( const OUString& /*aChars*/ )
     throw (SAXException, RuntimeException)
 {
 }
 
-void SAL_CALL FilterDetectDocHandler::ignorableWhitespace( const OUString& /*aWhitespaces*/ )
-    throw (SAXException, RuntimeException)
-{
-}
-
-void SAL_CALL FilterDetectDocHandler::processingInstruction(
+void SAL_CALL FilterDetectFragment::processingInstruction(
     const OUString& /*aTarget*/, const OUString& /*aData*/ )
     throw (SAXException, RuntimeException)
 {
 }
 
-void FilterDetectDocHandler::parseRelationship( const AttributeList& rAttribs )
+void FilterDetectFragment::parseRelationship( const AttributeList& rAttribs )
 {
     OUString aType = rAttribs.getString( XML_Type, OUString() );
     if( aType.equalsAscii( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" ) )
         maTargetPath = OUString( sal_Unicode( '/' ) ) + rAttribs.getString( XML_Target, OUString() );
 }
 
-OUString FilterDetectDocHandler::getFilterNameFromContentType( const OUString& rContentType ) const
+OUString FilterDetectFragment::getFilterNameFromContentType( const OUString& rContentType ) const
 {
     if( rContentType.equalsAscii( "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" ) ||
         rContentType.equalsAscii( "application/vnd.ms-word.document.macroEnabled.main+xml" ) )
     return OUString();
 }
 
-void FilterDetectDocHandler::parseContentTypesDefault( const AttributeList& rAttribs )
+void FilterDetectFragment::parseContentTypesDefault( const AttributeList& rAttribs )
 {
     // only if no overridden part name found
     if( mrFilterName.getLength() == 0 )
     }
 }
 
-void FilterDetectDocHandler::parseContentTypesOverride( const AttributeList& rAttribs )
+void FilterDetectFragment::parseContentTypesOverride( const AttributeList& rAttribs )
 {
     if( rAttribs.getString( XML_PartName, OUString() ).equals( maTargetPath ) )
         mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ) );
             aParser.registerNamespace( NMSP_packageRel );
             aParser.registerNamespace( NMSP_officeRel );
             aParser.registerNamespace( NMSP_packageContentTypes );
-            aParser.setDocumentHandler( new FilterDetectDocHandler( aFilterName ) );
+            aParser.setDocumentHandler( new FilterDetectFragment( aFilterName ) );
 
             /*  Parse '_rels/.rels' to get the target path and '[Content_Types].xml'
                 to determine the content type of the part at the target path. */
-            aParser.parseStream( aZipStorage, CREATE_OUSTRING( "_rels/.rels" ) );
-            aParser.parseStream( aZipStorage, CREATE_OUSTRING( "[Content_Types].xml" ) );
+            aParser.parseStream( aZipStorage, CREATE_OUSTRING( "_rels/.rels" ), true );
+            aParser.parseStream( aZipStorage, CREATE_OUSTRING( "[Content_Types].xml" ), true );
         }
     }
     catch( Exception& )

oox/source/core/fragmenthandler.cxx

 
 // ============================================================================
 
-FragmentBaseData::FragmentBaseData( XmlFilterBase& rFilter, const OUString& rFragmentPath, RelationsRef xRelations ) :
-    mrFilter( rFilter ),
-    maFragmentPath( rFragmentPath ),
-    mxRelations( xRelations )
-{
-}
-
-// ============================================================================
-
 FragmentHandler::FragmentHandler( XmlFilterBase& rFilter, const OUString& rFragmentPath ) :
     FragmentHandler_BASE( FragmentBaseDataRef( new FragmentBaseData( rFilter, rFragmentPath, rFilter.importRelations( rFragmentPath ) ) ) )
 {
 }
 
-FragmentHandler::FragmentHandler( XmlFilterBase& rFilter, const OUString& rFragmentPath, RelationsRef xRelations ) :
-    FragmentHandler_BASE( FragmentBaseDataRef( new FragmentBaseData( rFilter, rFragmentPath, xRelations ) ) )
-{
-}
-
-FragmentHandler::~FragmentHandler()
+FragmentHandler::FragmentHandler( XmlFilterBase& rFilter, const OUString& rFragmentPath, const RelationsRef& rxRelations ) :
+    FragmentHandler_BASE( FragmentBaseDataRef( new FragmentBaseData( rFilter, rFragmentPath, rxRelations ) ) )
 {
 }
 
 // com.sun.star.xml.sax.XFastDocumentHandler interface ------------------------
 
-void FragmentHandler::startDocument() throw( SAXException, RuntimeException )
+void FragmentHandler::startDocument() throw (SAXException, RuntimeException)
 {
 }
 
-void FragmentHandler::endDocument() throw( SAXException, RuntimeException )
+void FragmentHandler::endDocument() throw (SAXException, RuntimeException)
 {
 }
 
-void FragmentHandler::setDocumentLocator( const Reference< XLocator >& rxLocator ) throw( SAXException, RuntimeException )
+void FragmentHandler::setDocumentLocator( const Reference< XLocator >& rxLocator ) throw (SAXException, RuntimeException)
 {
     implSetLocator( rxLocator );
 }
 
 // com.sun.star.xml.sax.XFastContextHandler interface -------------------------
 
-void FragmentHandler::startFastElement( sal_Int32, const Reference< XFastAttributeList >& ) throw( SAXException, RuntimeException )
+void FragmentHandler::startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs ) throw (SAXException, RuntimeException)
+{
+    ContextHandler::startFastElement( nElement, rxAttribs );
+}
+
+void FragmentHandler::startUnknownElement( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) throw (SAXException, RuntimeException)
 {
 }
 
-void FragmentHandler::startUnknownElement( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) throw( SAXException, RuntimeException )
+void FragmentHandler::endFastElement( sal_Int32 ) throw (SAXException, RuntimeException)
 {
 }
 
-void FragmentHandler::endFastElement( sal_Int32 ) throw( SAXException, RuntimeException )
+void FragmentHandler::endUnknownElement( const OUString&, const OUString& ) throw (SAXException, RuntimeException)
 {
 }
 
-void FragmentHandler::endUnknownElement( const OUString&, const OUString& ) throw( SAXException, RuntimeException )
-{
-}
-
-Reference< XFastContextHandler > FragmentHandler::createFastChildContext( sal_Int32, const Reference< XFastAttributeList >& ) throw( SAXException, RuntimeException )
+Reference< XFastContextHandler > FragmentHandler::createFastChildContext( sal_Int32, const Reference< XFastAttributeList >& ) throw (SAXException, RuntimeException)
 {
     return 0;
 }
 
-Reference< XFastContextHandler > FragmentHandler::createUnknownChildContext( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) throw( SAXException, RuntimeException )
+Reference< XFastContextHandler > FragmentHandler::createUnknownChildContext( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) throw (SAXException, RuntimeException)
 {
     return 0;
 }
 
-void FragmentHandler::characters( const OUString& ) throw( SAXException, RuntimeException )
-{
-}
-
-void FragmentHandler::ignorableWhitespace( const OUString& ) throw( SAXException, RuntimeException )
-{
-}
-
-void FragmentHandler::processingInstruction( const OUString&, const OUString& ) throw( SAXException, RuntimeException )
+void FragmentHandler::characters( const OUString& ) throw (SAXException, RuntimeException)
 {
 }
 
     return getFilter().openInputStream( getFragmentPath() );
 }
 
-// binary records -------------------------------------------------------------
-
-const RecordInfo* FragmentHandler::getRecordInfos() const
-{
-    // default: no support for binary records
-    return 0;
-}
-
 // ============================================================================
 
 } // namespace core

oox/source/core/makefile.mk

 		$(SLO)$/filterdetect.obj			\
 		$(SLO)$/fragmenthandler.obj			\
 		$(SLO)$/fragmenthandler2.obj		\
+		$(SLO)$/recordhandler.obj			\
 		$(SLO)$/recordparser.obj			\
 		$(SLO)$/relations.obj				\
 		$(SLO)$/relationshandler.obj		\

oox/source/core/recordhandler.cxx

+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#include "oox/core/recordhandler.hxx"
+
+#include "oox/helper/containerhelper.hxx"
+
+namespace oox {
+namespace core {
+
+// ============================================================================
+
+RecordHandler::RecordHandler( const RecordContextInfo* pContextInfos, size_t nContextInfoCount )
+{
+    const RecordContextInfo* pContextInfoEnd = pContextInfos + nContextInfoCount;
+    for( ; pContextInfos != pContextInfoEnd; ++pContextInfos )
+    {
+        maOpenContextMap[ pContextInfos->mnOpenContextId ] = *pContextInfos;
+        maCloseContextMap[ pContextInfos->mnCloseContextId ] = *pContextInfos;
+    }
+}
+
+const RecordContextInfo* RecordHandler::getOpenContextInfo( sal_Int32 nIdentifier )
+{
+    return ContainerHelper::getMapElement( maOpenContextMap, nIdentifier );
+}
+
+const RecordContextInfo* RecordHandler::getCloseContextInfo( sal_Int32 nIdentifier )
+{
+    return ContainerHelper::getMapElement( maCloseContextMap, nIdentifier );
+}
+
+// ============================================================================
+
+} // namespace core
+} // namespace oox

oox/source/core/recordparser.cxx

 
 #include "oox/core/recordparser.hxx"
 
-#include <vector>
+#include <map>
+#include <stack>
 #include <com/sun/star/lang/DisposedException.hpp>
 #include <com/sun/star/xml/sax/XLocator.hpp>
 #include <cppuhelper/implbase1.hxx>
 #include "oox/core/fragmenthandler.hxx"
+#include "oox/core/recordhandler.hxx"
+#include "oox/helper/storagebase.hxx"
 
 namespace oox {
 namespace core {
 
 // ============================================================================
 
-namespace prv {
+namespace {
 
-class Locator : public ::cppu::WeakImplHelper1< XLocator >
+/** Context stack for a binary record stream. */
+class ContextStack
 {
 public:
-    inline explicit         Locator( RecordParser* pParser ) : mpParser( pParser ) {}
+    explicit            ContextStack( const FragmentHandlerRef& rxDocHandler );
 
-    void                    dispose();
-    void                    checkDispose() throw( RuntimeException );
+    inline bool         empty() const { return maEntries.empty(); }
 
-    // com.sun.star.sax.XLocator interface
+    sal_Int32           getCurrentRecId() const;
+    ContextHandlerRef   getCurrentContext() const;
 
-    virtual sal_Int32 SAL_CALL getColumnNumber() throw( RuntimeException );
-    virtual sal_Int32 SAL_CALL getLineNumber() throw( RuntimeException );
-    virtual OUString SAL_CALL getPublicId() throw( RuntimeException );
-    virtual OUString SAL_CALL getSystemId() throw( RuntimeException );
+    void                pushContext( const RecordContextInfo& rContextInfo, const ContextHandlerRef& rxContext );
+    void                popContext();
 
 private:
-    RecordParser*           mpParser;
+    typedef ::std::pair< RecordContextInfo, ContextHandlerRef > ContextEntry;
+    typedef ::std::stack< ContextEntry > ContextEntryStack;
+
+    FragmentHandlerRef  mxDocHandler;
+    ContextEntryStack   maEntries;
 };
 
 // ----------------------------------------------------------------------------
 
-void Locator::dispose()
-{
-    mpParser = 0;
-}
-
-void Locator::checkDispose() throw( RuntimeException )
-{
-    if( !mpParser )
-        throw DisposedException();
-}
-
-sal_Int32 SAL_CALL Locator::getColumnNumber() throw( RuntimeException )
-{
-    return -1;
-}
-
-sal_Int32 SAL_CALL Locator::getLineNumber() throw( RuntimeException )
-{
-    return -1;
-}
-
-OUString SAL_CALL Locator::getPublicId() throw( RuntimeException )
-{
-    checkDispose();
-    return mpParser->getInputSource().maPublicId;
-}
-
-OUString SAL_CALL Locator::getSystemId() throw( RuntimeException )
-{
-    checkDispose();
-    return mpParser->getInputSource().maSystemId;
-}
-
-// ============================================================================
-
-class ContextStack
-{
-public:
-    explicit            ContextStack( FragmentHandlerRef xHandler );
-
-    inline bool         empty() const { return maStack.empty(); }
-
-    sal_Int32           getCurrentRecId() const;
-    bool                hasCurrentEndRecId() const;
-    ContextHandlerRef   getCurrentContext() const;
-
-    void                pushContext( const RecordInfo& rRec, const ContextHandlerRef& rxContext );
-    void                popContext();
-
-private:
-    typedef ::std::pair< RecordInfo, ContextHandlerRef >    ContextInfo;
-    typedef ::std::vector< ContextInfo >                    ContextInfoVec;
-
-    FragmentHandlerRef  mxHandler;
-    ContextInfoVec      maStack;
-};
-
-// ----------------------------------------------------------------------------
-
-ContextStack::ContextStack( FragmentHandlerRef xHandler ) :
-    mxHandler( xHandler )
+ContextStack::ContextStack( const FragmentHandlerRef& rxDocHandler ) :
+    mxDocHandler( rxDocHandler )
 {
 }
 
 sal_Int32 ContextStack::getCurrentRecId() const
 {
-    return maStack.empty() ? -1 : maStack.back().first.mnStartRecId;
-}
-
-bool ContextStack::hasCurrentEndRecId() const
-{
-    return !maStack.empty() && (maStack.back().first.mnEndRecId >= 0);
+    return maEntries.empty() ? -1 : maEntries.top().first.mnOpenContextId;
 }
 
 ContextHandlerRef ContextStack::getCurrentContext() const
 {
-    if( !maStack.empty() )
-        return maStack.back().second;
-    return mxHandler.get();
+    if( !maEntries.empty() )
+        return maEntries.top().second;
+    return mxDocHandler.get();
 }
 
-void ContextStack::pushContext( const RecordInfo& rRecInfo, const ContextHandlerRef& rxContext )
+void ContextStack::pushContext( const RecordContextInfo& rContextInfo, const ContextHandlerRef& rxContext )
 {
-    OSL_ENSURE( (rRecInfo.mnEndRecId >= 0) || maStack.empty() || hasCurrentEndRecId(),
-        "ContextStack::pushContext - nested incomplete context record identifiers" );
-    maStack.push_back( ContextInfo( rRecInfo, rxContext ) );
+    maEntries.push( ContextEntry( rContextInfo, rxContext ) );
 }
 
 void ContextStack::popContext()
 {
-    OSL_ENSURE( !maStack.empty(), "ContextStack::popContext - no context on stack" );
-    if( !maStack.empty() )
+    OSL_ENSURE( !maEntries.empty(), "ContextStack::popContext - no context on stack" );
+    if( !maEntries.empty() )
     {
-        ContextInfo& rContextInfo = maStack.back();
-        if( rContextInfo.second.is() )
-            rContextInfo.second->endRecord( rContextInfo.first.mnStartRecId );
-        maStack.pop_back();
+        ContextEntry& rEntry = maEntries.top();
+        if( rEntry.second.is() )
+            rEntry.second->endRecord( rEntry.first.mnOpenContextId );
+        maEntries.pop();
     }
 }
 
-} // namespace prv
-
 // ============================================================================
 
-namespace {
+/** Parser state for every binary record stream to be parsed. */
+struct RecordParserEntity
+{
+    RecordHandlerRef    mxRecordHandler;    /// Handler that reads the record headers.
+    FragmentHandlerRef  mxDocHandler;       /// The document handler and root context.
+    InputSource         maInputSource;      /// The input source with the input stream.
+    BinaryInputStreamRef mxInStream;        /// The wrapper for the UNO input stream in maInputSource.
+    ContextStack        maContextStack;     /// The stack of open record contexts.
+    RecordHeader        maRecordHeader;     /// Record header with record identifier and body size.
+    StreamDataSequence  maRecordBody;       /// Data sequence containing the body of the current record.
 
-/** Reads a byte from the passed stream, returns true on success. */
-inline bool lclReadByte( sal_uInt8& ornByte, BinaryInputStream& rStrm )
+    explicit            RecordParserEntity(
+                            const RecordHandlerRef& rxRecordHandler,
+                            const FragmentHandlerRef& rxDocHandler,
+                            const InputSource& rInputSource );
+
+    bool                readRecord();
+};
+
+// ----------------------------------------------------------------------------
+
+RecordParserEntity::RecordParserEntity( const RecordHandlerRef& rxRecordHandler, const FragmentHandlerRef& rxDocHandler, const InputSource& rInputSource ) :
+    mxRecordHandler( rxRecordHandler ),
+    mxDocHandler( rxDocHandler ),
+    maInputSource( rInputSource ),
+    mxInStream( new BinaryXInputStream( rInputSource.aInputStream, false ) ),
+    maContextStack( rxDocHandler )
 {
-    return rStrm.readMemory( &ornByte, 1 ) == 1;
 }
 
-/** Reads a compressed signed 32-bit integer from the passed stream. */
-bool lclReadCompressedInt( sal_Int32& ornValue, BinaryInputStream& rStrm )
+bool RecordParserEntity::readRecord()
 {
-    ornValue = 0;
-    sal_uInt8 nByte;
-    if( !lclReadByte( nByte, rStrm ) ) return false;
-    ornValue = nByte & 0x7F;
-    if( (nByte & 0x80) == 0 ) return true;
-    if( !lclReadByte( nByte, rStrm ) ) return false;
-    ornValue |= sal_Int32( nByte & 0x7F ) << 7;
-    if( (nByte & 0x80) == 0 ) return true;
-    if( !lclReadByte( nByte, rStrm ) ) return false;
-    ornValue |= sal_Int32( nByte & 0x7F ) << 14;
-    if( (nByte & 0x80) == 0 ) return true;
-    if( !lclReadByte( nByte, rStrm ) ) return false;
-    ornValue |= sal_Int32( nByte & 0x7F ) << 21;
-    return true;
-}
-
-bool lclReadRecordHeader( sal_Int32& ornRecId, sal_Int32& ornRecSize, BinaryInputStream& rStrm )
-{
-    return
-        lclReadCompressedInt( ornRecId, rStrm ) && (ornRecId >= 0) &&
-        lclReadCompressedInt( ornRecSize, rStrm ) && (ornRecSize >= 0);
-}
-
-bool lclReadNextRecord( sal_Int32& ornRecId, StreamDataSequence& orData, BinaryInputStream& rStrm )
-{
-    sal_Int32 nRecSize = 0;
-    bool bValid = lclReadRecordHeader( ornRecId, nRecSize, rStrm );
+    bool bValid = mxRecordHandler->readRecordHeader( *mxInStream, maRecordHeader );
+    OSL_ENSURE( maRecordHeader.mnBodySize >= 0, "RecordParserEntity::readRecord - invalid record body size" );
     if( bValid )
     {
-        orData.realloc( nRecSize );
-        bValid = (nRecSize == 0) || (rStrm.readData( orData, nRecSize ) == nRecSize);
+        maRecordBody.realloc( maRecordHeader.mnBodySize );
+        bValid = (maRecordHeader.mnBodySize == 0) ||
+            (mxInStream->readData( maRecordBody, maRecordHeader.mnBodySize ) == maRecordHeader.mnBodySize);
     }
     return bValid;
 }
 
 // ============================================================================
 
-RecordParser::RecordParser()
+namespace { class Locator; }
+
+struct RecordParserImpl
 {
-    mxLocator.set( new prv::Locator( this ) );
+    typedef ::std::stack< RecordParserEntity > ParserEntityStack;
+
+    ::rtl::Reference< Locator > mxLocator;  /// The locator that will be set at all fragment handlers.
+    ParserEntityStack   maEntities;         /// Stack of active entities (one per call of parseStream()).
+    RecordHandlerRef    mxRecordHandler;    /// Handler that reads record headers and provides context information.
+    FragmentHandlerRef  mxDocHandler;       /// Stores the fragment handler to be used in the next call of parseStream().
+
+    explicit            RecordParserImpl();
+                        ~RecordParserImpl();
+};
+
+// ============================================================================
+
+namespace {
+
+/** Implementation of the com.sun.star.xml.sax.XLocator interface for a record
+    parser.
+ */
+class Locator : public ::cppu::WeakImplHelper1< XLocator >
+{
+public:
+    inline explicit         Locator( RecordParserImpl* pParser ) : mpParser( pParser ) {}
+
+    void                    dispose();
+
+    // com.sun.star.sax.XLocator interface
+
+    virtual sal_Int32 SAL_CALL getColumnNumber() throw (RuntimeException);
+    virtual sal_Int32 SAL_CALL getLineNumber() throw (RuntimeException);
+    virtual OUString SAL_CALL getPublicId() throw (RuntimeException);
+    virtual OUString SAL_CALL getSystemId() throw (RuntimeException);
+
+private:
+    RecordParserEntity&     getEntity() throw (RuntimeException);
+
+    ::osl::Mutex            maMutex;
+    RecordParserImpl*       mpParser;
+};
+
+// ----------------------------------------------------------------------------
+
+void Locator::dispose()
+{
+    ::osl::MutexGuard aGuard( maMutex );
+    mpParser = 0;
+}
+
+sal_Int32 SAL_CALL Locator::getColumnNumber() throw (RuntimeException)
+{
+    ::osl::MutexGuard aGuard( maMutex );
+    return -1;
+}
+
+sal_Int32 SAL_CALL Locator::getLineNumber() throw (RuntimeException)
+{
+    ::osl::MutexGuard aGuard( maMutex );
+    return -1;
+}
+
+OUString SAL_CALL Locator::getPublicId() throw (RuntimeException)
+{
+    ::osl::MutexGuard aGuard( maMutex );
+    return getEntity().maInputSource.sPublicId;
+}
+
+OUString SAL_CALL Locator::getSystemId() throw (RuntimeException)
+{
+    ::osl::MutexGuard aGuard( maMutex );
+    return getEntity().maInputSource.sSystemId;
+}
+
+RecordParserEntity& Locator::getEntity() throw (RuntimeException)
+{
+    if( !mpParser )
+        throw RuntimeException( CREATE_OUSTRING( "Locator is already disposed." ), 0 );
+    if( mpParser->maEntities.empty() )
+        throw RuntimeException( CREATE_OUSTRING( "No stream is parsed currently." ), 0 );
+    return mpParser->maEntities.top();
+}
+
+// ============================================================================
+
+/** On construction, pushes a new entity onto the entity stack of the passed
+    record parser. On destruction, pops the topmost entity from stack.
+ */
+class EntityStackGuard
+{
+public:
+    explicit            EntityStackGuard( RecordParserImpl& rParser, const InputSource& rInputSource );
+    inline              ~EntityStackGuard() { mrParser.maEntities.pop(); }
+
+    inline RecordParserEntity& getEntity() { return mrParser.maEntities.top(); }
+
+private:
+    RecordParserImpl&   mrParser;
+};
+
+// ----------------------------------------------------------------------------
+
+EntityStackGuard::EntityStackGuard( RecordParserImpl& rParser, const InputSource& rInputSource ) :
+    mrParser( rParser )
+{
+    mrParser.maEntities.push( RecordParserEntity( mrParser.mxRecordHandler, mrParser.mxDocHandler, rInputSource ) );
+}
+
+} // namespace
+
+// ============================================================================
+
+RecordParserImpl::RecordParserImpl() :
+    mxLocator( new Locator( this ) )
+{
+}
+
+RecordParserImpl::~RecordParserImpl()
+{
+    mxLocator->dispose();
+}
+
+// ============================================================================
+
+RecordParser::RecordParser() :
+    mxImpl( new RecordParserImpl )
+{
 }
 
 RecordParser::~RecordParser()
 {
-    if( mxLocator.is() )
-        mxLocator->dispose();
 }
 
-void RecordParser::setFragmentHandler( const ::rtl::Reference< FragmentHandler >& rxHandler )
+void RecordParser::setRecordHandler( const RecordHandlerRef& rxRecordHandler ) throw (RuntimeException)
 {
-    mxHandler = rxHandler;
-
-    // build record infos
-    maStartMap.clear();
-    maEndMap.clear();
-    const RecordInfo* pRecs = mxHandler.is() ? mxHandler->getRecordInfos() : 0;
-    OSL_ENSURE( pRecs, "RecordInfoProvider::RecordInfoProvider - missing record list" );
-    for( ; pRecs && pRecs->mnStartRecId >= 0; ++pRecs )
-    {
-        maStartMap[ pRecs->mnStartRecId ] = *pRecs;
-        if( pRecs->mnEndRecId >= 0 )
-            maEndMap[ pRecs->mnEndRecId ] = *pRecs;
-    }
+    if( !mxImpl->maEntities.empty() )
+        throw RuntimeException( CREATE_OUSTRING( "Parser is running already." ), 0 );
+    if( !rxRecordHandler.is() )
+        throw RuntimeException( CREATE_OUSTRING( "Missing record handler." ), 0 );
+    mxImpl->mxRecordHandler = rxRecordHandler;
 }
 
-void RecordParser::parseStream( const RecordInputSource& rInputSource ) throw( SAXException, IOException, RuntimeException )
+void RecordParser::setDocumentHandler( const FragmentHandlerRef& rxDocumentHandler ) throw (RuntimeException)
 {
-    maSource = rInputSource;
+    if( !rxDocumentHandler.is() )
+        throw RuntimeException( CREATE_OUSTRING( "Missing document handler." ), 0 );
+    mxImpl->mxDocHandler = rxDocumentHandler;
+}
 
-    if( !maSource.mxInStream || maSource.mxInStream->isEof() )
-        throw IOException();
-    if( !mxHandler.is() )
-        throw SAXException();
+void RecordParser::parseStream( const InputSource& rInputSource ) throw (SAXException, IOException, RuntimeException)
+{
+    // check preconditions
+    if( !mxImpl->mxRecordHandler.is() )
+        throw RuntimeException( CREATE_OUSTRING( "Missing record handler." ), 0 );
+    if( !mxImpl->mxDocHandler.is() )
+        throw RuntimeException( CREATE_OUSTRING( "Missing document handler." ), 0 );
+    if( !rInputSource.aInputStream.is() )
+        throw IOException( CREATE_OUSTRING( "Missing input stream." ), 0 );
+
+    // push an entity onto the entity stack, the guard makes it exception-save
+    EntityStackGuard aGuard( *mxImpl, rInputSource );
+    RecordParserEntity& rEntity = aGuard.getEntity();
 
     // start the document
-    Reference< XLocator > xLocator( mxLocator.get() );
-    mxHandler->setDocumentLocator( xLocator );
-    mxHandler->startDocument();
+    Reference< XLocator > xLocator( mxImpl->mxLocator.get() );
+    rEntity.mxDocHandler->setDocumentLocator( xLocator );
+    rEntity.mxDocHandler->startDocument();
 
     // parse the stream
-    mxStack.reset( new prv::ContextStack( mxHandler ) );
-    sal_Int32 nRecId = 0;
-    StreamDataSequence aRecData;
-    while( lclReadNextRecord( nRecId, aRecData, *maSource.mxInStream ) )
+    ContextStack& rContextStack = rEntity.maContextStack;
+    while( rEntity.readRecord() )
     {
+        sal_Int32 nRecId = rEntity.maRecordHeader.mnIdentifier;
         // create record stream object from imported record data
-        SequenceInputStream aRecStrm( aRecData );
+        SequenceInputStream aRecStrm( rEntity.maRecordBody );
         // try to leave a context, there may be other incomplete contexts on the stack
-        if( const RecordInfo* pEndRecInfo = getEndRecordInfo( nRecId ) )
+        if( const RecordContextInfo* pCloseContextInfo = rEntity.mxRecordHandler->getCloseContextInfo( nRecId ) )
         {
-            // finalize contexts without record identifier for context end
-            while( !mxStack->empty() && !mxStack->hasCurrentEndRecId() )
-                mxStack->popContext();
             // finalize the current context and pop context info from stack
-            OSL_ENSURE( mxStack->getCurrentRecId() == pEndRecInfo->mnStartRecId, "RecordParser::parseStream - context records mismatch" );
-            (void)pEndRecInfo;  // suppress compiler warning for unused variable
-            ContextHandlerRef xCurrContext = mxStack->getCurrentContext();
+            OSL_ENSURE( rContextStack.getCurrentRecId() == pCloseContextInfo->mnOpenContextId, "RecordParser::parseStream - context records mismatch" );
+            (void)pCloseContextInfo;  // suppress compiler warning for unused variable
+            ContextHandlerRef xCurrContext = rContextStack.getCurrentContext();
             if( xCurrContext.is() )
             {
                 // context end record may contain some data, handle it as simple record
                 xCurrContext->startRecord( nRecId, aRecStrm );
                 xCurrContext->endRecord( nRecId );
             }
-            mxStack->popContext();
+            rContextStack.popContext();
         }
         else
         {
-            // end context with incomplete record id, if the same id comes again
-            if( (mxStack->getCurrentRecId() == nRecId) && !mxStack->hasCurrentEndRecId() )
-                mxStack->popContext();
             // try to start a new context
-            ContextHandlerRef xCurrContext = mxStack->getCurrentContext();
+            ContextHandlerRef xCurrContext = rContextStack.getCurrentContext();
             if( xCurrContext.is() )
             {
                 aRecStrm.seekToStart();
                 xCurrContext = xCurrContext->createRecordContext( nRecId, aRecStrm );
             }
             // track all context identifiers on the stack (do not push simple records)
-            const RecordInfo* pStartRecInfo = getStartRecordInfo( nRecId );
-            if( pStartRecInfo )
-                mxStack->pushContext( *pStartRecInfo, xCurrContext );
+            const RecordContextInfo* pOpenContextInfo = rEntity.mxRecordHandler->getOpenContextInfo( nRecId );
+            if( pOpenContextInfo )
+                rContextStack.pushContext( *pOpenContextInfo, xCurrContext );
             // import the record
             if( xCurrContext.is() )
             {
                 aRecStrm.seekToStart();
                 xCurrContext->startRecord( nRecId, aRecStrm );
                 // end simple records (context records are finished in ContextStack::popContext)
-                if( !pStartRecInfo )
+                if( !pOpenContextInfo )
                     xCurrContext->endRecord( nRecId );
             }
         }
     }
     // close remaining contexts (missing context end records or stream error)
-    while( !mxStack->empty() )
-        mxStack->popContext();
-    mxStack.reset();
+    while( !rContextStack.empty() )
+        rContextStack.popContext();
 
     // finish document
-    mxHandler->endDocument();
-
-    maSource = RecordInputSource();
+    rEntity.mxDocHandler->endDocument();
 }
 
-const RecordInfo* RecordParser::getStartRecordInfo( sal_Int32 nRecId ) const
+
+void RecordParser::parseStream( const Reference< XInputStream >& rxInStream, const OUString& rStreamName ) throw (SAXException, IOException, RuntimeException)
 {
-    RecordInfoMap::const_iterator aIt = maStartMap.find( nRecId );
-    return (aIt == maStartMap.end()) ? 0 : &aIt->second;
+    InputSource aInputSource;
+    aInputSource.aInputStream = rxInStream;
+    aInputSource.sSystemId = rStreamName;
+    parseStream( aInputSource );
 }
 
-const RecordInfo* RecordParser::getEndRecordInfo( sal_Int32 nRecId ) const
+void RecordParser::parseStream( StorageBase& rStorage, const OUString& rStreamName, bool bCloseStream ) throw (SAXException, IOException, RuntimeException)
 {
-    RecordInfoMap::const_iterator aIt = maEndMap.find( nRecId );
-    return (aIt == maEndMap.end()) ? 0 : &aIt->second;
+    Reference< XInputStream > xInStrm = rStorage.openInputStream( rStreamName );
+    XInputStreamCloseGuard aGuard( xInStrm, bCloseStream );
+    parseStream( xInStrm, rStreamName );
 }
 
 // ============================================================================

oox/source/core/relationshandler.cxx

         }
         break;
         case PR_TOKEN( Relationships ):
-            xRet = getFastContextHandler();
+            xRet.set( (ContextHandler*)this );
         break;
     }
     return xRet;

oox/source/core/xmlfilterbase.cxx

 #include "oox/core/fastparser.hxx"
 #include "oox/core/filterdetect.hxx"
 #include "oox/core/fragmenthandler.hxx"
+#include "oox/core/recordhandler.hxx"
 #include "oox/core/recordparser.hxx"
 #include "oox/core/relationshandler.hxx"
 #include "oox/helper/containerhelper.hxx"
     typedef RefMap< OUString, Relations > RelationsMap;
 
     FastParser          maFastParser;
+    RecordParser        maRecordParser;
     const OUString      maBinSuffix;
     const OUString      maVmlSuffix;
     RelationsMap        maRelationsMap;
     TextFieldStack      maTextFieldStack;
 
-    explicit            XmlFilterBaseImpl( const Reference< XComponentContext >& rxContext ) throw( RuntimeException );
+    explicit            XmlFilterBaseImpl( const Reference< XComponentContext >& rxContext )
+                            throw( RuntimeException );
 };
 
 // ----------------------------------------------------------------------------
     return importRelations( OUString() )->getFragmentPathFromFirstType( rType );
 }
 
+void XmlFilterBase::setRecordHandler( const ::rtl::Reference< RecordHandler >& rxRecordHandler )
+{
+    try
+    {
+        mxImpl->maRecordParser.setRecordHandler( rxRecordHandler );
+    }
+    catch( Exception& )
+    {
+        OSL_ENSU