1 /*************************************************************************
2 *
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
6 *
7 * OpenOffice.org - a multi-platform office productivity suite
8 *
9 * This file is part of OpenOffice.org.
10 *
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
14 *
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org.  If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
25 *
26 ************************************************************************/
27 
28 #include "precompiled_configmgr.hxx"
29 #include "sal/config.h"
30 
31 #include "boost/noncopyable.hpp"
32 #include "com/sun/star/uno/Any.hxx"
33 #include "com/sun/star/uno/Reference.hxx"
34 #include "com/sun/star/uno/RuntimeException.hpp"
35 #include "com/sun/star/uno/Sequence.hxx"
36 #include "com/sun/star/uno/XInterface.hpp"
37 #include "osl/diagnose.h"
38 #include "osl/file.h"
39 #include "osl/file.hxx"
40 #include "rtl/string.h"
41 #include "rtl/string.hxx"
42 #include "rtl/textcvt.h"
43 #include "rtl/textenc.h"
44 #include "rtl/ustrbuf.hxx"
45 #include "rtl/ustring.h"
46 #include "rtl/ustring.hxx"
47 #include "sal/types.h"
48 #include "xmlreader/span.hxx"
49 
50 #include "data.hxx"
51 #include "groupnode.hxx"
52 #include "localizedpropertynode.hxx"
53 #include "localizedvaluenode.hxx"
54 #include "modifications.hxx"
55 #include "node.hxx"
56 #include "nodemap.hxx"
57 #include "propertynode.hxx"
58 #include "type.hxx"
59 #include "writemodfile.hxx"
60 
61 namespace configmgr {
62 
63 class Components;
64 
65 namespace {
66 
67 namespace css = com::sun::star;
68 
69 rtl::OString convertToUtf8(
70     rtl::OUString const & text, sal_Int32 offset, sal_Int32 length)
71 {
72     OSL_ASSERT(
73         offset <= text.getLength() && text.getLength() - offset >= length);
74     rtl::OString s;
75     if (!rtl_convertUStringToString(
76             &s.pData, text.pData->buffer + offset, length,
77             RTL_TEXTENCODING_UTF8,
78             (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
79              RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
80     {
81         throw css::uno::RuntimeException(
82             rtl::OUString(
83                 RTL_CONSTASCII_USTRINGPARAM("cannot convert to UTF-8")),
84             css::uno::Reference< css::uno::XInterface >());
85     }
86     return s;
87 }
88 
89 struct TempFile: public boost::noncopyable {
90     rtl::OUString url;
91     oslFileHandle handle;
92     bool closed;
93 
94     TempFile(): handle(0), closed(false) {}
95 
96     ~TempFile();
97 };
98 
99 TempFile::~TempFile() {
100     if (handle != 0) {
101         if (!closed) {
102             oslFileError e = osl_closeFile(handle);
103             if (e != osl_File_E_None) {
104                 OSL_TRACE(
105                     "osl_closeFile failed with %ld", static_cast< long >(e));
106             }
107         }
108         osl::FileBase::RC e = osl::File::remove(url);
109         if (e != osl::FileBase::E_None) {
110             OSL_TRACE("osl_removeFile failed with %ld", static_cast< long >(e));
111         }
112     }
113 }
114 
115 void writeData(oslFileHandle handle, char const * begin, sal_Int32 length) {
116     OSL_ASSERT(length >= 0);
117     sal_uInt64 n;
118     if ((osl_writeFile(handle, begin, static_cast< sal_uInt32 >(length), &n) !=
119          osl_File_E_None) ||
120         n != static_cast< sal_uInt32 >(length))
121     {
122         throw css::uno::RuntimeException(
123             rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("write failure")),
124             css::uno::Reference< css::uno::XInterface >());
125     }
126 }
127 
128 void writeData(oslFileHandle handle, rtl::OString const & text) {
129     writeData(handle, text.getStr(), text.getLength());
130 }
131 
132 void writeAttributeValue(oslFileHandle handle, rtl::OUString const & value) {
133     sal_Int32 i = 0;
134     sal_Int32 j = i;
135     for (; j < value.getLength(); ++j) {
136         OSL_ASSERT(
137             value[j] == 0x0009 || value[j] == 0x000A || value[j] == 0x000D ||
138             (value[j] >= 0x0020 && value[j] != 0xFFFE && value[j] != 0xFFFF));
139         switch(value[j]) {
140         case '\x09':
141             writeData(handle, convertToUtf8(value, i, j - i));
142             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&#9;"));
143             i = j + 1;
144             break;
145         case '\x0A':
146             writeData(handle, convertToUtf8(value, i, j - i));
147             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&#xA;"));
148             i = j + 1;
149             break;
150         case '\x0D':
151             writeData(handle, convertToUtf8(value, i, j - i));
152             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&#xD;"));
153             i = j + 1;
154             break;
155         case '"':
156             writeData(handle, convertToUtf8(value, i, j - i));
157             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&quot;"));
158             i = j + 1;
159             break;
160         case '&':
161             writeData(handle, convertToUtf8(value, i, j - i));
162             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&amp;"));
163             i = j + 1;
164             break;
165         case '<':
166             writeData(handle, convertToUtf8(value, i, j - i));
167             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&lt;"));
168             i = j + 1;
169             break;
170         default:
171             break;
172         }
173     }
174     writeData(handle, convertToUtf8(value, i, j - i));
175 }
176 
177 void writeValueContent(oslFileHandle handle, sal_Bool value) {
178     if (value) {
179         writeData(handle, RTL_CONSTASCII_STRINGPARAM("true"));
180     } else {
181         writeData(handle, RTL_CONSTASCII_STRINGPARAM("false"));
182     }
183 }
184 
185 void writeValueContent(oslFileHandle handle, sal_Int16 value) {
186     writeData(handle, rtl::OString::valueOf(static_cast< sal_Int32 >(value)));
187 }
188 
189 void writeValueContent(oslFileHandle handle, sal_Int32 value) {
190     writeData(handle, rtl::OString::valueOf(value));
191 }
192 
193 void writeValueContent(oslFileHandle handle, sal_Int64 value) {
194     writeData(handle, rtl::OString::valueOf(value));
195 }
196 
197 void writeValueContent(oslFileHandle handle, double value) {
198     writeData(handle, rtl::OString::valueOf(value));
199 }
200 
201 void writeValueContent(oslFileHandle handle, rtl::OUString const & value) {
202     sal_Int32 i = 0;
203     sal_Int32 j = i;
204     for (; j < value.getLength(); ++j) {
205         sal_Unicode c = value[j];
206         if ((c < 0x0020 && c != 0x0009 && c != 0x000A && c != 0x000D) ||
207             c == 0xFFFE || c == 0xFFFF)
208         {
209             writeData(handle, convertToUtf8(value, i, j - i));
210             writeData(
211                 handle, RTL_CONSTASCII_STRINGPARAM("<unicode oor:scalar=\""));
212             writeData(
213                 handle, rtl::OString::valueOf(static_cast< sal_Int32 >(c)));
214             writeData(handle, RTL_CONSTASCII_STRINGPARAM("\"/>"));
215             i = j + 1;
216         } else if (c == '\x0D') {
217             writeData(handle, convertToUtf8(value, i, j - i));
218             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&#xD;"));
219             i = j + 1;
220         } else if (c == '&') {
221             writeData(handle, convertToUtf8(value, i, j - i));
222             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&amp;"));
223             i = j + 1;
224         } else if (c == '<') {
225             writeData(handle, convertToUtf8(value, i, j - i));
226             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&lt;"));
227             i = j + 1;
228         } else if (c == '>') {
229             // "MUST, for compatibility, be escaped [...] when it appears in the
230             // string ']]>'":
231             writeData(handle, convertToUtf8(value, i, j - i));
232             writeData(handle, RTL_CONSTASCII_STRINGPARAM("&gt;"));
233             i = j + 1;
234         }
235     }
236     writeData(handle, convertToUtf8(value, i, j - i));
237 }
238 
239 void writeValueContent(
240     oslFileHandle handle, css::uno::Sequence< sal_Int8 > const & value)
241 {
242     for (sal_Int32 i = 0; i < value.getLength(); ++i) {
243         static char const hexDigit[16] = {
244             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
245             'D', 'E', 'F' };
246         writeData(handle, hexDigit + ((value[i] >> 4) & 0xF), 1);
247         writeData(handle, hexDigit + (value[i] & 0xF), 1);
248     }
249 }
250 
251 template< typename T > void writeSingleValue(
252     oslFileHandle handle, css::uno::Any const & value)
253 {
254     writeData(handle, RTL_CONSTASCII_STRINGPARAM(">"));
255     T val = T();
256     value >>= val;
257     writeValueContent(handle, val);
258     writeData(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
259 }
260 
261 template< typename T > void writeListValue(
262     oslFileHandle handle, css::uno::Any const & value)
263 {
264     writeData(handle, RTL_CONSTASCII_STRINGPARAM(">"));
265     css::uno::Sequence< T > val;
266     value >>= val;
267     for (sal_Int32 i = 0; i < val.getLength(); ++i) {
268         if (i != 0) {
269             writeData(handle, RTL_CONSTASCII_STRINGPARAM(" "));
270         }
271         writeValueContent(handle, val[i]);
272     }
273     writeData(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
274 }
275 
276 template< typename T > void writeItemListValue(
277     oslFileHandle handle, css::uno::Any const & value)
278 {
279     writeData(handle, RTL_CONSTASCII_STRINGPARAM(">"));
280     css::uno::Sequence< T > val;
281     value >>= val;
282     for (sal_Int32 i = 0; i < val.getLength(); ++i) {
283         writeData(handle, RTL_CONSTASCII_STRINGPARAM("<it>"));
284         writeValueContent(handle, val[i]);
285         writeData(handle, RTL_CONSTASCII_STRINGPARAM("</it>"));
286     }
287     writeData(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
288 }
289 
290 void writeValue(oslFileHandle handle, Type type, css::uno::Any const & value) {
291     switch (type) {
292     case TYPE_BOOLEAN:
293         writeSingleValue< sal_Bool >(handle, value);
294         break;
295     case TYPE_SHORT:
296         writeSingleValue< sal_Int16 >(handle, value);
297         break;
298     case TYPE_INT:
299         writeSingleValue< sal_Int32 >(handle, value);
300         break;
301     case TYPE_LONG:
302         writeSingleValue< sal_Int64 >(handle, value);
303         break;
304     case TYPE_DOUBLE:
305         writeSingleValue< double >(handle, value);
306         break;
307     case TYPE_STRING:
308         writeSingleValue< rtl::OUString >(handle, value);
309         break;
310     case TYPE_HEXBINARY:
311         writeSingleValue< css::uno::Sequence< sal_Int8 > >(handle, value);
312         break;
313     case TYPE_BOOLEAN_LIST:
314         writeListValue< sal_Bool >(handle, value);
315         break;
316     case TYPE_SHORT_LIST:
317         writeListValue< sal_Int16 >(handle, value);
318         break;
319     case TYPE_INT_LIST:
320         writeListValue< sal_Int32 >(handle, value);
321         break;
322     case TYPE_LONG_LIST:
323         writeListValue< sal_Int64 >(handle, value);
324         break;
325     case TYPE_DOUBLE_LIST:
326         writeListValue< double >(handle, value);
327         break;
328     case TYPE_STRING_LIST:
329         writeItemListValue< rtl::OUString >(handle, value);
330         break;
331     case TYPE_HEXBINARY_LIST:
332         writeItemListValue< css::uno::Sequence< sal_Int8 > >(handle, value);
333         break;
334     default: // TYPE_ERROR, TYPE_NIL, TYPE_ANY
335         OSL_ASSERT(false); // this cannot happen
336     }
337 }
338 
339 void writeNode(
340     Components & components, oslFileHandle handle,
341     rtl::Reference< Node > const & parent, rtl::OUString const & name,
342     rtl::Reference< Node > const & node)
343 {
344     static xmlreader::Span const typeNames[] = {
345         xmlreader::Span(), xmlreader::Span(), xmlreader::Span(),
346             // TYPE_ERROR, TYPE_NIL, TYPE_ANY
347         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:boolean")),
348         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:short")),
349         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:int")),
350         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:long")),
351         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:double")),
352         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:string")),
353         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:hexBinary")),
354         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:boolean-list")),
355         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:short-list")),
356         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:int-list")),
357         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:long-list")),
358         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:double-list")),
359         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:string-list")),
360         xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:hexBinary-list")) };
361     switch (node->kind()) {
362     case Node::KIND_PROPERTY:
363         {
364             PropertyNode * prop = dynamic_cast< PropertyNode * >(node.get());
365             writeData(handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
366             writeAttributeValue(handle, name);
367             writeData(handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"fuse\""));
368             Type type = prop->getStaticType();
369             Type dynType = getDynamicType(prop->getValue(components));
370             OSL_ASSERT(dynType != TYPE_ERROR);
371             if (type == TYPE_ANY) {
372                 type = dynType;
373                 if (type != TYPE_NIL) {
374                     writeData(
375                         handle, RTL_CONSTASCII_STRINGPARAM(" oor:type=\""));
376                     writeData(
377                         handle, typeNames[type].begin, typeNames[type].length);
378                     writeData(handle, RTL_CONSTASCII_STRINGPARAM("\""));
379                 }
380             }
381             writeData(handle, "><value");
382             if (dynType == TYPE_NIL) {
383                 writeData(
384                     handle, RTL_CONSTASCII_STRINGPARAM(" xsi:nil=\"true\"/>"));
385             } else {
386                 writeValue(handle, type, prop->getValue(components));
387             }
388             writeData(handle, "</prop>");
389         }
390         break;
391     case Node::KIND_LOCALIZED_PROPERTY:
392         writeData(handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
393         writeAttributeValue(handle, name);
394         writeData(handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"fuse\">"));
395         for (NodeMap::iterator i(node->getMembers().begin());
396              i != node->getMembers().end(); ++i)
397         {
398             writeNode(components, handle, node, i->first, i->second);
399         }
400         writeData(handle, RTL_CONSTASCII_STRINGPARAM("</prop>"));
401         break;
402     case Node::KIND_LOCALIZED_VALUE:
403         {
404             writeData(handle, RTL_CONSTASCII_STRINGPARAM("<value"));
405             if (name.getLength() != 0) {
406                 writeData(handle, RTL_CONSTASCII_STRINGPARAM(" xml:lang=\""));
407                 writeAttributeValue(handle, name);
408                 writeData(handle, RTL_CONSTASCII_STRINGPARAM("\""));
409             }
410             Type type = dynamic_cast< LocalizedPropertyNode * >(parent.get())->
411                 getStaticType();
412             css::uno::Any value(
413                 dynamic_cast< LocalizedValueNode * >(node.get())->getValue());
414             Type dynType = getDynamicType(value);
415             OSL_ASSERT(dynType != TYPE_ERROR);
416             if (type == TYPE_ANY) {
417                 type = dynType;
418                 if (type != TYPE_NIL) {
419                     writeData(
420                         handle, RTL_CONSTASCII_STRINGPARAM(" oor:type=\""));
421                     writeData(
422                         handle, typeNames[type].begin, typeNames[type].length);
423                     writeData(handle, RTL_CONSTASCII_STRINGPARAM("\""));
424                 }
425             }
426             if (dynType == TYPE_NIL) {
427                 writeData(
428                     handle, RTL_CONSTASCII_STRINGPARAM(" xsi:nil=\"true\"/>"));
429             } else {
430                 writeValue(handle, type, value);
431             }
432         }
433         break;
434     case Node::KIND_GROUP:
435     case Node::KIND_SET:
436         writeData(handle, RTL_CONSTASCII_STRINGPARAM("<node oor:name=\""));
437         writeAttributeValue(handle, name);
438         if (node->getTemplateName().getLength() != 0) { // set member
439             writeData(
440                 handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"replace"));
441         }
442         writeData(handle, RTL_CONSTASCII_STRINGPARAM("\">"));
443         for (NodeMap::iterator i(node->getMembers().begin());
444              i != node->getMembers().end(); ++i)
445         {
446             writeNode(components, handle, node, i->first, i->second);
447         }
448         writeData(handle, RTL_CONSTASCII_STRINGPARAM("</node>"));
449         break;
450     }
451 }
452 
453 void writeModifications(
454     Components & components, oslFileHandle handle,
455     rtl::OUString const & parentPathRepresentation,
456     rtl::Reference< Node > const & parent, rtl::OUString const & nodeName,
457     rtl::Reference< Node > const & node,
458     Modifications::Node const & modifications)
459 {
460     // It is never necessary to write oor:finalized or oor:mandatory attributes,
461     // as they cannot be set via the UNO API.
462     if (modifications.children.empty()) {
463         OSL_ASSERT(parent.is());
464             // components themselves have no parent but must have children
465         writeData(handle, RTL_CONSTASCII_STRINGPARAM("<item oor:path=\""));
466         writeAttributeValue(handle, parentPathRepresentation);
467         writeData(handle, RTL_CONSTASCII_STRINGPARAM("\">"));
468         if (node.is()) {
469             writeNode(components, handle, parent, nodeName, node);
470         } else {
471             switch (parent->kind()) {
472             case Node::KIND_LOCALIZED_PROPERTY:
473                 writeData(handle, RTL_CONSTASCII_STRINGPARAM("<value"));
474                 if (nodeName.getLength() != 0) {
475                     writeData(
476                         handle, RTL_CONSTASCII_STRINGPARAM(" xml:lang=\""));
477                     writeAttributeValue(handle, nodeName);
478                     writeData(handle, RTL_CONSTASCII_STRINGPARAM("\""));
479                 }
480                 writeData(
481                     handle, RTL_CONSTASCII_STRINGPARAM(" oor:op=\"remove\"/>"));
482                 break;
483             case Node::KIND_GROUP:
484                 OSL_ASSERT(
485                     dynamic_cast< GroupNode * >(parent.get())->isExtensible());
486                 writeData(
487                     handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
488                 writeAttributeValue(handle, nodeName);
489                 writeData(
490                     handle,
491                     RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"remove\"/>"));
492                 break;
493             case Node::KIND_SET:
494                 writeData(
495                     handle, RTL_CONSTASCII_STRINGPARAM("<node oor:name=\""));
496                 writeAttributeValue(handle, nodeName);
497                 writeData(
498                     handle,
499                     RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"remove\"/>"));
500                 break;
501             default:
502                 OSL_ASSERT(false); // this cannot happen
503                 break;
504             }
505         }
506         writeData(handle, RTL_CONSTASCII_STRINGPARAM("</item>"));
507     } else {
508         OSL_ASSERT(node.is());
509         rtl::OUString pathRep(
510             parentPathRepresentation +
511             rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")) +
512             Data::createSegment(node->getTemplateName(), nodeName));
513         for (Modifications::Node::Children::const_iterator i(
514                  modifications.children.begin());
515              i != modifications.children.end(); ++i)
516         {
517             writeModifications(
518                 components, handle, pathRep, node, i->first,
519                 node->getMember(i->first), i->second);
520         }
521     }
522 }
523 
524 }
525 
526 void writeModFile(
527     Components & components, rtl::OUString const & url, Data const & data)
528 {
529     sal_Int32 i = url.lastIndexOf('/');
530     OSL_ASSERT(i != -1);
531     rtl::OUString dir(url.copy(0, i));
532     switch (osl::Directory::createPath(dir)) {
533     case osl::FileBase::E_None:
534     case osl::FileBase::E_EXIST:
535         break;
536     case osl::FileBase::E_ACCES:
537         OSL_TRACE(
538             "cannot create registrymodifications.xcu path (E_ACCES); changes"
539             " will be lost");
540         return;
541     default:
542         throw css::uno::RuntimeException(
543             (rtl::OUString(
544                 RTL_CONSTASCII_USTRINGPARAM("cannot create directory ")) +
545              dir),
546             css::uno::Reference< css::uno::XInterface >());
547     }
548     TempFile tmp;
549     switch (osl::FileBase::createTempFile(&dir, &tmp.handle, &tmp.url)) {
550     case osl::FileBase::E_None:
551         break;
552     case osl::FileBase::E_ACCES:
553         OSL_TRACE(
554             "cannot create temp registrymodifications.xcu (E_ACCES); changes"
555             " will be lost");
556         return;
557     default:
558         throw css::uno::RuntimeException(
559             (rtl::OUString(
560                 RTL_CONSTASCII_USTRINGPARAM(
561                     "cannot create temporary file in ")) +
562              dir),
563             css::uno::Reference< css::uno::XInterface >());
564     }
565     writeData(
566         tmp.handle,
567         RTL_CONSTASCII_STRINGPARAM(
568             "<?xml version=\"1.0\" encoding=\"UTF-8\"?><oor:items"
569             " xmlns:oor=\"http://openoffice.org/2001/registry\""
570             " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
571             " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"));
572     //TODO: Do not write back information about those removed items that did not
573     // come from the .xcs/.xcu files, anyway (but had been added dynamically
574     // instead):
575     for (Modifications::Node::Children::const_iterator j(
576              data.modifications.getRoot().children.begin());
577          j != data.modifications.getRoot().children.end(); ++j)
578     {
579         writeModifications(
580             components, tmp.handle, rtl::OUString(), rtl::Reference< Node >(),
581             j->first, Data::findNode(Data::NO_LAYER, data.components, j->first),
582             j->second);
583     }
584     writeData(tmp.handle, RTL_CONSTASCII_STRINGPARAM("</oor:items>"));
585     oslFileError e = osl_closeFile(tmp.handle);
586     tmp.closed = true;
587     if (e != osl_File_E_None) {
588         throw css::uno::RuntimeException(
589             (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cannot close ")) +
590              tmp.url),
591             css::uno::Reference< css::uno::XInterface >());
592     }
593     if (osl::File::move(tmp.url, url) != osl::FileBase::E_None) {
594         throw css::uno::RuntimeException(
595             (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cannot move ")) +
596              tmp.url),
597             css::uno::Reference< css::uno::XInterface >());
598     }
599     tmp.handle = 0;
600 }
601 
602 }
603