gb_LinkTarget_use_clang: only use flto=thin with clang, not with gcc
[LibreOffice.git] / package / source / manifest / ManifestExport.cxx
blob7e7f22a3adfd439c46369216efa2e77de8697a54
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
21 #include <com/sun/star/xml/crypto/DigestID.hpp>
22 #include <com/sun/star/xml/crypto/CipherID.hpp>
23 #include <com/sun/star/beans/PropertyValue.hpp>
24 #include <com/sun/star/beans/NamedValue.hpp>
25 #include <com/sun/star/uno/RuntimeException.hpp>
27 #include "ManifestDefines.hxx"
28 #include "ManifestExport.hxx"
30 #include <osl/diagnose.h>
31 #include <rtl/ustrbuf.hxx>
32 #include <rtl/ref.hxx>
33 #include <sal/log.hxx>
34 #include <comphelper/base64.hxx>
35 #include <comphelper/documentconstants.hxx>
36 #include <comphelper/attributelist.hxx>
38 using namespace ::com::sun::star;
40 #if OSL_DEBUG_LEVEL > 0
41 #define THROW_WHERE SAL_WHERE
42 #else
43 #define THROW_WHERE ""
44 #endif
46 ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > const & xHandler, const uno::Sequence< uno::Sequence < beans::PropertyValue > >& rManList )
48 static const OUStringLiteral sKeyInfo ( u"KeyInfo" );
49 static const OUStringLiteral sPgpKeyIDProperty ( u"KeyId" );
50 static const OUStringLiteral sPgpKeyPacketProperty ( u"KeyPacket" );
51 static const OUStringLiteral sCipherValueProperty ( u"CipherValue" );
52 static const OUStringLiteral sFullPathProperty ( u"FullPath" );
53 static const OUStringLiteral sVersionProperty ( u"Version" );
54 static const OUStringLiteral sMediaTypeProperty ( u"MediaType" );
55 static const OUStringLiteral sIterationCountProperty ( u"IterationCount" );
56 static const OUStringLiteral sDerivedKeySizeProperty ( u"DerivedKeySize" );
57 static const OUStringLiteral sSaltProperty ( u"Salt" );
58 static const OUStringLiteral sInitialisationVectorProperty( u"InitialisationVector" );
59 static const OUStringLiteral sSizeProperty ( u"Size" );
60 static const OUStringLiteral sDigestProperty ( u"Digest" );
61 static const OUStringLiteral sEncryptionAlgProperty ( u"EncryptionAlgorithm" );
62 static const OUStringLiteral sStartKeyAlgProperty ( u"StartKeyAlgorithm" );
63 static const OUStringLiteral sDigestAlgProperty ( u"DigestAlgorithm" );
65 static const OUStringLiteral sWhiteSpace ( u" " );
67 const OUString sSHA256_URL_ODF12 ( SHA256_URL_ODF12 );
68 const OUString sSHA1_Name ( SHA1_NAME );
70 const OUString sSHA1_1k_Name ( SHA1_1K_NAME );
71 const OUString sSHA256_1k_URL ( SHA256_1K_URL );
73 const OUString sBlowfish_Name ( BLOWFISH_NAME );
74 const OUString sAES256_URL ( AES256_URL );
76 const OUString sPBKDF2_Name ( PBKDF2_NAME );
77 const OUString sPGP_Name ( PGP_NAME );
79 rtl::Reference<::comphelper::AttributeList> pRootAttrList = new ::comphelper::AttributeList;
81 // find the mediatype of the document if any
82 OUString aDocMediaType;
83 OUString aDocVersion;
84 const uno::Sequence<beans::PropertyValue>* pRootFolderPropSeq = nullptr;
85 for (const uno::Sequence < beans::PropertyValue >& rSequence : rManList)
87 OUString aMediaType;
88 OUString aPath;
89 OUString aVersion;
91 for (const beans::PropertyValue& rValue : rSequence)
93 if (rValue.Name == sMediaTypeProperty )
95 rValue.Value >>= aMediaType;
97 else if (rValue.Name == sFullPathProperty )
99 rValue.Value >>= aPath;
101 else if (rValue.Name == sVersionProperty )
103 rValue.Value >>= aVersion;
106 if ( !aPath.isEmpty() && !aMediaType.isEmpty() && !aVersion.isEmpty() )
107 break;
110 if ( aPath == "/" )
112 aDocMediaType = aMediaType;
113 aDocVersion = aVersion;
114 pRootFolderPropSeq = &rSequence;
115 break;
119 bool bProvideDTD = false;
120 bool bAcceptNonemptyVersion = false;
121 bool bStoreStartKeyGeneration = false;
122 if ( !aDocMediaType.isEmpty() )
124 if ( aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
125 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
126 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
127 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
128 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
129 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
130 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
131 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
132 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
133 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
134 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII
135 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
136 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
137 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
138 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
139 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII )
142 // oasis format
143 pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS,
144 ATTRIBUTE_CDATA,
145 MANIFEST_OASIS_NAMESPACE );
146 bAcceptNonemptyVersion = true;
147 if ( aDocVersion.compareTo( ODFVER_012_TEXT ) >= 0 )
149 // this is ODF12 or later generation, let encrypted
150 // streams contain start-key-generation entry
151 bStoreStartKeyGeneration = true;
152 pRootAttrList->AddAttribute ( ATTRIBUTE_VERSION, ATTRIBUTE_CDATA, aDocVersion );
153 // plus gpg4libre extensions - loext NS for that
154 pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS_LOEXT,
155 ATTRIBUTE_CDATA,
156 MANIFEST_LOEXT_NAMESPACE );
159 else
161 // even if it is no SO6 format the namespace must be specified
162 // thus SO6 format is used as default one
163 pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS,
164 ATTRIBUTE_CDATA,
165 MANIFEST_NAMESPACE );
167 bProvideDTD = true;
171 xHandler->startDocument();
172 uno::Reference < xml::sax::XExtendedDocumentHandler > xExtHandler ( xHandler, uno::UNO_QUERY );
173 if ( xExtHandler.is() && bProvideDTD )
175 xExtHandler->unknown ( MANIFEST_DOCTYPE );
176 xHandler->ignorableWhitespace ( sWhiteSpace );
178 xHandler->startElement( ELEMENT_MANIFEST, pRootAttrList );
180 const uno::Any *pKeyInfoProperty = nullptr;
181 if ( pRootFolderPropSeq )
183 // do we have package-wide encryption info?
184 for (const beans::PropertyValue& rValue : *pRootFolderPropSeq)
186 if (rValue.Name == sKeyInfo )
187 pKeyInfoProperty = &rValue.Value;
190 if ( pKeyInfoProperty )
192 // yeah, so that goes directly below the manifest:manifest
193 // element
194 OUStringBuffer aBuffer;
196 xHandler->ignorableWhitespace ( sWhiteSpace );
198 // ==== manifest:keyinfo & children
199 bool const isODF13(aDocVersion.compareTo(ODFVER_013_TEXT) >= 0);
200 if (!isODF13)
202 xHandler->startElement(ELEMENT_MANIFEST_KEYINFO, nullptr);
204 xHandler->ignorableWhitespace ( sWhiteSpace );
206 uno::Sequence< uno::Sequence < beans::NamedValue > > aKeyInfoSequence;
207 *pKeyInfoProperty >>= aKeyInfoSequence;
208 for (const uno::Sequence<beans::NamedValue>& rKeyInfoSequence : std::as_const(aKeyInfoSequence))
210 uno::Sequence < sal_Int8 > aPgpKeyID;
211 uno::Sequence < sal_Int8 > aPgpKeyPacket;
212 uno::Sequence < sal_Int8 > aCipherValue;
213 for (const beans::NamedValue& rNValue : rKeyInfoSequence)
215 if (rNValue.Name == sPgpKeyIDProperty )
216 rNValue.Value >>= aPgpKeyID;
217 else if (rNValue.Name == sPgpKeyPacketProperty )
218 rNValue.Value >>= aPgpKeyPacket;
219 else if (rNValue.Name == sCipherValueProperty )
220 rNValue.Value >>= aCipherValue;
223 if (aPgpKeyID.hasElements() && aCipherValue.hasElements() )
225 // ==== manifest:encrypted-key & children - one for each recipient
226 xHandler->startElement(isODF13 ? OUString(ELEMENT_ENCRYPTEDKEY13) : OUString(ELEMENT_ENCRYPTEDKEY), nullptr);
227 xHandler->ignorableWhitespace ( sWhiteSpace );
229 rtl::Reference<::comphelper::AttributeList> pNewAttrList = new ::comphelper::AttributeList;
230 // TODO: the algorithm should rather be configurable
231 pNewAttrList->AddAttribute(
232 isODF13 ? OUString(ATTRIBUTE_ALGORITHM13) : OUString(ATTRIBUTE_ALGORITHM),
233 ATTRIBUTE_CDATA,
234 "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" );
235 xHandler->startElement(isODF13 ? OUString(ELEMENT_ENCRYPTIONMETHOD13) : OUString(ELEMENT_ENCRYPTIONMETHOD), pNewAttrList);
236 xHandler->endElement(isODF13 ? OUString(ELEMENT_ENCRYPTIONMETHOD13) : OUString(ELEMENT_ENCRYPTIONMETHOD));
237 xHandler->ignorableWhitespace ( sWhiteSpace );
239 // note: the mismatch here corresponds to ODF 1.3 cs01 schema
240 xHandler->startElement(isODF13 ? OUString(ELEMENT_MANIFEST13_KEYINFO) : OUString(ELEMENT_MANIFEST_KEYINFO), nullptr);
241 xHandler->ignorableWhitespace ( sWhiteSpace );
243 xHandler->startElement(isODF13 ? OUString(ELEMENT_PGPDATA13) : OUString(ELEMENT_PGPDATA), nullptr);
244 xHandler->ignorableWhitespace ( sWhiteSpace );
246 xHandler->startElement(isODF13 ? OUString(ELEMENT_PGPKEYID13) : OUString(ELEMENT_PGPKEYID), nullptr);
247 ::comphelper::Base64::encode(aBuffer, aPgpKeyID);
248 xHandler->characters( aBuffer.makeStringAndClear() );
249 xHandler->endElement(isODF13 ? OUString(ELEMENT_PGPKEYID13) : OUString(ELEMENT_PGPKEYID));
250 xHandler->ignorableWhitespace ( sWhiteSpace );
252 // key packet is optional
253 if (aPgpKeyPacket.hasElements())
255 xHandler->startElement(isODF13 ? OUString(ELEMENT_PGPKEYPACKET13) : OUString(ELEMENT_PGPKEYPACKET), nullptr);
256 ::comphelper::Base64::encode(aBuffer, aPgpKeyPacket);
257 xHandler->characters( aBuffer.makeStringAndClear() );
258 xHandler->endElement(isODF13 ? OUString(ELEMENT_PGPKEYPACKET13) : OUString(ELEMENT_PGPKEYPACKET));
259 xHandler->ignorableWhitespace ( sWhiteSpace );
262 xHandler->endElement(isODF13 ? OUString(ELEMENT_PGPDATA13) : OUString(ELEMENT_PGPDATA));
263 xHandler->ignorableWhitespace ( sWhiteSpace );
265 xHandler->endElement(isODF13 ? OUString(ELEMENT_MANIFEST13_KEYINFO) : OUString(ELEMENT_MANIFEST_KEYINFO));
266 xHandler->ignorableWhitespace ( sWhiteSpace );
268 xHandler->startElement(isODF13 ? OUString(ELEMENT_CIPHERDATA13) : OUString(ELEMENT_CIPHERDATA), nullptr);
269 xHandler->ignorableWhitespace ( sWhiteSpace );
271 xHandler->startElement(isODF13 ? OUString(ELEMENT_CIPHERVALUE13) : OUString(ELEMENT_CIPHERVALUE), nullptr);
272 ::comphelper::Base64::encode(aBuffer, aCipherValue);
273 xHandler->characters( aBuffer.makeStringAndClear() );
274 xHandler->endElement(isODF13 ? OUString(ELEMENT_CIPHERVALUE13) : OUString(ELEMENT_CIPHERVALUE));
275 xHandler->ignorableWhitespace ( sWhiteSpace );
277 xHandler->endElement(isODF13 ? OUString(ELEMENT_CIPHERDATA13) : OUString(ELEMENT_CIPHERDATA));
278 xHandler->ignorableWhitespace ( sWhiteSpace );
280 xHandler->endElement(isODF13 ? OUString(ELEMENT_ENCRYPTEDKEY13) : OUString(ELEMENT_ENCRYPTEDKEY));
281 xHandler->ignorableWhitespace ( sWhiteSpace );
285 if (!isODF13)
287 xHandler->endElement(ELEMENT_MANIFEST_KEYINFO);
289 xHandler->ignorableWhitespace ( sWhiteSpace );
293 // now write individual file entries
294 for (const uno::Sequence<beans::PropertyValue>& rSequence : rManList)
296 rtl::Reference<::comphelper::AttributeList> pAttrList = new ::comphelper::AttributeList;
297 OUString aString;
298 const uno::Any *pVector = nullptr, *pSalt = nullptr, *pIterationCount = nullptr, *pDigest = nullptr, *pDigestAlg = nullptr, *pEncryptAlg = nullptr, *pStartKeyAlg = nullptr, *pDerivedKeySize = nullptr;
299 for (const beans::PropertyValue& rValue : rSequence)
301 if (rValue.Name == sMediaTypeProperty )
303 rValue.Value >>= aString;
304 pAttrList->AddAttribute ( ATTRIBUTE_MEDIA_TYPE, ATTRIBUTE_CDATA, aString );
306 else if (rValue.Name == sVersionProperty )
308 rValue.Value >>= aString;
309 // the version is stored only if it is not empty
310 if ( bAcceptNonemptyVersion && !aString.isEmpty() )
311 pAttrList->AddAttribute ( ATTRIBUTE_VERSION, ATTRIBUTE_CDATA, aString );
313 else if (rValue.Name == sFullPathProperty )
315 rValue.Value >>= aString;
316 pAttrList->AddAttribute ( ATTRIBUTE_FULL_PATH, ATTRIBUTE_CDATA, aString );
318 else if (rValue.Name == sSizeProperty )
320 sal_Int64 nSize = 0;
321 rValue.Value >>= nSize;
322 pAttrList->AddAttribute ( ATTRIBUTE_SIZE, ATTRIBUTE_CDATA, OUString::number( nSize ) );
324 else if (rValue.Name == sInitialisationVectorProperty )
325 pVector = &rValue.Value;
326 else if (rValue.Name == sSaltProperty )
327 pSalt = &rValue.Value;
328 else if (rValue.Name == sIterationCountProperty )
329 pIterationCount = &rValue.Value;
330 else if (rValue.Name == sDigestProperty )
331 pDigest = &rValue.Value;
332 else if (rValue.Name == sDigestAlgProperty )
333 pDigestAlg = &rValue.Value;
334 else if (rValue.Name == sEncryptionAlgProperty )
335 pEncryptAlg = &rValue.Value;
336 else if (rValue.Name == sStartKeyAlgProperty )
337 pStartKeyAlg = &rValue.Value;
338 else if (rValue.Name == sDerivedKeySizeProperty )
339 pDerivedKeySize = &rValue.Value;
342 xHandler->ignorableWhitespace ( sWhiteSpace );
343 xHandler->startElement( ELEMENT_FILE_ENTRY , pAttrList);
344 if ( pVector && pSalt && pIterationCount && pDigest && pDigestAlg && pEncryptAlg && pStartKeyAlg && pDerivedKeySize )
346 // ==== Encryption Data
347 rtl::Reference<::comphelper::AttributeList> pNewAttrList = new ::comphelper::AttributeList;
348 OUStringBuffer aBuffer;
349 uno::Sequence < sal_Int8 > aSequence;
351 xHandler->ignorableWhitespace ( sWhiteSpace );
353 // ==== Digest
354 OUString sChecksumType;
355 sal_Int32 nDigestAlgID = 0;
356 *pDigestAlg >>= nDigestAlgID;
357 if ( nDigestAlgID == xml::crypto::DigestID::SHA256_1K )
358 sChecksumType = sSHA256_1k_URL;
359 else if ( nDigestAlgID == xml::crypto::DigestID::SHA1_1K )
360 sChecksumType = sSHA1_1k_Name;
361 else
362 throw uno::RuntimeException( THROW_WHERE "Unexpected digest algorithm is provided!" );
364 pNewAttrList->AddAttribute ( ATTRIBUTE_CHECKSUM_TYPE, ATTRIBUTE_CDATA, sChecksumType );
365 *pDigest >>= aSequence;
366 ::comphelper::Base64::encode(aBuffer, aSequence);
367 pNewAttrList->AddAttribute ( ATTRIBUTE_CHECKSUM, ATTRIBUTE_CDATA, aBuffer.makeStringAndClear() );
369 xHandler->startElement( ELEMENT_ENCRYPTION_DATA , pNewAttrList);
371 // ==== Algorithm
372 pNewAttrList = new ::comphelper::AttributeList;
374 sal_Int32 nEncAlgID = 0;
375 sal_Int32 nDerivedKeySize = 0;
376 *pEncryptAlg >>= nEncAlgID;
377 *pDerivedKeySize >>= nDerivedKeySize;
379 OUString sEncAlgName;
380 if ( nEncAlgID == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
382 OSL_ENSURE( nDerivedKeySize, "Unexpected key size is provided!" );
383 if ( nDerivedKeySize != 32 )
384 throw uno::RuntimeException( THROW_WHERE "Unexpected key size is provided!" );
386 sEncAlgName = sAES256_URL;
388 else if ( nEncAlgID == xml::crypto::CipherID::BLOWFISH_CFB_8 )
390 sEncAlgName = sBlowfish_Name;
392 else
393 throw uno::RuntimeException( THROW_WHERE "Unexpected encryption algorithm is provided!" );
395 pNewAttrList->AddAttribute ( ATTRIBUTE_ALGORITHM_NAME, ATTRIBUTE_CDATA, sEncAlgName );
397 *pVector >>= aSequence;
398 ::comphelper::Base64::encode(aBuffer, aSequence);
399 pNewAttrList->AddAttribute ( ATTRIBUTE_INITIALISATION_VECTOR, ATTRIBUTE_CDATA, aBuffer.makeStringAndClear() );
401 xHandler->ignorableWhitespace ( sWhiteSpace );
402 xHandler->startElement( ELEMENT_ALGORITHM , pNewAttrList);
403 xHandler->ignorableWhitespace ( sWhiteSpace );
404 xHandler->endElement( ELEMENT_ALGORITHM );
406 if ( bStoreStartKeyGeneration )
408 // ==== Start Key Generation
409 pNewAttrList = new ::comphelper::AttributeList;
411 OUString sStartKeyAlg;
412 OUString sStartKeySize;
413 sal_Int32 nStartKeyAlgID = 0;
414 *pStartKeyAlg >>= nStartKeyAlgID;
415 if ( nStartKeyAlgID == xml::crypto::DigestID::SHA256 )
417 sStartKeyAlg = sSHA256_URL_ODF12; // TODO use SHA256_URL
418 aBuffer.append( sal_Int32(32) );
419 sStartKeySize = aBuffer.makeStringAndClear();
421 else if ( nStartKeyAlgID == xml::crypto::DigestID::SHA1 )
423 sStartKeyAlg = sSHA1_Name;
424 aBuffer.append( sal_Int32(20) );
425 sStartKeySize = aBuffer.makeStringAndClear();
427 else
428 throw uno::RuntimeException( THROW_WHERE "Unexpected start key algorithm is provided!" );
430 pNewAttrList->AddAttribute ( ATTRIBUTE_START_KEY_GENERATION_NAME, ATTRIBUTE_CDATA, sStartKeyAlg );
431 pNewAttrList->AddAttribute ( ATTRIBUTE_KEY_SIZE, ATTRIBUTE_CDATA, sStartKeySize );
433 xHandler->ignorableWhitespace ( sWhiteSpace );
434 xHandler->startElement( ELEMENT_START_KEY_GENERATION , pNewAttrList);
435 xHandler->ignorableWhitespace ( sWhiteSpace );
436 xHandler->endElement( ELEMENT_START_KEY_GENERATION );
439 // ==== Key Derivation
440 pNewAttrList = new ::comphelper::AttributeList;
442 if (pKeyInfoProperty)
444 pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
445 ATTRIBUTE_CDATA,
446 sPGP_Name);
447 // no start-key-generation needed, our session key has
448 // max size already
449 bStoreStartKeyGeneration = false;
451 else
453 pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
454 ATTRIBUTE_CDATA,
455 sPBKDF2_Name);
457 if (bStoreStartKeyGeneration)
459 aBuffer.append(nDerivedKeySize);
460 pNewAttrList->AddAttribute(ATTRIBUTE_KEY_SIZE, ATTRIBUTE_CDATA, aBuffer.makeStringAndClear());
463 sal_Int32 nCount = 0;
464 *pIterationCount >>= nCount;
465 aBuffer.append(nCount);
466 pNewAttrList->AddAttribute(ATTRIBUTE_ITERATION_COUNT, ATTRIBUTE_CDATA, aBuffer.makeStringAndClear());
468 *pSalt >>= aSequence;
469 ::comphelper::Base64::encode(aBuffer, aSequence);
470 pNewAttrList->AddAttribute(ATTRIBUTE_SALT, ATTRIBUTE_CDATA, aBuffer.makeStringAndClear());
473 xHandler->ignorableWhitespace(sWhiteSpace);
474 xHandler->startElement(ELEMENT_KEY_DERIVATION, pNewAttrList);
475 xHandler->ignorableWhitespace(sWhiteSpace);
476 xHandler->endElement(ELEMENT_KEY_DERIVATION);
478 xHandler->ignorableWhitespace ( sWhiteSpace );
479 xHandler->endElement( ELEMENT_ENCRYPTION_DATA );
481 xHandler->ignorableWhitespace ( sWhiteSpace );
482 xHandler->endElement( ELEMENT_FILE_ENTRY );
484 xHandler->ignorableWhitespace ( sWhiteSpace );
485 xHandler->endElement( ELEMENT_MANIFEST );
486 xHandler->endDocument();
489 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */