xref: /trunk/main/oox/source/core/recordparser.cxx (revision ca5ec200)
1*ca5ec200SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*ca5ec200SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*ca5ec200SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*ca5ec200SAndrew Rist  * distributed with this work for additional information
6*ca5ec200SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*ca5ec200SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*ca5ec200SAndrew Rist  * "License"); you may not use this file except in compliance
9*ca5ec200SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*ca5ec200SAndrew Rist  *
11*ca5ec200SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*ca5ec200SAndrew Rist  *
13*ca5ec200SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*ca5ec200SAndrew Rist  * software distributed under the License is distributed on an
15*ca5ec200SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*ca5ec200SAndrew Rist  * KIND, either express or implied.  See the License for the
17*ca5ec200SAndrew Rist  * specific language governing permissions and limitations
18*ca5ec200SAndrew Rist  * under the License.
19*ca5ec200SAndrew Rist  *
20*ca5ec200SAndrew Rist  *************************************************************/
21*ca5ec200SAndrew Rist 
22*ca5ec200SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #include "oox/core/recordparser.hxx"
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #include <vector>
27cdf0e10cSrcweir #include <com/sun/star/lang/DisposedException.hpp>
28cdf0e10cSrcweir #include <com/sun/star/xml/sax/XLocator.hpp>
29cdf0e10cSrcweir #include <cppuhelper/implbase1.hxx>
30cdf0e10cSrcweir #include "oox/core/fragmenthandler.hxx"
31cdf0e10cSrcweir 
32cdf0e10cSrcweir namespace oox {
33cdf0e10cSrcweir namespace core {
34cdf0e10cSrcweir 
35cdf0e10cSrcweir // ============================================================================
36cdf0e10cSrcweir 
37cdf0e10cSrcweir using namespace ::com::sun::star::io;
38cdf0e10cSrcweir using namespace ::com::sun::star::lang;
39cdf0e10cSrcweir using namespace ::com::sun::star::uno;
40cdf0e10cSrcweir using namespace ::com::sun::star::xml::sax;
41cdf0e10cSrcweir 
42cdf0e10cSrcweir using ::rtl::OUString;
43cdf0e10cSrcweir 
44cdf0e10cSrcweir // ============================================================================
45cdf0e10cSrcweir 
46cdf0e10cSrcweir namespace prv {
47cdf0e10cSrcweir 
48cdf0e10cSrcweir class Locator : public ::cppu::WeakImplHelper1< XLocator >
49cdf0e10cSrcweir {
50cdf0e10cSrcweir public:
Locator(RecordParser * pParser)51cdf0e10cSrcweir     inline explicit         Locator( RecordParser* pParser ) : mpParser( pParser ) {}
52cdf0e10cSrcweir 
53cdf0e10cSrcweir     void                    dispose();
54cdf0e10cSrcweir     void                    checkDispose() throw( RuntimeException );
55cdf0e10cSrcweir 
56cdf0e10cSrcweir     // com.sun.star.sax.XLocator interface
57cdf0e10cSrcweir 
58cdf0e10cSrcweir     virtual sal_Int32 SAL_CALL getColumnNumber() throw( RuntimeException );
59cdf0e10cSrcweir     virtual sal_Int32 SAL_CALL getLineNumber() throw( RuntimeException );
60cdf0e10cSrcweir     virtual OUString SAL_CALL getPublicId() throw( RuntimeException );
61cdf0e10cSrcweir     virtual OUString SAL_CALL getSystemId() throw( RuntimeException );
62cdf0e10cSrcweir 
63cdf0e10cSrcweir private:
64cdf0e10cSrcweir     RecordParser*           mpParser;
65cdf0e10cSrcweir };
66cdf0e10cSrcweir 
67cdf0e10cSrcweir // ----------------------------------------------------------------------------
68cdf0e10cSrcweir 
dispose()69cdf0e10cSrcweir void Locator::dispose()
70cdf0e10cSrcweir {
71cdf0e10cSrcweir     mpParser = 0;
72cdf0e10cSrcweir }
73cdf0e10cSrcweir 
checkDispose()74cdf0e10cSrcweir void Locator::checkDispose() throw( RuntimeException )
75cdf0e10cSrcweir {
76cdf0e10cSrcweir     if( !mpParser )
77cdf0e10cSrcweir         throw DisposedException();
78cdf0e10cSrcweir }
79cdf0e10cSrcweir 
getColumnNumber()80cdf0e10cSrcweir sal_Int32 SAL_CALL Locator::getColumnNumber() throw( RuntimeException )
81cdf0e10cSrcweir {
82cdf0e10cSrcweir     return -1;
83cdf0e10cSrcweir }
84cdf0e10cSrcweir 
getLineNumber()85cdf0e10cSrcweir sal_Int32 SAL_CALL Locator::getLineNumber() throw( RuntimeException )
86cdf0e10cSrcweir {
87cdf0e10cSrcweir     return -1;
88cdf0e10cSrcweir }
89cdf0e10cSrcweir 
getPublicId()90cdf0e10cSrcweir OUString SAL_CALL Locator::getPublicId() throw( RuntimeException )
91cdf0e10cSrcweir {
92cdf0e10cSrcweir     checkDispose();
93cdf0e10cSrcweir     return mpParser->getInputSource().maPublicId;
94cdf0e10cSrcweir }
95cdf0e10cSrcweir 
getSystemId()96cdf0e10cSrcweir OUString SAL_CALL Locator::getSystemId() throw( RuntimeException )
97cdf0e10cSrcweir {
98cdf0e10cSrcweir     checkDispose();
99cdf0e10cSrcweir     return mpParser->getInputSource().maSystemId;
100cdf0e10cSrcweir }
101cdf0e10cSrcweir 
102cdf0e10cSrcweir // ============================================================================
103cdf0e10cSrcweir 
104cdf0e10cSrcweir class ContextStack
105cdf0e10cSrcweir {
106cdf0e10cSrcweir public:
107cdf0e10cSrcweir     explicit            ContextStack( FragmentHandlerRef xHandler );
108cdf0e10cSrcweir 
empty() const109cdf0e10cSrcweir     inline bool         empty() const { return maStack.empty(); }
110cdf0e10cSrcweir 
111cdf0e10cSrcweir     sal_Int32           getCurrentRecId() const;
112cdf0e10cSrcweir     bool                hasCurrentEndRecId() const;
113cdf0e10cSrcweir     ContextHandlerRef   getCurrentContext() const;
114cdf0e10cSrcweir 
115cdf0e10cSrcweir     void                pushContext( const RecordInfo& rRec, const ContextHandlerRef& rxContext );
116cdf0e10cSrcweir     void                popContext();
117cdf0e10cSrcweir 
118cdf0e10cSrcweir private:
119cdf0e10cSrcweir     typedef ::std::pair< RecordInfo, ContextHandlerRef >    ContextInfo;
120cdf0e10cSrcweir     typedef ::std::vector< ContextInfo >                    ContextInfoVec;
121cdf0e10cSrcweir 
122cdf0e10cSrcweir     FragmentHandlerRef  mxHandler;
123cdf0e10cSrcweir     ContextInfoVec      maStack;
124cdf0e10cSrcweir };
125cdf0e10cSrcweir 
126cdf0e10cSrcweir // ----------------------------------------------------------------------------
127cdf0e10cSrcweir 
ContextStack(FragmentHandlerRef xHandler)128cdf0e10cSrcweir ContextStack::ContextStack( FragmentHandlerRef xHandler ) :
129cdf0e10cSrcweir     mxHandler( xHandler )
130cdf0e10cSrcweir {
131cdf0e10cSrcweir }
132cdf0e10cSrcweir 
getCurrentRecId() const133cdf0e10cSrcweir sal_Int32 ContextStack::getCurrentRecId() const
134cdf0e10cSrcweir {
135cdf0e10cSrcweir     return maStack.empty() ? -1 : maStack.back().first.mnStartRecId;
136cdf0e10cSrcweir }
137cdf0e10cSrcweir 
hasCurrentEndRecId() const138cdf0e10cSrcweir bool ContextStack::hasCurrentEndRecId() const
139cdf0e10cSrcweir {
140cdf0e10cSrcweir     return !maStack.empty() && (maStack.back().first.mnEndRecId >= 0);
141cdf0e10cSrcweir }
142cdf0e10cSrcweir 
getCurrentContext() const143cdf0e10cSrcweir ContextHandlerRef ContextStack::getCurrentContext() const
144cdf0e10cSrcweir {
145cdf0e10cSrcweir     if( !maStack.empty() )
146cdf0e10cSrcweir         return maStack.back().second;
147cdf0e10cSrcweir     return mxHandler.get();
148cdf0e10cSrcweir }
149cdf0e10cSrcweir 
pushContext(const RecordInfo & rRecInfo,const ContextHandlerRef & rxContext)150cdf0e10cSrcweir void ContextStack::pushContext( const RecordInfo& rRecInfo, const ContextHandlerRef& rxContext )
151cdf0e10cSrcweir {
152cdf0e10cSrcweir     OSL_ENSURE( (rRecInfo.mnEndRecId >= 0) || maStack.empty() || hasCurrentEndRecId(),
153cdf0e10cSrcweir         "ContextStack::pushContext - nested incomplete context record identifiers" );
154cdf0e10cSrcweir     maStack.push_back( ContextInfo( rRecInfo, rxContext ) );
155cdf0e10cSrcweir }
156cdf0e10cSrcweir 
popContext()157cdf0e10cSrcweir void ContextStack::popContext()
158cdf0e10cSrcweir {
159cdf0e10cSrcweir     OSL_ENSURE( !maStack.empty(), "ContextStack::popContext - no context on stack" );
160cdf0e10cSrcweir     if( !maStack.empty() )
161cdf0e10cSrcweir     {
162cdf0e10cSrcweir         ContextInfo& rContextInfo = maStack.back();
163cdf0e10cSrcweir         if( rContextInfo.second.is() )
164cdf0e10cSrcweir             rContextInfo.second->endRecord( rContextInfo.first.mnStartRecId );
165cdf0e10cSrcweir         maStack.pop_back();
166cdf0e10cSrcweir     }
167cdf0e10cSrcweir }
168cdf0e10cSrcweir 
169cdf0e10cSrcweir } // namespace prv
170cdf0e10cSrcweir 
171cdf0e10cSrcweir // ============================================================================
172cdf0e10cSrcweir 
173cdf0e10cSrcweir namespace {
174cdf0e10cSrcweir 
175cdf0e10cSrcweir /** Reads a byte from the passed stream, returns true on success. */
lclReadByte(sal_uInt8 & ornByte,BinaryInputStream & rStrm)176cdf0e10cSrcweir inline bool lclReadByte( sal_uInt8& ornByte, BinaryInputStream& rStrm )
177cdf0e10cSrcweir {
178cdf0e10cSrcweir     return rStrm.readMemory( &ornByte, 1 ) == 1;
179cdf0e10cSrcweir }
180cdf0e10cSrcweir 
181cdf0e10cSrcweir /** Reads a compressed signed 32-bit integer from the passed stream. */
lclReadCompressedInt(sal_Int32 & ornValue,BinaryInputStream & rStrm)182cdf0e10cSrcweir bool lclReadCompressedInt( sal_Int32& ornValue, BinaryInputStream& rStrm )
183cdf0e10cSrcweir {
184cdf0e10cSrcweir     ornValue = 0;
185cdf0e10cSrcweir     sal_uInt8 nByte;
186cdf0e10cSrcweir     if( !lclReadByte( nByte, rStrm ) ) return false;
187cdf0e10cSrcweir     ornValue = nByte & 0x7F;
188cdf0e10cSrcweir     if( (nByte & 0x80) == 0 ) return true;
189cdf0e10cSrcweir     if( !lclReadByte( nByte, rStrm ) ) return false;
190cdf0e10cSrcweir     ornValue |= sal_Int32( nByte & 0x7F ) << 7;
191cdf0e10cSrcweir     if( (nByte & 0x80) == 0 ) return true;
192cdf0e10cSrcweir     if( !lclReadByte( nByte, rStrm ) ) return false;
193cdf0e10cSrcweir     ornValue |= sal_Int32( nByte & 0x7F ) << 14;
194cdf0e10cSrcweir     if( (nByte & 0x80) == 0 ) return true;
195cdf0e10cSrcweir     if( !lclReadByte( nByte, rStrm ) ) return false;
196cdf0e10cSrcweir     ornValue |= sal_Int32( nByte & 0x7F ) << 21;
197cdf0e10cSrcweir     return true;
198cdf0e10cSrcweir }
199cdf0e10cSrcweir 
lclReadRecordHeader(sal_Int32 & ornRecId,sal_Int32 & ornRecSize,BinaryInputStream & rStrm)200cdf0e10cSrcweir bool lclReadRecordHeader( sal_Int32& ornRecId, sal_Int32& ornRecSize, BinaryInputStream& rStrm )
201cdf0e10cSrcweir {
202cdf0e10cSrcweir     return
203cdf0e10cSrcweir         lclReadCompressedInt( ornRecId, rStrm ) && (ornRecId >= 0) &&
204cdf0e10cSrcweir         lclReadCompressedInt( ornRecSize, rStrm ) && (ornRecSize >= 0);
205cdf0e10cSrcweir }
206cdf0e10cSrcweir 
lclReadNextRecord(sal_Int32 & ornRecId,StreamDataSequence & orData,BinaryInputStream & rStrm)207cdf0e10cSrcweir bool lclReadNextRecord( sal_Int32& ornRecId, StreamDataSequence& orData, BinaryInputStream& rStrm )
208cdf0e10cSrcweir {
209cdf0e10cSrcweir     sal_Int32 nRecSize = 0;
210cdf0e10cSrcweir     bool bValid = lclReadRecordHeader( ornRecId, nRecSize, rStrm );
211cdf0e10cSrcweir     if( bValid )
212cdf0e10cSrcweir     {
213cdf0e10cSrcweir         orData.realloc( nRecSize );
214cdf0e10cSrcweir         bValid = (nRecSize == 0) || (rStrm.readData( orData, nRecSize ) == nRecSize);
215cdf0e10cSrcweir     }
216cdf0e10cSrcweir     return bValid;
217cdf0e10cSrcweir }
218cdf0e10cSrcweir 
219cdf0e10cSrcweir } // namespace
220cdf0e10cSrcweir 
221cdf0e10cSrcweir // ============================================================================
222cdf0e10cSrcweir 
RecordParser()223cdf0e10cSrcweir RecordParser::RecordParser()
224cdf0e10cSrcweir {
225cdf0e10cSrcweir     mxLocator.set( new prv::Locator( this ) );
226cdf0e10cSrcweir }
227cdf0e10cSrcweir 
~RecordParser()228cdf0e10cSrcweir RecordParser::~RecordParser()
229cdf0e10cSrcweir {
230cdf0e10cSrcweir     if( mxLocator.is() )
231cdf0e10cSrcweir         mxLocator->dispose();
232cdf0e10cSrcweir }
233cdf0e10cSrcweir 
setFragmentHandler(const::rtl::Reference<FragmentHandler> & rxHandler)234cdf0e10cSrcweir void RecordParser::setFragmentHandler( const ::rtl::Reference< FragmentHandler >& rxHandler )
235cdf0e10cSrcweir {
236cdf0e10cSrcweir     mxHandler = rxHandler;
237cdf0e10cSrcweir 
238cdf0e10cSrcweir     // build record infos
239cdf0e10cSrcweir     maStartMap.clear();
240cdf0e10cSrcweir     maEndMap.clear();
241cdf0e10cSrcweir     const RecordInfo* pRecs = mxHandler.is() ? mxHandler->getRecordInfos() : 0;
242cdf0e10cSrcweir     OSL_ENSURE( pRecs, "RecordInfoProvider::RecordInfoProvider - missing record list" );
243cdf0e10cSrcweir     for( ; pRecs && pRecs->mnStartRecId >= 0; ++pRecs )
244cdf0e10cSrcweir     {
245cdf0e10cSrcweir         maStartMap[ pRecs->mnStartRecId ] = *pRecs;
246cdf0e10cSrcweir         if( pRecs->mnEndRecId >= 0 )
247cdf0e10cSrcweir             maEndMap[ pRecs->mnEndRecId ] = *pRecs;
248cdf0e10cSrcweir     }
249cdf0e10cSrcweir }
250cdf0e10cSrcweir 
parseStream(const RecordInputSource & rInputSource)251cdf0e10cSrcweir void RecordParser::parseStream( const RecordInputSource& rInputSource ) throw( SAXException, IOException, RuntimeException )
252cdf0e10cSrcweir {
253cdf0e10cSrcweir     maSource = rInputSource;
254cdf0e10cSrcweir 
255cdf0e10cSrcweir     if( !maSource.mxInStream || maSource.mxInStream->isEof() )
256cdf0e10cSrcweir         throw IOException();
257cdf0e10cSrcweir     if( !mxHandler.is() )
258cdf0e10cSrcweir         throw SAXException();
259cdf0e10cSrcweir 
260cdf0e10cSrcweir     // start the document
261cdf0e10cSrcweir     Reference< XLocator > xLocator( mxLocator.get() );
262cdf0e10cSrcweir     mxHandler->setDocumentLocator( xLocator );
263cdf0e10cSrcweir     mxHandler->startDocument();
264cdf0e10cSrcweir 
265cdf0e10cSrcweir     // parse the stream
266cdf0e10cSrcweir     mxStack.reset( new prv::ContextStack( mxHandler ) );
267cdf0e10cSrcweir     sal_Int32 nRecId = 0;
268cdf0e10cSrcweir     StreamDataSequence aRecData;
269cdf0e10cSrcweir     while( lclReadNextRecord( nRecId, aRecData, *maSource.mxInStream ) )
270cdf0e10cSrcweir     {
271cdf0e10cSrcweir         // create record stream object from imported record data
272cdf0e10cSrcweir         SequenceInputStream aRecStrm( aRecData );
273cdf0e10cSrcweir         // try to leave a context, there may be other incomplete contexts on the stack
274cdf0e10cSrcweir         if( const RecordInfo* pEndRecInfo = getEndRecordInfo( nRecId ) )
275cdf0e10cSrcweir         {
276cdf0e10cSrcweir             // finalize contexts without record identifier for context end
277cdf0e10cSrcweir             while( !mxStack->empty() && !mxStack->hasCurrentEndRecId() )
278cdf0e10cSrcweir                 mxStack->popContext();
279cdf0e10cSrcweir             // finalize the current context and pop context info from stack
280cdf0e10cSrcweir             OSL_ENSURE( mxStack->getCurrentRecId() == pEndRecInfo->mnStartRecId, "RecordParser::parseStream - context records mismatch" );
281cdf0e10cSrcweir             (void)pEndRecInfo;  // suppress compiler warning for unused variable
282cdf0e10cSrcweir             ContextHandlerRef xCurrContext = mxStack->getCurrentContext();
283cdf0e10cSrcweir             if( xCurrContext.is() )
284cdf0e10cSrcweir             {
285cdf0e10cSrcweir                 // context end record may contain some data, handle it as simple record
286cdf0e10cSrcweir                 aRecStrm.seekToStart();
287cdf0e10cSrcweir                 xCurrContext->startRecord( nRecId, aRecStrm );
288cdf0e10cSrcweir                 xCurrContext->endRecord( nRecId );
289cdf0e10cSrcweir             }
290cdf0e10cSrcweir             mxStack->popContext();
291cdf0e10cSrcweir         }
292cdf0e10cSrcweir         else
293cdf0e10cSrcweir         {
294cdf0e10cSrcweir             // end context with incomplete record id, if the same id comes again
295cdf0e10cSrcweir             if( (mxStack->getCurrentRecId() == nRecId) && !mxStack->hasCurrentEndRecId() )
296cdf0e10cSrcweir                 mxStack->popContext();
297cdf0e10cSrcweir             // try to start a new context
298cdf0e10cSrcweir             ContextHandlerRef xCurrContext = mxStack->getCurrentContext();
299cdf0e10cSrcweir             if( xCurrContext.is() )
300cdf0e10cSrcweir             {
301cdf0e10cSrcweir                 aRecStrm.seekToStart();
302cdf0e10cSrcweir                 xCurrContext = xCurrContext->createRecordContext( nRecId, aRecStrm );
303cdf0e10cSrcweir             }
304cdf0e10cSrcweir             // track all context identifiers on the stack (do not push simple records)
305cdf0e10cSrcweir             const RecordInfo* pStartRecInfo = getStartRecordInfo( nRecId );
306cdf0e10cSrcweir             if( pStartRecInfo )
307cdf0e10cSrcweir                 mxStack->pushContext( *pStartRecInfo, xCurrContext );
308cdf0e10cSrcweir             // import the record
309cdf0e10cSrcweir             if( xCurrContext.is() )
310cdf0e10cSrcweir             {
311cdf0e10cSrcweir                 // import the record
312cdf0e10cSrcweir                 aRecStrm.seekToStart();
313cdf0e10cSrcweir                 xCurrContext->startRecord( nRecId, aRecStrm );
314cdf0e10cSrcweir                 // end simple records (context records are finished in ContextStack::popContext)
315cdf0e10cSrcweir                 if( !pStartRecInfo )
316cdf0e10cSrcweir                     xCurrContext->endRecord( nRecId );
317cdf0e10cSrcweir             }
318cdf0e10cSrcweir         }
319cdf0e10cSrcweir     }
320cdf0e10cSrcweir     // close remaining contexts (missing context end records or stream error)
321cdf0e10cSrcweir     while( !mxStack->empty() )
322cdf0e10cSrcweir         mxStack->popContext();
323cdf0e10cSrcweir     mxStack.reset();
324cdf0e10cSrcweir 
325cdf0e10cSrcweir     // finish document
326cdf0e10cSrcweir     mxHandler->endDocument();
327cdf0e10cSrcweir 
328cdf0e10cSrcweir     maSource = RecordInputSource();
329cdf0e10cSrcweir }
330cdf0e10cSrcweir 
getStartRecordInfo(sal_Int32 nRecId) const331cdf0e10cSrcweir const RecordInfo* RecordParser::getStartRecordInfo( sal_Int32 nRecId ) const
332cdf0e10cSrcweir {
333cdf0e10cSrcweir     RecordInfoMap::const_iterator aIt = maStartMap.find( nRecId );
334cdf0e10cSrcweir     return (aIt == maStartMap.end()) ? 0 : &aIt->second;
335cdf0e10cSrcweir }
336cdf0e10cSrcweir 
getEndRecordInfo(sal_Int32 nRecId) const337cdf0e10cSrcweir const RecordInfo* RecordParser::getEndRecordInfo( sal_Int32 nRecId ) const
338cdf0e10cSrcweir {
339cdf0e10cSrcweir     RecordInfoMap::const_iterator aIt = maEndMap.find( nRecId );
340cdf0e10cSrcweir     return (aIt == maEndMap.end()) ? 0 : &aIt->second;
341cdf0e10cSrcweir }
342cdf0e10cSrcweir 
343cdf0e10cSrcweir // ============================================================================
344cdf0e10cSrcweir 
345cdf0e10cSrcweir } // namespace core
346cdf0e10cSrcweir } // namespace oox
347