1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
29 #include <comphelper/ofopxmlhelper.hxx>
30 #include <comphelper/attributelist.hxx>
32 #define RELATIONINFO_FORMAT 0
33 #define CONTENTTYPE_FORMAT 1
34 #define FORMAT_MAX_ID CONTENTTYPE_FORMAT
36 using namespace ::com::sun::star
;
38 namespace comphelper
{
40 // -----------------------------------
41 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
)
44 OUString aStringID
= OUString( "_rels/" );
45 aStringID
+= aStreamName
;
46 return ReadSequence_Impl( xInStream
, aStringID
, RELATIONINFO_FORMAT
, xContext
);
49 // -----------------------------------
50 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
)
53 OUString aStringID
= OUString( "[Content_Types].xml" );
54 return ReadSequence_Impl( xInStream
, aStringID
, CONTENTTYPE_FORMAT
, xContext
);
57 // -----------------------------------
58 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
)
61 if ( !xOutStream
.is() )
62 throw uno::RuntimeException();
64 uno::Reference
< xml::sax::XWriter
> xWriter
= xml::sax::Writer::create(xContext
);
66 xWriter
->setOutputStream( xOutStream
);
68 OUString
aRelListElement( "Relationships" );
69 OUString
aRelElement( "Relationship" );
70 OUString
aIDAttr( "Id" );
71 OUString
aTypeAttr( "Type" );
72 OUString
aTargetModeAttr( "TargetMode" );
73 OUString
aTargetAttr( "Target" );
74 OUString
aCDATAString( "CDATA" );
75 OUString
aWhiteSpace( " " );
77 // write the namespace
78 AttributeList
* pRootAttrList
= new AttributeList
;
79 uno::Reference
< xml::sax::XAttributeList
> xRootAttrList( pRootAttrList
);
80 pRootAttrList
->AddAttribute(
83 OUString( "http://schemas.openxmlformats.org/package/2006/relationships" ) );
85 xWriter
->startDocument();
86 xWriter
->startElement( aRelListElement
, xRootAttrList
);
88 for ( sal_Int32 nInd
= 0; nInd
< aSequence
.getLength(); nInd
++ )
90 AttributeList
*pAttrList
= new AttributeList
;
91 uno::Reference
< xml::sax::XAttributeList
> xAttrList( pAttrList
);
92 for( sal_Int32 nSecInd
= 0; nSecInd
< aSequence
[nInd
].getLength(); nSecInd
++ )
94 if ( aSequence
[nInd
][nSecInd
].First
.equals( aIDAttr
)
95 || aSequence
[nInd
][nSecInd
].First
.equals( aTypeAttr
)
96 || aSequence
[nInd
][nSecInd
].First
.equals( aTargetModeAttr
)
97 || aSequence
[nInd
][nSecInd
].First
.equals( aTargetAttr
) )
99 pAttrList
->AddAttribute( aSequence
[nInd
][nSecInd
].First
, aCDATAString
, aSequence
[nInd
][nSecInd
].Second
);
103 // TODO/LATER: should the extensions be allowed?
104 throw lang::IllegalArgumentException();
108 xWriter
->startElement( aRelElement
, xAttrList
);
109 xWriter
->ignorableWhitespace( aWhiteSpace
);
110 xWriter
->endElement( aRelElement
);
113 xWriter
->ignorableWhitespace( aWhiteSpace
);
114 xWriter
->endElement( aRelListElement
);
115 xWriter
->endDocument();
118 // -----------------------------------
119 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
)
122 if ( !xOutStream
.is() )
123 throw uno::RuntimeException();
125 uno::Reference
< xml::sax::XWriter
> xWriter
= xml::sax::Writer::create(xContext
);
127 xWriter
->setOutputStream( xOutStream
);
129 OUString
aTypesElement( "Types" );
130 OUString
aDefaultElement( "Default" );
131 OUString
aOverrideElement( "Override" );
132 OUString
aExtensionAttr( "Extension" );
133 OUString
aPartNameAttr( "PartName" );
134 OUString
aContentTypeAttr( "ContentType" );
135 OUString
aCDATAString( "CDATA" );
136 OUString
aWhiteSpace( " " );
138 // write the namespace
139 AttributeList
* pRootAttrList
= new AttributeList
;
140 uno::Reference
< xml::sax::XAttributeList
> xRootAttrList( pRootAttrList
);
141 pRootAttrList
->AddAttribute(
144 OUString( "http://schemas.openxmlformats.org/package/2006/content-types" ) );
146 xWriter
->startDocument();
147 xWriter
->startElement( aTypesElement
, xRootAttrList
);
149 for ( sal_Int32 nInd
= 0; nInd
< aDefaultsSequence
.getLength(); nInd
++ )
151 AttributeList
*pAttrList
= new AttributeList
;
152 uno::Reference
< xml::sax::XAttributeList
> xAttrList( pAttrList
);
153 pAttrList
->AddAttribute( aExtensionAttr
, aCDATAString
, aDefaultsSequence
[nInd
].First
);
154 pAttrList
->AddAttribute( aContentTypeAttr
, aCDATAString
, aDefaultsSequence
[nInd
].Second
);
156 xWriter
->startElement( aDefaultElement
, xAttrList
);
157 xWriter
->ignorableWhitespace( aWhiteSpace
);
158 xWriter
->endElement( aDefaultElement
);
161 for ( sal_Int32 nInd
= 0; nInd
< aOverridesSequence
.getLength(); nInd
++ )
163 AttributeList
*pAttrList
= new AttributeList
;
164 uno::Reference
< xml::sax::XAttributeList
> xAttrList( pAttrList
);
165 pAttrList
->AddAttribute( aPartNameAttr
, aCDATAString
, aOverridesSequence
[nInd
].First
);
166 pAttrList
->AddAttribute( aContentTypeAttr
, aCDATAString
, aOverridesSequence
[nInd
].Second
);
168 xWriter
->startElement( aOverrideElement
, xAttrList
);
169 xWriter
->ignorableWhitespace( aWhiteSpace
);
170 xWriter
->endElement( aOverrideElement
);
173 xWriter
->ignorableWhitespace( aWhiteSpace
);
174 xWriter
->endElement( aTypesElement
);
175 xWriter
->endDocument();
179 // ==================================================================================
181 // -----------------------------------
182 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
)
185 if ( !xContext
.is() || !xInStream
.is() || nFormat
> FORMAT_MAX_ID
)
186 throw uno::RuntimeException();
188 uno::Sequence
< uno::Sequence
< beans::StringPair
> > aResult
;
190 uno::Reference
< xml::sax::XParser
> xParser
= xml::sax::Parser::create( xContext
);
192 OFOPXMLHelper
* pHelper
= new OFOPXMLHelper( nFormat
);
193 uno::Reference
< xml::sax::XDocumentHandler
> xHelper( static_cast< xml::sax::XDocumentHandler
* >( pHelper
) );
194 xml::sax::InputSource aParserInput
;
195 aParserInput
.aInputStream
= xInStream
;
196 aParserInput
.sSystemId
= aStringID
;
197 xParser
->setDocumentHandler( xHelper
);
198 xParser
->parseStream( aParserInput
);
199 xParser
->setDocumentHandler( uno::Reference
< xml::sax::XDocumentHandler
> () );
201 return pHelper
->GetParsingResult();
204 // -----------------------------------
205 OFOPXMLHelper::OFOPXMLHelper( sal_uInt16 nFormat
)
206 : m_nFormat( nFormat
)
207 , m_aRelListElement( "Relationships" )
208 , m_aRelElement( "Relationship" )
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 , m_aContentTypeAttr( "ContentType" )
222 // -----------------------------------
223 OFOPXMLHelper::~OFOPXMLHelper()
227 // -----------------------------------
228 uno::Sequence
< uno::Sequence
< beans::StringPair
> > OFOPXMLHelper::GetParsingResult()
230 if ( m_aElementsSeq
.getLength() )
231 throw uno::RuntimeException(); // the parsing has still not finished!
236 // -----------------------------------
237 void SAL_CALL
OFOPXMLHelper::startDocument()
238 throw(xml::sax::SAXException
, uno::RuntimeException
)
242 // -----------------------------------
243 void SAL_CALL
OFOPXMLHelper::endDocument()
244 throw(xml::sax::SAXException
, uno::RuntimeException
)
248 // -----------------------------------
249 void SAL_CALL
OFOPXMLHelper::startElement( const OUString
& aName
, const uno::Reference
< xml::sax::XAttributeList
>& xAttribs
)
250 throw( xml::sax::SAXException
, uno::RuntimeException
)
252 if ( m_nFormat
== RELATIONINFO_FORMAT
)
254 if ( aName
== m_aRelListElement
)
256 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
258 if ( nNewLength
!= 1 )
259 throw xml::sax::SAXException(); // TODO: this element must be the first level element
261 m_aElementsSeq
.realloc( nNewLength
);
262 m_aElementsSeq
[nNewLength
-1] = aName
;
264 return; // nothing to do
266 else if ( aName
== m_aRelElement
)
268 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
269 if ( nNewLength
!= 2 )
270 throw xml::sax::SAXException(); // TODO: this element must be the second level element
272 m_aElementsSeq
.realloc( nNewLength
);
273 m_aElementsSeq
[nNewLength
-1] = aName
;
275 sal_Int32 nNewEntryNum
= m_aResultSeq
.getLength() + 1;
276 m_aResultSeq
.realloc( nNewEntryNum
);
277 sal_Int32 nAttrNum
= 0;
278 m_aResultSeq
[nNewEntryNum
-1].realloc( 4 ); // the maximal expected number of arguments is 4
280 OUString aIDValue
= xAttribs
->getValueByName( m_aIDAttr
);
281 if ( aIDValue
.isEmpty() )
282 throw xml::sax::SAXException(); // TODO: the ID value must present
284 OUString aTypeValue
= xAttribs
->getValueByName( m_aTypeAttr
);
285 OUString aTargetValue
= xAttribs
->getValueByName( m_aTargetAttr
);
286 OUString aTargetModeValue
= xAttribs
->getValueByName( m_aTargetModeAttr
);
288 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aIDAttr
;
289 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aIDValue
;
291 if ( !aTypeValue
.isEmpty() )
293 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTypeAttr
;
294 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTypeValue
;
297 if ( !aTargetValue
.isEmpty() )
299 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTargetAttr
;
300 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTargetValue
;
303 if ( !aTargetModeValue
.isEmpty() )
305 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTargetModeAttr
;
306 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTargetModeValue
;
309 m_aResultSeq
[nNewEntryNum
-1].realloc( nAttrNum
);
312 throw xml::sax::SAXException(); // TODO: no other elements expected!
314 else if ( m_nFormat
== CONTENTTYPE_FORMAT
)
316 if ( aName
== m_aTypesElement
)
318 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
320 if ( nNewLength
!= 1 )
321 throw xml::sax::SAXException(); // TODO: this element must be the first level element
323 m_aElementsSeq
.realloc( nNewLength
);
324 m_aElementsSeq
[nNewLength
-1] = aName
;
326 if ( !m_aResultSeq
.getLength() )
327 m_aResultSeq
.realloc( 2 );
329 return; // nothing to do
331 else if ( aName
== m_aDefaultElement
)
333 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
334 if ( nNewLength
!= 2 )
335 throw xml::sax::SAXException(); // TODO: this element must be the second level element
337 m_aElementsSeq
.realloc( nNewLength
);
338 m_aElementsSeq
[nNewLength
-1] = aName
;
340 if ( !m_aResultSeq
.getLength() )
341 m_aResultSeq
.realloc( 2 );
343 if ( m_aResultSeq
.getLength() != 2 )
344 throw uno::RuntimeException();
346 OUString aExtensionValue
= xAttribs
->getValueByName( m_aExtensionAttr
);
347 if ( aExtensionValue
.isEmpty() )
348 throw xml::sax::SAXException(); // TODO: the Extension value must present
350 OUString aContentTypeValue
= xAttribs
->getValueByName( m_aContentTypeAttr
);
351 if ( aContentTypeValue
.isEmpty() )
352 throw xml::sax::SAXException(); // TODO: the ContentType value must present
354 sal_Int32 nNewResultLen
= m_aResultSeq
[0].getLength() + 1;
355 m_aResultSeq
[0].realloc( nNewResultLen
);
357 m_aResultSeq
[0][nNewResultLen
-1].First
= aExtensionValue
;
358 m_aResultSeq
[0][nNewResultLen
-1].Second
= aContentTypeValue
;
360 else if ( aName
== m_aOverrideElement
)
362 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
363 if ( nNewLength
!= 2 )
364 throw xml::sax::SAXException(); // TODO: this element must be the second level element
366 m_aElementsSeq
.realloc( nNewLength
);
367 m_aElementsSeq
[nNewLength
-1] = aName
;
369 if ( !m_aResultSeq
.getLength() )
370 m_aResultSeq
.realloc( 2 );
372 if ( m_aResultSeq
.getLength() != 2 )
373 throw uno::RuntimeException();
375 OUString aPartNameValue
= xAttribs
->getValueByName( m_aPartNameAttr
);
376 if ( aPartNameValue
.isEmpty() )
377 throw xml::sax::SAXException(); // TODO: the PartName value must present
379 OUString aContentTypeValue
= xAttribs
->getValueByName( m_aContentTypeAttr
);
380 if ( aContentTypeValue
.isEmpty() )
381 throw xml::sax::SAXException(); // TODO: the ContentType value must present
383 sal_Int32 nNewResultLen
= m_aResultSeq
[1].getLength() + 1;
384 m_aResultSeq
[1].realloc( nNewResultLen
);
386 m_aResultSeq
[1][nNewResultLen
-1].First
= aPartNameValue
;
387 m_aResultSeq
[1][nNewResultLen
-1].Second
= aContentTypeValue
;
390 throw xml::sax::SAXException(); // TODO: no other elements expected!
393 throw xml::sax::SAXException(); // TODO: no other elements expected!
396 // -----------------------------------
397 void SAL_CALL
OFOPXMLHelper::endElement( const OUString
& aName
)
398 throw( xml::sax::SAXException
, uno::RuntimeException
)
400 if ( m_nFormat
== RELATIONINFO_FORMAT
|| m_nFormat
== CONTENTTYPE_FORMAT
)
402 sal_Int32 nLength
= m_aElementsSeq
.getLength();
404 throw xml::sax::SAXException(); // TODO: no other end elements expected!
406 if ( !m_aElementsSeq
[nLength
-1].equals( aName
) )
407 throw xml::sax::SAXException(); // TODO: unexpected element ended
409 m_aElementsSeq
.realloc( nLength
- 1 );
413 // -----------------------------------
414 void SAL_CALL
OFOPXMLHelper::characters( const OUString
& /*aChars*/ )
415 throw(xml::sax::SAXException
, uno::RuntimeException
)
419 // -----------------------------------
420 void SAL_CALL
OFOPXMLHelper::ignorableWhitespace( const OUString
& /*aWhitespaces*/ )
421 throw(xml::sax::SAXException
, uno::RuntimeException
)
425 // -----------------------------------
426 void SAL_CALL
OFOPXMLHelper::processingInstruction( const OUString
& /*aTarget*/, const OUString
& /*aData*/ )
427 throw(xml::sax::SAXException
, uno::RuntimeException
)
431 // -----------------------------------
432 void SAL_CALL
OFOPXMLHelper::setDocumentLocator( const uno::Reference
< xml::sax::XLocator
>& /*xLocator*/ )
433 throw(xml::sax::SAXException
, uno::RuntimeException
)
437 } // namespace comphelper
439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */