Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <com/sun/star/beans/StringPair.hpp>
22 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
23 : #include <com/sun/star/io/XActiveDataSource.hpp>
24 : #include <com/sun/star/xml/sax/Parser.hpp>
25 : #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
26 : #include <com/sun/star/xml/sax/Writer.hpp>
27 : #include <com/sun/star/lang/IllegalArgumentException.hpp>
28 :
29 : #include <comphelper/ofopxmlhelper.hxx>
30 : #include <comphelper/attributelist.hxx>
31 :
32 : #define RELATIONINFO_FORMAT 0
33 : #define CONTENTTYPE_FORMAT 1
34 : #define FORMAT_MAX_ID CONTENTTYPE_FORMAT
35 :
36 : using namespace ::com::sun::star;
37 :
38 : namespace comphelper {
39 :
40 : // -----------------------------------
41 520 : uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OFOPXMLHelper::ReadRelationsInfoSequence( const uno::Reference< io::XInputStream >& xInStream, const OUString aStreamName, const uno::Reference< uno::XComponentContext > xContext )
42 : throw( uno::Exception )
43 : {
44 520 : OUString aStringID = OUString( "_rels/" );
45 520 : aStringID += aStreamName;
46 520 : return ReadSequence_Impl( xInStream, aStringID, RELATIONINFO_FORMAT, xContext );
47 : }
48 :
49 : // -----------------------------------
50 347 : uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OFOPXMLHelper::ReadContentTypeSequence( const uno::Reference< io::XInputStream >& xInStream, const uno::Reference< uno::XComponentContext > xContext )
51 : throw( uno::Exception )
52 : {
53 347 : OUString aStringID = OUString( "[Content_Types].xml" );
54 347 : return ReadSequence_Impl( xInStream, aStringID, CONTENTTYPE_FORMAT, xContext );
55 : }
56 :
57 : // -----------------------------------
58 113 : void SAL_CALL OFOPXMLHelper::WriteRelationsInfoSequence( const uno::Reference< io::XOutputStream >& xOutStream, const uno::Sequence< uno::Sequence< beans::StringPair > >& aSequence, const uno::Reference< uno::XComponentContext > xContext )
59 : throw( uno::Exception )
60 : {
61 113 : if ( !xOutStream.is() )
62 0 : throw uno::RuntimeException();
63 :
64 113 : uno::Reference< xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
65 :
66 113 : xWriter->setOutputStream( xOutStream );
67 :
68 226 : OUString aRelListElement( "Relationships" );
69 226 : OUString aRelElement( "Relationship" );
70 226 : OUString aIDAttr( "Id" );
71 226 : OUString aTypeAttr( "Type" );
72 226 : OUString aTargetModeAttr( "TargetMode" );
73 226 : OUString aTargetAttr( "Target" );
74 226 : OUString aCDATAString( "CDATA" );
75 226 : OUString aWhiteSpace( " " );
76 :
77 : // write the namespace
78 113 : AttributeList* pRootAttrList = new AttributeList;
79 226 : uno::Reference< xml::sax::XAttributeList > xRootAttrList( pRootAttrList );
80 : pRootAttrList->AddAttribute(
81 : OUString( "xmlns" ),
82 : aCDATAString,
83 113 : OUString( "http://schemas.openxmlformats.org/package/2006/relationships" ) );
84 :
85 113 : xWriter->startDocument();
86 113 : xWriter->startElement( aRelListElement, xRootAttrList );
87 :
88 459 : for ( sal_Int32 nInd = 0; nInd < aSequence.getLength(); nInd++ )
89 : {
90 346 : AttributeList *pAttrList = new AttributeList;
91 346 : uno::Reference< xml::sax::XAttributeList > xAttrList( pAttrList );
92 1385 : for( sal_Int32 nSecInd = 0; nSecInd < aSequence[nInd].getLength(); nSecInd++ )
93 : {
94 2078 : if ( aSequence[nInd][nSecInd].First.equals( aIDAttr )
95 693 : || aSequence[nInd][nSecInd].First.equals( aTypeAttr )
96 347 : || aSequence[nInd][nSecInd].First.equals( aTargetModeAttr )
97 1385 : || aSequence[nInd][nSecInd].First.equals( aTargetAttr ) )
98 : {
99 1039 : pAttrList->AddAttribute( aSequence[nInd][nSecInd].First, aCDATAString, aSequence[nInd][nSecInd].Second );
100 : }
101 : else
102 : {
103 : // TODO/LATER: should the extensions be allowed?
104 0 : throw lang::IllegalArgumentException();
105 : }
106 : }
107 :
108 346 : xWriter->startElement( aRelElement, xAttrList );
109 346 : xWriter->ignorableWhitespace( aWhiteSpace );
110 346 : xWriter->endElement( aRelElement );
111 346 : }
112 :
113 113 : xWriter->ignorableWhitespace( aWhiteSpace );
114 113 : xWriter->endElement( aRelListElement );
115 226 : xWriter->endDocument();
116 113 : }
117 :
118 : // -----------------------------------
119 54 : void SAL_CALL OFOPXMLHelper::WriteContentSequence( const uno::Reference< io::XOutputStream >& xOutStream, const uno::Sequence< beans::StringPair >& aDefaultsSequence, const uno::Sequence< beans::StringPair >& aOverridesSequence, const uno::Reference< uno::XComponentContext > xContext )
120 : throw( uno::Exception )
121 : {
122 54 : if ( !xOutStream.is() )
123 0 : throw uno::RuntimeException();
124 :
125 54 : uno::Reference< xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
126 :
127 54 : xWriter->setOutputStream( xOutStream );
128 :
129 108 : OUString aTypesElement( "Types" );
130 108 : OUString aDefaultElement( "Default" );
131 108 : OUString aOverrideElement( "Override" );
132 108 : OUString aExtensionAttr( "Extension" );
133 108 : OUString aPartNameAttr( "PartName" );
134 108 : OUString aContentTypeAttr( "ContentType" );
135 108 : OUString aCDATAString( "CDATA" );
136 108 : OUString aWhiteSpace( " " );
137 :
138 : // write the namespace
139 54 : AttributeList* pRootAttrList = new AttributeList;
140 108 : uno::Reference< xml::sax::XAttributeList > xRootAttrList( pRootAttrList );
141 : pRootAttrList->AddAttribute(
142 : OUString( "xmlns" ),
143 : aCDATAString,
144 54 : OUString( "http://schemas.openxmlformats.org/package/2006/content-types" ) );
145 :
146 54 : xWriter->startDocument();
147 54 : xWriter->startElement( aTypesElement, xRootAttrList );
148 :
149 54 : for ( sal_Int32 nInd = 0; nInd < aDefaultsSequence.getLength(); nInd++ )
150 : {
151 0 : AttributeList *pAttrList = new AttributeList;
152 0 : uno::Reference< xml::sax::XAttributeList > xAttrList( pAttrList );
153 0 : pAttrList->AddAttribute( aExtensionAttr, aCDATAString, aDefaultsSequence[nInd].First );
154 0 : pAttrList->AddAttribute( aContentTypeAttr, aCDATAString, aDefaultsSequence[nInd].Second );
155 :
156 0 : xWriter->startElement( aDefaultElement, xAttrList );
157 0 : xWriter->ignorableWhitespace( aWhiteSpace );
158 0 : xWriter->endElement( aDefaultElement );
159 0 : }
160 :
161 512 : for ( sal_Int32 nInd = 0; nInd < aOverridesSequence.getLength(); nInd++ )
162 : {
163 458 : AttributeList *pAttrList = new AttributeList;
164 458 : uno::Reference< xml::sax::XAttributeList > xAttrList( pAttrList );
165 458 : pAttrList->AddAttribute( aPartNameAttr, aCDATAString, aOverridesSequence[nInd].First );
166 458 : pAttrList->AddAttribute( aContentTypeAttr, aCDATAString, aOverridesSequence[nInd].Second );
167 :
168 458 : xWriter->startElement( aOverrideElement, xAttrList );
169 458 : xWriter->ignorableWhitespace( aWhiteSpace );
170 458 : xWriter->endElement( aOverrideElement );
171 458 : }
172 :
173 54 : xWriter->ignorableWhitespace( aWhiteSpace );
174 54 : xWriter->endElement( aTypesElement );
175 108 : xWriter->endDocument();
176 :
177 54 : }
178 :
179 : // ==================================================================================
180 :
181 : // -----------------------------------
182 867 : uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OFOPXMLHelper::ReadSequence_Impl( const uno::Reference< io::XInputStream >& xInStream, const OUString& aStringID, sal_uInt16 nFormat, const uno::Reference< uno::XComponentContext > xContext )
183 : throw( uno::Exception )
184 : {
185 867 : if ( !xContext.is() || !xInStream.is() || nFormat > FORMAT_MAX_ID )
186 0 : throw uno::RuntimeException();
187 :
188 867 : uno::Sequence< uno::Sequence< beans::StringPair > > aResult;
189 :
190 1734 : uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create( xContext );
191 :
192 867 : OFOPXMLHelper* pHelper = new OFOPXMLHelper( nFormat );
193 1734 : uno::Reference< xml::sax::XDocumentHandler > xHelper( static_cast< xml::sax::XDocumentHandler* >( pHelper ) );
194 1734 : xml::sax::InputSource aParserInput;
195 867 : aParserInput.aInputStream = xInStream;
196 867 : aParserInput.sSystemId = aStringID;
197 867 : xParser->setDocumentHandler( xHelper );
198 867 : xParser->parseStream( aParserInput );
199 867 : xParser->setDocumentHandler( uno::Reference < xml::sax::XDocumentHandler > () );
200 :
201 1734 : return pHelper->GetParsingResult();
202 : }
203 :
204 : // -----------------------------------
205 867 : OFOPXMLHelper::OFOPXMLHelper( sal_uInt16 nFormat )
206 : : m_nFormat( nFormat )
207 : , m_aRelListElement( "Relationships" )
208 : , m_aRelElement( "Relationship" )
209 : , m_aIDAttr( "Id" )
210 : , m_aTypeAttr( "Type" )
211 : , m_aTargetModeAttr( "TargetMode" )
212 : , m_aTargetAttr( "Target" )
213 : , m_aTypesElement( "Types" )
214 : , m_aDefaultElement( "Default" )
215 : , m_aOverrideElement( "Override" )
216 : , m_aExtensionAttr( "Extension" )
217 : , m_aPartNameAttr( "PartName" )
218 867 : , m_aContentTypeAttr( "ContentType" )
219 : {
220 867 : }
221 :
222 : // -----------------------------------
223 1734 : OFOPXMLHelper::~OFOPXMLHelper()
224 : {
225 1734 : }
226 :
227 : // -----------------------------------
228 867 : uno::Sequence< uno::Sequence< beans::StringPair > > OFOPXMLHelper::GetParsingResult()
229 : {
230 867 : if ( m_aElementsSeq.getLength() )
231 0 : throw uno::RuntimeException(); // the parsing has still not finished!
232 :
233 867 : return m_aResultSeq;
234 : }
235 :
236 : // -----------------------------------
237 867 : void SAL_CALL OFOPXMLHelper::startDocument()
238 : throw(xml::sax::SAXException, uno::RuntimeException)
239 : {
240 867 : }
241 :
242 : // -----------------------------------
243 867 : void SAL_CALL OFOPXMLHelper::endDocument()
244 : throw(xml::sax::SAXException, uno::RuntimeException)
245 : {
246 867 : }
247 :
248 : // -----------------------------------
249 6523 : void SAL_CALL OFOPXMLHelper::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs )
250 : throw( xml::sax::SAXException, uno::RuntimeException )
251 : {
252 6523 : if ( m_nFormat == RELATIONINFO_FORMAT )
253 : {
254 2487 : if ( aName == m_aRelListElement )
255 : {
256 520 : sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1;
257 :
258 520 : if ( nNewLength != 1 )
259 0 : throw xml::sax::SAXException(); // TODO: this element must be the first level element
260 :
261 520 : m_aElementsSeq.realloc( nNewLength );
262 520 : m_aElementsSeq[nNewLength-1] = aName;
263 :
264 520 : return; // nothing to do
265 : }
266 1967 : else if ( aName == m_aRelElement )
267 : {
268 1967 : sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1;
269 1967 : if ( nNewLength != 2 )
270 0 : throw xml::sax::SAXException(); // TODO: this element must be the second level element
271 :
272 1967 : m_aElementsSeq.realloc( nNewLength );
273 1967 : m_aElementsSeq[nNewLength-1] = aName;
274 :
275 1967 : sal_Int32 nNewEntryNum = m_aResultSeq.getLength() + 1;
276 1967 : m_aResultSeq.realloc( nNewEntryNum );
277 1967 : sal_Int32 nAttrNum = 0;
278 1967 : m_aResultSeq[nNewEntryNum-1].realloc( 4 ); // the maximal expected number of arguments is 4
279 :
280 1967 : OUString aIDValue = xAttribs->getValueByName( m_aIDAttr );
281 1967 : if ( aIDValue.isEmpty() )
282 0 : throw xml::sax::SAXException(); // TODO: the ID value must present
283 :
284 3934 : OUString aTypeValue = xAttribs->getValueByName( m_aTypeAttr );
285 3934 : OUString aTargetValue = xAttribs->getValueByName( m_aTargetAttr );
286 3934 : OUString aTargetModeValue = xAttribs->getValueByName( m_aTargetModeAttr );
287 :
288 1967 : m_aResultSeq[nNewEntryNum-1][++nAttrNum - 1].First = m_aIDAttr;
289 1967 : m_aResultSeq[nNewEntryNum-1][nAttrNum - 1].Second = aIDValue;
290 :
291 1967 : if ( !aTypeValue.isEmpty() )
292 : {
293 1967 : m_aResultSeq[nNewEntryNum-1][++nAttrNum - 1].First = m_aTypeAttr;
294 1967 : m_aResultSeq[nNewEntryNum-1][nAttrNum - 1].Second = aTypeValue;
295 : }
296 :
297 1967 : if ( !aTargetValue.isEmpty() )
298 : {
299 1967 : m_aResultSeq[nNewEntryNum-1][++nAttrNum - 1].First = m_aTargetAttr;
300 1967 : m_aResultSeq[nNewEntryNum-1][nAttrNum - 1].Second = aTargetValue;
301 : }
302 :
303 1967 : if ( !aTargetModeValue.isEmpty() )
304 : {
305 5 : m_aResultSeq[nNewEntryNum-1][++nAttrNum - 1].First = m_aTargetModeAttr;
306 5 : m_aResultSeq[nNewEntryNum-1][nAttrNum - 1].Second = aTargetModeValue;
307 : }
308 :
309 3934 : m_aResultSeq[nNewEntryNum-1].realloc( nAttrNum );
310 : }
311 : else
312 0 : throw xml::sax::SAXException(); // TODO: no other elements expected!
313 : }
314 4036 : else if ( m_nFormat == CONTENTTYPE_FORMAT )
315 : {
316 4036 : if ( aName == m_aTypesElement )
317 : {
318 347 : sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1;
319 :
320 347 : if ( nNewLength != 1 )
321 0 : throw xml::sax::SAXException(); // TODO: this element must be the first level element
322 :
323 347 : m_aElementsSeq.realloc( nNewLength );
324 347 : m_aElementsSeq[nNewLength-1] = aName;
325 :
326 347 : if ( !m_aResultSeq.getLength() )
327 347 : m_aResultSeq.realloc( 2 );
328 :
329 347 : return; // nothing to do
330 : }
331 3689 : else if ( aName == m_aDefaultElement )
332 : {
333 436 : sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1;
334 436 : if ( nNewLength != 2 )
335 0 : throw xml::sax::SAXException(); // TODO: this element must be the second level element
336 :
337 436 : m_aElementsSeq.realloc( nNewLength );
338 436 : m_aElementsSeq[nNewLength-1] = aName;
339 :
340 436 : if ( !m_aResultSeq.getLength() )
341 0 : m_aResultSeq.realloc( 2 );
342 :
343 436 : if ( m_aResultSeq.getLength() != 2 )
344 0 : throw uno::RuntimeException();
345 :
346 436 : OUString aExtensionValue = xAttribs->getValueByName( m_aExtensionAttr );
347 436 : if ( aExtensionValue.isEmpty() )
348 0 : throw xml::sax::SAXException(); // TODO: the Extension value must present
349 :
350 872 : OUString aContentTypeValue = xAttribs->getValueByName( m_aContentTypeAttr );
351 436 : if ( aContentTypeValue.isEmpty() )
352 0 : throw xml::sax::SAXException(); // TODO: the ContentType value must present
353 :
354 436 : sal_Int32 nNewResultLen = m_aResultSeq[0].getLength() + 1;
355 436 : m_aResultSeq[0].realloc( nNewResultLen );
356 :
357 436 : m_aResultSeq[0][nNewResultLen-1].First = aExtensionValue;
358 872 : m_aResultSeq[0][nNewResultLen-1].Second = aContentTypeValue;
359 : }
360 3253 : else if ( aName == m_aOverrideElement )
361 : {
362 3253 : sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1;
363 3253 : if ( nNewLength != 2 )
364 0 : throw xml::sax::SAXException(); // TODO: this element must be the second level element
365 :
366 3253 : m_aElementsSeq.realloc( nNewLength );
367 3253 : m_aElementsSeq[nNewLength-1] = aName;
368 :
369 3253 : if ( !m_aResultSeq.getLength() )
370 0 : m_aResultSeq.realloc( 2 );
371 :
372 3253 : if ( m_aResultSeq.getLength() != 2 )
373 0 : throw uno::RuntimeException();
374 :
375 3253 : OUString aPartNameValue = xAttribs->getValueByName( m_aPartNameAttr );
376 3253 : if ( aPartNameValue.isEmpty() )
377 0 : throw xml::sax::SAXException(); // TODO: the PartName value must present
378 :
379 6506 : OUString aContentTypeValue = xAttribs->getValueByName( m_aContentTypeAttr );
380 3253 : if ( aContentTypeValue.isEmpty() )
381 0 : throw xml::sax::SAXException(); // TODO: the ContentType value must present
382 :
383 3253 : sal_Int32 nNewResultLen = m_aResultSeq[1].getLength() + 1;
384 3253 : m_aResultSeq[1].realloc( nNewResultLen );
385 :
386 3253 : m_aResultSeq[1][nNewResultLen-1].First = aPartNameValue;
387 6506 : m_aResultSeq[1][nNewResultLen-1].Second = aContentTypeValue;
388 : }
389 : else
390 0 : throw xml::sax::SAXException(); // TODO: no other elements expected!
391 : }
392 : else
393 0 : throw xml::sax::SAXException(); // TODO: no other elements expected!
394 : }
395 :
396 : // -----------------------------------
397 6523 : void SAL_CALL OFOPXMLHelper::endElement( const OUString& aName )
398 : throw( xml::sax::SAXException, uno::RuntimeException )
399 : {
400 6523 : if ( m_nFormat == RELATIONINFO_FORMAT || m_nFormat == CONTENTTYPE_FORMAT )
401 : {
402 6523 : sal_Int32 nLength = m_aElementsSeq.getLength();
403 6523 : if ( nLength <= 0 )
404 0 : throw xml::sax::SAXException(); // TODO: no other end elements expected!
405 :
406 6523 : if ( !m_aElementsSeq[nLength-1].equals( aName ) )
407 0 : throw xml::sax::SAXException(); // TODO: unexpected element ended
408 :
409 6523 : m_aElementsSeq.realloc( nLength - 1 );
410 : }
411 6523 : }
412 :
413 : // -----------------------------------
414 425 : void SAL_CALL OFOPXMLHelper::characters( const OUString& /*aChars*/ )
415 : throw(xml::sax::SAXException, uno::RuntimeException)
416 : {
417 425 : }
418 :
419 : // -----------------------------------
420 0 : void SAL_CALL OFOPXMLHelper::ignorableWhitespace( const OUString& /*aWhitespaces*/ )
421 : throw(xml::sax::SAXException, uno::RuntimeException)
422 : {
423 0 : }
424 :
425 : // -----------------------------------
426 0 : void SAL_CALL OFOPXMLHelper::processingInstruction( const OUString& /*aTarget*/, const OUString& /*aData*/ )
427 : throw(xml::sax::SAXException, uno::RuntimeException)
428 : {
429 0 : }
430 :
431 : // -----------------------------------
432 867 : void SAL_CALL OFOPXMLHelper::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ )
433 : throw(xml::sax::SAXException, uno::RuntimeException)
434 : {
435 867 : }
436 :
437 : } // namespace comphelper
438 :
439 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|