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
{
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
= "_rels/";
45 aStringID
+= aStreamName
;
46 return ReadSequence_Impl( xInStream
, aStringID
, RELATIONINFO_FORMAT
, xContext
);
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
= "[Content_Types].xml";
54 return ReadSequence_Impl( xInStream
, aStringID
, CONTENTTYPE_FORMAT
, xContext
);
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();
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();
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::Reference
< xml::sax::XParser
> xParser
= xml::sax::Parser::create( xContext
);
190 OFOPXMLHelper
* pHelper
= new OFOPXMLHelper( nFormat
);
191 uno::Reference
< xml::sax::XDocumentHandler
> xHelper( static_cast< xml::sax::XDocumentHandler
* >( pHelper
) );
192 xml::sax::InputSource aParserInput
;
193 aParserInput
.aInputStream
= xInStream
;
194 aParserInput
.sSystemId
= aStringID
;
195 xParser
->setDocumentHandler( xHelper
);
196 xParser
->parseStream( aParserInput
);
197 xParser
->setDocumentHandler( uno::Reference
< xml::sax::XDocumentHandler
> () );
199 return pHelper
->GetParsingResult();
203 OFOPXMLHelper::OFOPXMLHelper( sal_uInt16 nFormat
)
204 : m_nFormat( nFormat
)
205 , m_aRelListElement( "Relationships" )
206 , m_aRelElement( "Relationship" )
208 , m_aTypeAttr( "Type" )
209 , m_aTargetModeAttr( "TargetMode" )
210 , m_aTargetAttr( "Target" )
211 , m_aTypesElement( "Types" )
212 , m_aDefaultElement( "Default" )
213 , m_aOverrideElement( "Override" )
214 , m_aExtensionAttr( "Extension" )
215 , m_aPartNameAttr( "PartName" )
216 , m_aContentTypeAttr( "ContentType" )
221 OFOPXMLHelper::~OFOPXMLHelper()
226 uno::Sequence
< uno::Sequence
< beans::StringPair
> > OFOPXMLHelper::GetParsingResult()
228 if ( m_aElementsSeq
.getLength() )
229 throw uno::RuntimeException(); // the parsing has still not finished!
235 void SAL_CALL
OFOPXMLHelper::startDocument()
236 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
241 void SAL_CALL
OFOPXMLHelper::endDocument()
242 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
247 void SAL_CALL
OFOPXMLHelper::startElement( const OUString
& aName
, const uno::Reference
< xml::sax::XAttributeList
>& xAttribs
)
248 throw( xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
250 if ( m_nFormat
== RELATIONINFO_FORMAT
)
252 if ( aName
== m_aRelListElement
)
254 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
256 if ( nNewLength
!= 1 )
257 throw xml::sax::SAXException(); // TODO: this element must be the first level element
259 m_aElementsSeq
.realloc( nNewLength
);
260 m_aElementsSeq
[nNewLength
-1] = aName
;
262 return; // nothing to do
264 else if ( aName
== m_aRelElement
)
266 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
267 if ( nNewLength
!= 2 )
268 throw xml::sax::SAXException(); // TODO: this element must be the second level element
270 m_aElementsSeq
.realloc( nNewLength
);
271 m_aElementsSeq
[nNewLength
-1] = aName
;
273 sal_Int32 nNewEntryNum
= m_aResultSeq
.getLength() + 1;
274 m_aResultSeq
.realloc( nNewEntryNum
);
275 sal_Int32 nAttrNum
= 0;
276 m_aResultSeq
[nNewEntryNum
-1].realloc( 4 ); // the maximal expected number of arguments is 4
278 OUString aIDValue
= xAttribs
->getValueByName( m_aIDAttr
);
279 if ( aIDValue
.isEmpty() )
280 throw xml::sax::SAXException(); // TODO: the ID value must present
282 OUString aTypeValue
= xAttribs
->getValueByName( m_aTypeAttr
);
283 OUString aTargetValue
= xAttribs
->getValueByName( m_aTargetAttr
);
284 OUString aTargetModeValue
= xAttribs
->getValueByName( m_aTargetModeAttr
);
286 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aIDAttr
;
287 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aIDValue
;
289 if ( !aTypeValue
.isEmpty() )
291 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTypeAttr
;
292 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTypeValue
;
295 if ( !aTargetValue
.isEmpty() )
297 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTargetAttr
;
298 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTargetValue
;
301 if ( !aTargetModeValue
.isEmpty() )
303 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTargetModeAttr
;
304 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTargetModeValue
;
307 m_aResultSeq
[nNewEntryNum
-1].realloc( nAttrNum
);
310 throw xml::sax::SAXException(); // TODO: no other elements expected!
312 else if ( m_nFormat
== CONTENTTYPE_FORMAT
)
314 if ( aName
== m_aTypesElement
)
316 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
318 if ( nNewLength
!= 1 )
319 throw xml::sax::SAXException(); // TODO: this element must be the first level element
321 m_aElementsSeq
.realloc( nNewLength
);
322 m_aElementsSeq
[nNewLength
-1] = aName
;
324 if ( !m_aResultSeq
.getLength() )
325 m_aResultSeq
.realloc( 2 );
327 return; // nothing to do
329 else if ( aName
== m_aDefaultElement
)
331 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
332 if ( nNewLength
!= 2 )
333 throw xml::sax::SAXException(); // TODO: this element must be the second level element
335 m_aElementsSeq
.realloc( nNewLength
);
336 m_aElementsSeq
[nNewLength
-1] = aName
;
338 if ( !m_aResultSeq
.getLength() )
339 m_aResultSeq
.realloc( 2 );
341 if ( m_aResultSeq
.getLength() != 2 )
342 throw uno::RuntimeException();
344 OUString aExtensionValue
= xAttribs
->getValueByName( m_aExtensionAttr
);
345 if ( aExtensionValue
.isEmpty() )
346 throw xml::sax::SAXException(); // TODO: the Extension value must present
348 OUString aContentTypeValue
= xAttribs
->getValueByName( m_aContentTypeAttr
);
349 if ( aContentTypeValue
.isEmpty() )
350 throw xml::sax::SAXException(); // TODO: the ContentType value must present
352 sal_Int32 nNewResultLen
= m_aResultSeq
[0].getLength() + 1;
353 m_aResultSeq
[0].realloc( nNewResultLen
);
355 m_aResultSeq
[0][nNewResultLen
-1].First
= aExtensionValue
;
356 m_aResultSeq
[0][nNewResultLen
-1].Second
= aContentTypeValue
;
358 else if ( aName
== m_aOverrideElement
)
360 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
361 if ( nNewLength
!= 2 )
362 throw xml::sax::SAXException(); // TODO: this element must be the second level element
364 m_aElementsSeq
.realloc( nNewLength
);
365 m_aElementsSeq
[nNewLength
-1] = aName
;
367 if ( !m_aResultSeq
.getLength() )
368 m_aResultSeq
.realloc( 2 );
370 if ( m_aResultSeq
.getLength() != 2 )
371 throw uno::RuntimeException();
373 OUString aPartNameValue
= xAttribs
->getValueByName( m_aPartNameAttr
);
374 if ( aPartNameValue
.isEmpty() )
375 throw xml::sax::SAXException(); // TODO: the PartName value must present
377 OUString aContentTypeValue
= xAttribs
->getValueByName( m_aContentTypeAttr
);
378 if ( aContentTypeValue
.isEmpty() )
379 throw xml::sax::SAXException(); // TODO: the ContentType value must present
381 sal_Int32 nNewResultLen
= m_aResultSeq
[1].getLength() + 1;
382 m_aResultSeq
[1].realloc( nNewResultLen
);
384 m_aResultSeq
[1][nNewResultLen
-1].First
= aPartNameValue
;
385 m_aResultSeq
[1][nNewResultLen
-1].Second
= aContentTypeValue
;
388 throw xml::sax::SAXException(); // TODO: no other elements expected!
391 throw xml::sax::SAXException(); // TODO: no other elements expected!
395 void SAL_CALL
OFOPXMLHelper::endElement( const OUString
& aName
)
396 throw( xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
398 if ( m_nFormat
== RELATIONINFO_FORMAT
|| m_nFormat
== CONTENTTYPE_FORMAT
)
400 sal_Int32 nLength
= m_aElementsSeq
.getLength();
402 throw xml::sax::SAXException(); // TODO: no other end elements expected!
404 if ( !m_aElementsSeq
[nLength
-1].equals( aName
) )
405 throw xml::sax::SAXException(); // TODO: unexpected element ended
407 m_aElementsSeq
.realloc( nLength
- 1 );
412 void SAL_CALL
OFOPXMLHelper::characters( const OUString
& /*aChars*/ )
413 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
418 void SAL_CALL
OFOPXMLHelper::ignorableWhitespace( const OUString
& /*aWhitespaces*/ )
419 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
424 void SAL_CALL
OFOPXMLHelper::processingInstruction( const OUString
& /*aTarget*/, const OUString
& /*aData*/ )
425 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
430 void SAL_CALL
OFOPXMLHelper::setDocumentLocator( const uno::Reference
< xml::sax::XLocator
>& /*xLocator*/ )
431 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
435 } // namespace comphelper
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */