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 uno::Sequence
< uno::Sequence
< beans::StringPair
> > SAL_CALL
OFOPXMLHelper::ReadRelationsInfoSequence( const uno::Reference
< io::XInputStream
>& xInStream
, const OUString
& aStreamName
, const uno::Reference
< uno::XComponentContext
>& rContext
)
41 throw( uno::Exception
)
43 OUString aStringID
= "_rels/";
44 aStringID
+= aStreamName
;
45 return ReadSequence_Impl( xInStream
, aStringID
, RELATIONINFO_FORMAT
, rContext
);
49 uno::Sequence
< uno::Sequence
< beans::StringPair
> > SAL_CALL
OFOPXMLHelper::ReadContentTypeSequence( const uno::Reference
< io::XInputStream
>& xInStream
, const uno::Reference
< uno::XComponentContext
>& rContext
)
50 throw( uno::Exception
)
52 OUString aStringID
= "[Content_Types].xml";
53 return ReadSequence_Impl( xInStream
, aStringID
, CONTENTTYPE_FORMAT
, rContext
);
57 void SAL_CALL
OFOPXMLHelper::WriteRelationsInfoSequence( const uno::Reference
< io::XOutputStream
>& xOutStream
, const uno::Sequence
< uno::Sequence
< beans::StringPair
> >& aSequence
, const uno::Reference
< uno::XComponentContext
>& rContext
)
58 throw( uno::Exception
)
60 if ( !xOutStream
.is() )
61 throw uno::RuntimeException();
63 uno::Reference
< xml::sax::XWriter
> xWriter
= xml::sax::Writer::create(rContext
);
65 xWriter
->setOutputStream( xOutStream
);
67 OUString
aRelListElement( "Relationships" );
68 OUString
aRelElement( "Relationship" );
69 OUString
aIDAttr( "Id" );
70 OUString
aTypeAttr( "Type" );
71 OUString
aTargetModeAttr( "TargetMode" );
72 OUString
aTargetAttr( "Target" );
73 OUString
aCDATAString( "CDATA" );
74 OUString
aWhiteSpace( " " );
76 // write the namespace
77 AttributeList
* pRootAttrList
= new AttributeList
;
78 uno::Reference
< xml::sax::XAttributeList
> xRootAttrList( pRootAttrList
);
79 pRootAttrList
->AddAttribute(
82 OUString( "http://schemas.openxmlformats.org/package/2006/relationships" ) );
84 xWriter
->startDocument();
85 xWriter
->startElement( aRelListElement
, xRootAttrList
);
87 for ( sal_Int32 nInd
= 0; nInd
< aSequence
.getLength(); nInd
++ )
89 AttributeList
*pAttrList
= new AttributeList
;
90 uno::Reference
< xml::sax::XAttributeList
> xAttrList( pAttrList
);
91 for( sal_Int32 nSecInd
= 0; nSecInd
< aSequence
[nInd
].getLength(); nSecInd
++ )
93 if ( aSequence
[nInd
][nSecInd
].First
.equals( aIDAttr
)
94 || aSequence
[nInd
][nSecInd
].First
.equals( aTypeAttr
)
95 || aSequence
[nInd
][nSecInd
].First
.equals( aTargetModeAttr
)
96 || aSequence
[nInd
][nSecInd
].First
.equals( aTargetAttr
) )
98 pAttrList
->AddAttribute( aSequence
[nInd
][nSecInd
].First
, aCDATAString
, aSequence
[nInd
][nSecInd
].Second
);
102 // TODO/LATER: should the extensions be allowed?
103 throw lang::IllegalArgumentException();
107 xWriter
->startElement( aRelElement
, xAttrList
);
108 xWriter
->ignorableWhitespace( aWhiteSpace
);
109 xWriter
->endElement( aRelElement
);
112 xWriter
->ignorableWhitespace( aWhiteSpace
);
113 xWriter
->endElement( aRelListElement
);
114 xWriter
->endDocument();
118 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
>& rContext
)
119 throw( uno::Exception
)
121 if ( !xOutStream
.is() )
122 throw uno::RuntimeException();
124 uno::Reference
< xml::sax::XWriter
> xWriter
= xml::sax::Writer::create(rContext
);
126 xWriter
->setOutputStream( xOutStream
);
128 OUString
aTypesElement( "Types" );
129 OUString
aDefaultElement( "Default" );
130 OUString
aOverrideElement( "Override" );
131 OUString
aExtensionAttr( "Extension" );
132 OUString
aPartNameAttr( "PartName" );
133 OUString
aContentTypeAttr( "ContentType" );
134 OUString
aCDATAString( "CDATA" );
135 OUString
aWhiteSpace( " " );
137 // write the namespace
138 AttributeList
* pRootAttrList
= new AttributeList
;
139 uno::Reference
< xml::sax::XAttributeList
> xRootAttrList( pRootAttrList
);
140 pRootAttrList
->AddAttribute(
143 OUString( "http://schemas.openxmlformats.org/package/2006/content-types" ) );
145 xWriter
->startDocument();
146 xWriter
->startElement( aTypesElement
, xRootAttrList
);
148 for ( sal_Int32 nInd
= 0; nInd
< aDefaultsSequence
.getLength(); nInd
++ )
150 AttributeList
*pAttrList
= new AttributeList
;
151 uno::Reference
< xml::sax::XAttributeList
> xAttrList( pAttrList
);
152 pAttrList
->AddAttribute( aExtensionAttr
, aCDATAString
, aDefaultsSequence
[nInd
].First
);
153 pAttrList
->AddAttribute( aContentTypeAttr
, aCDATAString
, aDefaultsSequence
[nInd
].Second
);
155 xWriter
->startElement( aDefaultElement
, xAttrList
);
156 xWriter
->ignorableWhitespace( aWhiteSpace
);
157 xWriter
->endElement( aDefaultElement
);
160 for ( sal_Int32 nInd
= 0; nInd
< aOverridesSequence
.getLength(); nInd
++ )
162 AttributeList
*pAttrList
= new AttributeList
;
163 uno::Reference
< xml::sax::XAttributeList
> xAttrList( pAttrList
);
164 pAttrList
->AddAttribute( aPartNameAttr
, aCDATAString
, aOverridesSequence
[nInd
].First
);
165 pAttrList
->AddAttribute( aContentTypeAttr
, aCDATAString
, aOverridesSequence
[nInd
].Second
);
167 xWriter
->startElement( aOverrideElement
, xAttrList
);
168 xWriter
->ignorableWhitespace( aWhiteSpace
);
169 xWriter
->endElement( aOverrideElement
);
172 xWriter
->ignorableWhitespace( aWhiteSpace
);
173 xWriter
->endElement( aTypesElement
);
174 xWriter
->endDocument();
178 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
>& rContext
)
179 throw( uno::Exception
)
181 if ( !rContext
.is() || !xInStream
.is() || nFormat
> FORMAT_MAX_ID
)
182 throw uno::RuntimeException();
184 uno::Reference
< xml::sax::XParser
> xParser
= xml::sax::Parser::create( rContext
);
186 OFOPXMLHelper
* pHelper
= new OFOPXMLHelper( nFormat
);
187 uno::Reference
< xml::sax::XDocumentHandler
> xHelper( static_cast< xml::sax::XDocumentHandler
* >( pHelper
) );
188 xml::sax::InputSource aParserInput
;
189 aParserInput
.aInputStream
= xInStream
;
190 aParserInput
.sSystemId
= aStringID
;
191 xParser
->setDocumentHandler( xHelper
);
192 xParser
->parseStream( aParserInput
);
193 xParser
->setDocumentHandler( uno::Reference
< xml::sax::XDocumentHandler
> () );
195 return pHelper
->GetParsingResult();
198 OFOPXMLHelper::OFOPXMLHelper( sal_uInt16 nFormat
)
199 : m_nFormat( nFormat
)
200 , m_aRelListElement( "Relationships" )
201 , m_aRelElement( "Relationship" )
203 , m_aTypeAttr( "Type" )
204 , m_aTargetModeAttr( "TargetMode" )
205 , m_aTargetAttr( "Target" )
206 , m_aTypesElement( "Types" )
207 , m_aDefaultElement( "Default" )
208 , m_aOverrideElement( "Override" )
209 , m_aExtensionAttr( "Extension" )
210 , m_aPartNameAttr( "PartName" )
211 , m_aContentTypeAttr( "ContentType" )
216 OFOPXMLHelper::~OFOPXMLHelper()
221 uno::Sequence
< uno::Sequence
< beans::StringPair
> > OFOPXMLHelper::GetParsingResult()
223 if ( m_aElementsSeq
.getLength() )
224 throw uno::RuntimeException(); // the parsing has still not finished!
230 void SAL_CALL
OFOPXMLHelper::startDocument()
231 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
236 void SAL_CALL
OFOPXMLHelper::endDocument()
237 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
242 void SAL_CALL
OFOPXMLHelper::startElement( const OUString
& aName
, const uno::Reference
< xml::sax::XAttributeList
>& xAttribs
)
243 throw( xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
245 if ( m_nFormat
== RELATIONINFO_FORMAT
)
247 if ( aName
== m_aRelListElement
)
249 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
251 if ( nNewLength
!= 1 )
252 throw xml::sax::SAXException(); // TODO: this element must be the first level element
254 m_aElementsSeq
.realloc( nNewLength
);
255 m_aElementsSeq
[nNewLength
-1] = aName
;
257 return; // nothing to do
259 else if ( aName
== m_aRelElement
)
261 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
262 if ( nNewLength
!= 2 )
263 throw xml::sax::SAXException(); // TODO: this element must be the second level element
265 m_aElementsSeq
.realloc( nNewLength
);
266 m_aElementsSeq
[nNewLength
-1] = aName
;
268 sal_Int32 nNewEntryNum
= m_aResultSeq
.getLength() + 1;
269 m_aResultSeq
.realloc( nNewEntryNum
);
270 sal_Int32 nAttrNum
= 0;
271 m_aResultSeq
[nNewEntryNum
-1].realloc( 4 ); // the maximal expected number of arguments is 4
273 OUString aIDValue
= xAttribs
->getValueByName( m_aIDAttr
);
274 if ( aIDValue
.isEmpty() )
275 throw xml::sax::SAXException(); // TODO: the ID value must present
277 OUString aTypeValue
= xAttribs
->getValueByName( m_aTypeAttr
);
278 OUString aTargetValue
= xAttribs
->getValueByName( m_aTargetAttr
);
279 OUString aTargetModeValue
= xAttribs
->getValueByName( m_aTargetModeAttr
);
281 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aIDAttr
;
282 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aIDValue
;
284 if ( !aTypeValue
.isEmpty() )
286 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTypeAttr
;
287 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTypeValue
;
290 if ( !aTargetValue
.isEmpty() )
292 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTargetAttr
;
293 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTargetValue
;
296 if ( !aTargetModeValue
.isEmpty() )
298 m_aResultSeq
[nNewEntryNum
-1][++nAttrNum
- 1].First
= m_aTargetModeAttr
;
299 m_aResultSeq
[nNewEntryNum
-1][nAttrNum
- 1].Second
= aTargetModeValue
;
302 m_aResultSeq
[nNewEntryNum
-1].realloc( nAttrNum
);
305 throw xml::sax::SAXException(); // TODO: no other elements expected!
307 else if ( m_nFormat
== CONTENTTYPE_FORMAT
)
309 if ( aName
== m_aTypesElement
)
311 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
313 if ( nNewLength
!= 1 )
314 throw xml::sax::SAXException(); // TODO: this element must be the first level element
316 m_aElementsSeq
.realloc( nNewLength
);
317 m_aElementsSeq
[nNewLength
-1] = aName
;
319 if ( !m_aResultSeq
.getLength() )
320 m_aResultSeq
.realloc( 2 );
322 return; // nothing to do
324 else if ( aName
== m_aDefaultElement
)
326 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
327 if ( nNewLength
!= 2 )
328 throw xml::sax::SAXException(); // TODO: this element must be the second level element
330 m_aElementsSeq
.realloc( nNewLength
);
331 m_aElementsSeq
[nNewLength
-1] = aName
;
333 if ( !m_aResultSeq
.getLength() )
334 m_aResultSeq
.realloc( 2 );
336 if ( m_aResultSeq
.getLength() != 2 )
337 throw uno::RuntimeException();
339 OUString aExtensionValue
= xAttribs
->getValueByName( m_aExtensionAttr
);
340 if ( aExtensionValue
.isEmpty() )
341 throw xml::sax::SAXException(); // TODO: the Extension value must present
343 OUString aContentTypeValue
= xAttribs
->getValueByName( m_aContentTypeAttr
);
344 if ( aContentTypeValue
.isEmpty() )
345 throw xml::sax::SAXException(); // TODO: the ContentType value must present
347 sal_Int32 nNewResultLen
= m_aResultSeq
[0].getLength() + 1;
348 m_aResultSeq
[0].realloc( nNewResultLen
);
350 m_aResultSeq
[0][nNewResultLen
-1].First
= aExtensionValue
;
351 m_aResultSeq
[0][nNewResultLen
-1].Second
= aContentTypeValue
;
353 else if ( aName
== m_aOverrideElement
)
355 sal_Int32 nNewLength
= m_aElementsSeq
.getLength() + 1;
356 if ( nNewLength
!= 2 )
357 throw xml::sax::SAXException(); // TODO: this element must be the second level element
359 m_aElementsSeq
.realloc( nNewLength
);
360 m_aElementsSeq
[nNewLength
-1] = aName
;
362 if ( !m_aResultSeq
.getLength() )
363 m_aResultSeq
.realloc( 2 );
365 if ( m_aResultSeq
.getLength() != 2 )
366 throw uno::RuntimeException();
368 OUString aPartNameValue
= xAttribs
->getValueByName( m_aPartNameAttr
);
369 if ( aPartNameValue
.isEmpty() )
370 throw xml::sax::SAXException(); // TODO: the PartName value must present
372 OUString aContentTypeValue
= xAttribs
->getValueByName( m_aContentTypeAttr
);
373 if ( aContentTypeValue
.isEmpty() )
374 throw xml::sax::SAXException(); // TODO: the ContentType value must present
376 sal_Int32 nNewResultLen
= m_aResultSeq
[1].getLength() + 1;
377 m_aResultSeq
[1].realloc( nNewResultLen
);
379 m_aResultSeq
[1][nNewResultLen
-1].First
= aPartNameValue
;
380 m_aResultSeq
[1][nNewResultLen
-1].Second
= aContentTypeValue
;
383 throw xml::sax::SAXException(); // TODO: no other elements expected!
386 throw xml::sax::SAXException(); // TODO: no other elements expected!
390 void SAL_CALL
OFOPXMLHelper::endElement( const OUString
& aName
)
391 throw( xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
393 if ( m_nFormat
== RELATIONINFO_FORMAT
|| m_nFormat
== CONTENTTYPE_FORMAT
)
395 sal_Int32 nLength
= m_aElementsSeq
.getLength();
397 throw xml::sax::SAXException(); // TODO: no other end elements expected!
399 if ( !m_aElementsSeq
[nLength
-1].equals( aName
) )
400 throw xml::sax::SAXException(); // TODO: unexpected element ended
402 m_aElementsSeq
.realloc( nLength
- 1 );
407 void SAL_CALL
OFOPXMLHelper::characters( const OUString
& /*aChars*/ )
408 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
413 void SAL_CALL
OFOPXMLHelper::ignorableWhitespace( const OUString
& /*aWhitespaces*/ )
414 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
419 void SAL_CALL
OFOPXMLHelper::processingInstruction( const OUString
& /*aTarget*/, const OUString
& /*aData*/ )
420 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
425 void SAL_CALL
OFOPXMLHelper::setDocumentLocator( const uno::Reference
< xml::sax::XLocator
>& /*xLocator*/ )
426 throw(xml::sax::SAXException
, uno::RuntimeException
, std::exception
)
430 } // namespace comphelper
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */