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 .
20 #include "sal/config.h"
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"
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 "sal/log.hxx"
39 #include "sal/types.h"
40 #include "xmlreader/span.hxx"
43 #include "groupnode.hxx"
44 #include "localizedpropertynode.hxx"
45 #include "localizedvaluenode.hxx"
46 #include "modifications.hxx"
48 #include "nodemap.hxx"
49 #include "propertynode.hxx"
51 #include "writemodfile.hxx"
59 OString
convertToUtf8(
60 OUString
const & text
, sal_Int32 offset
, sal_Int32 length
)
62 assert(offset
<= text
.getLength() && text
.getLength() - offset
>= length
);
64 if (!rtl_convertUStringToString(
65 &s
.pData
, text
.pData
->buffer
+ offset
, length
,
66 RTL_TEXTENCODING_UTF8
,
67 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
68 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
70 throw css::uno::RuntimeException(
71 OUString("cannot convert to UTF-8"),
72 css::uno::Reference
< css::uno::XInterface
>());
77 struct TempFile
: public boost::noncopyable
{
82 TempFile(): handle(0), closed(false) {}
87 TempFile::~TempFile() {
90 oslFileError e
= osl_closeFile(handle
);
91 if (e
!= osl_File_E_None
) {
92 SAL_WARN("configmgr", "osl_closeFile failed with " << +e
);
95 osl::FileBase::RC e
= osl::File::remove(url
);
96 if (e
!= osl::FileBase::E_None
) {
99 "osl::File::remove(" << url
<< ") failed with " << +e
);
106 void writeData(oslFileHandle handle
, char const * begin
, sal_Int32 length
) {
109 if ((osl_writeFile(handle
, begin
, static_cast< sal_uInt32
>(length
), &n
) !=
111 n
!= static_cast< sal_uInt32
>(length
))
113 throw css::uno::RuntimeException(
114 OUString("write failure"),
115 css::uno::Reference
< css::uno::XInterface
>());
119 void writeData(oslFileHandle handle
, OString
const & text
) {
120 writeData(handle
, text
.getStr(), text
.getLength());
123 void writeAttributeValue(oslFileHandle handle
, OUString
const & value
) {
126 for (; j
< value
.getLength(); ++j
) {
128 value
[j
] == 0x0009 || value
[j
] == 0x000A || value
[j
] == 0x000D ||
129 (value
[j
] >= 0x0020 && value
[j
] != 0xFFFE && value
[j
] != 0xFFFF));
132 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
133 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("	"));
137 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
138 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("
"));
142 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
143 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("
"));
147 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
148 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("""));
152 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
153 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("&"));
157 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
158 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<"));
165 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
168 void writeValueContent(oslFileHandle handle
, sal_Bool value
) {
170 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("true"));
172 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("false"));
176 void writeValueContent(oslFileHandle handle
, sal_Int16 value
) {
177 writeData(handle
, OString::number(value
));
180 void writeValueContent(oslFileHandle handle
, sal_Int32 value
) {
181 writeData(handle
, OString::valueOf(value
));
184 void writeValueContent(oslFileHandle handle
, sal_Int64 value
) {
185 writeData(handle
, OString::valueOf(value
));
188 void writeValueContent(oslFileHandle handle
, double value
) {
189 writeData(handle
, OString::valueOf(value
));
192 void writeValueContent(oslFileHandle handle
, OUString
const & value
) {
195 for (; j
< value
.getLength(); ++j
) {
196 sal_Unicode c
= value
[j
];
197 if ((c
< 0x0020 && c
!= 0x0009 && c
!= 0x000A && c
!= 0x000D) ||
198 c
== 0xFFFE || c
== 0xFFFF)
200 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
202 handle
, RTL_CONSTASCII_STRINGPARAM("<unicode oor:scalar=\""));
204 handle
, OString::number(c
));
205 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\"/>"));
207 } else if (c
== '\x0D') {
208 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
209 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("
"));
211 } else if (c
== '&') {
212 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
213 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("&"));
215 } else if (c
== '<') {
216 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
217 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<"));
219 } else if (c
== '>') {
220 // "MUST, for compatibility, be escaped [...] when it appears in the
222 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
223 writeData(handle
, RTL_CONSTASCII_STRINGPARAM(">"));
227 writeData(handle
, convertToUtf8(value
, i
, j
- i
));
230 void writeValueContent(
231 oslFileHandle handle
, css::uno::Sequence
< sal_Int8
> const & value
)
233 for (sal_Int32 i
= 0; i
< value
.getLength(); ++i
) {
234 static char const hexDigit
[16] = {
235 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
237 writeData(handle
, hexDigit
+ ((value
[i
] >> 4) & 0xF), 1);
238 writeData(handle
, hexDigit
+ (value
[i
] & 0xF), 1);
242 template< typename T
> void writeSingleValue(
243 oslFileHandle handle
, css::uno::Any
const & value
)
245 writeData(handle
, RTL_CONSTASCII_STRINGPARAM(">"));
248 writeValueContent(handle
, val
);
249 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("</value>"));
252 template< typename T
> void writeListValue(
253 oslFileHandle handle
, css::uno::Any
const & value
)
255 writeData(handle
, RTL_CONSTASCII_STRINGPARAM(">"));
256 css::uno::Sequence
< T
> val
;
258 for (sal_Int32 i
= 0; i
< val
.getLength(); ++i
) {
260 writeData(handle
, RTL_CONSTASCII_STRINGPARAM(" "));
262 writeValueContent(handle
, val
[i
]);
264 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("</value>"));
267 template< typename T
> void writeItemListValue(
268 oslFileHandle handle
, css::uno::Any
const & value
)
270 writeData(handle
, RTL_CONSTASCII_STRINGPARAM(">"));
271 css::uno::Sequence
< T
> val
;
273 for (sal_Int32 i
= 0; i
< val
.getLength(); ++i
) {
274 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<it>"));
275 writeValueContent(handle
, val
[i
]);
276 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("</it>"));
278 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("</value>"));
281 void writeValue(oslFileHandle handle
, Type type
, css::uno::Any
const & value
) {
284 writeSingleValue
< sal_Bool
>(handle
, value
);
287 writeSingleValue
< sal_Int16
>(handle
, value
);
290 writeSingleValue
< sal_Int32
>(handle
, value
);
293 writeSingleValue
< sal_Int64
>(handle
, value
);
296 writeSingleValue
< double >(handle
, value
);
299 writeSingleValue
< OUString
>(handle
, value
);
302 writeSingleValue
< css::uno::Sequence
< sal_Int8
> >(handle
, value
);
304 case TYPE_BOOLEAN_LIST
:
305 writeListValue
< sal_Bool
>(handle
, value
);
307 case TYPE_SHORT_LIST
:
308 writeListValue
< sal_Int16
>(handle
, value
);
311 writeListValue
< sal_Int32
>(handle
, value
);
314 writeListValue
< sal_Int64
>(handle
, value
);
316 case TYPE_DOUBLE_LIST
:
317 writeListValue
< double >(handle
, value
);
319 case TYPE_STRING_LIST
:
320 writeItemListValue
< OUString
>(handle
, value
);
322 case TYPE_HEXBINARY_LIST
:
323 writeItemListValue
< css::uno::Sequence
< sal_Int8
> >(handle
, value
);
325 default: // TYPE_ERROR, TYPE_NIL, TYPE_ANY
326 assert(false); // this cannot happen
331 Components
& components
, oslFileHandle handle
,
332 rtl::Reference
< Node
> const & parent
, OUString
const & name
,
333 rtl::Reference
< Node
> const & node
)
335 static xmlreader::Span
const typeNames
[] = {
336 xmlreader::Span(), xmlreader::Span(), xmlreader::Span(),
337 // TYPE_ERROR, TYPE_NIL, TYPE_ANY
338 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:boolean")),
339 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:short")),
340 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:int")),
341 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:long")),
342 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:double")),
343 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:string")),
344 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:hexBinary")),
345 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:boolean-list")),
346 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:short-list")),
347 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:int-list")),
348 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:long-list")),
349 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:double-list")),
350 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:string-list")),
351 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:hexBinary-list")) };
352 switch (node
->kind()) {
353 case Node::KIND_PROPERTY
:
355 PropertyNode
* prop
= dynamic_cast< PropertyNode
* >(node
.get());
356 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
357 writeAttributeValue(handle
, name
);
358 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"fuse\""));
359 Type type
= prop
->getStaticType();
360 Type dynType
= getDynamicType(prop
->getValue(components
));
361 assert(dynType
!= TYPE_ERROR
);
362 if (type
== TYPE_ANY
) {
364 if (type
!= TYPE_NIL
) {
366 handle
, RTL_CONSTASCII_STRINGPARAM(" oor:type=\""));
368 handle
, typeNames
[type
].begin
, typeNames
[type
].length
);
369 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\""));
372 writeData(handle
, "><value");
373 if (dynType
== TYPE_NIL
) {
375 handle
, RTL_CONSTASCII_STRINGPARAM(" xsi:nil=\"true\"/>"));
377 writeValue(handle
, type
, prop
->getValue(components
));
379 writeData(handle
, "</prop>");
382 case Node::KIND_LOCALIZED_PROPERTY
:
383 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
384 writeAttributeValue(handle
, name
);
385 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"fuse\">"));
386 for (NodeMap::const_iterator
i(node
->getMembers().begin());
387 i
!= node
->getMembers().end(); ++i
)
389 writeNode(components
, handle
, node
, i
->first
, i
->second
);
391 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("</prop>"));
393 case Node::KIND_LOCALIZED_VALUE
:
395 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<value"));
396 if (!name
.isEmpty()) {
397 writeData(handle
, RTL_CONSTASCII_STRINGPARAM(" xml:lang=\""));
398 writeAttributeValue(handle
, name
);
399 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\""));
401 Type type
= dynamic_cast< LocalizedPropertyNode
* >(parent
.get())->
404 dynamic_cast< LocalizedValueNode
* >(node
.get())->getValue());
405 Type dynType
= getDynamicType(value
);
406 assert(dynType
!= TYPE_ERROR
);
407 if (type
== TYPE_ANY
) {
409 if (type
!= TYPE_NIL
) {
411 handle
, RTL_CONSTASCII_STRINGPARAM(" oor:type=\""));
413 handle
, typeNames
[type
].begin
, typeNames
[type
].length
);
414 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\""));
417 if (dynType
== TYPE_NIL
) {
419 handle
, RTL_CONSTASCII_STRINGPARAM(" xsi:nil=\"true\"/>"));
421 writeValue(handle
, type
, value
);
425 case Node::KIND_GROUP
:
427 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<node oor:name=\""));
428 writeAttributeValue(handle
, name
);
429 if (!node
->getTemplateName().isEmpty()) { // set member
431 handle
, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"replace"));
433 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\">"));
434 for (NodeMap::const_iterator
i(node
->getMembers().begin());
435 i
!= node
->getMembers().end(); ++i
)
437 writeNode(components
, handle
, node
, i
->first
, i
->second
);
439 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("</node>"));
441 case Node::KIND_ROOT
:
442 assert(false); // this cannot happen
447 void writeModifications(
448 Components
& components
, oslFileHandle handle
,
449 OUString
const & parentPathRepresentation
,
450 rtl::Reference
< Node
> const & parent
, OUString
const & nodeName
,
451 rtl::Reference
< Node
> const & node
,
452 Modifications::Node
const & modifications
)
454 // It is never necessary to write oor:finalized or oor:mandatory attributes,
455 // as they cannot be set via the UNO API.
456 if (modifications
.children
.empty()) {
458 // components themselves have no parent but must have children
459 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<item oor:path=\""));
460 writeAttributeValue(handle
, parentPathRepresentation
);
461 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\">"));
463 writeNode(components
, handle
, parent
, nodeName
, node
);
465 switch (parent
->kind()) {
466 case Node::KIND_LOCALIZED_PROPERTY
:
467 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("<value"));
468 if (!nodeName
.isEmpty()) {
470 handle
, RTL_CONSTASCII_STRINGPARAM(" xml:lang=\""));
471 writeAttributeValue(handle
, nodeName
);
472 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("\""));
475 handle
, RTL_CONSTASCII_STRINGPARAM(" oor:op=\"remove\"/>"));
477 case Node::KIND_GROUP
:
479 dynamic_cast< GroupNode
* >(parent
.get())->isExtensible());
481 handle
, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
482 writeAttributeValue(handle
, nodeName
);
485 RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"remove\"/>"));
489 handle
, RTL_CONSTASCII_STRINGPARAM("<node oor:name=\""));
490 writeAttributeValue(handle
, nodeName
);
493 RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"remove\"/>"));
496 assert(false); // this cannot happen
500 writeData(handle
, RTL_CONSTASCII_STRINGPARAM("</item>\n"));
504 parentPathRepresentation
+
506 Data::createSegment(node
->getTemplateName(), nodeName
));
507 for (Modifications::Node::Children::const_iterator
i(
508 modifications
.children
.begin());
509 i
!= modifications
.children
.end(); ++i
)
512 components
, handle
, pathRep
, node
, i
->first
,
513 node
->getMember(i
->first
), i
->second
);
519 Components
& components
, OUString
const & url
, Data
const & data
)
521 sal_Int32 i
= url
.lastIndexOf('/');
523 OUString
dir(url
.copy(0, i
));
524 switch (osl::Directory::createPath(dir
)) {
525 case osl::FileBase::E_None
:
526 case osl::FileBase::E_EXIST
:
528 case osl::FileBase::E_ACCES
:
531 ("cannot create registrymodifications.xcu path (E_ACCES); changes"
535 throw css::uno::RuntimeException(
536 (OUString("cannot create directory ") +
538 css::uno::Reference
< css::uno::XInterface
>());
541 switch (osl::FileBase::createTempFile(&dir
, &tmp
.handle
, &tmp
.url
)) {
542 case osl::FileBase::E_None
:
544 case osl::FileBase::E_ACCES
:
547 ("cannot create temp registrymodifications.xcu (E_ACCES); changes"
551 throw css::uno::RuntimeException(
552 (OUString("cannot create temporary file in ") +
554 css::uno::Reference
< css::uno::XInterface
>());
558 RTL_CONSTASCII_STRINGPARAM(
559 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<oor:items"
560 " xmlns:oor=\"http://openoffice.org/2001/registry\""
561 " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
562 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"));
563 //TODO: Do not write back information about those removed items that did not
564 // come from the .xcs/.xcu files, anyway (but had been added dynamically
566 for (Modifications::Node::Children::const_iterator
j(
567 data
.modifications
.getRoot().children
.begin());
568 j
!= data
.modifications
.getRoot().children
.end(); ++j
)
571 components
, tmp
.handle
, OUString(), rtl::Reference
< Node
>(),
573 Data::findNode(Data::NO_LAYER
, data
.getComponents(), j
->first
),
576 writeData(tmp
.handle
, RTL_CONSTASCII_STRINGPARAM("</oor:items>\n"));
577 oslFileError e
= osl_closeFile(tmp
.handle
);
579 if (e
!= osl_File_E_None
) {
580 throw css::uno::RuntimeException(
581 (OUString("cannot close ") +
583 css::uno::Reference
< css::uno::XInterface
>());
585 if (osl::File::move(tmp
.url
, url
) != osl::FileBase::E_None
) {
586 throw css::uno::RuntimeException(
587 (OUString("cannot move ") +
589 css::uno::Reference
< css::uno::XInterface
>());
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */