build fix
[LibreOffice.git] / configmgr / source / writemodfile.cxx
bloba1e545e5b5a36b382d88a2ff4922f5d0b678a030
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 <sal/config.h>
22 #include <cassert>
24 #include <com/sun/star/uno/Any.hxx>
25 #include <com/sun/star/uno/Reference.hxx>
26 #include <com/sun/star/uno/RuntimeException.hpp>
27 #include <com/sun/star/uno/Sequence.hxx>
28 #include <com/sun/star/uno/XInterface.hpp>
29 #include <osl/file.h>
30 #include <osl/file.hxx>
31 #include <rtl/string.h>
32 #include <rtl/string.hxx>
33 #include <rtl/textcvt.h>
34 #include <rtl/textenc.h>
35 #include <rtl/ustrbuf.hxx>
36 #include <rtl/ustring.h>
37 #include <rtl/ustring.hxx>
38 #include <rtl/strbuf.hxx>
39 #include <sal/log.hxx>
40 #include <sal/types.h>
41 #include <xmlreader/span.hxx>
43 #include "data.hxx"
44 #include "groupnode.hxx"
45 #include "localizedpropertynode.hxx"
46 #include "localizedvaluenode.hxx"
47 #include "modifications.hxx"
48 #include "node.hxx"
49 #include "nodemap.hxx"
50 #include "propertynode.hxx"
51 #include "type.hxx"
52 #include "writemodfile.hxx"
54 namespace configmgr {
56 class Components;
58 namespace {
60 OString convertToUtf8(
61 OUString const & text, sal_Int32 offset, sal_Int32 length)
63 assert(offset <= text.getLength() && text.getLength() - offset >= length);
64 OString s;
65 if (!rtl_convertUStringToString(
66 &s.pData, text.pData->buffer + offset, length,
67 RTL_TEXTENCODING_UTF8,
68 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
69 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
71 throw css::uno::RuntimeException(
72 "cannot convert to UTF-8");
74 return s;
77 } // anonymous namespace
79 TempFile::~TempFile() {
80 if (handle != nullptr) {
81 if (!closed) {
82 oslFileError e = osl_closeFile(handle);
83 if (e != osl_File_E_None) {
84 SAL_WARN("configmgr", "osl_closeFile failed with " << +e);
87 osl::FileBase::RC e = osl::File::remove(url);
88 if (e != osl::FileBase::E_None) {
89 SAL_WARN(
90 "configmgr",
91 "osl::File::remove(" << url << ") failed with " << +e);
96 #ifdef _WIN32
97 oslFileError TempFile::closeWithoutUnlink() {
98 flush();
99 oslFileError e = osl_closeFile(handle);
100 handle = nullptr;
101 closed = true;
102 return e;
104 #endif
106 void TempFile::closeAndRename(const OUString &_url) {
107 oslFileError e = flush();
108 if (e != osl_File_E_None) {
109 throw css::uno::RuntimeException(
110 "cannot write to " + url);
112 e = osl_closeFile(handle);
113 closed = true;
114 if (e != osl_File_E_None) {
115 throw css::uno::RuntimeException(
116 "cannot close " + url);
118 if (osl::File::move(url, _url) != osl::FileBase::E_None) {
119 throw css::uno::RuntimeException(
120 "cannot move " + url);
122 handle = nullptr;
125 oslFileError TempFile::flush() {
126 oslFileError e = osl_File_E_None;
127 if (!buffer.isEmpty()) {
128 sal_uInt64 nBytesWritten = 0;
129 e = osl_writeFile(handle, buffer.getStr(),
130 static_cast< sal_uInt32 >(buffer.getLength()),
131 &nBytesWritten);
132 if (nBytesWritten != static_cast< sal_uInt32 >(buffer.getLength())) {
133 // queue up any error / exception until close.
134 buffer.remove(0, static_cast< sal_Int32 >( nBytesWritten ) );
135 } else {
136 buffer.setLength(0);
139 return e;
142 void TempFile::writeString(char const *begin, sal_Int32 length) {
143 buffer.append(begin, length);
144 if (buffer.getLength() > 0x10000)
145 flush();
148 namespace {
150 void writeData_(TempFile &handle, char const * begin, sal_Int32 length) {
151 assert(length >= 0);
152 handle.writeString(begin, length);
155 void writeValueContent_(TempFile &, bool) = delete;
156 // silence loplugin:salbool
157 void writeValueContent_(TempFile &handle, sal_Bool value) {
158 if (value) {
159 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("true"));
160 } else {
161 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("false"));
165 void writeValueContent_(TempFile &handle, sal_Int16 value) {
166 writeData(handle, OString::number(value));
169 void writeValueContent_(TempFile &handle, sal_Int32 value) {
170 writeData(handle, OString::number(value));
173 void writeValueContent_(TempFile &handle, sal_Int64 value) {
174 writeData(handle, OString::number(value));
177 void writeValueContent_(TempFile &handle, double value) {
178 writeData(handle, OString::number(value));
181 void writeValueContent_(TempFile &handle, const OUString& value) {
182 writeValueContent(handle, value);
185 void writeValueContent_(
186 TempFile &handle, css::uno::Sequence< sal_Int8 > const & value)
188 for (sal_Int32 i = 0; i < value.getLength(); ++i) {
189 static char const hexDigit[16] = {
190 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
191 'D', 'E', 'F' };
192 writeData_(handle, hexDigit + ((value[i] >> 4) & 0xF), 1);
193 writeData_(handle, hexDigit + (value[i] & 0xF), 1);
197 template< typename T > void writeSingleValue(
198 TempFile &handle, css::uno::Any const & value)
200 writeData_(handle, RTL_CONSTASCII_STRINGPARAM(">"));
201 T val = T();
202 value >>= val;
203 writeValueContent_(handle, val);
204 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
207 template< typename T > void writeListValue(
208 TempFile &handle, css::uno::Any const & value)
210 writeData_(handle, RTL_CONSTASCII_STRINGPARAM(">"));
211 css::uno::Sequence< T > val;
212 value >>= val;
213 for (sal_Int32 i = 0; i < val.getLength(); ++i) {
214 if (i != 0) {
215 writeData_(handle, RTL_CONSTASCII_STRINGPARAM(" "));
217 writeValueContent_(handle, val[i]);
219 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
222 template< typename T > void writeItemListValue(
223 TempFile &handle, css::uno::Any const & value)
225 writeData_(handle, RTL_CONSTASCII_STRINGPARAM(">"));
226 css::uno::Sequence< T > val;
227 value >>= val;
228 for (sal_Int32 i = 0; i < val.getLength(); ++i) {
229 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<it>"));
230 writeValueContent_(handle, val[i]);
231 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</it>"));
233 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
236 void writeValue(TempFile &handle, Type type, css::uno::Any const & value) {
237 switch (type) {
238 case TYPE_BOOLEAN:
239 writeSingleValue< sal_Bool >(handle, value);
240 break;
241 case TYPE_SHORT:
242 writeSingleValue< sal_Int16 >(handle, value);
243 break;
244 case TYPE_INT:
245 writeSingleValue< sal_Int32 >(handle, value);
246 break;
247 case TYPE_LONG:
248 writeSingleValue< sal_Int64 >(handle, value);
249 break;
250 case TYPE_DOUBLE:
251 writeSingleValue< double >(handle, value);
252 break;
253 case TYPE_STRING:
254 writeSingleValue< OUString >(handle, value);
255 break;
256 case TYPE_HEXBINARY:
257 writeSingleValue< css::uno::Sequence< sal_Int8 > >(handle, value);
258 break;
259 case TYPE_BOOLEAN_LIST:
260 writeListValue< sal_Bool >(handle, value);
261 break;
262 case TYPE_SHORT_LIST:
263 writeListValue< sal_Int16 >(handle, value);
264 break;
265 case TYPE_INT_LIST:
266 writeListValue< sal_Int32 >(handle, value);
267 break;
268 case TYPE_LONG_LIST:
269 writeListValue< sal_Int64 >(handle, value);
270 break;
271 case TYPE_DOUBLE_LIST:
272 writeListValue< double >(handle, value);
273 break;
274 case TYPE_STRING_LIST:
275 writeItemListValue< OUString >(handle, value);
276 break;
277 case TYPE_HEXBINARY_LIST:
278 writeItemListValue< css::uno::Sequence< sal_Int8 > >(handle, value);
279 break;
280 default: // TYPE_ERROR, TYPE_NIL, TYPE_ANY
281 assert(false); // this cannot happen
285 void writeNode(
286 Components & components, TempFile &handle,
287 rtl::Reference< Node > const & parent, OUString const & name,
288 rtl::Reference< Node > const & node)
290 static xmlreader::Span const typeNames[] = {
291 xmlreader::Span(), xmlreader::Span(), xmlreader::Span(),
292 // TYPE_ERROR, TYPE_NIL, TYPE_ANY
293 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:boolean")),
294 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:short")),
295 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:int")),
296 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:long")),
297 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:double")),
298 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:string")),
299 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:hexBinary")),
300 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:boolean-list")),
301 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:short-list")),
302 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:int-list")),
303 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:long-list")),
304 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:double-list")),
305 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:string-list")),
306 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:hexBinary-list")) };
307 switch (node->kind()) {
308 case Node::KIND_PROPERTY:
310 PropertyNode * prop = static_cast< PropertyNode * >(node.get());
311 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
312 writeAttributeValue(handle, name);
313 writeData_(
314 handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"fuse\""));
315 Type type = prop->getStaticType();
316 Type dynType = getDynamicType(prop->getValue(components));
317 assert(dynType != TYPE_ERROR);
318 if (type == TYPE_ANY) {
319 type = dynType;
320 if (type != TYPE_NIL) {
321 writeData_(
322 handle, RTL_CONSTASCII_STRINGPARAM(" oor:type=\""));
323 writeData_(
324 handle, typeNames[type].begin, typeNames[type].length);
325 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\""));
328 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("><value"));
329 if (dynType == TYPE_NIL) {
330 writeData_(
331 handle, RTL_CONSTASCII_STRINGPARAM(" xsi:nil=\"true\"/>"));
332 } else {
333 writeValue(handle, type, prop->getValue(components));
335 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</prop>"));
337 break;
338 case Node::KIND_LOCALIZED_PROPERTY:
339 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
340 writeAttributeValue(handle, name);
341 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"fuse\">"));
342 for (NodeMap::const_iterator i(node->getMembers().begin());
343 i != node->getMembers().end(); ++i)
345 writeNode(components, handle, node, i->first, i->second);
347 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</prop>"));
348 break;
349 case Node::KIND_LOCALIZED_VALUE:
351 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<value"));
352 if (!name.isEmpty()) {
353 writeData_(handle, RTL_CONSTASCII_STRINGPARAM(" xml:lang=\""));
354 writeAttributeValue(handle, name);
355 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\""));
357 Type type = static_cast< LocalizedPropertyNode * >(parent.get())->
358 getStaticType();
359 css::uno::Any value(
360 static_cast< LocalizedValueNode * >(node.get())->getValue());
361 Type dynType = getDynamicType(value);
362 assert(dynType != TYPE_ERROR);
363 if (type == TYPE_ANY) {
364 type = dynType;
365 if (type != TYPE_NIL) {
366 writeData_(
367 handle, RTL_CONSTASCII_STRINGPARAM(" oor:type=\""));
368 writeData_(
369 handle, typeNames[type].begin, typeNames[type].length);
370 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\""));
373 if (dynType == TYPE_NIL) {
374 writeData_(
375 handle, RTL_CONSTASCII_STRINGPARAM(" xsi:nil=\"true\"/>"));
376 } else {
377 writeValue(handle, type, value);
380 break;
381 case Node::KIND_GROUP:
382 case Node::KIND_SET:
383 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<node oor:name=\""));
384 writeAttributeValue(handle, name);
385 if (!node->getTemplateName().isEmpty()) { // set member
386 writeData_(
387 handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"replace"));
389 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\">"));
390 for (NodeMap::const_iterator i(node->getMembers().begin());
391 i != node->getMembers().end(); ++i)
393 writeNode(components, handle, node, i->first, i->second);
395 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</node>"));
396 break;
397 case Node::KIND_ROOT:
398 assert(false); // this cannot happen
399 break;
403 // helpers to allow sorting of configmgr::Modifications::Node
404 typedef std::pair< const rtl::OUString, configmgr::Modifications::Node > ModNodePairEntry;
405 struct PairEntrySorter
407 bool operator() (const ModNodePairEntry* pValue1, const ModNodePairEntry* pValue2) const
409 return pValue1->first.compareTo(pValue2->first) < 0;
413 void writeModifications(
414 Components & components, TempFile &handle,
415 OUString const & parentPathRepresentation,
416 rtl::Reference< Node > const & parent, OUString const & nodeName,
417 rtl::Reference< Node > const & node,
418 Modifications::Node const & modifications)
420 // It is never necessary to write oor:finalized or oor:mandatory attributes,
421 // as they cannot be set via the UNO API.
422 if (modifications.children.empty()) {
423 assert(parent.is());
424 // components themselves have no parent but must have children
425 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<item oor:path=\""));
426 writeAttributeValue(handle, parentPathRepresentation);
427 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\">"));
428 if (node.is()) {
429 writeNode(components, handle, parent, nodeName, node);
430 } else {
431 switch (parent->kind()) {
432 case Node::KIND_LOCALIZED_PROPERTY:
433 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<value"));
434 if (!nodeName.isEmpty()) {
435 writeData_(
436 handle, RTL_CONSTASCII_STRINGPARAM(" xml:lang=\""));
437 writeAttributeValue(handle, nodeName);
438 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\""));
440 writeData_(
441 handle, RTL_CONSTASCII_STRINGPARAM(" oor:op=\"remove\"/>"));
442 break;
443 case Node::KIND_GROUP:
444 assert(
445 static_cast< GroupNode * >(parent.get())->isExtensible());
446 writeData_(
447 handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
448 writeAttributeValue(handle, nodeName);
449 writeData_(
450 handle,
451 RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"remove\"/>"));
452 break;
453 case Node::KIND_SET:
454 writeData_(
455 handle, RTL_CONSTASCII_STRINGPARAM("<node oor:name=\""));
456 writeAttributeValue(handle, nodeName);
457 writeData_(
458 handle,
459 RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"remove\"/>"));
460 break;
461 default:
462 assert(false); // this cannot happen
463 break;
466 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</item>\n"));
467 } else {
468 assert(node.is());
469 OUString pathRep(
470 parentPathRepresentation + "/" +
471 Data::createSegment(node->getTemplateName(), nodeName));
473 // copy configmgr::Modifications::Node's to a sortable list. Use pointers
474 // to just reference the data instead of copying it
475 std::vector< const ModNodePairEntry* > ModNodePairEntryVector;
476 ModNodePairEntryVector.reserve(modifications.children.size());
478 for (const auto& rCand : modifications.children)
480 ModNodePairEntryVector.push_back(&rCand);
483 // sort the list
484 std::sort(ModNodePairEntryVector.begin(), ModNodePairEntryVector.end(), PairEntrySorter());
486 // now use the list to write entries in sorted order
487 // instead of random as from the unordered map
488 for (const auto & i : ModNodePairEntryVector)
490 writeModifications(
491 components, handle, pathRep, node, i->first,
492 node->getMember(i->first), i->second);
499 void writeData(TempFile &handle, OString const & text) {
500 writeData_(handle, text.getStr(), text.getLength());
503 void writeAttributeValue(TempFile &handle, OUString const & value) {
504 sal_Int32 i = 0;
505 sal_Int32 j = i;
506 for (; j < value.getLength(); ++j) {
507 assert(
508 value[j] == 0x0009 || value[j] == 0x000A || value[j] == 0x000D ||
509 (value[j] >= 0x0020 && value[j] != 0xFFFE && value[j] != 0xFFFF));
510 switch(value[j]) {
511 case '\x09':
512 writeData(handle, convertToUtf8(value, i, j - i));
513 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&#9;"));
514 i = j + 1;
515 break;
516 case '\x0A':
517 writeData(handle, convertToUtf8(value, i, j - i));
518 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&#xA;"));
519 i = j + 1;
520 break;
521 case '\x0D':
522 writeData(handle, convertToUtf8(value, i, j - i));
523 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&#xD;"));
524 i = j + 1;
525 break;
526 case '"':
527 writeData(handle, convertToUtf8(value, i, j - i));
528 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&quot;"));
529 i = j + 1;
530 break;
531 case '&':
532 writeData(handle, convertToUtf8(value, i, j - i));
533 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&amp;"));
534 i = j + 1;
535 break;
536 case '<':
537 writeData(handle, convertToUtf8(value, i, j - i));
538 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&lt;"));
539 i = j + 1;
540 break;
541 default:
542 break;
545 writeData(handle, convertToUtf8(value, i, j - i));
548 void writeValueContent(TempFile &handle, OUString const & value) {
549 sal_Int32 i = 0;
550 sal_Int32 j = i;
551 for (; j < value.getLength(); ++j) {
552 sal_Unicode c = value[j];
553 if ((c < 0x0020 && c != 0x0009 && c != 0x000A && c != 0x000D) ||
554 c == 0xFFFE || c == 0xFFFF)
556 writeData(handle, convertToUtf8(value, i, j - i));
557 writeData_(
558 handle, RTL_CONSTASCII_STRINGPARAM("<unicode oor:scalar=\""));
559 writeData(
560 handle, OString::number(c));
561 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\"/>"));
562 i = j + 1;
563 } else if (c == '\x0D') {
564 writeData(handle, convertToUtf8(value, i, j - i));
565 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&#xD;"));
566 i = j + 1;
567 } else if (c == '&') {
568 writeData(handle, convertToUtf8(value, i, j - i));
569 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&amp;"));
570 i = j + 1;
571 } else if (c == '<') {
572 writeData(handle, convertToUtf8(value, i, j - i));
573 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&lt;"));
574 i = j + 1;
575 } else if (c == '>') {
576 // "MUST, for compatibility, be escaped [...] when it appears in the
577 // string ']]>'":
578 writeData(handle, convertToUtf8(value, i, j - i));
579 writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&gt;"));
580 i = j + 1;
583 writeData(handle, convertToUtf8(value, i, j - i));
586 void writeModFile(
587 Components & components, OUString const & url, Data const & data)
589 sal_Int32 i = url.lastIndexOf('/');
590 assert(i != -1);
591 OUString dir(url.copy(0, i));
592 switch (osl::Directory::createPath(dir)) {
593 case osl::FileBase::E_None:
594 case osl::FileBase::E_EXIST:
595 break;
596 case osl::FileBase::E_ACCES:
597 SAL_INFO(
598 "configmgr",
599 ("cannot create registrymodifications.xcu path (E_ACCES); changes"
600 " will be lost"));
601 return;
602 default:
603 throw css::uno::RuntimeException(
604 "cannot create directory " + dir);
606 TempFile tmp;
607 switch (osl::FileBase::createTempFile(&dir, &tmp.handle, &tmp.url)) {
608 case osl::FileBase::E_None:
609 break;
610 case osl::FileBase::E_ACCES:
611 SAL_INFO(
612 "configmgr",
613 ("cannot create temp registrymodifications.xcu (E_ACCES); changes"
614 " will be lost"));
615 return;
616 default:
617 throw css::uno::RuntimeException(
618 "cannot create temporary file in " + dir);
620 writeData_(
621 tmp,
622 RTL_CONSTASCII_STRINGPARAM(
623 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<oor:items"
624 " xmlns:oor=\"http://openoffice.org/2001/registry\""
625 " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
626 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"));
627 //TODO: Do not write back information about those removed items that did not
628 // come from the .xcs/.xcu files, anyway (but had been added dynamically
629 // instead):
631 // For profilesafemode it is necessary to detect changes in the
632 // registrymodifications file, this is done based on file size in bytes and crc32.
633 // Unfortunately this write is based on writing unordered map entries, which creates
634 // valid and semantically equal XML-Files, bubt with different crc32 checksums. For
635 // the future usage it will be preferable to have easily comparable config files
636 // which is guaranteed by writing the entries in sorted order. Indeed with this change
637 // (and in the recursive writeModifications call) the same config files get written
639 // copy configmgr::Modifications::Node's to a sortable list. Use pointers
640 // to just reference the data instead of copying it
641 std::vector< const ModNodePairEntry* > ModNodePairEntryVector;
642 ModNodePairEntryVector.reserve(data.modifications.getRoot().children.size());
644 for (const auto& rCand : data.modifications.getRoot().children)
646 ModNodePairEntryVector.push_back(&rCand);
649 // sort the list
650 std::sort(ModNodePairEntryVector.begin(), ModNodePairEntryVector.end(), PairEntrySorter());
652 // now use the list to write entries in sorted order
653 // instead of random as from the unordered map
654 for (const auto& j : ModNodePairEntryVector)
656 writeModifications(
657 components, tmp, "", rtl::Reference< Node >(), j->first,
658 data.getComponents().findNode(Data::NO_LAYER, j->first),
659 j->second);
661 writeData_(tmp, RTL_CONSTASCII_STRINGPARAM("</oor:items>\n"));
662 tmp.closeAndRename(url);
667 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */