LibreOffice Module configmgr (master) 1
writemodfile.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <cassert>
23#include <cstddef>
24#include <limits>
25#include <string_view>
26
27#include <com/sun/star/uno/Any.hxx>
28#include <com/sun/star/uno/RuntimeException.hpp>
29#include <com/sun/star/uno/Sequence.hxx>
30#include <o3tl/safeint.hxx>
31#include <osl/file.h>
32#include <osl/file.hxx>
33#include <rtl/string.h>
34#include <rtl/string.hxx>
35#include <rtl/textcvt.h>
36#include <rtl/textenc.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>
42
43#include "data.hxx"
44#include "groupnode.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"
53
54namespace configmgr {
55
56class Components;
57
58namespace {
59
60OString convertToUtf8(std::u16string_view text) {
61 OString s;
62 assert(text.size() <= o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max()));
63 if (!rtl_convertUStringToString(
64 &s.pData, text.data(), text.size(),
65 RTL_TEXTENCODING_UTF8,
66 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
67 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
68 {
69 throw css::uno::RuntimeException(
70 "cannot convert to UTF-8");
71 }
72 return s;
73}
74
75} // anonymous namespace
76
78 if (handle == nullptr)
79 return;
80
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);
85 }
86 }
87 osl::FileBase::RC e = osl::File::remove(url);
88 if (e != osl::FileBase::E_None) {
90 "configmgr",
91 "osl::File::remove(" << url << ") failed with " << +e);
92 }
93}
94
95#ifdef _WIN32
96oslFileError TempFile::closeWithoutUnlink() {
97 flush();
98 oslFileError e = osl_closeFile(handle);
99 handle = nullptr;
100 closed = true;
101 return e;
102}
103#endif
104
105void TempFile::closeAndRename(const OUString &_url) {
106 oslFileError e = flush();
107 if (e != osl_File_E_None) {
108 throw css::uno::RuntimeException(
109 "cannot write to " + url);
110 }
111 e = osl_closeFile(handle);
112 closed = true;
113 if (e != osl_File_E_None) {
114 throw css::uno::RuntimeException(
115 "cannot close " + url);
116 }
117 if (osl::File::replace(url, _url) != osl::FileBase::E_None) {
118 throw css::uno::RuntimeException(
119 "cannot move " + url);
120 }
121 handle = nullptr;
122}
123
124oslFileError TempFile::flush() {
125 oslFileError e = osl_File_E_None;
126 if (!buffer.isEmpty()) {
127 sal_uInt64 nBytesWritten = 0;
128 e = osl_writeFile(handle, buffer.getStr(),
129 static_cast< sal_uInt32 >(buffer.getLength()),
130 &nBytesWritten);
131 if (nBytesWritten != static_cast< sal_uInt32 >(buffer.getLength())) {
132 // queue up any error / exception until close.
133 buffer.remove(0, static_cast< sal_Int32 >( nBytesWritten ) );
134 } else {
135 buffer.setLength(0);
136 }
137 }
138 return e;
139}
140
141void TempFile::writeString(std::string_view text) {
142 buffer.append(text.data(), text.size());
143 if (buffer.getLength() > 0x10000)
144 flush();
145}
146
147namespace {
148
149void writeValueContent_(TempFile &, bool) = delete;
150 // silence loplugin:salbool
151void writeValueContent_(TempFile &handle, sal_Bool value) {
152 if (value) {
153 handle.writeString("true");
154 } else {
155 handle.writeString("false");
156 }
157}
158
159void writeValueContent_(TempFile &handle, sal_Int16 value) {
160 handle.writeString(OString::number(value));
161}
162
163void writeValueContent_(TempFile &handle, sal_Int32 value) {
164 handle.writeString(OString::number(value));
165}
166
167void writeValueContent_(TempFile &handle, sal_Int64 value) {
168 handle.writeString(OString::number(value));
169}
170
171void writeValueContent_(TempFile &handle, double value) {
172 handle.writeString(OString::number(value));
173}
174
175void writeValueContent_(TempFile &handle, std::u16string_view value) {
176 writeValueContent(handle, value);
177}
178
179void writeValueContent_(
180 TempFile &handle, css::uno::Sequence< sal_Int8 > const & value)
181{
182 for (const auto & v : value) {
183 static char const hexDigit[16] = {
184 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
185 'D', 'E', 'F' };
186 handle.writeString(
187 std::string_view(hexDigit + ((v >> 4) & 0xF), 1));
188 handle.writeString(std::string_view(hexDigit + (v & 0xF), 1));
189 }
190}
191
192template< typename T > void writeSingleValue(
193 TempFile &handle, css::uno::Any const & value)
194{
195 handle.writeString(">");
196 T val = T();
197 value >>= val;
198 writeValueContent_(handle, val);
199 handle.writeString("</value>");
200}
201
202template< typename T > void writeListValue(
203 TempFile &handle, css::uno::Any const & value)
204{
205 handle.writeString(">");
206 css::uno::Sequence< T > val;
207 value >>= val;
208 for (sal_Int32 i = 0; i < val.getLength(); ++i) {
209 if (i != 0) {
210 handle.writeString(" ");
211 }
212 writeValueContent_(handle, std::as_const(val)[i]);
213 }
214 handle.writeString("</value>");
215}
216
217template< typename T > void writeItemListValue(
218 TempFile &handle, css::uno::Any const & value)
219{
220 handle.writeString(">");
221 css::uno::Sequence< T > val;
222 value >>= val;
223 for (const auto & i : std::as_const(val)) {
224 handle.writeString("<it>");
225 writeValueContent_(handle, i);
226 handle.writeString("</it>");
227 }
228 handle.writeString("</value>");
229}
230
231void writeValue(TempFile &handle, Type type, css::uno::Any const & value) {
232 switch (type) {
233 case TYPE_BOOLEAN:
234 writeSingleValue< sal_Bool >(handle, value);
235 break;
236 case TYPE_SHORT:
237 writeSingleValue< sal_Int16 >(handle, value);
238 break;
239 case TYPE_INT:
240 writeSingleValue< sal_Int32 >(handle, value);
241 break;
242 case TYPE_LONG:
243 writeSingleValue< sal_Int64 >(handle, value);
244 break;
245 case TYPE_DOUBLE:
246 writeSingleValue< double >(handle, value);
247 break;
248 case TYPE_STRING:
249 writeSingleValue< OUString >(handle, value);
250 break;
251 case TYPE_HEXBINARY:
252 writeSingleValue< css::uno::Sequence< sal_Int8 > >(handle, value);
253 break;
255 writeListValue< sal_Bool >(handle, value);
256 break;
257 case TYPE_SHORT_LIST:
258 writeListValue< sal_Int16 >(handle, value);
259 break;
260 case TYPE_INT_LIST:
261 writeListValue< sal_Int32 >(handle, value);
262 break;
263 case TYPE_LONG_LIST:
264 writeListValue< sal_Int64 >(handle, value);
265 break;
266 case TYPE_DOUBLE_LIST:
267 writeListValue< double >(handle, value);
268 break;
269 case TYPE_STRING_LIST:
270 writeItemListValue< OUString >(handle, value);
271 break;
273 writeItemListValue< css::uno::Sequence< sal_Int8 > >(handle, value);
274 break;
275 default: // TYPE_ERROR, TYPE_NIL, TYPE_ANY
276 assert(false); // this cannot happen
277 }
278}
279
280void writeNode(
281 Components & components, TempFile &handle,
282 rtl::Reference< Node > const & parent, std::u16string_view name,
283 rtl::Reference< Node > const & node)
284{
285 static xmlreader::Span const typeNames[] = {
287 // TYPE_ERROR, TYPE_NIL, TYPE_ANY
288 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:boolean")),
289 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:short")),
290 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:int")),
291 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:long")),
292 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:double")),
293 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:string")),
294 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("xs:hexBinary")),
295 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:boolean-list")),
296 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:short-list")),
297 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:int-list")),
298 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:long-list")),
299 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:double-list")),
300 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:string-list")),
301 xmlreader::Span(RTL_CONSTASCII_STRINGPARAM("oor:hexBinary-list")) };
302 switch (node->kind()) {
304 {
305 PropertyNode * prop = static_cast< PropertyNode * >(node.get());
306 handle.writeString("<prop oor:name=\"");
307 writeAttributeValue(handle, name);
308 handle.writeString("\" oor:op=\"fuse\"");
309 Type type = prop->getStaticType();
310 Type dynType = getDynamicType(prop->getValue(components));
311 assert(dynType != TYPE_ERROR);
312 if (type == TYPE_ANY) {
313 type = dynType;
314 if (type != TYPE_NIL) {
315 handle.writeString(" oor:type=\"");
316 handle.writeString(
317 std::string_view(
318 typeNames[type].begin, typeNames[type].length));
319 handle.writeString("\"");
320 }
321 }
322 handle.writeString("><value");
323 if (dynType == TYPE_NIL) {
324 handle.writeString(" xsi:nil=\"true\"/>");
325 } else {
326 writeValue(handle, type, prop->getValue(components));
327 }
328 handle.writeString("</prop>");
329 }
330 break;
332 handle.writeString("<prop oor:name=\"");
333 writeAttributeValue(handle, name);
334 handle.writeString("\" oor:op=\"fuse\">");
335 for (auto const& member : node->getMembers())
336 {
337 writeNode(components, handle, node, member.first, member.second);
338 }
339 handle.writeString("</prop>");
340 break;
342 {
343 handle.writeString("<value");
344 if (!name.empty()) {
345 handle.writeString(" xml:lang=\"");
346 writeAttributeValue(handle, name);
347 handle.writeString("\"");
348 }
349 Type type = static_cast< LocalizedPropertyNode * >(parent.get())->
350 getStaticType();
351 css::uno::Any value(
352 static_cast< LocalizedValueNode * >(node.get())->getValue());
353 Type dynType = getDynamicType(value);
354 assert(dynType != TYPE_ERROR);
355 if (type == TYPE_ANY) {
356 type = dynType;
357 if (type != TYPE_NIL) {
358 handle.writeString(" oor:type=\"");
359 handle.writeString(
360 std::string_view(
361 typeNames[type].begin, typeNames[type].length));
362 handle.writeString("\"");
363 }
364 }
365 if (dynType == TYPE_NIL) {
366 handle.writeString(" xsi:nil=\"true\"/>");
367 } else {
368 writeValue(handle, type, value);
369 }
370 }
371 break;
372 case Node::KIND_GROUP:
373 case Node::KIND_SET:
374 handle.writeString("<node oor:name=\"");
375 writeAttributeValue(handle, name);
376 if (!node->getTemplateName().isEmpty()) { // set member
377 handle.writeString("\" oor:op=\"replace");
378 }
379 handle.writeString("\">");
380 for (auto const& member : node->getMembers())
381 {
382 writeNode(components, handle, node, member.first, member.second);
383 }
384 handle.writeString("</node>");
385 break;
386 case Node::KIND_ROOT:
387 assert(false); // this cannot happen
388 break;
389 }
390}
391
392// helpers to allow sorting of configmgr::Modifications::Node
393typedef std::pair< const OUString, configmgr::Modifications::Node > ModNodePairEntry;
394struct PairEntrySorter
395{
396 bool operator() (const ModNodePairEntry* pValue1, const ModNodePairEntry* pValue2) const
397 {
398 return pValue1->first.compareTo(pValue2->first) < 0;
399 }
400};
401
403 Components & components, TempFile &handle,
404 std::u16string_view parentPathRepresentation,
405 rtl::Reference< Node > const & parent, OUString const & nodeName,
406 rtl::Reference< Node > const & node,
407 Modifications::Node const & modifications)
408{
409 // It is never necessary to write oor:finalized or oor:mandatory attributes,
410 // as they cannot be set via the UNO API.
411 if (modifications.children.empty()) {
412 assert(parent.is());
413 // components themselves have no parent but must have children
414 handle.writeString("<item oor:path=\"");
415 writeAttributeValue(handle, parentPathRepresentation);
416 handle.writeString("\">");
417 if (node.is()) {
418 writeNode(components, handle, parent, nodeName, node);
419 } else {
420 switch (parent->kind()) {
422 handle.writeString("<value");
423 if (!nodeName.isEmpty()) {
424 handle.writeString(" xml:lang=\"");
425 writeAttributeValue(handle, nodeName);
426 handle.writeString("\"");
427 }
428 handle.writeString(" oor:op=\"remove\"/>");
429 break;
430 case Node::KIND_GROUP:
431 assert(
432 static_cast< GroupNode * >(parent.get())->isExtensible());
433 handle.writeString("<prop oor:name=\"");
434 writeAttributeValue(handle, nodeName);
435 handle.writeString("\" oor:op=\"remove\"/>");
436 break;
437 case Node::KIND_SET:
438 handle.writeString("<node oor:name=\"");
439 writeAttributeValue(handle, nodeName);
440 handle.writeString("\" oor:op=\"remove\"/>");
441 break;
442 default:
443 assert(false); // this cannot happen
444 break;
445 }
446 }
447 handle.writeString("</item>\n");
448 } else {
449 assert(node.is());
450 OUString pathRep(
451 OUString::Concat(parentPathRepresentation) + "/" +
452 Data::createSegment(node->getTemplateName(), nodeName));
453
454 // copy configmgr::Modifications::Node's to a sortable list. Use pointers
455 // to just reference the data instead of copying it
456 std::vector< const ModNodePairEntry* > ModNodePairEntryVector;
457 ModNodePairEntryVector.reserve(modifications.children.size());
458
459 for (const auto& rCand : modifications.children)
460 {
461 ModNodePairEntryVector.push_back(&rCand);
462 }
463
464 // sort the list
465 std::sort(ModNodePairEntryVector.begin(), ModNodePairEntryVector.end(), PairEntrySorter());
466
467 // now use the list to write entries in sorted order
468 // instead of random as from the unordered map
469 for (const auto & i : ModNodePairEntryVector)
470 {
472 components, handle, pathRep, node, i->first,
473 node->getMember(i->first), i->second);
474 }
475 }
476}
477
478}
479
480void writeAttributeValue(TempFile &handle, std::u16string_view value) {
481 std::size_t i = 0;
482 std::size_t j = i;
483 for (; j != value.size(); ++j) {
484 assert(
485 value[j] == 0x0009 || value[j] == 0x000A || value[j] == 0x000D ||
486 (value[j] >= 0x0020 && value[j] != 0xFFFE && value[j] != 0xFFFF));
487 switch(value[j]) {
488 case '\x09':
489 handle.writeString(convertToUtf8(value.substr(i, j - i)));
490 handle.writeString("&#9;");
491 i = j + 1;
492 break;
493 case '\x0A':
494 handle.writeString(convertToUtf8(value.substr(i, j - i)));
495 handle.writeString("&#xA;");
496 i = j + 1;
497 break;
498 case '\x0D':
499 handle.writeString(convertToUtf8(value.substr(i, j - i)));
500 handle.writeString("&#xD;");
501 i = j + 1;
502 break;
503 case '"':
504 handle.writeString(convertToUtf8(value.substr(i, j - i)));
505 handle.writeString("&quot;");
506 i = j + 1;
507 break;
508 case '&':
509 handle.writeString(convertToUtf8(value.substr(i, j - i)));
510 handle.writeString("&amp;");
511 i = j + 1;
512 break;
513 case '<':
514 handle.writeString(convertToUtf8(value.substr(i, j - i)));
515 handle.writeString("&lt;");
516 i = j + 1;
517 break;
518 default:
519 break;
520 }
521 }
522 handle.writeString(convertToUtf8(value.substr(i, j - i)));
523}
524
525void writeValueContent(TempFile &handle, std::u16string_view value) {
526 std::size_t i = 0;
527 std::size_t j = i;
528 for (; j != value.size(); ++j) {
529 char16_t c = value[j];
530 if ((c < 0x0020 && c != 0x0009 && c != 0x000A && c != 0x000D) ||
531 c == 0xFFFE || c == 0xFFFF)
532 {
533 handle.writeString(convertToUtf8(value.substr(i, j - i)));
534 handle.writeString("<unicode oor:scalar=\"");
535 handle.writeString(OString::number(c));
536 handle.writeString("\"/>");
537 i = j + 1;
538 } else if (c == '\x0D') {
539 handle.writeString(convertToUtf8(value.substr(i, j - i)));
540 handle.writeString("&#xD;");
541 i = j + 1;
542 } else if (c == '&') {
543 handle.writeString(convertToUtf8(value.substr(i, j - i)));
544 handle.writeString("&amp;");
545 i = j + 1;
546 } else if (c == '<') {
547 handle.writeString(convertToUtf8(value.substr(i, j - i)));
548 handle.writeString("&lt;");
549 i = j + 1;
550 } else if (c == '>') {
551 // "MUST, for compatibility, be escaped [...] when it appears in the
552 // string ']]>'":
553 handle.writeString(convertToUtf8(value.substr(i, j - i)));
554 handle.writeString("&gt;");
555 i = j + 1;
556 }
557 }
558 handle.writeString(convertToUtf8(value.substr(i, j - i)));
559}
560
562 Components & components, OUString const & url, Data const & data)
563{
564 sal_Int32 i = url.lastIndexOf('/');
565 assert(i != -1);
566 OUString dir(url.copy(0, i));
567 switch (osl::Directory::createPath(dir)) {
568 case osl::FileBase::E_None:
569 case osl::FileBase::E_EXIST:
570 break;
571 case osl::FileBase::E_ACCES:
572 SAL_INFO(
573 "configmgr",
574 ("cannot create registrymodifications.xcu path (E_ACCES); changes"
575 " will be lost"));
576 return;
577 default:
578 throw css::uno::RuntimeException(
579 "cannot create directory " + dir);
580 }
581 TempFile tmp;
582 switch (osl::FileBase::createTempFile(&dir, &tmp.handle, &tmp.url)) {
583 case osl::FileBase::E_None:
584 break;
585 case osl::FileBase::E_ACCES:
586 SAL_INFO(
587 "configmgr",
588 ("cannot create temp registrymodifications.xcu (E_ACCES); changes"
589 " will be lost"));
590 return;
591 default:
592 throw css::uno::RuntimeException(
593 "cannot create temporary file in " + dir);
594 }
595 tmp.writeString(
596 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<oor:items"
597 " xmlns:oor=\"http://openoffice.org/2001/registry\""
598 " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
599 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n");
600 //TODO: Do not write back information about those removed items that did not
601 // come from the .xcs/.xcu files, anyway (but had been added dynamically
602 // instead):
603
604 // For profilesafemode it is necessary to detect changes in the
605 // registrymodifications file, this is done based on file size in bytes and crc32.
606 // Unfortunately this write is based on writing unordered map entries, which creates
607 // valid and semantically equal XML-Files, bubt with different crc32 checksums. For
608 // the future usage it will be preferable to have easily comparable config files
609 // which is guaranteed by writing the entries in sorted order. Indeed with this change
610 // (and in the recursive writeModifications call) the same config files get written
611
612 // copy configmgr::Modifications::Node's to a sortable list. Use pointers
613 // to just reference the data instead of copying it
614 std::vector< const ModNodePairEntry* > ModNodePairEntryVector;
615 ModNodePairEntryVector.reserve(data.modifications.getRoot().children.size());
616
617 for (const auto& rCand : data.modifications.getRoot().children)
618 {
619 ModNodePairEntryVector.push_back(&rCand);
620 }
621
622 // sort the list
623 std::sort(ModNodePairEntryVector.begin(), ModNodePairEntryVector.end(), PairEntrySorter());
624
625 // now use the list to write entries in sorted order
626 // instead of random as from the unordered map
627 for (const auto& j : ModNodePairEntryVector)
628 {
630 components, tmp, u"", rtl::Reference< Node >(), j->first,
631 data.getComponents().findNode(Data::NO_LAYER, j->first),
632 j->second);
633 }
634 tmp.writeString("</oor:items>\n");
635 tmp.closeAndRename(url);
636}
637
638}
639
640/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Node const & getRoot() const
rtl::Reference< Node > findNode(int layer, OUString const &name) const
Definition: nodemap.cxx:43
@ KIND_LOCALIZED_PROPERTY
Definition: node.hxx:35
@ KIND_LOCALIZED_VALUE
Definition: node.hxx:35
Any value
OUString name
Definition: components.cxx:85
float u
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
def text(shape, orig_st)
void writeModifications(Components &components, Data &data)
Definition: dconf.cxx:1560
void writeValueContent(TempFile &handle, std::u16string_view value)
void writeModFile(Components &components, OUString const &url, Data const &data)
@ TYPE_HEXBINARY_LIST
Definition: type.hxx:36
@ TYPE_HEXBINARY
Definition: type.hxx:34
@ TYPE_BOOLEAN
Definition: type.hxx:33
@ TYPE_STRING_LIST
Definition: type.hxx:36
@ TYPE_INT_LIST
Definition: type.hxx:35
@ TYPE_NIL
Definition: type.hxx:33
@ TYPE_ANY
Definition: type.hxx:33
@ TYPE_DOUBLE
Definition: type.hxx:34
@ TYPE_LONG
Definition: type.hxx:34
@ TYPE_BOOLEAN_LIST
Definition: type.hxx:34
@ TYPE_SHORT
Definition: type.hxx:33
@ TYPE_INT
Definition: type.hxx:33
@ TYPE_DOUBLE_LIST
Definition: type.hxx:35
@ TYPE_STRING
Definition: type.hxx:34
@ TYPE_ERROR
Definition: type.hxx:33
@ TYPE_LONG_LIST
Definition: type.hxx:35
@ TYPE_SHORT_LIST
Definition: type.hxx:35
Type getDynamicType(css::uno::Any const &value)
Definition: type.cxx:101
void writeAttributeValue(TempFile &handle, std::u16string_view value)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
Modifications modifications
Definition: data.hxx:51
NodeMap & getComponents() const
Definition: data.cxx:294
static OUString createSegment(std::u16string_view templateName, OUString const &name)
Definition: data.cxx:81
void writeString(std::string_view text)
void closeAndRename(const OUString &url)
oslFileHandle handle
oslFileError flush()
OStringBuffer buffer
unsigned char sal_Bool
ResultType type
std::vector< uno::Reference< sheet::XSpreadsheetDocument > > Components