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